Co-authored-by: Aaron D. Lee <himself@adlee.work> Co-committed-by: Aaron D. Lee <himself@adlee.work>
70 lines
2.8 KiB
Rust
70 lines
2.8 KiB
Rust
//! # TapMetrics — the "observe" half of "drop + observe" (slice-1 §3.8)
|
|
//!
|
|
//! Atomic counters shared between `TapAudioPipe` (hot path — inbound/outbound
|
|
//! drops, playout overflow/underflow) and `TapClient` (seq gaps, unknown
|
|
//! frames, malformed frames, reconnect attempts). All ops are
|
|
//! `fetch_add(_, Ordering::Relaxed)` — we're using the counts for
|
|
//! observability, not synchronization, so relaxed ordering is correct +
|
|
//! cheapest. A snapshot read is taken at log time (e.g. once per second or
|
|
//! on tap-disconnect).
|
|
|
|
use std::sync::Arc;
|
|
use std::sync::atomic::{AtomicU64, Ordering};
|
|
|
|
/// Bounded playout ring capacity (spec §4.1: 5 frames = 100 ms at 20 ms/frame).
|
|
/// Tunable *constant* (no runtime config in slice-2; a future-rung concern).
|
|
pub const TAP_PLAYOUT_FRAMES: usize = 5;
|
|
|
|
#[derive(Debug, Default)]
|
|
pub struct TapMetrics {
|
|
pub inbound_dropped: AtomicU64,
|
|
pub outbound_dropped: AtomicU64,
|
|
pub playout_overflow: AtomicU64,
|
|
pub playout_underflow: AtomicU64,
|
|
pub seq_gaps: AtomicU64,
|
|
pub unknown_frames: AtomicU64,
|
|
pub malformed_frames: AtomicU64,
|
|
pub reconnect_attempts: AtomicU64,
|
|
/// slice-4 §3.3: count of in-flight `audio_out` frames dropped from
|
|
/// `rx_audio_out` during `barge_in_flush`. The drain makes the resume
|
|
/// condition race-free — the first `audio_out` observed post-barge is
|
|
/// provably post-barge.
|
|
pub barge_drained_inflight: AtomicU64,
|
|
}
|
|
|
|
impl TapMetrics {
|
|
pub fn new() -> Arc<Self> {
|
|
Arc::new(Self::default())
|
|
}
|
|
|
|
/// Read a consistent-ish snapshot. Not atomic across fields (each is
|
|
/// independently read), but for log/observability purposes that's fine —
|
|
/// we're reporting "approximately this many X happened," not synchronizing.
|
|
pub fn snapshot(&self) -> MetricsSnapshot {
|
|
MetricsSnapshot {
|
|
inbound_dropped: self.inbound_dropped.load(Ordering::Relaxed),
|
|
outbound_dropped: self.outbound_dropped.load(Ordering::Relaxed),
|
|
playout_overflow: self.playout_overflow.load(Ordering::Relaxed),
|
|
playout_underflow: self.playout_underflow.load(Ordering::Relaxed),
|
|
seq_gaps: self.seq_gaps.load(Ordering::Relaxed),
|
|
unknown_frames: self.unknown_frames.load(Ordering::Relaxed),
|
|
malformed_frames: self.malformed_frames.load(Ordering::Relaxed),
|
|
reconnect_attempts: self.reconnect_attempts.load(Ordering::Relaxed),
|
|
barge_drained_inflight: self.barge_drained_inflight.load(Ordering::Relaxed),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Default)]
|
|
pub struct MetricsSnapshot {
|
|
pub inbound_dropped: u64,
|
|
pub outbound_dropped: u64,
|
|
pub playout_overflow: u64,
|
|
pub playout_underflow: u64,
|
|
pub seq_gaps: u64,
|
|
pub unknown_frames: u64,
|
|
pub malformed_frames: u64,
|
|
pub reconnect_attempts: u64,
|
|
pub barge_drained_inflight: u64,
|
|
}
|