cpal/src/alsa/mod.rs

307 lines
10 KiB
Rust
Raw Normal View History

2015-03-26 09:03:13 +00:00
extern crate alsa_sys as alsa;
2014-12-16 15:45:45 +00:00
extern crate libc;
2015-09-01 15:15:49 +00:00
pub use self::enumerate::{EndpointsIterator, get_default_endpoint};
2015-09-10 10:43:37 +00:00
use ChannelPosition;
2015-09-01 15:15:49 +00:00
use CreationError;
use Format;
use FormatsEnumerationError;
use SampleFormat;
use SamplesRate;
use std::{ffi, iter, mem, ptr};
use std::vec::IntoIter as VecIntoIter;
use std::sync::Mutex;
2014-12-16 15:45:45 +00:00
pub type SupportedFormatsIterator = VecIntoIter<Format>;
2015-09-01 15:15:49 +00:00
mod enumerate;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Endpoint(String);
impl Endpoint {
pub fn get_supported_formats_list(&self)
-> Result<SupportedFormatsIterator, FormatsEnumerationError>
{
unsafe {
let mut playback_handle = mem::uninitialized();
check_errors(alsa::snd_pcm_open(&mut playback_handle, b"hw\0".as_ptr() as *const _,
alsa::SND_PCM_STREAM_PLAYBACK,
alsa::SND_PCM_NONBLOCK)).unwrap();
let hw_params = HwParams::alloc();
check_errors(alsa::snd_pcm_hw_params_any(playback_handle, hw_params.0)).unwrap();
const FORMATS: [(SampleFormat, alsa::snd_pcm_format_t); 3] = [
//SND_PCM_FORMAT_S8,
//SND_PCM_FORMAT_U8,
(SampleFormat::I16, alsa::SND_PCM_FORMAT_S16_LE),
//SND_PCM_FORMAT_S16_BE,
(SampleFormat::U16, alsa::SND_PCM_FORMAT_U16_LE),
//SND_PCM_FORMAT_U16_BE,
/*SND_PCM_FORMAT_S24_LE,
SND_PCM_FORMAT_S24_BE,
SND_PCM_FORMAT_U24_LE,
SND_PCM_FORMAT_U24_BE,
SND_PCM_FORMAT_S32_LE,
SND_PCM_FORMAT_S32_BE,
SND_PCM_FORMAT_U32_LE,
SND_PCM_FORMAT_U32_BE,*/
(SampleFormat::F32, alsa::SND_PCM_FORMAT_FLOAT_LE),
/*SND_PCM_FORMAT_FLOAT_BE,
SND_PCM_FORMAT_FLOAT64_LE,
SND_PCM_FORMAT_FLOAT64_BE,
SND_PCM_FORMAT_IEC958_SUBFRAME_LE,
SND_PCM_FORMAT_IEC958_SUBFRAME_BE,
SND_PCM_FORMAT_MU_LAW,
SND_PCM_FORMAT_A_LAW,
SND_PCM_FORMAT_IMA_ADPCM,
SND_PCM_FORMAT_MPEG,
SND_PCM_FORMAT_GSM,
SND_PCM_FORMAT_SPECIAL,
SND_PCM_FORMAT_S24_3LE,
SND_PCM_FORMAT_S24_3BE,
SND_PCM_FORMAT_U24_3LE,
SND_PCM_FORMAT_U24_3BE,
SND_PCM_FORMAT_S20_3LE,
SND_PCM_FORMAT_S20_3BE,
SND_PCM_FORMAT_U20_3LE,
SND_PCM_FORMAT_U20_3BE,
SND_PCM_FORMAT_S18_3LE,
SND_PCM_FORMAT_S18_3BE,
SND_PCM_FORMAT_U18_3LE,
SND_PCM_FORMAT_U18_3BE,*/
];
let mut supported_formats = Vec::new();
for &(sample_format, alsa_format) in FORMATS.iter() {
if alsa::snd_pcm_hw_params_test_format(playback_handle, hw_params.0, alsa_format) == 0 {
supported_formats.push(sample_format);
}
}
let mut min_rate = mem::uninitialized();
check_errors(alsa::snd_pcm_hw_params_get_rate_min(hw_params.0, &mut min_rate, ptr::null_mut())).unwrap();
let mut max_rate = mem::uninitialized();
check_errors(alsa::snd_pcm_hw_params_get_rate_max(hw_params.0, &mut max_rate, ptr::null_mut())).unwrap();
let samples_rates = if min_rate == max_rate {
vec![min_rate]
} else if alsa::snd_pcm_hw_params_test_rate(playback_handle, hw_params.0, min_rate + 1, 0) == 0 {
(min_rate .. max_rate + 1).collect()
} else {
const RATES: [libc::c_uint; 13] = [
5512,
8000,
11025,
16000,
22050,
32000,
44100,
48000,
64000,
88200,
96000,
176400,
192000,
];
let mut rates = Vec::new();
for &rate in RATES.iter() {
if alsa::snd_pcm_hw_params_test_rate(playback_handle, hw_params.0, rate, 0) == 0 {
rates.push(rate);
}
}
if rates.len() == 0 {
(min_rate .. max_rate + 1).collect()
} else {
rates
}
};
let mut min_channels = mem::uninitialized();
check_errors(alsa::snd_pcm_hw_params_get_channels_min(hw_params.0, &mut min_channels)).unwrap();
let mut max_channels = mem::uninitialized();
check_errors(alsa::snd_pcm_hw_params_get_channels_max(hw_params.0, &mut max_channels)).unwrap();
let supported_channels = (min_channels .. max_channels + 1).filter_map(|num| {
if alsa::snd_pcm_hw_params_test_channels(playback_handle, hw_params.0, num) == 0 {
Some(iter::repeat(ChannelPosition::FrontLeft).take(num as usize).collect::<Vec<_>>()) // FIXME:
} else {
None
}
}).collect::<Vec<_>>();
let mut output = Vec::with_capacity(supported_formats.len() * supported_channels.len() *
samples_rates.len());
for &data_type in supported_formats.iter() {
for channels in supported_channels.iter() {
for &rate in samples_rates.iter() {
output.push(Format {
channels: channels.clone(),
samples_rate: SamplesRate(rate as u32),
data_type: data_type,
});
}
}
}
// TODO: RAII
alsa::snd_pcm_close(playback_handle);
Ok(output.into_iter())
}
2015-09-01 15:15:49 +00:00
}
#[inline]
pub fn get_name(&self) -> String {
"unknown".to_owned() // TODO:
}
2015-09-01 15:15:49 +00:00
}
2014-12-17 08:16:26 +00:00
pub struct Voice {
channel: Mutex<*mut alsa::snd_pcm_t>,
2014-12-16 15:45:45 +00:00
num_channels: u16,
}
pub struct Buffer<'a, T> {
2014-12-17 08:16:26 +00:00
channel: &'a mut Voice,
2014-12-16 15:45:45 +00:00
buffer: Vec<T>,
}
/// Wrapper around `hw_params`.
struct HwParams(*mut alsa::snd_pcm_hw_params_t);
impl HwParams {
pub fn alloc() -> HwParams {
unsafe {
let mut hw_params = mem::uninitialized();
check_errors(alsa::snd_pcm_hw_params_malloc(&mut hw_params)).unwrap();
HwParams(hw_params)
}
}
}
impl Drop for HwParams {
fn drop(&mut self) {
unsafe {
alsa::snd_pcm_hw_params_free(self.0);
}
}
}
2014-12-17 08:16:26 +00:00
impl Voice {
2015-09-01 15:15:49 +00:00
pub fn new(endpoint: &Endpoint, _format: &Format) -> Result<Voice, CreationError> {
2014-12-16 15:45:45 +00:00
unsafe {
2015-09-01 15:15:49 +00:00
let name = ffi::CString::new(endpoint.0.clone()).unwrap();
2014-12-16 15:45:45 +00:00
let mut playback_handle = mem::uninitialized();
check_errors(alsa::snd_pcm_open(&mut playback_handle, name.as_ptr(),
alsa::SND_PCM_STREAM_PLAYBACK,
alsa::SND_PCM_NONBLOCK)).unwrap();
let hw_params = HwParams::alloc();
check_errors(alsa::snd_pcm_hw_params_any(playback_handle, hw_params.0)).unwrap();
check_errors(alsa::snd_pcm_hw_params_set_access(playback_handle, hw_params.0, alsa::SND_PCM_ACCESS_RW_INTERLEAVED)).unwrap();
check_errors(alsa::snd_pcm_hw_params_set_format(playback_handle, hw_params.0, alsa::SND_PCM_FORMAT_S16_LE)).unwrap(); // TODO: check endianess
check_errors(alsa::snd_pcm_hw_params_set_rate(playback_handle, hw_params.0, 44100, 0)).unwrap();
check_errors(alsa::snd_pcm_hw_params_set_channels(playback_handle, hw_params.0, 2)).unwrap();
check_errors(alsa::snd_pcm_hw_params(playback_handle, hw_params.0)).unwrap();
2014-12-16 15:45:45 +00:00
check_errors(alsa::snd_pcm_prepare(playback_handle)).unwrap();
2015-09-01 15:15:49 +00:00
Ok(Voice {
channel: Mutex::new(playback_handle),
2014-12-16 15:45:45 +00:00
num_channels: 2,
2015-09-01 15:15:49 +00:00
})
2014-12-16 15:45:45 +00:00
}
}
2015-01-09 20:25:51 +00:00
pub fn append_data<'a, T>(&'a mut self, max_elements: usize) -> Buffer<'a, T> where T: Clone {
let available = {
let channel = self.channel.lock().unwrap();
let available = unsafe { alsa::snd_pcm_avail(*channel) };
available * self.num_channels as alsa::snd_pcm_sframes_t
};
2014-12-16 15:45:45 +00:00
2015-01-09 20:25:51 +00:00
let elements = ::std::cmp::min(available as usize, max_elements);
2014-12-16 15:45:45 +00:00
Buffer {
channel: self,
2015-01-08 19:34:27 +00:00
buffer: iter::repeat(unsafe { mem::uninitialized() }).take(elements).collect(),
2014-12-16 15:45:45 +00:00
}
}
2014-12-22 13:16:47 +00:00
2015-09-11 08:55:29 +00:00
#[inline]
2014-12-22 13:16:47 +00:00
pub fn play(&mut self) {
// already playing
//unimplemented!()
}
2015-09-11 08:55:29 +00:00
#[inline]
2014-12-22 13:16:47 +00:00
pub fn pause(&mut self) {
unimplemented!()
}
2015-09-10 19:03:40 +00:00
pub fn underflowed(&self) -> bool {
false // TODO:
}
2014-12-16 15:45:45 +00:00
}
2014-12-30 07:35:13 +00:00
unsafe impl Send for Voice {}
unsafe impl Sync for Voice {}
2014-12-17 08:16:26 +00:00
impl Drop for Voice {
2015-09-11 08:55:29 +00:00
#[inline]
2014-12-16 15:45:45 +00:00
fn drop(&mut self) {
unsafe {
alsa::snd_pcm_close(*self.channel.lock().unwrap());
2014-12-16 15:45:45 +00:00
}
}
}
impl<'a, T> Buffer<'a, T> {
2015-09-11 08:55:29 +00:00
#[inline]
2014-12-16 15:45:45 +00:00
pub fn get_buffer<'b>(&'b mut self) -> &'b mut [T] {
2015-03-30 09:06:46 +00:00
&mut self.buffer
2014-12-16 15:45:45 +00:00
}
2015-09-11 08:55:29 +00:00
#[inline]
2015-09-10 19:21:46 +00:00
pub fn len(&self) -> usize {
self.buffer.len()
}
2014-12-16 15:45:45 +00:00
pub fn finish(self) {
let written = (self.buffer.len() / self.channel.num_channels as usize)
as alsa::snd_pcm_uframes_t;
let channel = self.channel.channel.lock().unwrap();
2014-12-16 15:45:45 +00:00
unsafe {
let result = alsa::snd_pcm_writei(*channel,
2014-12-16 15:45:45 +00:00
self.buffer.as_ptr() as *const libc::c_void,
written);
if result < 0 {
check_errors(result as libc::c_int).unwrap();
}
}
}
}
2015-09-11 08:55:29 +00:00
#[inline]
2014-12-16 15:45:45 +00:00
fn check_errors(err: libc::c_int) -> Result<(), String> {
2015-01-08 19:34:27 +00:00
use std::ffi;
2014-12-16 15:45:45 +00:00
if err < 0 {
unsafe {
2015-04-04 07:06:46 +00:00
let s = ffi::CStr::from_ptr(alsa::snd_strerror(err)).to_bytes().to_vec();
let s = String::from_utf8(s).unwrap();
return Err(s);
2014-12-16 15:45:45 +00:00
}
}
Ok(())
}