voirs_vocoder/drivers/
mod.rs1use crate::{AudioBuffer, VocoderError};
8use async_trait::async_trait;
9use std::sync::Arc;
10
11pub mod core_audio;
12
13#[cfg(target_os = "windows")]
14pub mod asio;
15
16#[cfg(target_os = "linux")]
17pub mod linux;
18
19pub type DriverResult<T> = Result<T, AudioDriverError>;
21
22#[derive(thiserror::Error, Debug)]
24pub enum AudioDriverError {
25 #[error("Audio device not found: {0}")]
26 DeviceNotFound(String),
27
28 #[error("Audio stream initialization failed: {0}")]
29 StreamInitFailed(String),
30
31 #[error("Audio buffer underrun occurred")]
32 BufferUnderrun,
33
34 #[error("Audio buffer overrun occurred")]
35 BufferOverrun,
36
37 #[error("Unsupported sample rate: {rate} Hz")]
38 UnsupportedSampleRate { rate: u32 },
39
40 #[error("Unsupported channel configuration: {channels} channels")]
41 UnsupportedChannelCount { channels: u32 },
42
43 #[error("Audio stream is not initialized")]
44 StreamNotInitialized,
45
46 #[error("Audio device disconnected")]
47 DeviceDisconnected,
48
49 #[error("Real-time constraint violation: {message}")]
50 RealTimeViolation { message: String },
51
52 #[error("Driver internal error: {0}")]
53 InternalError(String),
54}
55
56impl From<AudioDriverError> for VocoderError {
57 fn from(err: AudioDriverError) -> Self {
58 VocoderError::RuntimeError(format!("Audio driver error: {err}"))
59 }
60}
61
62#[derive(Debug, Clone)]
64pub struct AudioDeviceInfo {
65 pub id: String,
67 pub name: String,
69 pub is_default: bool,
71 pub supported_sample_rates: Vec<u32>,
73 pub max_output_channels: u32,
75 pub min_buffer_size: u32,
77 pub max_buffer_size: u32,
79 pub default_buffer_size: u32,
81}
82
83#[derive(Debug, Clone)]
85pub struct AudioStreamConfig {
86 pub sample_rate: u32,
88 pub channels: u32,
90 pub buffer_size: u32,
92 pub target_latency_ms: f32,
94}
95
96impl Default for AudioStreamConfig {
97 fn default() -> Self {
98 Self {
99 sample_rate: 22050,
100 channels: 1,
101 buffer_size: 256,
102 target_latency_ms: 10.0,
103 }
104 }
105}
106
107#[derive(Debug, Clone, Default)]
109pub struct AudioStreamMetrics {
110 pub frames_processed: u64,
112 pub underruns: u32,
114 pub overruns: u32,
116 pub current_latency_ms: f32,
118 pub cpu_load_percent: f32,
120 pub is_active: bool,
122}
123
124pub type AudioCallback = Arc<dyn Fn(&mut [f32]) -> DriverResult<()> + Send + Sync>;
126
127#[async_trait(?Send)]
129pub trait AudioDriver {
130 async fn enumerate_devices(&self) -> DriverResult<Vec<AudioDeviceInfo>>;
132
133 async fn default_device(&self) -> DriverResult<AudioDeviceInfo>;
135
136 async fn initialize_stream(
138 &mut self,
139 device_id: Option<&str>,
140 config: AudioStreamConfig,
141 callback: AudioCallback,
142 ) -> DriverResult<()>;
143
144 async fn start_stream(&mut self) -> DriverResult<()>;
146
147 async fn stop_stream(&mut self) -> DriverResult<()>;
149
150 fn is_stream_running(&self) -> bool;
152
153 fn get_metrics(&self) -> AudioStreamMetrics;
155
156 fn driver_name(&self) -> &'static str;
158
159 fn is_available() -> bool
161 where
162 Self: Sized;
163}
164
165pub struct AudioDriverFactory;
167
168impl AudioDriverFactory {
169 pub fn create_default() -> DriverResult<Box<dyn AudioDriver>> {
171 #[cfg(target_os = "macos")]
172 {
173 if core_audio::CoreAudioDriver::is_available() {
174 return Ok(Box::new(core_audio::CoreAudioDriver::new()?));
175 }
176 Err(AudioDriverError::InternalError(
177 "Core Audio driver not available on this system".to_string(),
178 ))
179 }
180
181 #[cfg(target_os = "windows")]
182 {
183 if asio::AsioDriver::is_available() {
184 return Ok(Box::new(asio::AsioDriver::new()?));
185 }
186 return Err(AudioDriverError::InternalError(
187 "ASIO audio driver not available on this system".to_string(),
188 ));
189 }
190
191 #[cfg(target_os = "linux")]
192 {
193 return linux::create_linux_driver();
194 }
195
196 #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "linux")))]
197 {
198 Err(AudioDriverError::InternalError(
199 "No audio driver available for this platform".to_string(),
200 ))
201 }
202 }
203
204 pub fn available_drivers() -> Vec<&'static str> {
206 let mut drivers = Vec::new();
207
208 #[cfg(target_os = "macos")]
209 {
210 if core_audio::CoreAudioDriver::is_available() {
211 drivers.push("Core Audio");
212 }
213 }
214
215 #[cfg(target_os = "windows")]
216 {
217 if asio::AsioDriver::is_available() {
218 drivers.push("ASIO");
219 }
220 }
221
222 #[cfg(target_os = "linux")]
223 {
224 if linux::AlsaDriver::is_available() {
225 drivers.push("ALSA");
226 }
227 if linux::PulseAudioDriver::is_available() {
228 drivers.push("PulseAudio");
229 }
230 }
231
232 drivers
233 }
234}
235
236pub struct RealTimeAudioOutput {
238 driver: Box<dyn AudioDriver>,
239 config: AudioStreamConfig,
240 buffer_queue: Arc<parking_lot::Mutex<std::collections::VecDeque<AudioBuffer>>>,
241 metrics: Arc<parking_lot::Mutex<AudioStreamMetrics>>,
242}
243
244impl RealTimeAudioOutput {
245 pub fn new(config: AudioStreamConfig) -> DriverResult<Self> {
247 let driver = AudioDriverFactory::create_default()?;
248 let buffer_queue = Arc::new(parking_lot::Mutex::new(std::collections::VecDeque::new()));
249 let metrics = Arc::new(parking_lot::Mutex::new(AudioStreamMetrics::default()));
250
251 Ok(Self {
252 driver,
253 config,
254 buffer_queue,
255 metrics,
256 })
257 }
258
259 pub async fn start(&mut self) -> DriverResult<()> {
261 let metrics = Arc::clone(&self.metrics);
262 let buffer_queue = Arc::clone(&self.buffer_queue);
263
264 let callback: AudioCallback = Arc::new(move |output: &mut [f32]| {
266 let mut queue = buffer_queue.lock();
268
269 if let Some(audio_buffer) = queue.pop_front() {
270 let samples = audio_buffer.samples();
271 let frames_needed = output.len();
272
273 if samples.len() >= frames_needed {
274 output.copy_from_slice(&samples[..frames_needed]);
276
277 if samples.len() > frames_needed {
279 let remaining_samples = samples[frames_needed..].to_vec();
280 let remaining_buffer = AudioBuffer::new(
281 remaining_samples,
282 audio_buffer.sample_rate(),
283 audio_buffer.channels(),
284 );
285 queue.push_front(remaining_buffer);
286 }
287 } else {
288 output[..samples.len()].copy_from_slice(samples);
290 output[samples.len()..].fill(0.0);
291 }
292
293 drop(queue); let mut m = metrics.lock();
297 m.frames_processed += frames_needed as u64;
298 m.is_active = true;
299
300 Ok(())
301 } else {
302 output.fill(0.0);
304 drop(queue); let mut m = metrics.lock();
307 m.underruns += 1;
308
309 Ok(())
310 }
311 });
312
313 self.driver
315 .initialize_stream(None, self.config.clone(), callback)
316 .await?;
317 self.driver.start_stream().await?;
318
319 Ok(())
320 }
321
322 pub async fn stop(&mut self) -> DriverResult<()> {
324 self.driver.stop_stream().await
325 }
326
327 pub fn metrics(&self) -> AudioStreamMetrics {
329 self.metrics.lock().clone()
330 }
331
332 pub fn queue_audio(&self, buffer: AudioBuffer) -> DriverResult<()> {
334 let mut queue = self.buffer_queue.lock();
335 queue.push_back(buffer);
336 Ok(())
337 }
338}