From c841be235cc718306ae76c9d96eced4f926a9ebb Mon Sep 17 00:00:00 2001 From: Ronald Kinard Date: Wed, 23 Sep 2015 22:02:28 -0500 Subject: [PATCH 01/10] Restore CoreAudio support after API overhaul. --- src/coreaudio/enumerate.rs | 29 ++++++ src/coreaudio/mod.rs | 198 ++++++++++++++++++++++--------------- 2 files changed, 147 insertions(+), 80 deletions(-) create mode 100644 src/coreaudio/enumerate.rs 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..e70ce86 100644 --- a/src/coreaudio/mod.rs +++ b/src/coreaudio/mod.rs @@ -1,65 +1,63 @@ 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::mem; -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, Type, SubType}; + +#[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(512), + 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, + len: usize, 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 - } -} - impl<'a, T> Buffer<'a, T> { #[inline] pub fn get_buffer<'b>(&'b mut self) -> &'b mut [T] { &mut self.samples[..] } + + #[inline] + pub fn len(&self) -> usize { + self.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 +70,90 @@ impl<'a, T> Buffer<'a, T> { } } +type NumChannels = usize; +type NumFrames = usize; -/// Construct a new Voice. -fn new_voice() -> Result { +pub struct Voice { + audio_unit: AudioUnit, + ready_receiver: Receiver<(NumChannels, NumFrames)>, + samples_sender: Sender<(Vec, NumChannels)>, +} - // 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(); +impl Voice { + pub fn new(endpoint: &Endpoint, format: &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 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; + 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; + } } - } - break; - }; - } - Ok(()) + break; + }; + } + Ok(()) - })) - .start(); + })) + .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()) - }, + match audio_unit_result { + Ok(audio_unit) => Ok(Voice { + audio_unit: audio_unit, + ready_receiver: ready_receiver, + samples_sender: samples_sender + }), + Err(_) => { + 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. + 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, + len: 512 + } + } + } + } + + #[inline] + pub fn play(&mut self) { + // implicitly playing + } + + #[inline] + pub fn pause(&mut self) { + unimplemented!() + } + + pub fn get_pending_samples(&self) -> usize { + 0 + } + + pub fn underflowed(&self) -> bool { + false + } } From dbf9ae20dae56f22f47f24ae236e884efa1f3371 Mon Sep 17 00:00:00 2001 From: Ronald Kinard Date: Wed, 23 Sep 2015 22:14:32 -0500 Subject: [PATCH 02/10] Make coreaudio Voice Send/Sync. --- src/coreaudio/mod.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/coreaudio/mod.rs b/src/coreaudio/mod.rs index e70ce86..8c8fc00 100644 --- a/src/coreaudio/mod.rs +++ b/src/coreaudio/mod.rs @@ -28,7 +28,7 @@ impl Endpoint { { Ok(vec!(Format { channels: vec![ChannelPosition::FrontLeft, ChannelPosition::FrontRight], - samples_rate: SamplesRate(512), + samples_rate: SamplesRate(64), data_type: SampleFormat::F32 }).into_iter()) } @@ -79,6 +79,9 @@ pub struct Voice { samples_sender: Sender<(Vec, NumChannels)>, } +unsafe impl Sync for Voice {} +unsafe impl Send for Voice {} + impl Voice { pub fn new(endpoint: &Endpoint, format: &Format) -> Result { // A channel for signalling that the audio unit is ready for data. @@ -133,7 +136,7 @@ impl Voice { samples: vec![unsafe{ mem::uninitialized() }; buffer_size], num_channels: channels as usize, marker: ::std::marker::PhantomData, - len: 512 + len: 64 } } } From 54fb5b03cc8d27e89981cfc3738be95a17c898cf Mon Sep 17 00:00:00 2001 From: Ronald Kinard Date: Wed, 23 Sep 2015 22:23:40 -0500 Subject: [PATCH 03/10] Set coreaudio sample rate to 44100. This makes rodio demos work correctly! --- src/coreaudio/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreaudio/mod.rs b/src/coreaudio/mod.rs index 8c8fc00..e93e771 100644 --- a/src/coreaudio/mod.rs +++ b/src/coreaudio/mod.rs @@ -28,7 +28,7 @@ impl Endpoint { { Ok(vec!(Format { channels: vec![ChannelPosition::FrontLeft, ChannelPosition::FrontRight], - samples_rate: SamplesRate(64), + samples_rate: SamplesRate(44100), data_type: SampleFormat::F32 }).into_iter()) } From bdef4fb3fe034cebf7ed6b47509e06a31cb22e65 Mon Sep 17 00:00:00 2001 From: Ronald Kinard Date: Wed, 23 Sep 2015 23:19:29 -0500 Subject: [PATCH 04/10] coreaudio: Add support for U16/I16 PCM formats. The conversion is done Rust-side instead of using AUHAL's automatic conversion because I haven't gotten around generics issues yet. --- src/coreaudio/mod.rs | 26 +++++++++++++++++++------- src/samples_formats.rs | 7 +++++++ 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/src/coreaudio/mod.rs b/src/coreaudio/mod.rs index e93e771..2039f14 100644 --- a/src/coreaudio/mod.rs +++ b/src/coreaudio/mod.rs @@ -10,6 +10,7 @@ use FormatsEnumerationError; use SampleFormat; use SamplesRate; use ChannelPosition; +use Sample; mod enumerate; @@ -26,11 +27,21 @@ 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()) + // AUHAL converts internally for simple PCM translations. + // However, an additional AudioConverter unit is needed in order to + // change sample rate. + // TODO support other sample rates. + let formats = [SampleFormat::F32, SampleFormat::I16, SampleFormat::U16] + .into_iter() + .map(|f| { + Format { + channels: vec![ChannelPosition::FrontLeft, ChannelPosition::FrontRight], + samples_rate: SamplesRate(44100), + data_type: *f + } + }) + .collect::>(); + Ok(formats.into_iter()) } pub fn get_name(&self) -> String { @@ -46,7 +57,7 @@ pub struct Buffer<'a, T: 'a> { marker: ::std::marker::PhantomData<&'a T>, } -impl<'a, T> Buffer<'a, T> { +impl<'a, T: Sample> Buffer<'a, T> { #[inline] pub fn get_buffer<'b>(&'b mut self) -> &'b mut [T] { &mut self.samples[..] @@ -62,7 +73,8 @@ impl<'a, T> Buffer<'a, T> { let Buffer { samples_sender, samples, num_channels, .. } = self; // TODO: At the moment this assumes the Vec is a Vec. // Need to add T: Sample and use Sample::to_vec_f32. - let samples = unsafe { mem::transmute(samples) }; + //let samples = unsafe { mem::transmute(samples) }; + let samples = samples.into_iter().map(|x| x.as_f32()).collect(); match samples_sender.send((samples, num_channels)) { Err(_) => panic!("Failed to send samples to audio unit callback."), Ok(()) => (), diff --git a/src/samples_formats.rs b/src/samples_formats.rs index ebf6525..14f88ee 100644 --- a/src/samples_formats.rs +++ b/src/samples_formats.rs @@ -27,6 +27,7 @@ impl SampleFormat { pub unsafe trait Sample: Copy + Clone { /// Returns the `SampleFormat` corresponding to this data type. fn get_format() -> SampleFormat; + fn as_f32(&self) -> f32; } unsafe impl Sample for u16 { @@ -34,6 +35,8 @@ unsafe impl Sample for u16 { fn get_format() -> SampleFormat { SampleFormat::U16 } + + fn as_f32(&self) -> f32 { (*self as f32 - 32768.0) / (32768.0) } } unsafe impl Sample for i16 { @@ -41,6 +44,8 @@ unsafe impl Sample for i16 { fn get_format() -> SampleFormat { SampleFormat::I16 } + + fn as_f32(&self) -> f32 { (*self as f32) / (32768.0) } } unsafe impl Sample for f32 { @@ -48,4 +53,6 @@ unsafe impl Sample for f32 { fn get_format() -> SampleFormat { SampleFormat::F32 } + + fn as_f32(&self) -> f32 { *self } } From fd50a113a1b5fc9af8af5a037a89bfb45d3985ec Mon Sep 17 00:00:00 2001 From: Ronald Kinard Date: Thu, 24 Sep 2015 12:54:54 -0500 Subject: [PATCH 05/10] Revert "coreaudio: Add support for U16/I16 PCM formats." This reverts commit bdef4fb3fe034cebf7ed6b47509e06a31cb22e65. --- src/coreaudio/mod.rs | 26 +++++++------------------- src/samples_formats.rs | 7 ------- 2 files changed, 7 insertions(+), 26 deletions(-) diff --git a/src/coreaudio/mod.rs b/src/coreaudio/mod.rs index 2039f14..e93e771 100644 --- a/src/coreaudio/mod.rs +++ b/src/coreaudio/mod.rs @@ -10,7 +10,6 @@ use FormatsEnumerationError; use SampleFormat; use SamplesRate; use ChannelPosition; -use Sample; mod enumerate; @@ -27,21 +26,11 @@ impl Endpoint { pub fn get_supported_formats_list(&self) -> Result { - // AUHAL converts internally for simple PCM translations. - // However, an additional AudioConverter unit is needed in order to - // change sample rate. - // TODO support other sample rates. - let formats = [SampleFormat::F32, SampleFormat::I16, SampleFormat::U16] - .into_iter() - .map(|f| { - Format { - channels: vec![ChannelPosition::FrontLeft, ChannelPosition::FrontRight], - samples_rate: SamplesRate(44100), - data_type: *f - } - }) - .collect::>(); - Ok(formats.into_iter()) + 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 { @@ -57,7 +46,7 @@ pub struct Buffer<'a, T: 'a> { marker: ::std::marker::PhantomData<&'a T>, } -impl<'a, T: Sample> Buffer<'a, T> { +impl<'a, T> Buffer<'a, T> { #[inline] pub fn get_buffer<'b>(&'b mut self) -> &'b mut [T] { &mut self.samples[..] @@ -73,8 +62,7 @@ impl<'a, T: Sample> Buffer<'a, T> { let Buffer { samples_sender, samples, num_channels, .. } = self; // TODO: At the moment this assumes the Vec is a Vec. // Need to add T: Sample and use Sample::to_vec_f32. - //let samples = unsafe { mem::transmute(samples) }; - let samples = samples.into_iter().map(|x| x.as_f32()).collect(); + let samples = unsafe { mem::transmute(samples) }; match samples_sender.send((samples, num_channels)) { Err(_) => panic!("Failed to send samples to audio unit callback."), Ok(()) => (), diff --git a/src/samples_formats.rs b/src/samples_formats.rs index 14f88ee..ebf6525 100644 --- a/src/samples_formats.rs +++ b/src/samples_formats.rs @@ -27,7 +27,6 @@ impl SampleFormat { pub unsafe trait Sample: Copy + Clone { /// Returns the `SampleFormat` corresponding to this data type. fn get_format() -> SampleFormat; - fn as_f32(&self) -> f32; } unsafe impl Sample for u16 { @@ -35,8 +34,6 @@ unsafe impl Sample for u16 { fn get_format() -> SampleFormat { SampleFormat::U16 } - - fn as_f32(&self) -> f32 { (*self as f32 - 32768.0) / (32768.0) } } unsafe impl Sample for i16 { @@ -44,8 +41,6 @@ unsafe impl Sample for i16 { fn get_format() -> SampleFormat { SampleFormat::I16 } - - fn as_f32(&self) -> f32 { (*self as f32) / (32768.0) } } unsafe impl Sample for f32 { @@ -53,6 +48,4 @@ unsafe impl Sample for f32 { fn get_format() -> SampleFormat { SampleFormat::F32 } - - fn as_f32(&self) -> f32 { *self } } From 53c5529b16fcfad602878ea90d072a29d181a48c Mon Sep 17 00:00:00 2001 From: Ronald Kinard Date: Thu, 24 Sep 2015 13:19:42 -0500 Subject: [PATCH 06/10] Return correct length of buffer, stub unimpl funcs --- src/coreaudio/mod.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/coreaudio/mod.rs b/src/coreaudio/mod.rs index e93e771..181c1d0 100644 --- a/src/coreaudio/mod.rs +++ b/src/coreaudio/mod.rs @@ -42,7 +42,6 @@ pub struct Buffer<'a, T: 'a> { samples_sender: Sender<(Vec, NumChannels)>, samples: Vec, num_channels: NumChannels, - len: usize, marker: ::std::marker::PhantomData<&'a T>, } @@ -54,7 +53,7 @@ impl<'a, T> Buffer<'a, T> { #[inline] pub fn len(&self) -> usize { - self.len + self.samples.len() } #[inline] @@ -135,8 +134,7 @@ impl Voice { samples_sender: self.samples_sender.clone(), samples: vec![unsafe{ mem::uninitialized() }; buffer_size], num_channels: channels as usize, - marker: ::std::marker::PhantomData, - len: 64 + marker: ::std::marker::PhantomData } } } @@ -152,11 +150,13 @@ impl Voice { unimplemented!() } + #[inline] pub fn get_pending_samples(&self) -> usize { - 0 + unimplemented!() } + #[inline] pub fn underflowed(&self) -> bool { - false + unimplemented!() } } From 1cdf5af808ba3ed124121623b259cf0f8d80aee5 Mon Sep 17 00:00:00 2001 From: Ronald Kinard Date: Thu, 24 Sep 2015 16:24:12 -0500 Subject: [PATCH 07/10] coreaudio: Implement some missing functions. underflow and get_pending_samples. --- src/coreaudio/mod.rs | 119 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 101 insertions(+), 18 deletions(-) diff --git a/src/coreaudio/mod.rs b/src/coreaudio/mod.rs index 181c1d0..7d33d59 100644 --- a/src/coreaudio/mod.rs +++ b/src/coreaudio/mod.rs @@ -2,6 +2,8 @@ extern crate coreaudio_rs as coreaudio; extern crate libc; use std::sync::mpsc::{channel, Sender, Receiver}; +use std::sync::{Arc, Mutex}; +use std::cell::RefCell; use std::mem; use CreationError; @@ -72,22 +74,28 @@ impl<'a, T> Buffer<'a, T> { type NumChannels = usize; type NumFrames = usize; +#[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>>> } unsafe impl Sync for Voice {} unsafe impl Send for Voice {} impl Voice { - pub fn new(endpoint: &Endpoint, format: &Format) -> Result { + 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(Type::Output, SubType::HalOutput) .render_callback(Box::new(move |channels, num_frames| { if let Err(_) = ready_sender.send((channels.len(), num_frames)) { @@ -96,10 +104,10 @@ impl Voice { 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); + 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; @@ -117,7 +125,9 @@ impl Voice { Ok(audio_unit) => Ok(Voice { audio_unit: audio_unit, ready_receiver: ready_receiver, - samples_sender: samples_sender + samples_sender: samples_sender, + underflow: underflow, + last_ready: Arc::new(Mutex::new(RefCell::new(None))) }), Err(_) => { Err(CreationError::DeviceNotAvailable) @@ -127,16 +137,13 @@ impl Voice { 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 - } - } + let (channels, frames) = self.block_until_ready(); + let buffer_size = ::std::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: ::std::marker::PhantomData } } @@ -152,11 +159,87 @@ impl Voice { #[inline] pub fn get_pending_samples(&self) -> usize { - unimplemented!() + 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)> { + use std::ops::Deref; + + if let Ok(lr) = self.last_ready.lock() { + let refcell = lr.deref(); + { + 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; + } + } + } + drop(refcell); + None + } else { + panic!("could not lock last_ready mutex; the previous user must \ + have panicked."); + } + } + + /// 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) { + use std::ops::Deref; + + if let Ok(lr) = self.last_ready.lock() { + let ret: (NumChannels, NumFrames); + let refcell = lr.deref(); + { + let data = refcell.borrow(); + if let Some(s) = *data { + drop(data); + let mut data = refcell.borrow_mut(); + *data = None; + ret = s; + } else { + match self.ready_receiver.recv() { + Ok(ready) => { + ret = ready; + }, + Err(e) => panic!("Couldn't receive a ready message: \ + {:?}", e) + } + } + } + drop(refcell); + + ret + } else { + panic!("could not lock last_ready mutex; the previous user must \ + have panicked."); + } } #[inline] pub fn underflowed(&self) -> bool { - unimplemented!() + let uf = self.underflow.lock().unwrap(); + let v = uf.borrow(); + *v } } From 30e96aa15a94eadd3c646f1f84de38f08d52dd8b Mon Sep 17 00:00:00 2001 From: Ronald Kinard Date: Sat, 26 Sep 2015 23:04:17 -0500 Subject: [PATCH 08/10] coreaudio: implementation cleanup --- src/coreaudio/mod.rs | 85 +++++++++++++++++--------------------------- 1 file changed, 32 insertions(+), 53 deletions(-) diff --git a/src/coreaudio/mod.rs b/src/coreaudio/mod.rs index 7d33d59..f699ebb 100644 --- a/src/coreaudio/mod.rs +++ b/src/coreaudio/mod.rs @@ -5,6 +5,8 @@ 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; use CreationError; use Format; @@ -44,7 +46,7 @@ pub struct Buffer<'a, T: 'a> { samples_sender: Sender<(Vec, NumChannels)>, samples: Vec, num_channels: NumChannels, - marker: ::std::marker::PhantomData<&'a T>, + marker: PhantomData<&'a T>, } impl<'a, T> Buffer<'a, T> { @@ -138,12 +140,12 @@ impl Voice { 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 = ::std::cmp::min(channels * frames, max_elements); + 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: ::std::marker::PhantomData + marker: PhantomData } } @@ -175,64 +177,41 @@ impl Voice { /// returned. #[inline] fn update_last_ready(&self) -> Option<(NumChannels, NumFrames)> { - use std::ops::Deref; - - if let Ok(lr) = self.last_ready.lock() { - let refcell = lr.deref(); - { - 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; - } - } - } - drop(refcell); - None + let refcell = self.last_ready.lock().unwrap(); + let data = refcell.borrow(); + if let Some(s) = *data { + // + return Some(s); } else { - panic!("could not lock last_ready mutex; the previous user must \ - have panicked."); + 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) { - use std::ops::Deref; - - if let Ok(lr) = self.last_ready.lock() { - let ret: (NumChannels, NumFrames); - let refcell = lr.deref(); - { - let data = refcell.borrow(); - if let Some(s) = *data { - drop(data); - let mut data = refcell.borrow_mut(); - *data = None; - ret = s; - } else { - match self.ready_receiver.recv() { - Ok(ready) => { - ret = ready; - }, - Err(e) => panic!("Couldn't receive a ready message: \ - {:?}", e) - } - } - } - drop(refcell); - - ret + 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 { - panic!("could not lock last_ready mutex; the previous user must \ - have panicked."); + match self.ready_receiver.recv() { + Ok(ready) => { + return ready; + }, + Err(e) => panic!("Couldn't receive a ready message: \ + {:?}", e) + } } } From dd87dbc1d25ea443150872326652591cef3ddd9f Mon Sep 17 00:00:00 2001 From: Geoffroy Couprie Date: Tue, 12 Jan 2016 17:06:14 +0100 Subject: [PATCH 09/10] Fix compilation on OSX with the new API for coreaudio-rs this builds upon the following pull request: https://github.com/tomaka/cpal/pull/81 --- src/coreaudio/mod.rs | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/src/coreaudio/mod.rs b/src/coreaudio/mod.rs index f699ebb..e3b6598 100644 --- a/src/coreaudio/mod.rs +++ b/src/coreaudio/mod.rs @@ -21,7 +21,7 @@ pub use self::enumerate::{EndpointsIterator, SupportedFormatsIterator, get_default_endpoint}; -use self::coreaudio::audio_unit::{AudioUnit, Type, SubType}; +use self::coreaudio::audio_unit::{AudioUnit, IOType}; #[derive(Clone, PartialEq, Eq)] pub struct Endpoint; @@ -98,8 +98,10 @@ impl Voice { let underflow = Arc::new(Mutex::new(RefCell::new(false))); let uf_clone = underflow.clone(); - let audio_unit_result = AudioUnit::new(Type::Output, SubType::HalOutput) - .render_callback(Box::new(move |channels, num_frames| { + 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()); } @@ -120,21 +122,20 @@ impl Voice { } Ok(()) - })) - .start(); - - match audio_unit_result { - Ok(audio_unit) => 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))) - }), - Err(_) => { - Err(CreationError::DeviceNotAvailable) - }, + }))) { + 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))) + }) + } + } } + + Err(CreationError::DeviceNotAvailable) } pub fn append_data<'a, T>(&'a mut self, max_elements: usize) -> Buffer<'a, T> where T: Clone { From 41d86ce17b95077ec29352b1236c4b512e53972e Mon Sep 17 00:00:00 2001 From: Geoffroy Couprie Date: Tue, 12 Jan 2016 17:16:15 +0100 Subject: [PATCH 10/10] Do not use a wildcard version number --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 27830ce..23fce7c 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"