diff --git a/src/alsa/enumerate.rs b/src/alsa/enumerate.rs new file mode 100644 index 0000000..b087acb --- /dev/null +++ b/src/alsa/enumerate.rs @@ -0,0 +1,78 @@ +use super::alsa; +use super::check_errors; +use super::Endpoint; + +use std::ffi::CStr; +use std::mem; + +/// ALSA implementation for `EndpointsIterator`. +pub struct EndpointsIterator { + // we keep the original list so that we can pass it to the free function + global_list: *const *const u8, + + // pointer to the next string ; contained within `global_list` + next_str: *const *const u8, +} + +unsafe impl Send for EndpointsIterator {} +unsafe impl Sync for EndpointsIterator {} + +impl Drop for EndpointsIterator { + fn drop(&mut self) { + unsafe { + alsa::snd_device_name_free_hint(self.global_list as *mut _); + } + } +} + +impl Default for EndpointsIterator { + fn default() -> EndpointsIterator { + unsafe { + let mut hints = mem::uninitialized(); + // TODO: check in which situation this can fail + check_errors(alsa::snd_device_name_hint(-1, b"pcm\0".as_ptr() as *const _, + &mut hints)).unwrap(); + + let hints = hints as *const *const u8; + + EndpointsIterator { + global_list: hints, + next_str: hints, + } + } + } +} + +impl Iterator for EndpointsIterator { + type Item = Endpoint; + + fn next(&mut self) -> Option { + loop { + unsafe { + if (*self.next_str).is_null() { + return None; + } + + let name = alsa::snd_device_name_get_hint(*self.next_str as *const _, + b"NAME".as_ptr() as *const _); + self.next_str = self.next_str.offset(1); + + if name.is_null() { + continue; + } + + let name = CStr::from_ptr(name).to_bytes().to_vec(); + let name = String::from_utf8(name).unwrap(); + + if name != "null" { + return Some(Endpoint(name)); + } + } + } + } +} + +pub fn get_default_endpoint() -> Option { + // TODO: do in a different way? + Some(Endpoint("default".to_owned())) +} diff --git a/src/alsa/mod.rs b/src/alsa/mod.rs index ce7889e..4472ed5 100644 --- a/src/alsa/mod.rs +++ b/src/alsa/mod.rs @@ -1,9 +1,39 @@ extern crate alsa_sys as alsa; extern crate libc; +pub use self::enumerate::{EndpointsIterator, get_default_endpoint}; + +use CreationError; +use Format; +use FormatsEnumerationError; +use SampleFormat; +use SamplesRate; + use std::{ffi, iter, mem}; +use std::option::IntoIter as OptionIntoIter; use std::sync::Mutex; +pub type SupportedFormatsIterator = OptionIntoIter; + +mod enumerate; + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Endpoint(String); + +impl Endpoint { + pub fn get_supported_formats_list(&self) + -> Result + { + let format = Format { + channels: 2, + samples_rate: SamplesRate(44100), + data_type: SampleFormat::I16, + }; + + Ok(Some(format).into_iter()) + } +} + pub struct Voice { channel: Mutex<*mut alsa::snd_pcm_t>, num_channels: u16, @@ -15,9 +45,9 @@ pub struct Buffer<'a, T> { } impl Voice { - pub fn new() -> Voice { + pub fn new(endpoint: &Endpoint, _format: &Format) -> Result { unsafe { - let name = ffi::CString::new(b"default".to_vec()).unwrap(); + let name = ffi::CString::new(endpoint.0.clone()).unwrap(); 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(); @@ -34,10 +64,10 @@ impl Voice { check_errors(alsa::snd_pcm_prepare(playback_handle)).unwrap(); - Voice { + Ok(Voice { channel: Mutex::new(playback_handle), num_channels: 2, - } + }) } }