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) => (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_uninit = mem::MaybeUninit::<sys::AudioUnit>::uninit();
160             try_os_status!(
161                 sys::AudioComponentInstanceNew(component, instance_uninit.as_mut_ptr() as *mut sys::AudioUnit)
162             );
163             let instance: sys::AudioUnit = instance_uninit.assume_init();
164 
165             // Initialise the audio unit!
166             try_os_status!(sys::AudioUnitInitialize(instance));
167             Ok(AudioUnit {
168                 instance: instance,
169                 maybe_render_callback: None,
170                 maybe_input_callback: None,
171             })
172         }
173     }
174 
175     /// On successful initialization, the audio formats for input and output are valid
176     /// and the audio unit is ready to render. During initialization, an audio unit
177     /// allocates memory according to the maximum number of audio frames it can produce
178     /// in response to a single render call.
179     ///
180     /// Usually, the state of an audio unit (such as its I/O formats and memory allocations)
181     /// cannot be changed while an audio unit is initialized.
initialize(&mut self) -> Result<(), Error>182     pub fn initialize(&mut self) -> Result<(), Error> {
183         unsafe { try_os_status!(sys::AudioUnitInitialize(self.instance)); }
184         Ok(())
185     }
186 
187     /// Before you change an initialize audio unit’s processing characteristics,
188     /// such as its input or output audio data format or its sample rate, you must
189     /// first uninitialize it. Calling this function deallocates the audio unit’s resources.
190     ///
191     /// After calling this function, you can reconfigure the audio unit and then call
192     /// AudioUnitInitialize to reinitialize it.
uninitialize(&mut self) -> Result<(), Error>193     pub fn uninitialize(&mut self) -> Result<(), Error> {
194         unsafe { try_os_status!(sys::AudioUnitUninitialize(self.instance)); }
195         Ok(())
196     }
197 
198     /// Sets the value for some property of the **AudioUnit**.
199     ///
200     /// To clear an audio unit property value, set the data paramater with `None::<()>`.
201     ///
202     /// Clearing properties only works for those properties that do not have a default value.
203     ///
204     /// For more on "properties" see [the reference](https://developer.apple.com/library/ios/documentation/AudioUnit/Reference/AudioUnitPropertiesReference/index.html#//apple_ref/doc/uid/TP40007288).
205     ///
206     /// **Available** in iOS 2.0 and later.
207     ///
208     /// Parameters
209     /// ----------
210     ///
211     /// - **id**: The identifier of the property.
212     /// - **scope**: The audio unit scope for the property.
213     /// - **elem**: The audio unit element for the property.
214     /// - **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>215     pub fn set_property<T>(&mut self, id: u32, scope: Scope, elem: Element, maybe_data: Option<&T>)
216         -> Result<(), Error>
217     {
218         set_property(self.instance, id, scope, elem, maybe_data)
219     }
220 
221     /// Gets the value of an **AudioUnit** property.
222     ///
223     /// **Available** in iOS 2.0 and later.
224     ///
225     /// Parameters
226     /// ----------
227     ///
228     /// - **id**: The identifier of the property.
229     /// - **scope**: The audio unit scope for the property.
230     /// - **elem**: The audio unit element for the property.
get_property<T>(&self, id: u32, scope: Scope, elem: Element) -> Result<T, Error>231     pub fn get_property<T>(&self, id: u32, scope: Scope, elem: Element) -> Result<T, Error> {
232         get_property(self.instance, id, scope, elem)
233     }
234 
235     /// Starts an I/O **AudioUnit**, which in turn starts the audio unit processing graph that it is
236     /// connected to.
237     ///
238     /// **Available** in OS X v10.0 and later.
start(&mut self) -> Result<(), Error>239     pub fn start(&mut self) -> Result<(), Error> {
240         unsafe { try_os_status!(sys::AudioOutputUnitStart(self.instance)); }
241         Ok(())
242     }
243 
244     /// Stops an I/O **AudioUnit**, which in turn stops the audio unit processing graph that it is
245     /// connected to.
246     ///
247     /// **Available** in OS X v10.0 and later.
stop(&mut self) -> Result<(), Error>248     pub fn stop(&mut self) -> Result<(), Error> {
249         unsafe { try_os_status!(sys::AudioOutputUnitStop(self.instance)); }
250         Ok(())
251     }
252 
253     /// Set the **AudioUnit**'s sample rate.
254     ///
255     /// **Available** in iOS 2.0 and later.
set_sample_rate(&mut self, sample_rate: f64) -> Result<(), Error>256     pub fn set_sample_rate(&mut self, sample_rate: f64) -> Result<(), Error> {
257         let id = sys::kAudioUnitProperty_SampleRate;
258         self.set_property(id, Scope::Input, Element::Output, Some(&sample_rate))
259     }
260 
261     /// Get the **AudioUnit**'s sample rate.
sample_rate(&self) -> Result<f64, Error>262     pub fn sample_rate(&self) -> Result<f64, Error> {
263         let id = sys::kAudioUnitProperty_SampleRate;
264         self.get_property(id, Scope::Input, Element::Output)
265     }
266 
267     /// Sets the current **StreamFormat** for the AudioUnit.
268     ///
269     /// Core Audio uses slightly different defaults depending on the platform.
270     ///
271     /// From the Core Audio Overview:
272     ///
273     /// > The canonical formats in Core Audio are as follows:
274     /// >
275     /// > - iOS input and output: Linear PCM with 16-bit integer samples.
276     /// > - iOS audio units and other audio processing: Noninterleaved linear PCM with 8.24-bit
277     /// fixed-point samples
278     /// > - Mac input and output: Linear PCM with 32-bit floating point samples.
279     /// > - Mac audio units and other audio processing: Noninterleaved linear PCM with 32-bit
280     /// floating-point
set_stream_format( &mut self, stream_format: StreamFormat, scope: Scope, ) -> Result<(), Error>281     pub fn set_stream_format(
282         &mut self,
283         stream_format: StreamFormat,
284         scope: Scope,
285     ) -> Result<(), Error> {
286         let id = sys::kAudioUnitProperty_StreamFormat;
287         let asbd = stream_format.to_asbd();
288         self.set_property(id, scope, Element::Output, Some(&asbd))
289     }
290 
291     /// Return the current Stream Format for the AudioUnit.
stream_format(&self, scope: Scope) -> Result<StreamFormat, Error>292     pub fn stream_format(&self, scope: Scope) -> Result<StreamFormat, Error> {
293         let id = sys::kAudioUnitProperty_StreamFormat;
294         let asbd = self.get_property(id, scope, Element::Output)?;
295         StreamFormat::from_asbd(asbd)
296     }
297 
298     /// Return the current output Stream Format for the AudioUnit.
output_stream_format(&self) -> Result<StreamFormat, Error>299     pub fn output_stream_format(&self) -> Result<StreamFormat, Error> {
300         self.stream_format(Scope::Output)
301     }
302 
303     /// Return the current input Stream Format for the AudioUnit.
input_stream_format(&self) -> Result<StreamFormat, Error>304     pub fn input_stream_format(&self) -> Result<StreamFormat, Error> {
305         self.stream_format(Scope::Input)
306     }
307 }
308 
309 
310 unsafe impl Send for AudioUnit {}
311 
312 
313 impl Drop for AudioUnit {
drop(&mut self)314     fn drop(&mut self) {
315         unsafe {
316             use error;
317 
318             // We don't want to panic in `drop`, so we'll ignore returned errors.
319             //
320             // A user should explicitly terminate the `AudioUnit` if they want to handle errors (we
321             // still need to provide a way to actually do that).
322             self.stop().ok();
323             error::Error::from_os_status(sys::AudioUnitUninitialize(self.instance)).ok();
324 
325             self.free_render_callback();
326             self.free_input_callback();
327 
328             error::Error::from_os_status(sys::AudioComponentInstanceDispose(self.instance)).ok();
329         }
330     }
331 }
332 
333 
334 /// Sets the value for some property of the **AudioUnit**.
335 ///
336 /// To clear an audio unit property value, set the data paramater with `None::<()>`.
337 ///
338 /// Clearing properties only works for those properties that do not have a default value.
339 ///
340 /// For more on "properties" see [the reference](https://developer.apple.com/library/ios/documentation/AudioUnit/Reference/AudioUnitPropertiesReference/index.html#//apple_ref/doc/uid/TP40007288).
341 ///
342 /// **Available** in iOS 2.0 and later.
343 ///
344 /// Parameters
345 /// ----------
346 ///
347 /// - **au**: The AudioUnit instance.
348 /// - **id**: The identifier of the property.
349 /// - **scope**: The audio unit scope for the property.
350 /// - **elem**: The audio unit element for the property.
351 /// - **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>352 pub fn set_property<T>(
353     au: sys::AudioUnit,
354     id: u32,
355     scope: Scope,
356     elem: Element,
357     maybe_data: Option<&T>,
358 ) -> Result<(), Error>
359 {
360     let (data_ptr, size) = maybe_data.map(|data| {
361         let ptr = data as *const _ as *const c_void;
362         let size = ::std::mem::size_of::<T>() as u32;
363         (ptr, size)
364     }).unwrap_or_else(|| (::std::ptr::null(), 0));
365     let scope = scope as c_uint;
366     let elem = elem as c_uint;
367     unsafe {
368         try_os_status!(sys::AudioUnitSetProperty(au, id, scope, elem, data_ptr, size))
369     }
370     Ok(())
371 }
372 
373 /// Gets the value of an **AudioUnit** property.
374 ///
375 /// **Available** in iOS 2.0 and later.
376 ///
377 /// Parameters
378 /// ----------
379 ///
380 /// - **au**: The AudioUnit instance.
381 /// - **id**: The identifier of the property.
382 /// - **scope**: The audio unit scope for the property.
383 /// - **elem**: The audio unit element for the property.
get_property<T>( au: sys::AudioUnit, id: u32, scope: Scope, elem: Element, ) -> Result<T, Error>384 pub fn get_property<T>(
385     au: sys::AudioUnit,
386     id: u32,
387     scope: Scope,
388     elem: Element,
389 ) -> Result<T, Error>
390 {
391     let scope = scope as c_uint;
392     let elem = elem as c_uint;
393     let mut size = ::std::mem::size_of::<T>() as u32;
394     unsafe {
395         let mut data_uninit = ::std::mem::MaybeUninit::<T>::uninit();
396         let data_ptr = data_uninit.as_mut_ptr() as *mut _ as *mut c_void;
397         let size_ptr = &mut size as *mut _;
398         try_os_status!(
399             sys::AudioUnitGetProperty(au, id, scope, elem, data_ptr, size_ptr)
400         );
401         let data: T = data_uninit.assume_init();
402         Ok(data)
403     }
404 }
405 
406 /// Gets the value of a specified audio session property.
407 ///
408 /// **Available** in iOS 2.0 and later.
409 ///
410 /// Parameters
411 /// ----------
412 ///
413 /// - **id**: The identifier of the property.
414 #[cfg(target_os = "ios")]
audio_session_get_property<T>( id: u32, ) -> Result<T, Error>415 pub fn audio_session_get_property<T>(
416     id: u32,
417 ) -> Result<T, Error>
418 {
419     let mut size = ::std::mem::size_of::<T>() as u32;
420     unsafe {
421         let mut data: T = ::std::mem::uninitialized();
422         let data_ptr = &mut data as *mut _ as *mut c_void;
423         let size_ptr = &mut size as *mut _;
424         try_os_status!(
425             sys::AudioSessionGetProperty(id, size_ptr, data_ptr)
426         );
427         Ok(data)
428     }
429 }
430