Skip to content

Commit fe496fa

Browse files
committed
Merge pull request #33 from mitchmindtree/audio_unit_api
Improve APIs of both AudioUnit and StreamFormat types.
2 parents 657ad58 + 5b9eb46 commit fe496fa

File tree

3 files changed

+40
-30
lines changed

3 files changed

+40
-30
lines changed

examples/sine.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@ fn main() {
2929

3030
// Construct an Output audio unit.
3131
let mut audio_unit = AudioUnit::new(Type::Output, SubType::HalOutput).unwrap();
32-
audio_unit.render_callback(Some(Box::new(move |buffer, num_frames| {
32+
33+
// Pass the audio unit a callback for filling the buffer.
34+
audio_unit.set_render_callback(Some(Box::new(move |buffer, num_frames| {
3335
for frame in 0..num_frames {
3436
let sample = samples.next().unwrap();
3537
for channel in buffer.iter_mut() {
@@ -38,7 +40,8 @@ fn main() {
3840
}
3941
Ok(())
4042
}))).ok();
41-
audio_unit.start().ok();
43+
44+
audio_unit.start().unwrap();
4245

4346
::std::thread::sleep_ms(3000);
4447
}

src/audio_unit/mod.rs

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ pub type RenderCallback = FnMut(&mut[&mut[f32]], NumFrames) -> Result<(), String
112112
/// Find the original Audio Unit Programming Guide [here](https://developer.apple.com/library/mac/documentation/MusicAudio/Conceptual/AudioUnitProgrammingGuide/TheAudioUnit/TheAudioUnit.html).
113113
pub struct AudioUnit {
114114
instance: au::AudioUnit,
115-
callback: Option<*mut libc::c_void>
115+
maybe_callback: Option<*mut libc::c_void>
116116
}
117117

118118
macro_rules! try_os_status {
@@ -148,22 +148,24 @@ impl AudioUnit {
148148
try_os_status!(au::AudioUnitInitialize(instance));
149149
Ok(AudioUnit {
150150
instance: instance,
151-
callback: None
151+
maybe_callback: None
152152
})
153153
}
154154
}
155155

156-
fn free_render_callback(&self) {
157-
if let Some(callback) = self.callback {
156+
/// Retrieves ownership over the render callback and drops it.
157+
fn free_render_callback(&mut self) {
158+
if let Some(callback) = self.maybe_callback.take() {
158159
// Here, we transfer ownership of the callback back to the current scope so that it
159160
// is dropped and cleaned up. Without this line, we would leak the Boxed callback.
160-
let _: Box<Box<RenderCallback>> = unsafe { Box::from_raw(callback as *mut Box<RenderCallback>) };
161+
let _: Box<Box<RenderCallback>> = unsafe {
162+
Box::from_raw(callback as *mut Box<RenderCallback>)
163+
};
161164
}
162165
}
163166

164-
/// Pass a render callback (aka "Input Procedure") to the audio unit.
165-
pub fn render_callback(&mut self, f: Option<Box<RenderCallback>>) -> Result<(), Error>
166-
{
167+
/// Pass a render callback (aka "Input Procedure") to the **AudioUnit**.
168+
pub fn set_render_callback(&mut self, f: Option<Box<RenderCallback>>) -> Result<(), Error> {
167169
// Setup render callback. Notice that we relinquish ownership of the Callback
168170
// here so that it can be used as the C render callback via a void pointer.
169171
// We do however store the *mut so that we can convert back to a
@@ -191,24 +193,32 @@ impl AudioUnit {
191193
}
192194

193195
self.free_render_callback();
194-
self.callback = if !callback_ptr.is_null() { Some(callback_ptr) } else { None };
196+
self.maybe_callback = if !callback_ptr.is_null() { Some(callback_ptr) } else { None };
195197
Ok(())
196198
}
197199

198-
/// Start the audio unit.
199-
pub fn start(&self) -> Result<(), Error> {
200+
/// Starts an I/O **AudioUnit**, which in turn starts the audio unit processing graph that it is
201+
/// connected to.
202+
///
203+
/// **Available** in OS X v10.0 and later.
204+
pub fn start(&mut self) -> Result<(), Error> {
200205
unsafe { try_os_status!(au::AudioOutputUnitStart(self.instance)); }
201206
Ok(())
202207
}
203208

204-
/// Stop the audio unit.
205-
pub fn stop(&self) -> Result<(), Error> {
209+
/// Stops an I/O **AudioUnit**, which in turn stops the audio unit processing graph that it is
210+
/// connected to.
211+
///
212+
/// **Available** in OS X v10.0 and later.
213+
pub fn stop(&mut self) -> Result<(), Error> {
206214
unsafe { try_os_status!(au::AudioOutputUnitStop(self.instance)); }
207215
Ok(())
208216
}
209217

210-
/// Set the audio unit's sample rate.
211-
pub fn set_sample_rate(&self, sample_rate: f64) -> Result<(), Error> {
218+
/// Set the **AudioUnit**'s sample rate.
219+
///
220+
/// **Available** in iOS 2.0 and later.
221+
pub fn set_sample_rate(&mut self, sample_rate: f64) -> Result<(), Error> {
212222
unsafe {
213223
try_os_status!(au::AudioUnitSetProperty(
214224
self.instance,
@@ -221,7 +231,7 @@ impl AudioUnit {
221231
}
222232
}
223233

224-
/// Get the audio unit's sample rate.
234+
/// Get the **AudioUnit**'s sample rate.
225235
pub fn sample_rate(&self) -> Result<f64, Error> {
226236
unsafe {
227237
let mut sample_rate: f64 = 0.0;
@@ -237,8 +247,8 @@ impl AudioUnit {
237247
}
238248
}
239249

240-
/// Sets the current Stream Format for the AudioUnit.
241-
pub fn set_stream_format(&self, stream_format: StreamFormat) -> Result<(), Error> {
250+
/// Sets the current **StreamFormat** for the AudioUnit.
251+
pub fn set_stream_format(&mut self, stream_format: StreamFormat) -> Result<(), Error> {
242252
unsafe {
243253
let mut asbd = stream_format.to_asbd();
244254
try_os_status!(au::AudioUnitSetProperty(
@@ -264,7 +274,7 @@ impl AudioUnit {
264274
Element::Output as libc::c_uint,
265275
&mut asbd as *mut _ as *mut libc::c_void,
266276
&mut size as *mut au::UInt32));
267-
Ok(StreamFormat::from_asbd(asbd))
277+
StreamFormat::from_asbd(asbd)
268278
}
269279
}
270280

src/audio_unit/stream_format.rs

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33
//! Find the original `AudioStreamBasicDescription` reference [here](https://developer.apple.com/library/mac/documentation/MusicAudio/Reference/CoreAudioDataTypesRef/#//apple_ref/c/tdef/AudioStreamBasicDescription).
44
55
use bindings::audio_unit as au;
6+
use error::{self, Error};
67
use super::audio_format::AudioFormat;
78

89
/// Representation of the AudioStreamBasicDescription.
9-
#[derive(Clone, Debug)]
10+
#[derive(Copy, Clone, Debug)]
1011
pub struct StreamFormat {
1112
pub sample_rate: f64,
1213
pub audio_format: AudioFormat,
@@ -19,13 +20,9 @@ pub struct StreamFormat {
1920

2021
impl StreamFormat {
2122

22-
// /// Construct a new StreamFormat.
23-
// pub fn new(channels: u32, sample_rate: f64) -> StreamFormat {
24-
// }
25-
2623
/// Convert an AudioStreamBasicDescription into a StreamFormat.
2724
#[allow(non_snake_case)]
28-
pub fn from_asbd(asbd: au::AudioStreamBasicDescription) -> StreamFormat {
25+
pub fn from_asbd(asbd: au::AudioStreamBasicDescription) -> Result<StreamFormat, Error> {
2926
let au::Struct_AudioStreamBasicDescription {
3027
mSampleRate,
3128
mFormatID,
@@ -37,18 +34,18 @@ impl StreamFormat {
3734
mBitsPerChannel,
3835
..
3936
} = asbd;
40-
StreamFormat {
37+
Ok(StreamFormat {
4138
sample_rate: mSampleRate,
4239
audio_format: match AudioFormat::from_format_and_flag(mFormatID, Some(mFormatFlags)) {
4340
Some(audio_format) => audio_format,
44-
None => panic!("Failed to convert the ASBD's format and flag to AudioFormat"),
41+
None => return Err(Error::AudioUnit(error::audio_unit::Error::FormatNotSupported)),
4542
},
4643
bytes_per_packet: mBytesPerPacket,
4744
frames_per_packet: mFramesPerPacket,
4845
bytes_per_frame: mBytesPerFrame,
4946
channels_per_frame: mChannelsPerFrame,
5047
bits_per_channel: mBitsPerChannel,
51-
}
48+
})
5249
}
5350

5451
/// Convert a StreamFormat into an AudioStreamBasicDescription.

0 commit comments

Comments
 (0)