Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions examples/sine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand All @@ -38,7 +40,8 @@ fn main() {
}
Ok(())
}))).ok();
audio_unit.start().ok();

audio_unit.start().unwrap();

::std::thread::sleep_ms(3000);
}
48 changes: 29 additions & 19 deletions src/audio_unit/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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<Box<RenderCallback>> = unsafe { Box::from_raw(callback as *mut Box<RenderCallback>) };
let _: Box<Box<RenderCallback>> = unsafe {
Box::from_raw(callback as *mut Box<RenderCallback>)
};
}
}

/// Pass a render callback (aka "Input Procedure") to the audio unit.
pub fn render_callback(&mut self, f: Option<Box<RenderCallback>>) -> Result<(), Error>
{
/// Pass a render callback (aka "Input Procedure") to the **AudioUnit**.
pub fn set_render_callback(&mut self, f: Option<Box<RenderCallback>>) -> 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
Expand Down Expand Up @@ -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,
Expand All @@ -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<f64, Error> {
unsafe {
let mut sample_rate: f64 = 0.0;
Expand All @@ -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(
Expand All @@ -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)
}
}

Expand Down
15 changes: 6 additions & 9 deletions src/audio_unit/stream_format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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<StreamFormat, Error> {
let au::Struct_AudioStreamBasicDescription {
mSampleRate,
mFormatID,
Expand All @@ -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.
Expand Down