pub struct AudioMixer { /* private fields */ }Expand description
Sums an arbitrary, dynamically-changing number of audio sources into
one output stream — the structural mirror of crate::elements::Tee:
Tee is one input fanned out to a dynamic set of outputs behind a
lock; AudioMixer is a dynamic set of inputs (added/removed via
MixerHandle, from whatever thread each one’s own source pipeline
runs on) summed into one output. Unlike Tee, which is a passive
Sink driven entirely by whatever calls consume, AudioMixer has
to drive itself: it’s a SourceElement with its own run thread,
ticking every TICK_INTERVAL to sum however many samples each
currently-attached input has ready — because mixing has to keep
producing something on a steady clock even when some (or all) inputs
have gone quiet, the same reason
WasapiCaptureSource synthesizes silence for gaps
rather than just emitting nothing.
Every input is resampled to this mixer’s own fixed
sample_rate/channels (always Sample::F32(Packed) internally —
float headroom during summation, same reason real mixing consoles
work in float even when everything else is integer PCM) — an input
short on samples for a given tick contributes silence for the
shortfall rather than blocking the whole mix. Samples are summed and
hard-clipped to [-1.0, 1.0], not averaged: two or three sources
is the expected case, where clipping is rare, and averaging would
quietly lower the whole mix’s volume every time a source count
changes — a caller who wants headroom can lower an individual input’s
gain before it ever reaches the mixer (not implemented — nothing needs
it yet).
pts is a plain, always-continuous sample count (see
AudioMixer::time_base), advancing in lockstep with wall-clock time
regardless of which/how many inputs are actually contributing at any
moment.
Runs until Stop — never reaches Eos on its own, same as every
other live source in this crate; an individual input reaching Eos or
being removed just drops out of future ticks, it doesn’t end the mix.
Implementations§
Source§impl AudioMixer
impl AudioMixer
Sourcepub fn new(
name: impl Into<String>,
options: AudioMixerOptions,
) -> (Self, MixerHandle)
pub fn new( name: impl Into<String>, options: AudioMixerOptions, ) -> (Self, MixerHandle)
Starts with no inputs — add some via the returned MixerHandle
before (or any time after) wiring AudioMixer into a
crate::pipeline::Pipeline (Pipeline::new registers it as that
pipeline’s own source automatically, same as any other
SourceElement — no crate::element::Context needed here,
unlike crate::elements::TeeBuilder::new, since AudioMixer has no
chains of its own for a handle to build).
Trait Implementations§
Source§impl Element for AudioMixer
impl Element for AudioMixer
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.impl Send for AudioMixer
Source§impl SourceElement for AudioMixer
impl SourceElement for AudioMixer
Source§fn run(&mut self, control: &ControlReceiver, bus: &Bus) -> Result<()>
fn run(&mut self, control: &ControlReceiver, bus: &Bus) -> Result<()>
Eos (normal completion),
crate::pipeline::Pipeline::finish, or Stop (see
ControlMsg::Stop) — call crate::control::drain_control
once per loop iteration to make control responsive between
blocking reads. Read moreSource§fn seek(&mut self, _target: Duration) -> Result<Duration>
fn seek(&mut self, _target: Duration) -> Result<Duration>
target, an absolute position from the
start of the media (e.g. av_seek_frame for
crate::elements::FileDemuxer). Called by
crate::control::drain_control as part of handling
ControlMsg::Seek, before that message is forwarded to the
source’s own pads — so whatever’s read next comes from the new
position by the time downstream elements are told to flush for it. Read more