use crate::alsa::{Access, Direction, Error, Format, Pcm, Result, Sample};
use crate::libc as c;
use std::marker;
const DEFAULT_ACCESS: Access = Access::ReadWriteInterleaved;
const DEFAULT_LATENCY: c::c_uint = 500_000;
const DEFAULT_CHANNELS: c::c_uint = 2;
const DEFAULT_RATE: c::c_uint = 44100;
#[derive(Debug, Clone, Copy)]
pub struct Config {
pub channels: c::c_uint,
pub rate: c::c_uint,
pub buffer_time: c::c_uint,
pub period_time: c::c_uint,
pub period_size: c::c_ulong,
}
pub struct Configurator<'a, T> {
pcm: &'a mut Pcm,
access: Access,
format: Format,
latency: c::c_uint,
channels: c::c_uint,
rate: c::c_uint,
_marker: marker::PhantomData<T>,
}
impl<'a, T> Configurator<'a, T>
where
T: Sample,
{
pub(super) fn new(pcm: &'a mut Pcm) -> Self {
Self {
pcm,
access: DEFAULT_ACCESS,
format: T::DEFAULT_FORMAT,
latency: DEFAULT_LATENCY,
channels: DEFAULT_CHANNELS,
rate: DEFAULT_RATE,
_marker: marker::PhantomData,
}
}
pub fn access(self, access: Access) -> Self {
Self { access, ..self }
}
pub fn format(self, format: Format) -> Result<Self> {
if !T::test(format) {
return Err(Error::FormatMismatch {
ty: T::describe(),
format,
});
}
Ok(Self { format, ..self })
}
pub fn latency(self, latency: std::time::Duration) -> Self {
let latency = u128::min(u32::MAX as u128, latency.as_micros()) as u32;
Self { latency, ..self }
}
pub fn channels(self, channels: c::c_uint) -> Self {
Self { channels, ..self }
}
pub fn rate(self, rate: c::c_uint) -> Self {
Self { rate, ..self }
}
pub fn install(self) -> Result<Config> {
let mut hw = self.pcm.hardware_parameters_any()?;
hw.set_rate_resample(false)?;
hw.set_access(self.access)?;
hw.set_format(self.format)?;
hw.set_channels(self.channels)?;
let (rate, _) = hw.set_rate_near(self.rate, Direction::Nearest)?;
let (buffer_time, _) = hw.set_buffer_time_near(self.latency, Direction::Nearest)?;
let period_time = self.latency / 4;
let (period_time, _) = hw.set_period_time_near(period_time, Direction::Nearest)?;
let buffer_size = hw.buffer_size()?;
let (period_size, _) = hw.period_size()?;
hw.install()?;
let mut sw = self.pcm.software_parameters_mut()?;
sw.set_start_threshold((buffer_size / period_size) * period_size)?;
sw.set_available_min(period_size)?;
sw.install()?;
Ok(Config {
channels: self.channels,
rate,
buffer_time,
period_time,
period_size,
})
}
}