pub struct WasapiCaptureSource { /* private fields */ }wasapi-capture and (crate features dxgi-capture or wasapi-capture) only.Expand description
Captures audio via WASAPI (IAudioClient/IAudioCaptureClient) —
GStreamer’s wasapi2src equivalent. One src pad, pushing
MediaBuffer::Audio frames in the captured device’s own native mix
format/rate/channel count — no resampling. Same division of labor as
crate::elements::DxgiCaptureSource emitting raw Pixel::BGRA and
leaving conversion to a downstream crate::elements::Scaler: if
something downstream needs a fixed sample rate/format, use
crate::elements::AudioResampler rather than hiding conversion in
this element.
Polls IAudioCaptureClient::GetNextPacketSize on a short fixed
interval (POLL_INTERVAL) rather than waiting on a WASAPI-signaled
event — see that constant’s own docs on why event-driven mode isn’t
used here.
Emits continuously from the moment run starts, pts always in
lockstep with wall-clock time — backed by real WASAPI data when it’s
available and synthesized silence otherwise (see
WasapiCaptureSource::fill_silence_gap), since WASAPI itself
delivers literally nothing whenever the render engine has no active
session at all (e.g. nothing currently playing, for
WasapiDeviceKind::Render). Without this, a quiet period would be a
real gap in the audio timeline rather than silence, which would leave
a downstream muxer/encoder with no way to keep audio and video in
sync across it.
Every WASAPI object here is created by WasapiCaptureSource::open on
its caller’s thread, then actually driven by SourceElement::run on
whichever thread crate::pipeline::Pipeline spawns for this source
— a different thread in the normal case. COM requires every thread
that touches an interface to have joined an apartment itself (even
though the interfaces here are free-threaded/agile and can be handed
across threads freely), so run makes its own CoInitializeEx call
before touching anything, paired with CoUninitialize when it returns
— the same two-CoInitializeEx-calls-per-object-lifetime pattern
cpal’s own WASAPI backend uses. open also joins its caller’s COM
apartment while it creates the agile WASAPI interfaces, then balances
that call before returning; the pipeline worker joins its own apartment
independently in run.
Deliberately does not retry internally on
AUDCLNT_E_DEVICE_INVALIDATED (default device changed, unplugged,
format changed) — same “fail fast, caller rebuilds” contract as
DxgiCaptureSource/RtspSource; watch for
WasapiCaptureSourceError::DeviceInvalidated and call
WasapiCaptureSource::open again.
Runs until Stop — never reaches Eos on its own, same as every other
live source in this crate.
Implementations§
Source§impl WasapiCaptureSource
impl WasapiCaptureSource
Sourcepub fn list_devices() -> Result<Vec<WasapiDevice>, WasapiCaptureSourceError>
pub fn list_devices() -> Result<Vec<WasapiDevice>, WasapiCaptureSourceError>
Enumerates every currently-active audio endpoint — both Render
(playback) and Capture (recording) — as an WasapiDevice list a
caller can show in a picker UI and index/search into, then hand the
chosen entry straight to WasapiCaptureOptions::device. No
concept of “mode” to reason about beforehand: the picked device’s
own WasapiDeviceKind is what tells open whether to use
loopback.
Sourcepub fn open(
name: impl Into<String>,
options: WasapiCaptureOptions,
) -> Result<(Self, u32, u16), WasapiCaptureSourceError>
pub fn open( name: impl Into<String>, options: WasapiCaptureOptions, ) -> Result<(Self, u32, u16), WasapiCaptureSourceError>
Opens options.device and starts a shared-mode WASAPI capture
session. Returns the element alongside the captured stream’s
actual (sample_rate, channels) — what a caller needs to build a
matching downstream encoder/muxer, same pattern as
crate::elements::DxgiCaptureSource::open returning
(width, height).
Trait Implementations§
Source§impl Element for WasapiCaptureSource
impl Element for WasapiCaptureSource
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 WasapiCaptureSource
Source§impl SourceElement for WasapiCaptureSource
impl SourceElement for WasapiCaptureSource
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