use std::{
hash::DefaultHasher,
sync::{Arc, RwLock},
};
use cpal::{PauseStreamError, PlayStreamError, SupportedStreamConfigRange};
use crate::{
audio_buffer::{AudioBuffer, AudioChannelLayout},
float_type::FloatType,
};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RawAudioStreamError {
DeviceNotAvailable,
Internal(String),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RawAudioStreamState {
Ok,
Err,
Silence,
Other(String),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AudioHostError {
NoDevice,
NoConfig,
UnknownSampleFormat,
UnknownChannelCount,
UnknownStreamConfig,
DeviceNotAvailable,
InvalidArgument,
StreamIdOverflow,
UnknownError,
Internal(String),
}
#[derive(Debug, Clone)]
pub struct Device {
pub name: String,
pub sample_rate: u32,
pub channels: AudioChannelLayout,
pub id: usize,
}
pub trait AudioHostImpl {
fn new() -> AudioHost;
fn default_output_device(&self) -> Option<Device>;
fn get_device_by_id(&self, id: usize) -> Result<Device, AudioHostError>;
fn devices(&self) -> Vec<Device>;
fn create_stream_default(
&mut self,
feeder: Box<dyn StreamFeederTrait<f32>>,
buffer_size: usize,
) -> Result<RawAudioStream<f32>, AudioHostError>;
fn create_stream(
&mut self,
feeder: Box<dyn StreamFeederTrait<f32>>,
buffer_size: usize,
device_id: usize,
) -> Result<RawAudioStream<f32>, AudioHostError>;
}
pub trait RawAudioStreamImpl: Sized {
fn close(&mut self);
fn play(&mut self) -> Result<(), RawAudioStreamError>;
fn pause(&mut self) -> Result<(), RawAudioStreamError>;
fn is_running(&self) -> bool;
fn get_sample_rate(&self) -> u32;
fn get_timestamp(&self) -> usize;
}
pub trait StreamFeederTrait<T: FloatType + Send + Sync> {
fn process(&mut self, input: &mut AudioBuffer<T>) -> RawAudioStreamState;
fn emit_stream_error(&mut self, error: &str);
fn emit_stream_close(&mut self);
fn emit_stream_play(&mut self);
fn emit_stream_pause(&mut self);
}
#[derive(Clone)]
pub struct AudioHost {
pub(super) core: Arc<RwLock<cpal::Host>>,
}
pub struct RawAudioStreamInner<T: FloatType> {
pub(super) core: Option<cpal::Stream>,
pub(super) is_running: bool,
pub(super) buffer: AudioBuffer<T>,
pub(super) buffer_offset: usize,
pub(super) sample_rate: u32,
pub(super) sample_rate_1000: f64,
pub(super) feeder: Box<dyn StreamFeederTrait<T>>,
pub(super) timestamp: usize,
}
#[derive(Clone)]
pub struct RawAudioStream<T: FloatType> {
pub(super) inner: Arc<RwLock<RawAudioStreamInner<T>>>,
}
pub trait PrivateImpl: Sized {
fn channels_to_layout(channels: usize) -> Option<AudioChannelLayout>;
fn conv_cpal_play_stream_error(error: PlayStreamError) -> RawAudioStreamError;
fn conv_cpal_pause_stream_error(error: PauseStreamError) -> RawAudioStreamError;
fn cpal_device_to_device(device: cpal::Device) -> Option<Device>;
fn generate_id_from_cpal_device(device: &cpal::Device) -> i64;
fn hash_config_range(config: &SupportedStreamConfigRange, hasher: &mut DefaultHasher);
}
pub trait AudioHostPrivateImpl: Sized {
fn get_cpal_device_by_id(&self, id: usize) -> Result<cpal::Device, AudioHostError>;
fn create_stream_with_device<T: FloatType + Send + Sync + 'static>(
&mut self,
device: &cpal::Device,
buffer_size: usize,
feeder: Box<dyn StreamFeederTrait<T>>,
) -> Result<Arc<RwLock<RawAudioStreamInner<T>>>, AudioHostError>;
}
pub trait RawAudioStreamPrivateImpl<T: FloatType + Send + Sync>: Sized {
fn user_cpal_process(&mut self, buffer: &mut [f32], channels: AudioChannelLayout);
}
pub struct Private {}