diff --git a/Cargo.toml b/Cargo.toml index 1b64b73..a35e1c0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ version = "0" path = "alsa-sys" [target.x86_64-apple-darwin.dependencies] -coreaudio-rs = "*" +coreaudio-rs = "~0.4.0" [dev-dependencies] vorbis = "0" diff --git a/src/coreaudio/enumerate.rs b/src/coreaudio/enumerate.rs new file mode 100644 index 0000000..a69f998 --- /dev/null +++ b/src/coreaudio/enumerate.rs @@ -0,0 +1,29 @@ +use super::Endpoint; + +use ::Format; + +use std::vec::IntoIter as VecIntoIter; + +pub struct EndpointsIterator(bool); + +unsafe impl Send for EndpointsIterator {} +unsafe impl Sync for EndpointsIterator {} + +impl Default for EndpointsIterator { + fn default() -> Self { + EndpointsIterator(false) + } +} + +impl Iterator for EndpointsIterator { + type Item = Endpoint; + fn next(&mut self) -> Option { + if self.0 { None } else { self.0 = true; Some(Endpoint) } + } +} + +pub fn get_default_endpoint() -> Option { + Some(Endpoint) +} + +pub type SupportedFormatsIterator = VecIntoIter; diff --git a/src/coreaudio/mod.rs b/src/coreaudio/mod.rs index b57eec6..e3b6598 100644 --- a/src/coreaudio/mod.rs +++ b/src/coreaudio/mod.rs @@ -1,58 +1,52 @@ extern crate coreaudio_rs as coreaudio; extern crate libc; -use self::coreaudio::audio_unit::{AudioUnit, Type, SubType}; -use std::mem; use std::sync::mpsc::{channel, Sender, Receiver}; +use std::sync::{Arc, Mutex}; +use std::cell::RefCell; +use std::mem; +use std::cmp; +use std::marker::PhantomData; -type NumChannels = usize; -type NumFrames = usize; +use CreationError; +use Format; +use FormatsEnumerationError; +use SampleFormat; +use SamplesRate; +use ChannelPosition; -#[allow(dead_code)] -pub struct Voice { - audio_unit: AudioUnit, - ready_receiver: Receiver<(NumChannels, NumFrames)>, - samples_sender: Sender<(Vec, NumChannels)>, +mod enumerate; + +pub use self::enumerate::{EndpointsIterator, + SupportedFormatsIterator, + get_default_endpoint}; + +use self::coreaudio::audio_unit::{AudioUnit, IOType}; + +#[derive(Clone, PartialEq, Eq)] +pub struct Endpoint; + +impl Endpoint { + pub fn get_supported_formats_list(&self) + -> Result + { + Ok(vec!(Format { + channels: vec![ChannelPosition::FrontLeft, ChannelPosition::FrontRight], + samples_rate: SamplesRate(44100), + data_type: SampleFormat::F32 + }).into_iter()) + } + + pub fn get_name(&self) -> String { + "Default AudioUnit Endpoint".to_string() + } } pub struct Buffer<'a, T: 'a> { samples_sender: Sender<(Vec, NumChannels)>, samples: Vec, num_channels: NumChannels, - marker: ::std::marker::PhantomData<&'a T>, -} - -impl Voice { - - #[inline] - pub fn new() -> Voice { - new_voice().unwrap() - } - - pub fn append_data<'a, T>(&'a mut self, max_elements: usize) -> Buffer<'a, T> where T: Clone { - // Block until the audio callback is ready for more data. - loop { - if let Ok((channels, frames)) = self.ready_receiver.try_recv() { - let buffer_size = ::std::cmp::min(channels * frames, max_elements); - return Buffer { - samples_sender: self.samples_sender.clone(), - samples: vec![unsafe{ mem::uninitialized() }; buffer_size], - num_channels: channels as usize, - marker: ::std::marker::PhantomData, - } - } - } - } - - #[inline] - pub fn play(&mut self) { - // TODO - } - - #[inline] - pub fn pause(&mut self) { - // TODO - } + marker: PhantomData<&'a T>, } impl<'a, T> Buffer<'a, T> { @@ -60,6 +54,13 @@ impl<'a, T> Buffer<'a, T> { pub fn get_buffer<'b>(&'b mut self) -> &'b mut [T] { &mut self.samples[..] } + + #[inline] + pub fn len(&self) -> usize { + self.samples.len() + } + + #[inline] pub fn finish(self) { let Buffer { samples_sender, samples, num_channels, .. } = self; // TODO: At the moment this assumes the Vec is a Vec. @@ -72,50 +73,153 @@ impl<'a, T> Buffer<'a, T> { } } +type NumChannels = usize; +type NumFrames = usize; -/// Construct a new Voice. -fn new_voice() -> Result { +#[allow(dead_code)] // the audio_unit will be dropped if we don't hold it. +pub struct Voice { + audio_unit: AudioUnit, + ready_receiver: Receiver<(NumChannels, NumFrames)>, + samples_sender: Sender<(Vec, NumChannels)>, + underflow: Arc>>, + last_ready: Arc>>> +} - // A channel for signalling that the audio unit is ready for data. - let (ready_sender, ready_receiver) = channel(); - // A channel for sending the audio callback a pointer to the sample data. - let (samples_sender, samples_receiver) = channel(); +unsafe impl Sync for Voice {} +unsafe impl Send for Voice {} - let audio_unit_result = AudioUnit::new(Type::Output, SubType::HalOutput) - .render_callback(Box::new(move |channels, num_frames| { - if let Err(_) = ready_sender.send((channels.len(), num_frames)) { - return Err("Callback failed to send 'ready' message.".to_string()); - } - loop { - if let Ok((samples, num_channels)) = samples_receiver.try_recv() { - let samples: Vec = samples; - assert!(num_frames == (samples.len() / num_channels) as usize, - "The number of input frames given differs from the number \ - requested by the AudioUnit: {:?} and {:?} respectively", - (samples.len() / num_channels as usize), num_frames); - for (i, frame) in samples.chunks(num_channels).enumerate() { - for (channel, sample) in channels.iter_mut().zip(frame.iter()) { - channel[i] = *sample; +impl Voice { + pub fn new(_: &Endpoint, _: &Format) -> Result { + // A channel for signalling that the audio unit is ready for data. + let (ready_sender, ready_receiver) = channel(); + // A channel for sending the audio callback a pointer to the sample data. + let (samples_sender, samples_receiver) = channel(); + + let underflow = Arc::new(Mutex::new(RefCell::new(false))); + let uf_clone = underflow.clone(); + + let audio_unit_result = AudioUnit::new(IOType::HalOutput); + + if let Ok(mut audio_unit) = audio_unit_result { + if let Ok(()) = audio_unit.set_render_callback(Some(Box::new(move |channels: &mut[&mut[f32]], num_frames: NumFrames| { + if let Err(_) = ready_sender.send((channels.len(), num_frames)) { + return Err("Callback failed to send 'ready' message.".to_string()); + } + loop { + if let Ok((samples, num_channels)) = samples_receiver.try_recv() { + let samples: Vec = samples; + if let Ok(uf) = uf_clone.lock() { + *(uf.borrow_mut()) = num_frames > samples.len() / num_channels; + } else { return Err("Couldn't lock underflow flag field.".to_string()) } + + for (i, frame) in samples.chunks(num_channels).enumerate() { + for (channel, sample) in channels.iter_mut().zip(frame.iter()) { + channel[i] = *sample; + } } - } - break; - }; + break; + }; + } + Ok(()) + + }))) { + if let Ok(()) = audio_unit.start() { + return Ok(Voice { + audio_unit: audio_unit, + ready_receiver: ready_receiver, + samples_sender: samples_sender, + underflow: underflow, + last_ready: Arc::new(Mutex::new(RefCell::new(None))) + }) + } } - Ok(()) + } - })) - .start(); - - match audio_unit_result { - Ok(audio_unit) => Ok(Voice { - audio_unit: audio_unit, - ready_receiver: ready_receiver, - samples_sender: samples_sender - }), - Err(err) => { - use ::std::error::Error; - Err(err.description().to_string()) - }, + Err(CreationError::DeviceNotAvailable) } + pub fn append_data<'a, T>(&'a mut self, max_elements: usize) -> Buffer<'a, T> where T: Clone { + // Block until the audio callback is ready for more data. + let (channels, frames) = self.block_until_ready(); + let buffer_size = cmp::min(channels * frames, max_elements); + Buffer { + samples_sender: self.samples_sender.clone(), + samples: vec![unsafe { mem::uninitialized() }; buffer_size], + num_channels: channels as usize, + marker: PhantomData + } + } + + #[inline] + pub fn play(&mut self) { + // implicitly playing + } + + #[inline] + pub fn pause(&mut self) { + unimplemented!() + } + + #[inline] + pub fn get_pending_samples(&self) -> usize { + if let Some(ready) = self.update_last_ready() { + (ready.0 * ready.1) as usize + } else { + 0 + } + } + + /// Attempts to store the most recent ready message into the internal + /// ref cell, then return the last ready message. If the last ready hasn't + /// been reset with `clear_last_ready`, then it will not be set and the + /// current value will be returned. Else, the ready_receiver will be + /// try_recv'd and if it is ready, the last ready will be set and returned. + /// Finally, if the ready_receiver had no data at try_recv, None will be + /// returned. + #[inline] + fn update_last_ready(&self) -> Option<(NumChannels, NumFrames)> { + let refcell = self.last_ready.lock().unwrap(); + let data = refcell.borrow(); + if let Some(s) = *data { + // + return Some(s); + } else { + drop(data); + let mut data = refcell.borrow_mut(); + if let Ok(ready) = self.ready_receiver.try_recv() { + // the audiounit is ready so we can set last_ready + *data = Some(ready); + return *data; + } + } + None + } + + /// Block until ready to send data. This checks last_ready first. In any + /// case, last_ready will be set to None when this function returns. + fn block_until_ready(&self) -> (NumChannels, NumFrames) { + let refcell = self.last_ready.lock().unwrap(); + let data = refcell.borrow(); + if let Some(s) = *data { + drop(data); + let mut data = refcell.borrow_mut(); + *data = None; + return s; + } else { + match self.ready_receiver.recv() { + Ok(ready) => { + return ready; + }, + Err(e) => panic!("Couldn't receive a ready message: \ + {:?}", e) + } + } + } + + #[inline] + pub fn underflowed(&self) -> bool { + let uf = self.underflow.lock().unwrap(); + let v = uf.borrow(); + *v + } }