Skip to main content

MicrophoneStream

Struct MicrophoneStream 

Source
pub struct MicrophoneStream { /* private fields */ }
Expand description

An open capture stream you pull AudioChunks from.

Obtained from Microphone::start. Read audio with next_chunk (blocking, with a timeout) or try_next_chunk (non-blocking). Call stop to end capture and release the device; dropping the handle also releases it. The type is Send + Sync.

Implementations§

Source§

impl MicrophoneStream

Source

pub fn receiver(&self) -> &Receiver<AudioChunk>

Direct access to the underlying crossbeam_channel::Receiver.

Intended for in-process Rust consumers and for bindings (like the decibri Node.js addon) that integrate the channel into their own drain pump or event loop.

FFI bindings targeting languages without native crossbeam_channel support, such as Python and the eventual mobile platforms, should prefer try_next_chunk and next_chunk: they expose the same data with a three-state return (Some / None / Err(MicrophoneStreamClosed)) that maps cleanly across a language boundary.

Source

pub fn try_next_chunk( &self, samples: usize, ) -> Result<Option<AudioChunk>, DecibriError>

Attempt to read exactly samples interleaved samples without blocking.

samples is the requested block size in interleaved f32 samples (frames times channels). The device’s native capture buffers are re-blocked on the consumer side, so every returned chunk holds exactly samples samples. samples should be non-zero and, for frame alignment, a multiple of the channel count.

§Returns
  • Ok(Some(chunk)): a full block of exactly samples samples was available and has been dequeued.
  • Ok(None): the stream is open and running, but fewer than samples samples are buffered. Try again shortly, or call next_chunk to block until a full block arrives.
  • Err(DecibriError::MicrophoneStreamClosed): the stream is closed (either by explicit stop or by an audio-driver error reported via the cpal error callback) and the buffer is now empty (any final tail was already delivered as a short chunk). No further chunks will ever be available.

Buffered samples that form one or more full blocks are delivered first. Once the stream closes with fewer than samples remaining, the final partial block (1..samples samples) is delivered as one short chunk, and the closed signal is returned on the next call once the buffer is empty. No captured sample is dropped: every chunk is exactly samples long except the final chunk at close, which carries the remaining tail.

§Thread safety

May be called from any thread. Takes the re-block buffer mutex, so concurrent callers serialize on it; a non-blocking crossbeam_channel::try_recv drains the native buffers into it.

§Stability

Part of decibri’s stable FFI-consumer API surface, alongside next_chunk.

Source

pub fn next_chunk( &self, samples: usize, timeout: Option<Duration>, ) -> Result<Option<AudioChunk>, DecibriError>

Read exactly samples interleaved samples, blocking the calling thread until a full block arrives, the stream closes, or timeout elapses.

samples is the requested block size in interleaved f32 samples (frames times channels). The device’s native capture buffers are re-blocked on the consumer side, so a returned chunk holds exactly samples samples. samples should be non-zero and, for frame alignment, a multiple of the channel count.

§Arguments
  • timeout = None: block indefinitely until a full block arrives or the stream closes.
  • timeout = Some(dur): block at most dur; return Ok(None) if the deadline passes before a full block accumulates. The partial block is retained for the next call.
§Returns
  • Ok(Some(chunk)): a full block of exactly samples samples was received within the deadline.
  • Ok(None): timeout elapsed before a full block accumulated. The stream is still open and the partial stays buffered.
  • Err(DecibriError::MicrophoneStreamClosed): the stream closed and the buffer is now empty. Any full blocks buffered at the time of close are delivered first, then the final partial block (1..samples samples) as one short chunk; this error is only returned once the buffer is empty. No captured sample is dropped.
§Thread safety

May be called from any thread. Blocks only the calling thread; other threads can call stop concurrently to unblock this call within approximately 20 ms. Holds the re-block buffer mutex for the duration of the call, so concurrent reads serialize.

Implementation note: this method polls both the channel and is_open at a short interval. An explicit stop disconnects the channel (it drops the cpal Stream, and with it the sender), which wakes a blocked wait promptly; the poll additionally covers a driver-error stop, which flips is_open without dropping the stream.

§Stability

Part of decibri’s stable FFI-consumer API surface.

Source

pub fn is_open(&self) -> bool

Check whether the stream is still actively capturing.

Source

pub fn sample_rate(&self) -> u32

The sample rate (Hz) this stream was opened with.

Source

pub fn channels(&self) -> u16

The channel count this stream was opened with.

Source

pub fn vad_input(&self, samples: usize) -> Option<Vec<f32>>

The pre-transform (post-normalize) samples for the VAD feed, drained as next_chunk delivers blocks.

Binding-internal plumbing: a binding that runs voice-activity detection calls this right after a next_chunk / try_next_chunk delivery, passing the delivered chunk’s length, and feeds the returned samples to the detector instead of the delivered chunk. This makes the detector read the signal BEFORE the opt-in enhancement step, so enabling enhancement does not change detection. Not part of the stable FFI-consumer surface.

§Returns
  • Some(v): the chain has an enhancement step, so the delivered output is the post-enhancement signal; v holds up to samples post-normalize samples from the front of the tap, the pre-enhancement signal a detector should read. With only a length-preserving transform (DC removal) those are the exact pre-transform twin of the just-delivered block. With a length-changing, latency-introducing transform (denoise), the tap is the real-time pre-enhancement signal and LEADS the delivered enhanced block by the chain’s latency, so v is a bounded amount ahead rather than sample- aligned. That lead is intended (the detector reads audio sooner, never later) and invisible to consumers, which keep only a rolling probability and never pair a score to specific returned samples.
  • None: the chain has no enhancement step, so the delivered chunk already is the post-normalize signal; feed the detector the delivered chunk exactly as before, with no allocation or copy.
§Thread safety

Takes only the tap mutex (never the reblock or chain locks), so it composes with a concurrent next_chunk. The lead stays bounded as long as the same consumer calls this once per delivered block, as the binding pump does.

Source

pub fn take_last_error(&self) -> Option<DecibriError>

Take the last device/driver error reported while streaming, if any.

When the cpal error callback fires (device unplug, driver failure) it records a typed DecibriError::DeviceFailed and closes the stream. Reading it here drains it (returns None afterwards), letting a consumer that observes a closed stream tell a driver failure apart from an explicit stop.

Source

pub fn overrun_count(&self) -> u64

Total number of capture buffers dropped because the channel was full (a consumer that could not keep up). Stays 0 while the consumer keeps pace; a rising count means audio is being dropped to bound memory.

Source

pub fn stop(&self)

Stop capturing audio and release the device.

Flips the running flag, then drops the held stream, so the OS releases the input device (and the mic-in-use indicator clears) at once rather than only when this handle is dropped. Dropping the stream also disconnects the capture channel; chunks already buffered remain readable via try_next_chunk or next_chunk until the buffer is drained, after which those methods return Err(MicrophoneStreamClosed).

May be called from any thread; wakes a concurrent next_chunk waiter promptly (the channel disconnect unblocks it). Releasing the device blocks briefly while the audio thread tears down.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<S, T> Duplex<S> for T
where T: FromSample<S> + ToSample<S>,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<S> FromSample<S> for S

Source§

fn from_sample_(s: S) -> S

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> ToSample<U> for T
where U: FromSample<T>,

Source§

fn to_sample_(self) -> U

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more