Skip to main content

AudioLatencyMeasurementService

Struct AudioLatencyMeasurementService 

Source
pub struct AudioLatencyMeasurementService;
Expand description

Stateless facade that groups all latency measurement operations.

Every method takes a shared reference to an AudioService (or a raw AudioHandlerTrait for round-trip) so the caller can hold whichever lock granularity is appropriate. None of the methods start or stop the loopback.

Implementations§

Source§

impl AudioLatencyMeasurementService

Source

pub fn measure_gain_latency( audio_service: &AudioService, block_size: usize, ) -> f64

Measures the CPU execution cost added by the GainProcessor in the current channel.

Internally this benchmarks the gain processor against a zero-work passthrough over iterations × block_size samples and returns the net cost — i.e. the passthrough baseline is subtracted so the result isolates the processor’s own work.

§Arguments
  • audio_service — Service snapshot used to read the current channel’s gain arc.
  • block_size — Number of samples per iteration. Larger values reduce timer overhead noise; 2 048 is the recommended default for command calls.
§Returns

Added execution cost in microseconds per sample (µs/sample), clamped to ≥ 0.

Source

pub fn measure_tone_stack_latency( audio_service: &AudioService, block_size: usize, ) -> f64

Measures the CPU execution cost added by the ToneStackProcessor in the current channel.

Uses the same baseline-subtraction methodology as measure_gain_latency: the result is the net cost of the biquad filter chain, not the total wall-clock time per sample.

§Arguments
  • audio_service — Service snapshot used to read the current channel’s tone-stack arc.
  • block_size — Number of samples per benchmark iteration.
§Returns

Added execution cost in microseconds per sample (µs/sample), clamped to ≥ 0.

Source

pub fn measure_volume_latency( audio_service: &AudioService, block_size: usize, ) -> f64

Measures the CPU execution cost added by the per-channel volume GainProcessor.

The channel volume is a separate gain stage that sits after the tone stack and before the master volume in the DSP chain. Its cost is benchmarked the same way as the input gain — baseline-subtracted and clamped to ≥ 0.

§Arguments
  • audio_service — Service snapshot used to read the current channel’s volume arc.
  • block_size — Number of samples per benchmark iteration.
§Returns

Added execution cost in microseconds per sample (µs/sample), clamped to ≥ 0.

Source

pub fn measure_all_dsp_timings( audio_service: &AudioService, block_size: usize, ) -> Vec<ExecutionTimingDto>

Measures the CPU execution cost of every processor in the active DSP chain.

Runs individual benchmarks for all four processors in signal-chain order and returns the results as a vector.

§Arguments
  • audio_service — Service snapshot providing channel and master-volume arcs.
  • block_size — Number of samples per benchmark iteration (recommended: 2 048).
§Returns

A Vec<ExecutionTimingDto> with exactly four entries, in signal-chain order:

IndexProcessor
0Gain
1Tone Stack
2Volume
3Master Volume
Source

pub fn measure_all_dsp_algorithmic_latency( audio_service: &AudioService, ) -> Vec<AlgorithmicLatencyDto>

Returns the algorithmic (design-inherent) delay for every processor in the DSP chain.

For the current chain (Gain → Tone Stack → Volume → Master Volume) every processor is a sample-by-sample filter with no lookahead or delay line, so all values are zero.

§Arguments
  • audio_service — Used only to read the output sample rate for ms conversion.
§Returns

A Vec<AlgorithmicLatencyDto> with exactly four entries (Gain, Tone Stack, Volume, Master Volume), each reporting latency_samples = 0 and latency_ms = 0.0.

Source

pub fn measure_buffer_latency(audio_service: &AudioService) -> BufferLatencyDto

Estimates the I/O buffer latency from the current CPAL stream configuration.

Buffer latency is the delay introduced by the hardware frame buffers: each side accumulates a full buffer of samples before the driver delivers or accepts them. The formula is:

latency_ms = (buffer_frames / sample_rate_hz) × 1000

When CPAL is configured with BufferSize::Default the actual frame count is unknown at runtime. In that case a conservative fallback of 256 frames is used so the UI can display a practical estimate rather than zero or an error.

§Arguments
  • audio_service — Used to read both stream configs and sample rates.
§Returns

A BufferLatencyDto containing input_buffer_latency_ms, output_buffer_latency_ms, and their sum as total_buffer_latency_ms.

Source

pub fn measure_round_trip_latency( handler: &dyn AudioHandlerTrait, ) -> RoundTripLatencyDto

Measures true end-to-end round-trip latency using a dedicated pair of CPAL streams.

Unlike the other measurement functions this one performs a real-world, hardware measurement rather than an analytical estimate. It delegates to RoundTripLatencySession::run, which:

  1. Opens its own private input/output CPAL streams — completely separate from the main loopback.
  2. Warms up the streams for 1.5 s so the OS audio stack stabilises.
  3. Calibrates a detection threshold from ambient noise.
  4. Injects three impulses and times how long each takes to return on the input.
  5. Returns the average of the three round-trip durations.

The caller (measure_round_trip_latency Tauri command) is responsible for releasing the Mutex<AudioService> lock and spawning a dedicated thread before calling this function, so the main audio engine and UI remain responsive throughout.

§Arguments
  • handler — The audio I/O factory cloned from AudioService before the mutex was released. Used only to open the temporary measurement streams.
§Returns

A RoundTripLatencyDto with is_valid = true and latency_ms set on success, or is_valid = false and a human-readable error message on failure.

§Physical requirement

The audio output must be physically (or virtually) looped back into the input for the echo to be detectable. If it is not, the measurement times out and returns an error explaining the likely cause.

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
§

impl<T> Any for T
where T: Any,

§

fn into_any(self: Box<T>) -> Box<dyn Any>

§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

§

fn type_name(&self) -> &'static str

§

impl<T> AnySync for T
where T: Any + Send + Sync,

§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Sync + Send>

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<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<S> FromSample<S> for S

§

fn from_sample_(s: S) -> S

§

impl<T> Instrument for T

§

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

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

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.

§

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

§

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.
§

impl<T> WithSubscriber for T

§

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
§

fn with_current_subscriber(self) -> WithDispatch<Self>

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

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