1 //! This module is an attempt to provide a friendly, rust-esque interface to Apple's Audio Unit API.
2 //!
3 //! Learn more about the Audio Unit API [here](https://developer.apple.com/library/mac/documentation/MusicAudio/Conceptual/AudioUnitProgrammingGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40003278-CH1-SW2)
4 //! and [here](https://developer.apple.com/library/mac/documentation/MusicAudio/Conceptual/AudioUnitProgrammingGuide/TheAudioUnit/TheAudioUnit.html).
5 //!
6 //! TODO: The following are `kAudioUnitSubType`s (along with their const u32) generated by
7 //! rust-bindgen that we could not find any documentation on:
8 //!
9 //! - MIDISynth = 1836284270,
10 //! - RoundTripAAC = 1918984547,
11 //! - SpatialMixer = 862217581,
12 //! - SphericalHeadPanner = 1936746610,
13 //! - VectorPanner = 1986158963,
14 //! - SoundFieldPanner = 1634558569,
15 //! - HRTFPanner = 1752331366,
16 //! - NetReceive = 1852990326,
17 //!
18 //! If you can find documentation on these, please feel free to submit an issue or PR with the
19 //! fixes!
20
21
22 use error::Error;
23 use std::mem;
24 use std::ptr;
25 use std::os::raw::{c_uint, c_void};
26 use sys;
27
28 pub use self::audio_format::AudioFormat;
29 pub use self::sample_format::{SampleFormat, Sample};
30 pub use self::stream_format::StreamFormat;
31 pub use self::types::{
32 Type,
33 EffectType,
34 FormatConverterType,
35 GeneratorType,
36 IOType,
37 MixerType,
38 MusicDeviceType,
39 };
40
41
42 pub mod audio_format;
43 pub mod render_callback;
44 pub mod sample_format;
45 pub mod stream_format;
46 pub mod types;
47
48
49 /// The input and output **Scope**s.
50 ///
51 /// More info [here](https://developer.apple.com/library/ios/documentation/AudioUnit/Reference/AudioUnitPropertiesReference/index.html#//apple_ref/doc/constant_group/Audio_Unit_Scopes)
52 /// and [here](https://developer.apple.com/library/mac/documentation/MusicAudio/Conceptual/AudioUnitProgrammingGuide/TheAudioUnit/TheAudioUnit.html).
53 #[derive(Copy, Clone, Debug)]
54 pub enum Scope {
55 Global = 0,
56 Input = 1,
57 Output = 2,
58 Group = 3,
59 Part = 4,
60 Note = 5,
61 Layer = 6,
62 LayerItem = 7,
63 }
64
65 /// Represents the **Input** and **Output** **Element**s.
66 ///
67 /// These are used when specifying which **Element** we're setting the properties of.
68 #[derive(Copy, Clone, Debug)]
69 pub enum Element {
70 Output = 0,
71 Input = 1,
72 }
73
74
75 /// A rust representation of the sys::AudioUnit, including a pointer to the current rendering callback.
76 ///
77 /// Find the original Audio Unit Programming Guide [here](https://developer.apple.com/library/mac/documentation/MusicAudio/Conceptual/AudioUnitProgrammingGuide/TheAudioUnit/TheAudioUnit.html).
78 pub struct AudioUnit {
79 instance: sys::AudioUnit,
80 maybe_render_callback: Option<*mut render_callback::InputProcFnWrapper>,
81 maybe_input_callback: Option<InputCallback>,
82 }
83
84 struct InputCallback {
85 // The audio buffer list to which input data is rendered.
86 buffer_list: *mut sys::AudioBufferList,
87 callback: *mut render_callback::InputProcFnWrapper,
88 }
89
90
91 macro_rules! try_os_status {
92 ($expr:expr) => (try!(Error::from_os_status($expr)))
93 }
94
95
96 impl AudioUnit {
97
98 /// Construct a new AudioUnit with any type that may be automatically converted into
99 /// [**Type**](./enum.Type).
100 ///
101 /// Here is a list of compatible types:
102 ///
103 /// - [**Type**](./types/enum.Type)
104 /// - [**IOType**](./types/enum.IOType)
105 /// - [**MusicDeviceType**](./types/enum.MusicDeviceType)
106 /// - [**GeneratorType**](./types/enum.GeneratorType)
107 /// - [**FormatConverterType**](./types/enum.FormatConverterType)
108 /// - [**EffectType**](./types/enum.EffectType)
109 /// - [**MixerType**](./types/enum.MixerType)
110 ///
111 /// To construct the **AudioUnit** with some component flags, see
112 /// [**AudioUnit::new_with_flags**](./struct.AudioUnit#method.new_with_flags).
113 ///
114 /// Note: the `AudioUnit` is constructed with the `kAudioUnitManufacturer_Apple` Manufacturer
115 /// Identifier, as this is the only Audio Unit Manufacturer Identifier documented by Apple in
116 /// the AudioUnit reference (see [here](https://developer.apple.com/library/prerelease/mac/documentation/AudioUnit/Reference/AUComponentServicesReference/index.html#//apple_ref/doc/constant_group/Audio_Unit_Manufacturer_Identifier)).
new<T>(ty: T) -> Result<AudioUnit, Error> where T: Into<Type>,117 pub fn new<T>(ty: T) -> Result<AudioUnit, Error>
118 where T: Into<Type>,
119 {
120 AudioUnit::new_with_flags(ty, 0, 0)
121 }
122
123 /// The same as [**AudioUnit::new**](./struct.AudioUnit#method.new) but with the given
124 /// component flags and mask.
new_with_flags<T>(ty: T, flags: u32, mask: u32) -> Result<AudioUnit, Error> where T: Into<Type>,125 pub fn new_with_flags<T>(ty: T, flags: u32, mask: u32) -> Result<AudioUnit, Error>
126 where T: Into<Type>,
127 {
128 const MANUFACTURER_IDENTIFIER: u32 = sys::kAudioUnitManufacturer_Apple;
129 let au_type: Type = ty.into();
130 let sub_type_u32 = match au_type.to_subtype_u32() {
131 Some(u) => u,
132 None => return Err(Error::NoKnownSubtype),
133 };
134
135 // A description of the audio unit we desire.
136 let desc = sys::AudioComponentDescription {
137 componentType: au_type.to_u32() as c_uint,
138 componentSubType: sub_type_u32 as c_uint,
139 componentManufacturer: MANUFACTURER_IDENTIFIER,
140 componentFlags: flags,
141 componentFlagsMask: mask,
142 };
143
144 unsafe {
145 // Find the default audio unit for the description.
146 //
147 // From the "Audio Unit Hosting Guide for iOS":
148 //
149 // Passing NULL to the first parameter of AudioComponentFindNext tells this function to
150 // find the first system audio unit matching the description, using a system-defined
151 // ordering. If you instead pass a previously found audio unit reference in this
152 // parameter, the function locates the next audio unit matching the description.
153 let component = sys::AudioComponentFindNext(ptr::null_mut(), &desc as *const _);
154 if component.is_null() {
155 return Err(Error::NoMatchingDefaultAudioUnitFound);
156 }
157
158 // Create an instance of the default audio unit using the component.
159 let mut instance: sys::AudioUnit = mem::uninitialized();
160 try_os_status!(
161 sys::AudioComponentInstanceNew(component, &mut instance as *mut sys::AudioUnit)
162 );
163
164 // Initialise the audio unit!
165 try_os_status!(sys::AudioUnitInitialize(instance));
166 Ok(AudioUnit {
167 instance: instance,
168 maybe_render_callback: None,
169 maybe_input_callback: None,
170 })
171 }
172 }
173
174 /// Sets the value for some property of the **AudioUnit**.
175 ///
176 /// To clear an audio unit property value, set the data paramater with `None::<()>`.
177 ///
178 /// Clearing properties only works for those properties that do not have a default value.
179 ///
180 /// For more on "properties" see [the reference](https://developer.apple.com/library/ios/documentation/AudioUnit/Reference/AudioUnitPropertiesReference/index.html#//apple_ref/doc/uid/TP40007288).
181 ///
182 /// **Available** in iOS 2.0 and later.
183 ///
184 /// Parameters
185 /// ----------
186 ///
187 /// - **id**: The identifier of the property.
188 /// - **scope**: The audio unit scope for the property.
189 /// - **elem**: The audio unit element for the property.
190 /// - **maybe_data**: The value that you want to apply to the property.
set_property<T>(&mut self, id: u32, scope: Scope, elem: Element, maybe_data: Option<&T>) -> Result<(), Error>191 pub fn set_property<T>(&mut self, id: u32, scope: Scope, elem: Element, maybe_data: Option<&T>)
192 -> Result<(), Error>
193 {
194 set_property(self.instance, id, scope, elem, maybe_data)
195 }
196
197 /// Gets the value of an **AudioUnit** property.
198 ///
199 /// **Available** in iOS 2.0 and later.
200 ///
201 /// Parameters
202 /// ----------
203 ///
204 /// - **id**: The identifier of the property.
205 /// - **scope**: The audio unit scope for the property.
206 /// - **elem**: The audio unit element for the property.
get_property<T>(&self, id: u32, scope: Scope, elem: Element) -> Result<T, Error>207 pub fn get_property<T>(&self, id: u32, scope: Scope, elem: Element) -> Result<T, Error> {
208 get_property(self.instance, id, scope, elem)
209 }
210
211 /// Starts an I/O **AudioUnit**, which in turn starts the audio unit processing graph that it is
212 /// connected to.
213 ///
214 /// **Available** in OS X v10.0 and later.
start(&mut self) -> Result<(), Error>215 pub fn start(&mut self) -> Result<(), Error> {
216 unsafe { try_os_status!(sys::AudioOutputUnitStart(self.instance)); }
217 Ok(())
218 }
219
220 /// Stops an I/O **AudioUnit**, which in turn stops the audio unit processing graph that it is
221 /// connected to.
222 ///
223 /// **Available** in OS X v10.0 and later.
stop(&mut self) -> Result<(), Error>224 pub fn stop(&mut self) -> Result<(), Error> {
225 unsafe { try_os_status!(sys::AudioOutputUnitStop(self.instance)); }
226 Ok(())
227 }
228
229 /// Set the **AudioUnit**'s sample rate.
230 ///
231 /// **Available** in iOS 2.0 and later.
set_sample_rate(&mut self, sample_rate: f64) -> Result<(), Error>232 pub fn set_sample_rate(&mut self, sample_rate: f64) -> Result<(), Error> {
233 let id = sys::kAudioUnitProperty_SampleRate;
234 self.set_property(id, Scope::Input, Element::Output, Some(&sample_rate))
235 }
236
237 /// Get the **AudioUnit**'s sample rate.
sample_rate(&self) -> Result<f64, Error>238 pub fn sample_rate(&self) -> Result<f64, Error> {
239 let id = sys::kAudioUnitProperty_SampleRate;
240 self.get_property(id, Scope::Input, Element::Output)
241 }
242
243 /// Sets the current **StreamFormat** for the AudioUnit.
244 ///
245 /// Core Audio uses slightly different defaults depending on the platform.
246 ///
247 /// From the Core Audio Overview:
248 ///
249 /// > The canonical formats in Core Audio are as follows:
250 /// >
251 /// > - iOS input and output: Linear PCM with 16-bit integer samples.
252 /// > - iOS audio units and other audio processing: Noninterleaved linear PCM with 8.24-bit
253 /// fixed-point samples
254 /// > - Mac input and output: Linear PCM with 32-bit floating point samples.
255 /// > - Mac audio units and other audio processing: Noninterleaved linear PCM with 32-bit
256 /// floating-point
set_stream_format( &mut self, stream_format: StreamFormat, scope: Scope, ) -> Result<(), Error>257 pub fn set_stream_format(
258 &mut self,
259 stream_format: StreamFormat,
260 scope: Scope,
261 ) -> Result<(), Error> {
262 let id = sys::kAudioUnitProperty_StreamFormat;
263 let asbd = stream_format.to_asbd();
264 self.set_property(id, scope, Element::Output, Some(&asbd))
265 }
266
267 /// Return the current Stream Format for the AudioUnit.
stream_format(&self, scope: Scope) -> Result<StreamFormat, Error>268 pub fn stream_format(&self, scope: Scope) -> Result<StreamFormat, Error> {
269 let id = sys::kAudioUnitProperty_StreamFormat;
270 let asbd = try!(self.get_property(id, scope, Element::Output));
271 StreamFormat::from_asbd(asbd)
272 }
273
274 /// Return the current output Stream Format for the AudioUnit.
output_stream_format(&self) -> Result<StreamFormat, Error>275 pub fn output_stream_format(&self) -> Result<StreamFormat, Error> {
276 self.stream_format(Scope::Output)
277 }
278
279 /// Return the current input Stream Format for the AudioUnit.
input_stream_format(&self) -> Result<StreamFormat, Error>280 pub fn input_stream_format(&self) -> Result<StreamFormat, Error> {
281 self.stream_format(Scope::Input)
282 }
283 }
284
285
286 unsafe impl Send for AudioUnit {}
287
288
289 impl Drop for AudioUnit {
drop(&mut self)290 fn drop(&mut self) {
291 unsafe {
292 use error;
293
294 // We don't want to panic in `drop`, so we'll ignore returned errors.
295 //
296 // A user should explicitly terminate the `AudioUnit` if they want to handle errors (we
297 // still need to provide a way to actually do that).
298 self.stop().ok();
299 error::Error::from_os_status(sys::AudioUnitUninitialize(self.instance)).ok();
300
301 self.free_render_callback();
302 self.free_input_callback();
303 }
304 }
305 }
306
307
308 /// Sets the value for some property of the **AudioUnit**.
309 ///
310 /// To clear an audio unit property value, set the data paramater with `None::<()>`.
311 ///
312 /// Clearing properties only works for those properties that do not have a default value.
313 ///
314 /// For more on "properties" see [the reference](https://developer.apple.com/library/ios/documentation/AudioUnit/Reference/AudioUnitPropertiesReference/index.html#//apple_ref/doc/uid/TP40007288).
315 ///
316 /// **Available** in iOS 2.0 and later.
317 ///
318 /// Parameters
319 /// ----------
320 ///
321 /// - **au**: The AudioUnit instance.
322 /// - **id**: The identifier of the property.
323 /// - **scope**: The audio unit scope for the property.
324 /// - **elem**: The audio unit element for the property.
325 /// - **maybe_data**: The value that you want to apply to the property.
set_property<T>( au: sys::AudioUnit, id: u32, scope: Scope, elem: Element, maybe_data: Option<&T>, ) -> Result<(), Error>326 pub fn set_property<T>(
327 au: sys::AudioUnit,
328 id: u32,
329 scope: Scope,
330 elem: Element,
331 maybe_data: Option<&T>,
332 ) -> Result<(), Error>
333 {
334 let (data_ptr, size) = maybe_data.map(|data| {
335 let ptr = data as *const _ as *const c_void;
336 let size = ::std::mem::size_of::<T>() as u32;
337 (ptr, size)
338 }).unwrap_or_else(|| (::std::ptr::null(), 0));
339 let scope = scope as c_uint;
340 let elem = elem as c_uint;
341 unsafe {
342 try_os_status!(sys::AudioUnitSetProperty(au, id, scope, elem, data_ptr, size))
343 }
344 Ok(())
345 }
346
347 /// Gets the value of an **AudioUnit** property.
348 ///
349 /// **Available** in iOS 2.0 and later.
350 ///
351 /// Parameters
352 /// ----------
353 ///
354 /// - **au**: The AudioUnit instance.
355 /// - **id**: The identifier of the property.
356 /// - **scope**: The audio unit scope for the property.
357 /// - **elem**: The audio unit element for the property.
get_property<T>( au: sys::AudioUnit, id: u32, scope: Scope, elem: Element, ) -> Result<T, Error>358 pub fn get_property<T>(
359 au: sys::AudioUnit,
360 id: u32,
361 scope: Scope,
362 elem: Element,
363 ) -> Result<T, Error>
364 {
365 let scope = scope as c_uint;
366 let elem = elem as c_uint;
367 let mut size = ::std::mem::size_of::<T>() as u32;
368 unsafe {
369 let mut data: T = ::std::mem::uninitialized();
370 let data_ptr = &mut data as *mut _ as *mut c_void;
371 let size_ptr = &mut size as *mut _;
372 try_os_status!(
373 sys::AudioUnitGetProperty(au, id, scope, elem, data_ptr, size_ptr)
374 );
375 Ok(data)
376 }
377 }
378