augmented_audio_metrics/audio_processor_metrics/
audio_thread.rs1use std::sync::atomic::{AtomicU64, AtomicUsize};
24use std::time::{Duration, Instant};
25
26use audio_garbage_collector::{make_shared, Shared};
27use audio_processor_traits::AudioProcessorSettings;
28use augmented_atomics::{AtomicF32, AtomicValue};
29
30#[derive(Default)]
31pub struct AudioProcessorMetricsHandle {
32 duration_micros: AtomicU64,
35 sample_rate: AtomicF32,
36 buffer_size: AtomicUsize,
37}
38
39impl AudioProcessorMetricsHandle {
40 pub fn duration(&self) -> Duration {
41 let duration_micros = self.duration_micros.get();
42 Duration::from_micros(duration_micros)
43 }
44
45 pub fn cpu_percent(&self) -> f32 {
46 let time_per_sample = 1.0 / self.sample_rate.get();
47 let time_per_block = time_per_sample * self.buffer_size.get() as f32;
48 let duration = self.duration();
49 duration.as_secs_f32() / time_per_block
50 }
51
52 pub fn prepare(&self, settings: AudioProcessorSettings) {
53 self.sample_rate.set(settings.sample_rate());
54 self.buffer_size.set(settings.block_size());
55 }
56
57 pub fn set_duration(&self, duration: Duration) {
58 self.duration_micros.set(duration.as_micros() as u64);
59 }
60}
61
62pub struct AudioProcessorMetrics {
63 last_start_time: Instant,
64 handle: Shared<AudioProcessorMetricsHandle>,
65}
66
67impl Default for AudioProcessorMetrics {
68 fn default() -> Self {
69 Self {
70 last_start_time: Instant::now(),
71 handle: make_shared(Default::default()),
72 }
73 }
74}
75
76impl AudioProcessorMetrics {
77 pub fn from_handle(handle: Shared<AudioProcessorMetricsHandle>) -> Self {
78 Self {
79 last_start_time: Instant::now(),
80 handle,
81 }
82 }
83
84 pub fn handle(&self) -> Shared<AudioProcessorMetricsHandle> {
85 self.handle.clone()
86 }
87
88 pub fn prepare(&self, settings: AudioProcessorSettings) {
89 self.handle.prepare(settings);
90 }
91
92 pub fn on_process_start(&mut self) {
93 self.last_start_time = Instant::now();
94 }
95
96 pub fn on_process_end(&self) {
97 let duration = self.last_start_time.elapsed();
98 self.handle.set_duration(duration)
99 }
100}
101
102#[cfg(test)]
103mod test {
104 use std::ops::{Add, Sub};
105 use std::time::Duration;
106
107 use augmented_atomics::AtomicValue;
108
109 use super::*;
110
111 #[test]
112 fn test_handle_duration() {
113 let handle = AudioProcessorMetricsHandle::default();
114 handle
115 .duration_micros
116 .set(Duration::from_secs(10).as_micros() as u64);
117 assert_eq!(handle.duration().as_secs(), 10);
118 }
119
120 #[test]
121 fn test_handle_cpu_percent() {
122 let handle = AudioProcessorMetricsHandle::default();
123 handle.sample_rate.set(1000.0);
124 handle.buffer_size.set(100);
126 handle
128 .duration_micros
129 .set(Duration::from_millis(50).as_micros() as u64);
130 assert!((handle.cpu_percent() - 0.5).abs() < f32::EPSILON);
132 }
133
134 #[test]
135 fn test_handle_prepare() {
136 let mut settings = AudioProcessorSettings::default();
137 settings.sample_rate = 100.0;
138 settings.block_size = 10;
139 let handle = AudioProcessorMetricsHandle::default();
140 handle.prepare(settings);
141 assert!((handle.sample_rate.get() - 100.0).abs() < f32::EPSILON);
142 assert_eq!(handle.buffer_size.get(), 10);
143 }
144
145 #[test]
146 fn test_processor_prepare() {
147 let processor = AudioProcessorMetrics::default();
148 let mut settings = AudioProcessorSettings::default();
149 settings.sample_rate = 100.0;
150 settings.block_size = 10;
151
152 let handle = processor.handle();
153 processor.prepare(settings);
154 assert!((handle.sample_rate.get() - 100.0).abs() < f32::EPSILON);
155 assert_eq!(handle.buffer_size.get(), 10);
156 }
157
158 #[test]
159 fn test_processor_start() {
160 let mut processor = AudioProcessorMetrics::default();
161 processor.last_start_time = Instant::now().add(Duration::from_secs(1000));
162 let prev_start = processor.last_start_time;
163 processor.on_process_start();
164 assert_ne!(processor.last_start_time, prev_start);
165 }
166
167 #[test]
168 fn test_processor_end_will_set_duration_on_handle() {
169 let mut processor = AudioProcessorMetrics::default();
170 processor.last_start_time = Instant::now().sub(Duration::from_micros(1000));
171 processor.handle().duration_micros.set(0);
172 processor.on_process_end();
173 assert_ne!(processor.handle().duration_micros.get(), 0);
174 }
175}