use alsa::pcm::{Access, Format, HwParams, PCM};
use alsa::{Direction, ValueOr};
pub struct AudioOut {
pcm: PCM,
}
impl AudioOut {
pub fn open(device: &str, period_frames: u64) -> AudioOut {
let pcm = PCM::new(device, Direction::Playback, false)
.expect("failed to open ALSA PCM device");
{
let hwp = HwParams::any(&pcm)
.expect("failed to get ALSA hardware params");
hwp.set_access(Access::RWInterleaved)
.expect("failed to set access mode");
hwp.set_format(Format::s16())
.expect("failed to set format S16_LE");
hwp.set_channels(2).expect("failed to set channels to 2");
hwp.set_rate(moont::SAMPLE_RATE, ValueOr::Nearest)
.expect("failed to set sample rate");
hwp.set_period_size(period_frames as i64, ValueOr::Nearest)
.expect("failed to set period size");
hwp.set_periods(4, ValueOr::Nearest)
.expect("failed to set period count");
pcm.hw_params(&hwp)
.expect("failed to apply hardware params");
let rate = hwp.get_rate().unwrap();
if rate != moont::SAMPLE_RATE {
eprintln!(
"Warning: requested {}Hz, got {}Hz",
moont::SAMPLE_RATE,
rate
);
}
}
AudioOut { pcm }
}
pub fn writei(&self, buf: &[i16]) {
let io = self.pcm.io_i16().expect("failed to get PCM I/O");
match io.writei(buf) {
Ok(_) => {}
Err(e) => {
self.pcm
.try_recover(e, true)
.expect("failed to recover from xrun");
let _ = io.writei(buf);
}
}
}
}