pub struct Queue { /* private fields */ }Expand description
An explicit thread boundary.
Pushing into a Queue hands the buffer off through a bounded channel
and returns immediately — it never blocks the caller on whatever is
downstream (unless the channel is full and policy is Block). A
dedicated worker thread owns everything downstream of the queue and
drives it via direct Sink::consume calls, until it hits another
Queue.
ControlMsg crosses this same thread boundary through a separate
channel from data. The worker checks that channel before entering its
combined wait on every iteration, so a control message already pending
at that point jumps ahead of the data backlog. A control message that
arrives in the narrow window after that check can race one ready data
buffer in select!, but is checked again before another buffer is
pulled. Every worker acks a control message before acting on
it any further (e.g. before blocking on Pause), so the channel stays
responsive to the next one — Resume/Stop always reaches a paused
worker immediately, it’s never stuck behind the pause itself. See the
worker loop below.
Cheap elements (e.g. a muxer sitting right after an encoder) should
simply not have a Queue between them and their upstream — they run
as a direct call on the upstream element’s thread instead of paying for
a dedicated thread they don’t need.
A failing downstream.consume() doesn’t end the worker thread either —
that buffer is dropped, BusEvent::Error is posted, and the loop moves
on to the next one. This crate never decides an error is fatal on your
behalf; watch crate::pipeline::Pipeline::bus and call
crate::pipeline::Pipeline::stop yourself if a particular error
means the whole pipeline should end.
Implementations§
Source§impl Queue
impl Queue
Sourcepub fn spawn(
name: impl Into<String>,
capacity: usize,
downstream: Box<dyn Sink>,
bus: Bus,
pipeline_id: Option<&str>,
) -> Queue
pub fn spawn( name: impl Into<String>, capacity: usize, downstream: Box<dyn Sink>, bus: Bus, pipeline_id: Option<&str>, ) -> Queue
Spawns with OverflowPolicy::default. Use
Queue::spawn_with_policy to drop instead of blocking when full.
Sourcepub fn spawn_with_policy(
name: impl Into<String>,
capacity: usize,
downstream: Box<dyn Sink>,
bus: Bus,
policy: OverflowPolicy,
pipeline_id: Option<&str>,
) -> Queue
pub fn spawn_with_policy( name: impl Into<String>, capacity: usize, downstream: Box<dyn Sink>, bus: Bus, policy: OverflowPolicy, pipeline_id: Option<&str>, ) -> Queue
Spawns the worker thread that owns downstream and starts pulling
from the channel immediately. pipeline_id (typically the owning
crate::pipeline::Pipeline’s own id — see
crate::pipeline::ChainBuilder, which is what actually passes
one when this Queue came from a .queue()/.queue_with_policy()
call) becomes this Queue’s pp_log pipeline_id; None if it
wasn’t built through a Pipeline at all (e.g. the tests below).
Trait Implementations§
Source§impl Element for Queue
impl Element for Queue
Source§fn name(&self) -> Arc<str> ⓘ
fn name(&self) -> Arc<str> ⓘ
crate::bus::BusEvent stores names as
Arc<str> for exactly this reason: a hot path like
crate::queue::Queue posting BusEvent::Dropped once per
overflowed buffer shouldn’t pay for a fresh heap allocation every
time it wants to report which element it is.Source§fn element_type(&self) -> ElementType
fn element_type(&self) -> ElementType
ElementType.Source§fn pp_log(&self) -> &PpLog
fn pp_log(&self) -> &PpLog
crate::bus::Bus::post — same
id/name as Element::name, just already wrapped as the
crate::pp_log::PpLog its pp_info!/pp_warn!/pp_error! macros need. A
stored private field, not built fresh per call, for the same reason
name() returns a cheap Arc<str> clone instead of a fresh String
— see its own docs.Source§fn pp_log_mut(&mut self) -> &mut PpLog
fn pp_log_mut(&mut self) -> &mut PpLog
Element::pp_log reads — used by
crate::pipeline::ChainBuilder to stamp the owning
crate::pipeline::Pipeline’s id onto every element that
passes through it, via element_pp_log. Not meant to be called
from anywhere else.Source§impl Sink for Queue
impl Sink for Queue
fn consume(&mut self, buf: MediaBuffer) -> Result<()>
Source§fn control(&mut self, msg: ControlMsg) -> Result<()>
fn control(&mut self, msg: ControlMsg) -> Result<()>
ControlMsg (pause/resume/stop) and, for anything
with a downstream of its own, forwards it on — same shape as
consume, just a separate channel from MediaBuffer so it can
reach every element (not just ones that already know how to
interpret a data buffer) and, at a crate::queue::Queue, jump
ahead of whatever data is backed up instead of waiting behind it.
No default: every Sink has to consciously decide what this means
for it, rather than silently dropping it.