sim_lib_audio_graph_live/
transport.rs1use std::collections::BTreeMap;
2
3use sim_kernel::{Result, Symbol};
4use sim_lib_audio_graph_core::Transport;
5use sim_lib_stream_clock::Clock;
6use sim_lib_stream_core::{StreamDiagnostic, StreamEnvelope, StreamMedia, StreamPacket};
7
8pub fn live_clock_symbol() -> Symbol {
10 Symbol::qualified("clock", "audio-graph-live")
11}
12
13#[derive(Clone, Debug, PartialEq, Eq)]
15pub struct LiveTransportClock {
16 clock: Clock,
17 sample_rate_hz: u32,
18}
19
20#[derive(Clone, Debug)]
23pub struct LanBufferedPreviewWindow {
24 next_sequence: u64,
25 reorder_depth: u64,
26 pending: BTreeMap<u64, StreamEnvelope>,
27 diagnostics: Vec<StreamPacket>,
28}
29
30impl LiveTransportClock {
31 pub fn sample_frame(sample_rate_hz: u32) -> Result<Self> {
33 Ok(Self {
34 clock: Clock::frame(live_clock_symbol(), u64::from(sample_rate_hz))?,
35 sample_rate_hz,
36 })
37 }
38
39 pub fn clock(&self) -> &Clock {
41 &self.clock
42 }
43
44 pub fn sample_rate_hz(&self) -> u32 {
46 self.sample_rate_hz
47 }
48
49 pub fn transport_at(&self, sample_pos: u64, playing: bool) -> Transport {
51 Transport {
52 playing,
53 sample_pos,
54 tempo_bpm: 120.0,
55 ppq_pos: 0.0,
56 }
57 }
58}
59
60impl LanBufferedPreviewWindow {
61 pub fn new(next_sequence: u64, reorder_depth: u64) -> Self {
64 Self {
65 next_sequence,
66 reorder_depth,
67 pending: BTreeMap::new(),
68 diagnostics: Vec::new(),
69 }
70 }
71
72 pub fn push(&mut self, envelope: StreamEnvelope) -> Result<Vec<StreamEnvelope>> {
77 validate_lan_buffered_preview_envelope(&envelope)?;
78 let sequence = envelope.sequence();
79 if sequence < self.next_sequence || self.pending.contains_key(&sequence) {
80 self.record(
81 lan_buffered_preview_late_packet_diagnostic_kind(),
82 format!(
83 "LAN preview packet {sequence} arrived after sequence {} was expected",
84 self.next_sequence
85 ),
86 );
87 return Ok(Vec::new());
88 }
89 if sequence > self.next_sequence {
90 let gap = sequence - self.next_sequence;
91 self.record(
92 lan_buffered_preview_jitter_diagnostic_kind(),
93 format!("LAN preview packet {sequence} arrived with a sequence gap of {gap}"),
94 );
95 self.record(
96 lan_buffered_preview_reorder_diagnostic_kind(),
97 format!(
98 "LAN preview packet {sequence} arrived before expected sequence {}",
99 self.next_sequence
100 ),
101 );
102 if gap > self.reorder_depth {
103 self.record(
104 lan_buffered_preview_drop_diagnostic_kind(),
105 format!(
106 "LAN preview dropped missing sequence range {}..{sequence}",
107 self.next_sequence
108 ),
109 );
110 self.next_sequence = sequence;
111 return Ok(self.accept_ready(envelope));
112 }
113 self.pending.insert(sequence, envelope);
114 return Ok(Vec::new());
115 }
116 Ok(self.accept_ready(envelope))
117 }
118
119 pub fn drain_diagnostics(&mut self) -> Vec<StreamPacket> {
121 std::mem::take(&mut self.diagnostics)
122 }
123
124 fn accept_ready(&mut self, envelope: StreamEnvelope) -> Vec<StreamEnvelope> {
125 let mut ready = vec![envelope];
126 self.next_sequence = self.next_sequence.saturating_add(1);
127 while let Some(envelope) = self.pending.remove(&self.next_sequence) {
128 ready.push(envelope);
129 self.next_sequence = self.next_sequence.saturating_add(1);
130 }
131 ready
132 }
133
134 fn record(&mut self, kind: Symbol, message: String) {
135 self.diagnostics
136 .push(StreamPacket::Diagnostic(StreamDiagnostic::new(
137 kind, message,
138 )));
139 }
140}
141
142pub fn validate_lan_buffered_preview_envelope(envelope: &StreamEnvelope) -> Result<()> {
145 if envelope.media() != StreamMedia::Pcm {
146 return Err(sim_kernel::Error::Eval(
147 "LAN buffered audio preview requires PCM media".to_owned(),
148 ));
149 }
150 if envelope.profile().name()
151 != sim_lib_stream_core::TransportProfile::lan_buffered_audio_preview().name()
152 {
153 return Err(sim_kernel::Error::Eval(
154 "LAN buffered audio preview requires stream/profile/lan-buffered-audio-preview"
155 .to_owned(),
156 ));
157 }
158 Ok(())
159}
160
161pub fn lan_buffered_preview_jitter_diagnostic_kind() -> Symbol {
163 Symbol::qualified("stream/preview", "Jitter")
164}
165
166pub fn lan_buffered_preview_drop_diagnostic_kind() -> Symbol {
168 Symbol::qualified("stream/preview", "Drop")
169}
170
171pub fn lan_buffered_preview_reorder_diagnostic_kind() -> Symbol {
173 Symbol::qualified("stream/preview", "Reorder")
174}
175
176pub fn lan_buffered_preview_late_packet_diagnostic_kind() -> Symbol {
178 Symbol::qualified("stream/preview", "LatePacket")
179}