Skip to content

Commit da45790

Browse files
Merge pull request #44 from mitchmindtree/audio_unit_fixes
[Breaking Change] Remove unnecessary lifetimes. Add `action_flags::Handle` type. Update to bitflags 0.7.
2 parents 18e607f + ea82258 commit da45790

File tree

6 files changed

+121
-46
lines changed

6 files changed

+121
-46
lines changed

Cargo.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22

33
name = "coreaudio-rs"
4-
version = "0.5.0"
4+
version = "0.6.0"
55
authors = ["mitchmindtree <mitchell.nordine@gmail.com>", "yupferris <jake@fusetools.com>"]
66
description = "A friendly rust interface for Apple's CoreAudio API."
77
keywords = ["core", "audio", "unit", "osx", "ios"]
@@ -14,6 +14,6 @@ homepage = "https://github.com/RustAudio/coreaudio-rs"
1414
name = "coreaudio"
1515

1616
[dependencies]
17-
bitflags = "0.3.2"
18-
coreaudio-sys = "0.1.2"
19-
libc = "0.2.1"
17+
bitflags = "0.7"
18+
coreaudio-sys = "0.1"
19+
libc = "0.2"

examples/sine.rs

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -39,22 +39,20 @@ fn run() -> Result<(), coreaudio::Error> {
3939
// For this example, our sine wave expects `f32` data.
4040
assert!(SampleFormat::F32 == stream_format.sample_format);
4141

42-
try!(audio_unit.set_render_callback(move |args| callback(args, &mut samples)));
42+
type Args = render_callback::Args<data::NonInterleaved<f32>>;
43+
try!(audio_unit.set_render_callback(move |args| {
44+
let Args { num_frames, mut data, .. } = args;
45+
for i in 0..num_frames {
46+
let sample = samples.next().unwrap();
47+
for channel in data.channels_mut() {
48+
channel[i] = sample;
49+
}
50+
}
51+
Ok(())
52+
}));
4353
try!(audio_unit.start());
4454

45-
std::thread::sleep_ms(3000);
46-
47-
Ok(())
48-
}
55+
std::thread::sleep(std::time::Duration::from_millis(3000));
4956

50-
type Args<'a> = render_callback::Args<'a, data::NonInterleaved<'a, f32>>;
51-
fn callback<'a, I: Iterator<Item=f32>>(args: Args<'a>, samples: &mut I) -> Result<(), ()> {
52-
let Args { num_frames, mut data, .. } = args;
53-
for i in 0..num_frames {
54-
let sample = samples.next().unwrap();
55-
for channel in data.channels_mut() {
56-
channel[i] = sample;
57-
}
58-
}
5957
Ok(())
6058
}

src/audio_unit/audio_format.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ pub mod standard_flags {
279279
/// the **AudioFormat** type.
280280
///
281281
/// Original documentation [here](https://developer.apple.com/library/mac/documentation/MusicAudio/Reference/CoreAudioDataTypesRef/#//apple_ref/doc/constant_group/AudioStreamBasicDescription_Flags).
282-
flags StandardFlags: u32 {
282+
pub flags StandardFlags: u32 {
283283
/// Set for floating point, clear for integer.
284284
///
285285
/// **Available** in OS X v10.2 and later.
@@ -337,7 +337,7 @@ pub mod linear_pcm_flags {
337337
/// the **AudioFormat** type.
338338
///
339339
/// Original documentation [here](https://developer.apple.com/library/mac/documentation/MusicAudio/Reference/CoreAudioDataTypesRef/#//apple_ref/doc/constant_group/AudioStreamBasicDescription_Flags).
340-
flags LinearPCMFlags: u32 {
340+
pub flags LinearPCMFlags: u32 {
341341
/// Synonmyn for the **IS_FLOAT** **StandardFlags**.
342342
///
343343
/// **Available** in OS X v10.0 and later.
@@ -404,7 +404,7 @@ pub mod apple_lossless_flags {
404404
/// the **AudioFormat** type.
405405
///
406406
/// Original documentation [here](https://developer.apple.com/library/mac/documentation/MusicAudio/Reference/CoreAudioDataTypesRef/#//apple_ref/doc/constant_group/AudioStreamBasicDescription_Flags).
407-
flags AppleLosslessFlags: u32 {
407+
pub flags AppleLosslessFlags: u32 {
408408
/// Sourced from 16 bit native endian signed integer data.
409409
const BIT_16_SOURCE_DATA = 1,
410410
/// Sourced from 20 bit native endian signed integer data aligned high in 24 bits.
@@ -483,7 +483,7 @@ pub mod audio_time_stamp_flags {
483483
/// **Available** in OS X v10.0 and later.
484484
///
485485
/// Original Documentation [here](https://developer.apple.com/library/mac/documentation/MusicAudio/Reference/CoreAudioDataTypesRef/#//apple_ref/doc/constant_group/Audio_Time_Stamp_Flags).
486-
flags AudioTimeStampFlags: u32 {
486+
pub flags AudioTimeStampFlags: u32 {
487487
/// The sample frame time is valid.
488488
const SAMPLE_TIME_VALID = 1,
489489
/// The host time is valid.

src/audio_unit/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,11 +277,13 @@ impl AudioUnit {
277277
}
278278

279279

280+
unsafe impl Send for AudioUnit {}
281+
282+
280283
impl Drop for AudioUnit {
281284
fn drop(&mut self) {
282285
unsafe {
283286
use error;
284-
use std::error::Error;
285287

286288
// We don't want to panic in `drop`, so we'll ignore returned errors.
287289
//

src/audio_unit/render_callback.rs

Lines changed: 97 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use bindings::audio_unit as au;
22
use error::{self, Error};
33
use libc;
4-
use std::marker::PhantomData;
54
use super::{AudioUnit, Element, Scope};
65

76
pub use self::action_flags::ActionFlags;
@@ -25,25 +24,25 @@ pub struct InputProcFnWrapper {
2524
}
2625

2726
/// Arguments given to the render callback function.
28-
#[derive(Copy, Clone)]
29-
pub struct Args<'a, D> {
27+
pub struct Args<D> {
3028
/// A type wrapping the the buffer that matches the expected audio format.
3129
pub data: D,
3230
/// Timing information for the callback.
3331
pub time_stamp: au::AudioTimeStamp,
34-
/// Flags for configuring audio unit rendering.
35-
///
36-
/// TODO: I can't find any solid documentation on this, but it looks like we should be allowing
37-
/// the user to also *set* these flags, as `rust-bindgen` generated a `*mut` to them. If that's
38-
/// the case, then perhaps we should change the return type to `Result<ActionFlags, ()>`?
39-
pub flags: ActionFlags,
4032
/// TODO
4133
pub bus_number: u32,
4234
/// The number of frames in the buffer as `usize` for easier indexing.
4335
pub num_frames: usize,
44-
callback_lifetime: PhantomData<&'a ()>,
36+
/// Flags for configuring audio unit rendering.
37+
///
38+
/// This parameter lets a callback provide various hints to the audio unit.
39+
///
40+
/// For example: if there is no audio to process, we can insert the `OUTPUT_IS_SILENCE` flag to
41+
/// indicate to the audio unit that the buffer does not need to be processed.
42+
pub flags: action_flags::Handle,
4543
}
4644

45+
4746
/// Format specific render callback data.
4847
pub mod data {
4948
use bindings::audio_unit as au;
@@ -120,7 +119,7 @@ pub mod data {
120119
// }
121120

122121
/// A wrapper around the pointer to the `mBuffers` array.
123-
pub struct NonInterleaved<'a, S: 'a> {
122+
pub struct NonInterleaved<S> {
124123
/// A pointer to the first buffer.
125124
///
126125
/// TODO: Work out why this works and `&'a mut [au::AudioBuffer]` does not!
@@ -129,7 +128,7 @@ pub mod data {
129128
num_buffers: usize,
130129
/// The number of frames in each channel.
131130
frames: usize,
132-
sample_format: PhantomData<&'a S>,
131+
sample_format: PhantomData<S>,
133132
}
134133

135134
/// An iterator produced by a `NoneInterleaved`, yielding a reference to each channel.
@@ -146,6 +145,8 @@ pub mod data {
146145
sample_format: PhantomData<S>,
147146
}
148147

148+
unsafe impl<S> Send for NonInterleaved<S> where S: Send {}
149+
149150
impl<'a, S> Iterator for Channels<'a, S> {
150151
type Item = &'a [S];
151152
#[allow(non_snake_case)]
@@ -170,7 +171,7 @@ pub mod data {
170171
}
171172
}
172173

173-
impl<'a, S> NonInterleaved<'a, S> {
174+
impl<S> NonInterleaved<S> {
174175

175176
/// An iterator yielding a reference to each channel in the array.
176177
pub fn channels(&self) -> Channels<S> {
@@ -193,11 +194,11 @@ pub mod data {
193194
}
194195

195196
// Implementation for a non-interleaved linear PCM audio format.
196-
impl<'a, S> Data for NonInterleaved<'a, S>
197+
impl<S> Data for NonInterleaved<S>
197198
where S: Sample,
198199
{
199200
fn does_stream_format_match(format: &StreamFormat) -> bool {
200-
// TODO: This is never set, in though the default ABSD on OS X is non-interleaved!
201+
// TODO: This is never set, even though the default ABSD on OS X is non-interleaved!
201202
// Should really investigate why this is.
202203
// format.flags.contains(linear_pcm_flags::IS_NON_INTERLEAVED) &&
203204
S::sample_format().does_match_flags(format.flags)
@@ -224,7 +225,7 @@ pub mod action_flags {
224225
use bindings::audio_unit as au;
225226

226227
bitflags!{
227-
flags ActionFlags: u32 {
228+
pub flags ActionFlags: u32 {
228229
/// Called on a render notification Proc, which is called either before or after the
229230
/// render operation of the audio unit. If this flag is set, the proc is being called
230231
/// before the render operation is performed.
@@ -266,7 +267,7 @@ pub mod action_flags {
266267
const OFFLINE_COMPLETE = au::kAudioOfflineUnitRenderAction_Complete,
267268
/// If this flag is set on the post-render call an error was returned by the audio
268269
/// unit's render operation. In this case, the error can be retrieved through the
269-
/// `lastRenderError` property and the aduio data in `ioData` handed to the post-render
270+
/// `lastRenderError` property and the audio data in `ioData` handed to the post-render
270271
/// notification will be invalid.
271272
///
272273
/// **Available** in OS X v10.5 and later.
@@ -281,6 +282,83 @@ pub mod action_flags {
281282
}
282283
}
283284

285+
/// A safe handle around the `AudioUnitRenderActionFlags` pointer provided by the render
286+
/// callback.
287+
///
288+
/// This type lets a callback provide various hints to the audio unit.
289+
///
290+
/// For example: if there is no audio to process, we can insert the `OUTPUT_IS_SILENCE` flag to
291+
/// indicate to the audio unit that the buffer does not need to be processed.
292+
pub struct Handle {
293+
ptr: *mut au::AudioUnitRenderActionFlags,
294+
}
295+
296+
impl Handle {
297+
298+
/// Retrieve the current state of the `ActionFlags`.
299+
pub fn get(&self) -> ActionFlags {
300+
ActionFlags::from_bits_truncate(unsafe { *self.ptr })
301+
}
302+
303+
fn set(&mut self, flags: ActionFlags) {
304+
unsafe { *self.ptr = flags.bits() }
305+
}
306+
307+
/// The raw value of the flags currently stored.
308+
pub fn bits(&self) -> u32 {
309+
self.get().bits()
310+
}
311+
312+
/// Returns `true` if no flags are currently stored.
313+
pub fn is_empty(&self) -> bool {
314+
self.get().is_empty()
315+
}
316+
317+
/// Returns `true` if all flags are currently stored.
318+
pub fn is_all(&self) -> bool {
319+
self.get().is_all()
320+
}
321+
322+
/// Returns `true` if there are flags common to both `self` and `other`.
323+
pub fn intersects(&self, other: ActionFlags) -> bool {
324+
self.get().intersects(other)
325+
}
326+
327+
/// Returns `true` if all of the flags in `other` are contained within `self`.
328+
pub fn contains(&self, other: ActionFlags) -> bool {
329+
self.get().contains(other)
330+
}
331+
332+
/// Insert the specified flags in-place.
333+
pub fn insert(&mut self, other: ActionFlags) {
334+
let mut flags = self.get();
335+
flags.insert(other);
336+
self.set(flags);
337+
}
338+
339+
/// Remove the specified flags in-place.
340+
pub fn remove(&mut self, other: ActionFlags) {
341+
let mut flags = self.get();
342+
flags.remove(other);
343+
self.set(flags);
344+
}
345+
346+
/// Toggles the specified flags in-place.
347+
pub fn toggle(&mut self, other: ActionFlags) {
348+
let mut flags = self.get();
349+
flags.toggle(other);
350+
self.set(flags);
351+
}
352+
353+
/// Wrap the given pointer with a `Handle`.
354+
pub fn from_ptr(ptr: *mut au::AudioUnitRenderActionFlags) -> Self {
355+
Handle { ptr: ptr }
356+
}
357+
358+
}
359+
360+
unsafe impl Send for Handle {}
361+
284362
impl ::std::fmt::Display for ActionFlags {
285363
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
286364
write!(f, "{:?}", match self.bits() {
@@ -303,7 +381,7 @@ impl AudioUnit {
303381

304382
/// Pass a render callback (aka "Input Procedure") to the **AudioUnit**.
305383
pub fn set_render_callback<F, D>(&mut self, mut f: F) -> Result<(), Error>
306-
where F: for<'a> FnMut(Args<'a, D>) -> Result<(), ()> + 'static,
384+
where F: FnMut(Args<D>) -> Result<(), ()> + 'static,
307385
D: Data,
308386
{
309387
// First, we'll retrieve the stream format so that we can ensure that the given callback
@@ -328,15 +406,13 @@ impl AudioUnit {
328406
{
329407
let args = unsafe {
330408
let data = D::from_input_proc_args(in_number_frames, io_data);
331-
let flags = ActionFlags::from_bits(*io_action_flags)
332-
.unwrap_or_else(|| ActionFlags::empty());
409+
let flags = action_flags::Handle::from_ptr(io_action_flags);
333410
Args {
334411
data: data,
335412
time_stamp: *in_time_stamp,
336413
flags: flags,
337414
bus_number: in_bus_number as u32,
338415
num_frames: in_number_frames as usize,
339-
callback_lifetime: PhantomData,
340416
}
341417
};
342418

src/lib.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@
99
//! eventually we'd like to cover at least the majority of the C API.
1010
1111
#[macro_use] extern crate bitflags;
12-
extern crate coreaudio_sys;
13-
pub use coreaudio_sys as bindings;
12+
pub extern crate coreaudio_sys as bindings;
1413

1514
extern crate libc;
1615

0 commit comments

Comments
 (0)