Skip to main content

rustriff_lib/domain/dto/
round_trip_latency_dto.rs

1//! DTO for the result of a hardware round-trip latency measurement.
2//!
3//! Produced by [`AudioLatencyMeasurementService::measure_round_trip_latency`] and
4//! serialised across the Tauri IPC boundary so the frontend can display the result
5//! or an actionable error message.
6//!
7//! [`AudioLatencyMeasurementService::measure_round_trip_latency`]: crate::services::audio_latency_measurement_service::AudioLatencyMeasurementService::measure_round_trip_latency
8
9use serde::{Deserialize, Serialize};
10
11/// Result of a hardware round-trip latency measurement.
12///
13/// Round-trip latency is the total wall-clock time from when a sample is written to
14/// the output ring buffer to when it returns on the input ring buffer after passing
15/// through the DAC, the physical audio path, and the ADC.  It captures:
16///
17/// - Input and output buffer delays
18/// - Hardware AD/DA conversion time
19/// - OS scheduling and driver latency
20/// - Any resampler buffering in the signal path
21///
22/// The measurement is performed by [`RoundTripLatencySession`] on a dedicated thread
23/// using private CPAL streams, completely separate from the main audio loopback.
24///
25/// # Validity
26///
27/// Always check [`is_valid`] before using [`latency_ms`].  When `is_valid` is `false`
28/// the `latency_ms` field is `0.0` and [`error`] contains a human-readable description
29/// of what went wrong (e.g. no echo detected, timeout).
30///
31/// [`RoundTripLatencySession`]: crate::services::round_trip_latency_session::RoundTripLatencySession
32/// [`is_valid`]: RoundTripLatencyDto::is_valid
33/// [`latency_ms`]: RoundTripLatencyDto::latency_ms
34/// [`error`]: RoundTripLatencyDto::error
35#[derive(Debug, Clone, Serialize, Deserialize)]
36#[serde(crate = "serde")]
37pub struct RoundTripLatencyDto {
38    /// Average round-trip latency in milliseconds across all impulse/echo cycles.
39    ///
40    /// Only meaningful when [`is_valid`] is `true`.  Set to `0.0` on failure.
41    ///
42    /// [`is_valid`]: RoundTripLatencyDto::is_valid
43    pub latency_ms: f64,
44
45    /// Whether the measurement completed successfully.
46    ///
47    /// `true` when at least [`IMPULSE_COUNT`] echoes were detected within the timeout.
48    /// `false` when the measurement timed out or the echo signal was undetectable.
49    ///
50    /// [`IMPULSE_COUNT`]: crate::services::round_trip_latency_session::IMPULSE_AMPLITUDE
51    pub is_valid: bool,
52
53    /// Human-readable failure reason, or `None` on success.
54    ///
55    /// Typical messages:
56    /// - `"Echo not detected above threshold …"` — output not routed to input.
57    /// - `"Round-trip measurement timed out …"` — overall deadline exceeded.
58    /// - `"Round-trip measurement thread panicked"` — unexpected internal error.
59    pub error: Option<String>,
60}
61
62impl RoundTripLatencyDto {
63    /// Creates a successful result with the given averaged latency.
64    ///
65    /// Sets `is_valid = true` and `error = None`.
66    pub fn success(latency_ms: f64) -> Self {
67        Self {
68            latency_ms,
69            is_valid: true,
70            error: None,
71        }
72    }
73
74    /// Creates a failed result with the given error message.
75    ///
76    /// Sets `is_valid = false` and `latency_ms = 0.0`.
77    pub fn failure(error: String) -> Self {
78        Self {
79            latency_ms: 0.0,
80            is_valid: false,
81            error: Some(error),
82        }
83    }
84}