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}