Skip to main content

voirs_vocoder/drivers/
mod.rs

1//! Real-time audio drivers for voirs-vocoder
2//!
3//! This module provides real-time audio output capabilities through various
4//! audio drivers and APIs, enabling low-latency audio playback for real-time
5//! vocoding applications.
6
7use 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
19/// Result type for audio driver operations
20pub type DriverResult<T> = Result<T, AudioDriverError>;
21
22/// Audio driver errors
23#[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/// Audio device information
63#[derive(Debug, Clone)]
64pub struct AudioDeviceInfo {
65    /// Device identifier
66    pub id: String,
67    /// Human-readable device name
68    pub name: String,
69    /// Whether this is the default output device
70    pub is_default: bool,
71    /// Supported sample rates
72    pub supported_sample_rates: Vec<u32>,
73    /// Maximum number of output channels
74    pub max_output_channels: u32,
75    /// Minimum buffer size in frames
76    pub min_buffer_size: u32,
77    /// Maximum buffer size in frames
78    pub max_buffer_size: u32,
79    /// Default buffer size in frames
80    pub default_buffer_size: u32,
81}
82
83/// Audio stream configuration
84#[derive(Debug, Clone)]
85pub struct AudioStreamConfig {
86    /// Sample rate in Hz
87    pub sample_rate: u32,
88    /// Number of channels (1 = mono, 2 = stereo)
89    pub channels: u32,
90    /// Buffer size in frames
91    pub buffer_size: u32,
92    /// Target latency in milliseconds
93    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/// Audio stream metrics
108#[derive(Debug, Clone, Default)]
109pub struct AudioStreamMetrics {
110    /// Number of audio frames processed
111    pub frames_processed: u64,
112    /// Number of buffer underruns
113    pub underruns: u32,
114    /// Number of buffer overruns
115    pub overruns: u32,
116    /// Current latency in milliseconds
117    pub current_latency_ms: f32,
118    /// Average CPU load percentage
119    pub cpu_load_percent: f32,
120    /// Whether the stream is currently active
121    pub is_active: bool,
122}
123
124/// Callback function type for real-time audio processing
125pub type AudioCallback = Arc<dyn Fn(&mut [f32]) -> DriverResult<()> + Send + Sync>;
126
127/// Trait for real-time audio drivers
128#[async_trait(?Send)]
129pub trait AudioDriver {
130    /// Get available audio output devices
131    async fn enumerate_devices(&self) -> DriverResult<Vec<AudioDeviceInfo>>;
132
133    /// Get the default output device
134    async fn default_device(&self) -> DriverResult<AudioDeviceInfo>;
135
136    /// Initialize an audio stream with the specified configuration
137    async fn initialize_stream(
138        &mut self,
139        device_id: Option<&str>,
140        config: AudioStreamConfig,
141        callback: AudioCallback,
142    ) -> DriverResult<()>;
143
144    /// Start the audio stream
145    async fn start_stream(&mut self) -> DriverResult<()>;
146
147    /// Stop the audio stream
148    async fn stop_stream(&mut self) -> DriverResult<()>;
149
150    /// Check if the stream is currently running
151    fn is_stream_running(&self) -> bool;
152
153    /// Get current stream metrics
154    fn get_metrics(&self) -> AudioStreamMetrics;
155
156    /// Get the driver name
157    fn driver_name(&self) -> &'static str;
158
159    /// Check if the driver is available on the current platform
160    fn is_available() -> bool
161    where
162        Self: Sized;
163}
164
165/// Factory for creating audio drivers
166pub struct AudioDriverFactory;
167
168impl AudioDriverFactory {
169    /// Create the best available audio driver for the current platform
170    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    /// List all available drivers on the current platform
205    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
236/// Real-time audio output manager
237pub 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    /// Create a new real-time audio output manager
246    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    /// Initialize and start the audio stream
260    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        // Create the audio callback
265        let callback: AudioCallback = Arc::new(move |output: &mut [f32]| {
266            // Try to get the next audio buffer from the queue
267            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                    // Copy audio data to output
275                    output.copy_from_slice(&samples[..frames_needed]);
276
277                    // If there are remaining samples, put them back in the queue
278                    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                    // Zero-pad if not enough samples
289                    output[..samples.len()].copy_from_slice(samples);
290                    output[samples.len()..].fill(0.0);
291                }
292
293                drop(queue); // Release lock early
294
295                // Update metrics
296                let mut m = metrics.lock();
297                m.frames_processed += frames_needed as u64;
298                m.is_active = true;
299
300                Ok(())
301            } else {
302                // No audio data available - output silence
303                output.fill(0.0);
304                drop(queue); // Release lock early
305
306                let mut m = metrics.lock();
307                m.underruns += 1;
308
309                Ok(())
310            }
311        });
312
313        // Initialize and start the audio stream
314        self.driver
315            .initialize_stream(None, self.config.clone(), callback)
316            .await?;
317        self.driver.start_stream().await?;
318
319        Ok(())
320    }
321
322    /// Stop the audio stream
323    pub async fn stop(&mut self) -> DriverResult<()> {
324        self.driver.stop_stream().await
325    }
326
327    /// Get current audio metrics
328    pub fn metrics(&self) -> AudioStreamMetrics {
329        self.metrics.lock().clone()
330    }
331
332    /// Queue an audio buffer for playback
333    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}