1use super::command::Command;
4use crate::traits::{NodeId, ParameterId, PortId};
5use std::fmt;
6use std::time::{SystemTime, UNIX_EPOCH};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
10pub enum TelemetryKind {
11 Parameter,
13 Signal,
15 Peak,
17 Event,
19 Violation,
21}
22
23impl fmt::Display for TelemetryKind {
24 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25 match self {
26 TelemetryKind::Parameter => write!(f, "parameter"),
27 TelemetryKind::Signal => write!(f, "signal"),
28 TelemetryKind::Peak => write!(f, "peak"),
29 TelemetryKind::Event => write!(f, "event"),
30 TelemetryKind::Violation => write!(f, "violation"),
31 }
32 }
33}
34
35#[derive(Debug, Clone)]
37pub enum Telemetry {
38 ParameterValue {
40 port: PortId,
41 parameter: ParameterId,
42 value: f32,
43 timestamp: u64,
44 },
45
46 SignalData {
48 node_id: NodeId,
49 channel: usize,
50 data: Vec<f32>,
51 timestamp: u64,
52 sample_rate: f32,
53 },
54
55 Peak {
57 port: PortId,
58 value: f32,
59 timestamp: u64,
60 hold_time_ms: Option<u32>,
61 },
62
63 Event {
65 source: String,
66 kind: String,
67 data: Vec<f32>,
68 timestamp: u64,
69 description: Option<String>,
70 },
71
72 Violation {
74 component: String,
75 expected_ns: u64,
76 actual_ns: u64,
77 value: Option<f32>,
78 timestamp: u64,
79 },
80}
81
82impl Command for Telemetry {}
84
85impl Telemetry {
86 pub fn now() -> u64 {
88 SystemTime::now()
89 .duration_since(UNIX_EPOCH)
90 .unwrap_or_default()
91 .as_micros() as u64
92 }
93
94 pub fn parameter(port: PortId, parameter: ParameterId, value: f32) -> Self {
96 Telemetry::ParameterValue {
97 port,
98 parameter,
99 value,
100 timestamp: Self::now(),
101 }
102 }
103
104 pub fn parameter_with_time(
106 port: PortId,
107 parameter: ParameterId,
108 value: f32,
109 timestamp: u64,
110 ) -> Self {
111 Telemetry::ParameterValue {
112 port,
113 parameter,
114 value,
115 timestamp,
116 }
117 }
118
119 pub fn audio(node_id: NodeId, channel: usize, data: Vec<f32>) -> Self {
121 Telemetry::SignalData {
122 node_id,
123 channel,
124 data,
125 timestamp: Self::now(),
126 sample_rate: 44100.0,
127 }
128 }
129
130 pub fn audio_with_sample_rate(
132 node_id: NodeId,
133 channel: usize,
134 data: Vec<f32>,
135 sample_rate: f32,
136 ) -> Self {
137 Telemetry::SignalData {
138 node_id,
139 channel,
140 data,
141 timestamp: Self::now(),
142 sample_rate,
143 }
144 }
145
146 pub fn peak(port: PortId, value: f32) -> Self {
148 Telemetry::Peak {
149 port,
150 value,
151 timestamp: Self::now(),
152 hold_time_ms: None,
153 }
154 }
155
156 pub fn peak_with_hold(port: PortId, value: f32, hold_time_ms: u32) -> Self {
158 Telemetry::Peak {
159 port,
160 value,
161 timestamp: Self::now(),
162 hold_time_ms: Some(hold_time_ms),
163 }
164 }
165
166 pub fn event(source: impl Into<String>, kind: impl Into<String>, data: Vec<f32>) -> Self {
168 Telemetry::Event {
169 source: source.into(),
170 kind: kind.into(),
171 data,
172 timestamp: Self::now(),
173 description: None,
174 }
175 }
176
177 pub fn event_with_description(
179 source: impl Into<String>,
180 kind: impl Into<String>,
181 data: Vec<f32>,
182 description: impl Into<String>,
183 ) -> Self {
184 Telemetry::Event {
185 source: source.into(),
186 kind: kind.into(),
187 data,
188 timestamp: Self::now(),
189 description: Some(description.into()),
190 }
191 }
192
193 pub fn violation(
195 component: impl Into<String>,
196 expected_ns: u64,
197 actual_ns: u64,
198 value: Option<f32>,
199 ) -> Self {
200 Telemetry::Violation {
201 component: component.into(),
202 expected_ns,
203 actual_ns,
204 value,
205 timestamp: Self::now(),
206 }
207 }
208
209 pub fn kind(&self) -> TelemetryKind {
211 match self {
212 Telemetry::ParameterValue { .. } => TelemetryKind::Parameter,
213 Telemetry::SignalData { .. } => TelemetryKind::Signal,
214 Telemetry::Peak { .. } => TelemetryKind::Peak,
215 Telemetry::Event { .. } => TelemetryKind::Event,
216 Telemetry::Violation { .. } => TelemetryKind::Violation,
217 }
218 }
219
220 pub fn timestamp(&self) -> u64 {
222 match self {
223 Telemetry::ParameterValue { timestamp, .. } => *timestamp,
224 Telemetry::SignalData { timestamp, .. } => *timestamp,
225 Telemetry::Peak { timestamp, .. } => *timestamp,
226 Telemetry::Event { timestamp, .. } => *timestamp,
227 Telemetry::Violation { timestamp, .. } => *timestamp,
228 }
229 }
230}
231
232impl fmt::Display for Telemetry {
233 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
234 match self {
235 Telemetry::ParameterValue {
236 port,
237 parameter,
238 value,
239 timestamp,
240 } => {
241 write!(
242 f,
243 "[{}] 📊 {}::{} = {:.3}",
244 timestamp, port, parameter, value
245 )
246 }
247 Telemetry::SignalData {
248 node_id,
249 channel,
250 data,
251 timestamp,
252 sample_rate,
253 } => {
254 let duration_ms = data.len() as f32 / sample_rate * 1000.0;
255 write!(
256 f,
257 "[{}] 🎵 {}:{} ({} samples, {:.1}ms)",
258 timestamp,
259 node_id,
260 channel,
261 data.len(),
262 duration_ms
263 )
264 }
265 Telemetry::Peak {
266 port,
267 value,
268 timestamp,
269 hold_time_ms,
270 } => {
271 if let Some(hold) = hold_time_ms {
272 write!(
273 f,
274 "[{}] 📈 {} = {:.3} (hold {}ms)",
275 timestamp, port, value, hold
276 )
277 } else {
278 write!(f, "[{}] 📈 {} = {:.3}", timestamp, port, value)
279 }
280 }
281 Telemetry::Event {
282 source,
283 kind,
284 data,
285 timestamp,
286 description,
287 } => {
288 if let Some(desc) = description {
289 write!(
290 f,
291 "[{}] 📢 {}:{} ({}) {:?}",
292 timestamp, source, kind, desc, data
293 )
294 } else {
295 write!(f, "[{}] 📢 {}:{} {:?}", timestamp, source, kind, data)
296 }
297 }
298 Telemetry::Violation {
299 component,
300 expected_ns,
301 actual_ns,
302 value,
303 timestamp,
304 } => {
305 if let Some(v) = value {
306 write!(
307 f,
308 "[{}] ⚠️ {} нарушение: {}нс > {}нс, value={:.3}",
309 timestamp, component, actual_ns, expected_ns, v
310 )
311 } else {
312 write!(
313 f,
314 "[{}] ⚠️ {} нарушение: {}нс > {}нс",
315 timestamp, component, actual_ns, expected_ns
316 )
317 }
318 }
319 }
320 }
321}
322
323pub type TelemetryQueue = super::command::CommandQueue<Telemetry>;
325
326pub trait TelemetryQueueExt {
328 fn send_parameter(
329 &self,
330 port: PortId,
331 parameter: ParameterId,
332 value: f32,
333 ) -> Result<(), super::error::QueueError>;
334 fn send_audio(
335 &self,
336 node_id: NodeId,
337 channel: usize,
338 data: Vec<f32>,
339 ) -> Result<(), super::error::QueueError>;
340 fn send_audio_with_sample_rate(
341 &self,
342 node_id: NodeId,
343 channel: usize,
344 data: Vec<f32>,
345 sample_rate: f32,
346 ) -> Result<(), super::error::QueueError>;
347 fn send_peak(&self, port: PortId, value: f32) -> Result<(), super::error::QueueError>;
348 fn send_peak_with_hold(
349 &self,
350 port: PortId,
351 value: f32,
352 hold_time_ms: u32,
353 ) -> Result<(), super::error::QueueError>;
354 fn send_event(
355 &self,
356 source: &str,
357 kind: &str,
358 data: Vec<f32>,
359 ) -> Result<(), super::error::QueueError>;
360 fn send_event_with_description(
361 &self,
362 source: &str,
363 kind: &str,
364 data: Vec<f32>,
365 description: &str,
366 ) -> Result<(), super::error::QueueError>;
367 fn send_violation(
368 &self,
369 component: &str,
370 expected_ns: u64,
371 actual_ns: u64,
372 value: Option<f32>,
373 ) -> Result<(), super::error::QueueError>;
374}
375
376impl TelemetryQueueExt for super::command::CommandQueue<Telemetry> {
377 fn send_parameter(
378 &self,
379 port: PortId,
380 parameter: ParameterId,
381 value: f32,
382 ) -> Result<(), super::error::QueueError> {
383 self.send(Telemetry::parameter(port, parameter, value))
384 .map_err(|e| e.into())
385 }
386
387 fn send_audio(
388 &self,
389 node_id: NodeId,
390 channel: usize,
391 data: Vec<f32>,
392 ) -> Result<(), super::error::QueueError> {
393 self.send(Telemetry::audio(node_id, channel, data))
394 .map_err(|e| e.into())
395 }
396
397 fn send_audio_with_sample_rate(
398 &self,
399 node_id: NodeId,
400 channel: usize,
401 data: Vec<f32>,
402 sample_rate: f32,
403 ) -> Result<(), super::error::QueueError> {
404 self.send(Telemetry::audio_with_sample_rate(
405 node_id,
406 channel,
407 data,
408 sample_rate,
409 ))
410 .map_err(|e| e.into())
411 }
412
413 fn send_peak(&self, port: PortId, value: f32) -> Result<(), super::error::QueueError> {
414 self.send(Telemetry::peak(port, value))
415 .map_err(|e| e.into())
416 }
417
418 fn send_peak_with_hold(
419 &self,
420 port: PortId,
421 value: f32,
422 hold_time_ms: u32,
423 ) -> Result<(), super::error::QueueError> {
424 self.send(Telemetry::peak_with_hold(port, value, hold_time_ms))
425 .map_err(|e| e.into())
426 }
427
428 fn send_event(
429 &self,
430 source: &str,
431 kind: &str,
432 data: Vec<f32>,
433 ) -> Result<(), super::error::QueueError> {
434 self.send(Telemetry::event(source, kind, data))
435 .map_err(|e| e.into())
436 }
437
438 fn send_event_with_description(
439 &self,
440 source: &str,
441 kind: &str,
442 data: Vec<f32>,
443 description: &str,
444 ) -> Result<(), super::error::QueueError> {
445 self.send(Telemetry::event_with_description(
446 source,
447 kind,
448 data,
449 description,
450 ))
451 .map_err(|e| e.into())
452 }
453
454 fn send_violation(
455 &self,
456 component: &str,
457 expected_ns: u64,
458 actual_ns: u64,
459 value: Option<f32>,
460 ) -> Result<(), super::error::QueueError> {
461 self.send(Telemetry::violation(
462 component,
463 expected_ns,
464 actual_ns,
465 value,
466 ))
467 .map_err(|e| e.into())
468 }
469}