Skip to content

Commit be1c354

Browse files
committed
Add an action_flags::Handle type to safely wrap the ptr given to the render callback.
1 parent ace15ec commit be1c354

File tree

1 file changed

+87
-10
lines changed

1 file changed

+87
-10
lines changed

src/audio_unit/render_callback.rs

Lines changed: 87 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,24 +24,25 @@ pub struct InputProcFnWrapper {
2424
}
2525

2626
/// Arguments given to the render callback function.
27-
#[derive(Copy, Clone)]
2827
pub struct Args<D> {
2928
/// A type wrapping the the buffer that matches the expected audio format.
3029
pub data: D,
3130
/// Timing information for the callback.
3231
pub time_stamp: au::AudioTimeStamp,
33-
/// Flags for configuring audio unit rendering.
34-
///
35-
/// TODO: I can't find any solid documentation on this, but it looks like we should be allowing
36-
/// the user to also *set* these flags, as `rust-bindgen` generated a `*mut` to them. If that's
37-
/// the case, then perhaps we should change the return type to `Result<ActionFlags, ()>`?
38-
pub flags: ActionFlags,
3932
/// TODO
4033
pub bus_number: u32,
4134
/// The number of frames in the buffer as `usize` for easier indexing.
4235
pub num_frames: usize,
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,
4343
}
4444

45+
4546
/// Format specific render callback data.
4647
pub mod data {
4748
use bindings::audio_unit as au;
@@ -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() {
@@ -328,8 +406,7 @@ 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,

0 commit comments

Comments
 (0)