diff --git a/examples/sine.rs b/examples/sine.rs index b8d23185b..e4ee2aec5 100644 --- a/examples/sine.rs +++ b/examples/sine.rs @@ -29,7 +29,9 @@ fn main() { // Construct an Output audio unit. let mut audio_unit = AudioUnit::new(Type::Output, SubType::HalOutput).unwrap(); - audio_unit.render_callback(Some(Box::new(move |buffer, num_frames| { + + // Pass the audio unit a callback for filling the buffer. + audio_unit.set_render_callback(Some(Box::new(move |buffer, num_frames| { for frame in 0..num_frames { let sample = samples.next().unwrap(); for channel in buffer.iter_mut() { @@ -38,7 +40,8 @@ fn main() { } Ok(()) }))).ok(); - audio_unit.start().ok(); + + audio_unit.start().unwrap(); ::std::thread::sleep_ms(3000); } diff --git a/src/audio_unit/mod.rs b/src/audio_unit/mod.rs index 70c5dcbe7..819f8b2e4 100644 --- a/src/audio_unit/mod.rs +++ b/src/audio_unit/mod.rs @@ -112,7 +112,7 @@ pub type RenderCallback = FnMut(&mut[&mut[f32]], NumFrames) -> Result<(), String /// Find the original Audio Unit Programming Guide [here](https://developer.apple.com/library/mac/documentation/MusicAudio/Conceptual/AudioUnitProgrammingGuide/TheAudioUnit/TheAudioUnit.html). pub struct AudioUnit { instance: au::AudioUnit, - callback: Option<*mut libc::c_void> + maybe_callback: Option<*mut libc::c_void> } macro_rules! try_os_status { @@ -148,22 +148,24 @@ impl AudioUnit { try_os_status!(au::AudioUnitInitialize(instance)); Ok(AudioUnit { instance: instance, - callback: None + maybe_callback: None }) } } - fn free_render_callback(&self) { - if let Some(callback) = self.callback { + /// Retrieves ownership over the render callback and drops it. + fn free_render_callback(&mut self) { + if let Some(callback) = self.maybe_callback.take() { // Here, we transfer ownership of the callback back to the current scope so that it // is dropped and cleaned up. Without this line, we would leak the Boxed callback. - let _: Box> = unsafe { Box::from_raw(callback as *mut Box) }; + let _: Box> = unsafe { + Box::from_raw(callback as *mut Box) + }; } } - /// Pass a render callback (aka "Input Procedure") to the audio unit. - pub fn render_callback(&mut self, f: Option>) -> Result<(), Error> - { + /// Pass a render callback (aka "Input Procedure") to the **AudioUnit**. + pub fn set_render_callback(&mut self, f: Option>) -> Result<(), Error> { // Setup render callback. Notice that we relinquish ownership of the Callback // here so that it can be used as the C render callback via a void pointer. // We do however store the *mut so that we can convert back to a @@ -191,24 +193,32 @@ impl AudioUnit { } self.free_render_callback(); - self.callback = if !callback_ptr.is_null() { Some(callback_ptr) } else { None }; + self.maybe_callback = if !callback_ptr.is_null() { Some(callback_ptr) } else { None }; Ok(()) } - /// Start the audio unit. - pub fn start(&self) -> Result<(), Error> { + /// Starts an I/O **AudioUnit**, which in turn starts the audio unit processing graph that it is + /// connected to. + /// + /// **Available** in OS X v10.0 and later. + pub fn start(&mut self) -> Result<(), Error> { unsafe { try_os_status!(au::AudioOutputUnitStart(self.instance)); } Ok(()) } - /// Stop the audio unit. - pub fn stop(&self) -> Result<(), Error> { + /// Stops an I/O **AudioUnit**, which in turn stops the audio unit processing graph that it is + /// connected to. + /// + /// **Available** in OS X v10.0 and later. + pub fn stop(&mut self) -> Result<(), Error> { unsafe { try_os_status!(au::AudioOutputUnitStop(self.instance)); } Ok(()) } - /// Set the audio unit's sample rate. - pub fn set_sample_rate(&self, sample_rate: f64) -> Result<(), Error> { + /// Set the **AudioUnit**'s sample rate. + /// + /// **Available** in iOS 2.0 and later. + pub fn set_sample_rate(&mut self, sample_rate: f64) -> Result<(), Error> { unsafe { try_os_status!(au::AudioUnitSetProperty( self.instance, @@ -221,7 +231,7 @@ impl AudioUnit { } } - /// Get the audio unit's sample rate. + /// Get the **AudioUnit**'s sample rate. pub fn sample_rate(&self) -> Result { unsafe { let mut sample_rate: f64 = 0.0; @@ -237,8 +247,8 @@ impl AudioUnit { } } - /// Sets the current Stream Format for the AudioUnit. - pub fn set_stream_format(&self, stream_format: StreamFormat) -> Result<(), Error> { + /// Sets the current **StreamFormat** for the AudioUnit. + pub fn set_stream_format(&mut self, stream_format: StreamFormat) -> Result<(), Error> { unsafe { let mut asbd = stream_format.to_asbd(); try_os_status!(au::AudioUnitSetProperty( @@ -264,7 +274,7 @@ impl AudioUnit { Element::Output as libc::c_uint, &mut asbd as *mut _ as *mut libc::c_void, &mut size as *mut au::UInt32)); - Ok(StreamFormat::from_asbd(asbd)) + StreamFormat::from_asbd(asbd) } } diff --git a/src/audio_unit/stream_format.rs b/src/audio_unit/stream_format.rs index 491d53bc0..3c8551751 100644 --- a/src/audio_unit/stream_format.rs +++ b/src/audio_unit/stream_format.rs @@ -3,10 +3,11 @@ //! Find the original `AudioStreamBasicDescription` reference [here](https://developer.apple.com/library/mac/documentation/MusicAudio/Reference/CoreAudioDataTypesRef/#//apple_ref/c/tdef/AudioStreamBasicDescription). use bindings::audio_unit as au; +use error::{self, Error}; use super::audio_format::AudioFormat; /// Representation of the AudioStreamBasicDescription. -#[derive(Clone, Debug)] +#[derive(Copy, Clone, Debug)] pub struct StreamFormat { pub sample_rate: f64, pub audio_format: AudioFormat, @@ -19,13 +20,9 @@ pub struct StreamFormat { impl StreamFormat { - // /// Construct a new StreamFormat. - // pub fn new(channels: u32, sample_rate: f64) -> StreamFormat { - // } - /// Convert an AudioStreamBasicDescription into a StreamFormat. #[allow(non_snake_case)] - pub fn from_asbd(asbd: au::AudioStreamBasicDescription) -> StreamFormat { + pub fn from_asbd(asbd: au::AudioStreamBasicDescription) -> Result { let au::Struct_AudioStreamBasicDescription { mSampleRate, mFormatID, @@ -37,18 +34,18 @@ impl StreamFormat { mBitsPerChannel, .. } = asbd; - StreamFormat { + Ok(StreamFormat { sample_rate: mSampleRate, audio_format: match AudioFormat::from_format_and_flag(mFormatID, Some(mFormatFlags)) { Some(audio_format) => audio_format, - None => panic!("Failed to convert the ASBD's format and flag to AudioFormat"), + None => return Err(Error::AudioUnit(error::audio_unit::Error::FormatNotSupported)), }, bytes_per_packet: mBytesPerPacket, frames_per_packet: mFramesPerPacket, bytes_per_frame: mBytesPerFrame, channels_per_frame: mChannelsPerFrame, bits_per_channel: mBitsPerChannel, - } + }) } /// Convert a StreamFormat into an AudioStreamBasicDescription.