Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change Element datatype to be u32. #65

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ homepage = "https://github.com/RustAudio/coreaudio-rs"
[lib]
name = "coreaudio"

[[bin]]
name = "example-sine"
path = "examples/sine.rs"

[features]
default = ["audio_toolbox", "audio_unit", "core_audio", "open_al", "core_midi"]
audio_toolbox = ["coreaudio-sys/audio_toolbox"]
Expand Down
9 changes: 5 additions & 4 deletions examples/sine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,23 +41,24 @@ fn main() -> Result<(), coreaudio::Error> {
// Construct an Output audio unit that delivers audio to the default output device.
let mut audio_unit = AudioUnit::new(IOType::DefaultOutput)?;

let stream_format = audio_unit.output_stream_format()?;
let stream_format = audio_unit.output_stream_format(0)?;
println!("{:#?}", &stream_format);

// For this example, our sine wave expects `f32` data.
assert!(SampleFormat::F32 == stream_format.sample_format);
assert_eq!(SampleFormat::F32, stream_format.sample_format);

type Args = render_callback::Args<data::NonInterleaved<f32>>;
audio_unit.set_render_callback(move |args| {
let Args { num_frames, mut data, .. } = args;
for i in 0..num_frames {
let sample = samples.next().unwrap();
for channel in data.channels_mut() {
for mut channel in data.channels_mut() {
channel[i] = sample;
}
}
Ok(())
})?;
}, 0)?;

audio_unit.start()?;

std::thread::sleep(std::time::Duration::from_millis(3000));
Expand Down
47 changes: 25 additions & 22 deletions src/audio_unit/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ pub use self::types::{
MixerType,
MusicDeviceType,
};
use std::collections::HashMap;


pub mod audio_format;
Expand All @@ -62,22 +63,17 @@ pub enum Scope {
LayerItem = 7,
}

/// Represents the **Input** and **Output** **Element**s.
///
/// These are used when specifying which **Element** we're setting the properties of.
#[derive(Copy, Clone, Debug)]
pub enum Element {
Output = 0,
Input = 1,
}
/// These are used when specifying which **Element** (bus) we're setting the properties of.
/// [The anatomy of an AudioUnit](https://developer.apple.com/library/archive/documentation/MusicAudio/Conceptual/AudioUnitProgrammingGuide/TheAudioUnit/TheAudioUnit.html#//apple_ref/doc/uid/TP40003278-CH12-SW11)
type Element = u32;


/// A rust representation of the sys::AudioUnit, including a pointer to the current rendering callback.
///
/// 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: sys::AudioUnit,
maybe_render_callback: Option<*mut render_callback::InputProcFnWrapper>,
registered_render_callbacks: HashMap<u32, *mut render_callback::InputProcFnWrapper>,
maybe_input_callback: Option<InputCallback>,
}

Expand Down Expand Up @@ -165,7 +161,7 @@ impl AudioUnit {
try_os_status!(sys::AudioUnitInitialize(instance));
Ok(AudioUnit {
instance: instance,
maybe_render_callback: None,
registered_render_callbacks: HashMap::new(),
maybe_input_callback: None,
})
}
Expand Down Expand Up @@ -229,15 +225,15 @@ impl AudioUnit {
/// 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> {
pub fn set_sample_rate(&mut self, element: u32, sample_rate: f64) -> Result<(), Error> {
let id = sys::kAudioUnitProperty_SampleRate;
self.set_property(id, Scope::Input, Element::Output, Some(&sample_rate))
self.set_property(id, Scope::Input, element, Some(&sample_rate))
}

/// Get the **AudioUnit**'s sample rate.
pub fn sample_rate(&self) -> Result<f64, Error> {
pub fn sample_rate(&self, element: Element) -> Result<f64, Error> {
let id = sys::kAudioUnitProperty_SampleRate;
self.get_property(id, Scope::Input, Element::Output)
self.get_property(id, Scope::Input, element)
}

/// Sets the current **StreamFormat** for the AudioUnit.
Expand All @@ -258,27 +254,28 @@ impl AudioUnit {
&mut self,
stream_format: StreamFormat,
scope: Scope,
element: Element,
) -> Result<(), Error> {
let id = sys::kAudioUnitProperty_StreamFormat;
let asbd = stream_format.to_asbd();
self.set_property(id, scope, Element::Output, Some(&asbd))
self.set_property(id, scope, element, Some(&asbd))
}

/// Return the current Stream Format for the AudioUnit.
pub fn stream_format(&self, scope: Scope) -> Result<StreamFormat, Error> {
pub fn stream_format(&self, scope: Scope, element: Element) -> Result<StreamFormat, Error> {
let id = sys::kAudioUnitProperty_StreamFormat;
let asbd = try!(self.get_property(id, scope, Element::Output));
let asbd = self.get_property(id, scope, element)?;
StreamFormat::from_asbd(asbd)
}

/// Return the current output Stream Format for the AudioUnit.
pub fn output_stream_format(&self) -> Result<StreamFormat, Error> {
self.stream_format(Scope::Output)
pub fn output_stream_format(&self, element: Element) -> Result<StreamFormat, Error> {
self.stream_format(Scope::Output, element)
}

/// Return the current input Stream Format for the AudioUnit.
pub fn input_stream_format(&self) -> Result<StreamFormat, Error> {
self.stream_format(Scope::Input)
pub fn input_stream_format(&self, element: Element) -> Result<StreamFormat, Error> {
self.stream_format(Scope::Input, element)
}
}

Expand All @@ -298,7 +295,13 @@ impl Drop for AudioUnit {
self.stop().ok();
error::Error::from_os_status(sys::AudioUnitUninitialize(self.instance)).ok();

self.free_render_callback();
let elements: Vec<u32> = self.registered_render_callbacks
.iter()
.map(|(k, _v)| { *k })
.collect();
for e in elements {
self.free_render_callback(e);
}
self.free_input_callback();
}
}
Expand Down
23 changes: 12 additions & 11 deletions src/audio_unit/render_callback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -390,15 +390,15 @@ pub mod action_flags {

impl AudioUnit {
/// Pass a render callback (aka "Input Procedure") to the **AudioUnit**.
pub fn set_render_callback<F, D>(&mut self, mut f: F) -> Result<(), Error>
pub fn set_render_callback<F, D>(&mut self, mut f: F, element: Element) -> Result<(), Error>
where
F: FnMut(Args<D>) -> Result<(), ()> + 'static,
D: Data,
{
// First, we'll retrieve the stream format so that we can ensure that the given callback
// format matches the audio unit's format.
let id = sys::kAudioUnitProperty_StreamFormat;
let asbd = try!(self.get_property(id, Scope::Output, Element::Output));
let asbd = self.get_property(id, Scope::Output, element)?;
let stream_format = super::StreamFormat::from_asbd(asbd)?;

// If the stream format does not match, return an error indicating this.
Expand Down Expand Up @@ -453,12 +453,12 @@ impl AudioUnit {
self.set_property(
sys::kAudioUnitProperty_SetRenderCallback,
Scope::Input,
Element::Output,
element,
Some(&render_callback),
)?;

self.free_render_callback();
self.maybe_render_callback = Some(input_proc_fn_wrapper_ptr as *mut InputProcFnWrapper);
self.free_render_callback(element);
self.registered_render_callbacks.insert(element, input_proc_fn_wrapper_ptr as *mut InputProcFnWrapper);
Ok(())
}

Expand All @@ -471,7 +471,7 @@ impl AudioUnit {
// First, we'll retrieve the stream format so that we can ensure that the given callback
// format matches the audio unit's format.
let id = sys::kAudioUnitProperty_StreamFormat;
let asbd = self.get_property(id, Scope::Input, Element::Input)?;
let asbd = self.get_property(id, Scope::Input, 1)?;
let stream_format = super::StreamFormat::from_asbd(asbd)?;

// If the stream format does not match, return an error indicating this.
Expand All @@ -483,7 +483,7 @@ impl AudioUnit {
//
// First, get the current buffer size for pre-allocating the `AudioBuffer`s.
let id = sys::kAudioDevicePropertyBufferFrameSize;
let mut buffer_frame_size: u32 = self.get_property(id, Scope::Global, Element::Output)?;
let mut buffer_frame_size: u32 = self.get_property(id, Scope::Global, 0)?; // Always 0 bus for Scope::Global
let mut data: Vec<u8> = vec![];
let sample_bytes = stream_format.sample_format.size_in_bytes();
let n_channels = stream_format.channels_per_frame;
Expand Down Expand Up @@ -525,7 +525,7 @@ impl AudioUnit {
unsafe {
// Retrieve the up-to-date stream format.
let id = sys::kAudioUnitProperty_StreamFormat;
let asbd = match super::get_property(audio_unit, id, Scope::Input, Element::Output) {
let asbd = match super::get_property(audio_unit, id, Scope::Input, in_bus_number) {
Err(err) => return err.to_os_status(),
Ok(asbd) => asbd,
};
Expand Down Expand Up @@ -607,7 +607,7 @@ impl AudioUnit {
self.set_property(
sys::kAudioOutputUnitProperty_SetInputCallback,
Scope::Global,
Element::Output,
0,
Some(&render_callback),
)?;

Expand All @@ -622,8 +622,9 @@ impl AudioUnit {

/// Retrieves ownership over the render callback and returns it where it can be re-used or
/// safely dropped.
pub fn free_render_callback(&mut self) -> Option<Box<InputProcFnWrapper>> {
if let Some(callback) = self.maybe_render_callback.take() {
pub fn free_render_callback(&mut self, element: Element) -> Option<Box<InputProcFnWrapper>> {
let maybe_callback = self.registered_render_callbacks.remove(&element);
if let Some(callback) = maybe_callback {
// 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 callback: Box<InputProcFnWrapper> = unsafe { Box::from_raw(callback) };
Expand Down