What draining pending source requests actually did — whether Stop or
source-only Finish ended it, and how long (if any) was spent frozen
inside a Pause/Resume pair. A source built on wall-clock scheduling (an elapsed-time
budget like crate::elements::TestAudioSource/
crate::elements::AudioMixer, or an absolute next-tick deadline like
crate::elements::TestVideoSource/DxgiCaptureSource)
has to fold paused_for back into its own schedule after every
drain_control call — real (Instant) time keeps moving during a
Pause, but the media timeline must not, or Resume would look like a
burst of catch-up work owed all at once.
The receiving half — not Clone in spirit (only one thing should be
driving a given control channel at a time) but crossbeam’s
Receiver<T> is a cheap shared handle under the hood, which is
exactly what crate::pipeline::Pipeline::run needs: it clones this
into a fresh worker thread on every call.
The sending half of a control channel — cloneable, cheap, Send + Sync. crate::pipeline::Pipeline holds one to reach its source;
crate::queue::Queue holds one internally to reach its worker
thread across the thread boundary it owns.
A command that can be sent down a running crate::pipeline::Pipeline
— travels the same pad-to-pad path MediaBuffer does (see
crate::element::Sink::control), but through a dedicated channel
instead of riding along as data: unlike Eos, it has to be able to
reach every element even mid-stream, and (for Queue) jump ahead of
whatever data is already backed up rather than wait in line behind it.
Call once per loop iteration in a SourceElement::run implementation,
right before pulling the next unit of work — mirrors how a natural
Eos is pushed into the source’s own pads at the end of that same
loop, just for externally-triggered control instead.