coreaudio/audio_unit/
mod.rs

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
21use objc2_audio_toolbox::{
22    kAudioUnitManufacturer_Apple, kAudioUnitProperty_SampleRate, kAudioUnitProperty_StreamFormat,
23    kAudioUnitScope_Global, kAudioUnitScope_Group, kAudioUnitScope_Input, kAudioUnitScope_Layer,
24    kAudioUnitScope_LayerItem, kAudioUnitScope_Note, kAudioUnitScope_Output, kAudioUnitScope_Part,
25    AudioComponentDescription, AudioComponentFindNext, AudioComponentInstanceDispose,
26    AudioComponentInstanceNew, AudioOutputUnitStart, AudioOutputUnitStop,
27    AudioUnit as InnerAudioUnit, AudioUnitGetProperty, AudioUnitInitialize, AudioUnitSetProperty,
28    AudioUnitUninitialize,
29};
30use objc2_core_audio_types::AudioBufferList;
31
32use crate::error::Error;
33use std::mem;
34use std::os::raw::{c_uint, c_void};
35use std::ptr::{self, NonNull};
36
37pub use self::audio_format::AudioFormat;
38pub use self::sample_format::{Sample, SampleFormat};
39pub use self::stream_format::StreamFormat;
40pub use self::types::{
41    EffectType, FormatConverterType, GeneratorType, IOType, MixerType, MusicDeviceType, Type,
42};
43
44#[cfg(target_os = "macos")]
45pub mod macos_helpers;
46
47pub mod audio_format;
48pub mod render_callback;
49pub mod sample_format;
50pub mod stream_format;
51pub mod types;
52
53/// The input and output **Scope**s.
54///
55/// More info [here](https://developer.apple.com/library/ios/documentation/AudioUnit/Reference/AudioUnitPropertiesReference/index.html#//apple_ref/doc/constant_group/Audio_Unit_Scopes)
56/// and [here](https://developer.apple.com/library/mac/documentation/MusicAudio/Conceptual/AudioUnitProgrammingGuide/TheAudioUnit/TheAudioUnit.html).
57#[derive(Copy, Clone, Debug)]
58pub enum Scope {
59    Global = kAudioUnitScope_Global as isize,
60    Input = kAudioUnitScope_Input as isize,
61    Output = kAudioUnitScope_Output as isize,
62    Group = kAudioUnitScope_Group as isize,
63    Part = kAudioUnitScope_Part as isize,
64    Note = kAudioUnitScope_Note as isize,
65    Layer = kAudioUnitScope_Layer as isize,
66    LayerItem = kAudioUnitScope_LayerItem as isize,
67}
68
69/// Represents the **Input** and **Output** **Element**s.
70///
71/// These are used when specifying which **Element** we're setting the properties of.
72#[derive(Copy, Clone, Debug)]
73pub enum Element {
74    Output = 0,
75    Input = 1,
76}
77
78/// A rust representation of the [`objc2_audio_toolbox::AudioUnit`], including
79/// a pointer to the current rendering callback.
80///
81/// Find the original Audio Unit Programming Guide [here](https://developer.apple.com/library/mac/documentation/MusicAudio/Conceptual/AudioUnitProgrammingGuide/TheAudioUnit/TheAudioUnit.html).
82pub struct AudioUnit {
83    instance: InnerAudioUnit,
84    maybe_render_callback: Option<*mut render_callback::InputProcFnWrapper>,
85    maybe_input_callback: Option<InputCallback>,
86}
87
88struct InputCallback {
89    // The audio buffer list to which input data is rendered.
90    buffer_list: *mut AudioBufferList,
91    callback: *mut render_callback::InputProcFnWrapper,
92}
93
94macro_rules! try_os_status {
95    ($expr:expr) => {
96        Error::from_os_status($expr)?
97    };
98}
99
100impl AudioUnit {
101    /// Construct a new AudioUnit with any type that may be automatically converted into
102    /// [**Type**](./enum.Type).
103    ///
104    /// Here is a list of compatible types:
105    ///
106    /// - [**Type**](./types/enum.Type)
107    /// - [**IOType**](./types/enum.IOType)
108    /// - [**MusicDeviceType**](./types/enum.MusicDeviceType)
109    /// - [**GeneratorType**](./types/enum.GeneratorType)
110    /// - [**FormatConverterType**](./types/enum.FormatConverterType)
111    /// - [**EffectType**](./types/enum.EffectType)
112    /// - [**MixerType**](./types/enum.MixerType)
113    ///
114    /// To construct the **AudioUnit** with some component flags, see
115    /// [**AudioUnit::new_with_flags**](./struct.AudioUnit#method.new_with_flags).
116    ///
117    /// Note: the `AudioUnit` is constructed with the `kAudioUnitManufacturer_Apple` Manufacturer
118    /// Identifier, as this is the only Audio Unit Manufacturer Identifier documented by Apple in
119    /// 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)).
120    pub fn new<T>(ty: T) -> Result<AudioUnit, Error>
121    where
122        T: Into<Type>,
123    {
124        AudioUnit::new_with_flags(ty, 0, 0)
125    }
126
127    /// The same as [**AudioUnit::new**](./struct.AudioUnit#method.new) but with the given
128    /// component flags and mask.
129    pub fn new_with_flags<T>(ty: T, flags: u32, mask: u32) -> Result<AudioUnit, Error>
130    where
131        T: Into<Type>,
132    {
133        const MANUFACTURER_IDENTIFIER: u32 = kAudioUnitManufacturer_Apple;
134        let au_type: Type = ty.into();
135        let sub_type_u32 = match au_type.as_subtype_u32() {
136            Some(u) => u,
137            None => return Err(Error::NoKnownSubtype),
138        };
139
140        // A description of the audio unit we desire.
141        let desc = AudioComponentDescription {
142            componentType: au_type.as_u32() as c_uint,
143            componentSubType: sub_type_u32 as c_uint,
144            componentManufacturer: MANUFACTURER_IDENTIFIER,
145            componentFlags: flags,
146            componentFlagsMask: mask,
147        };
148
149        unsafe {
150            // Find the default audio unit for the description.
151            //
152            // From the "Audio Unit Hosting Guide for iOS":
153            //
154            // Passing NULL to the first parameter of AudioComponentFindNext tells this function to
155            // find the first system audio unit matching the description, using a system-defined
156            // ordering. If you instead pass a previously found audio unit reference in this
157            // parameter, the function locates the next audio unit matching the description.
158            let component = AudioComponentFindNext(ptr::null_mut(), NonNull::from(&desc));
159            if component.is_null() {
160                return Err(Error::NoMatchingDefaultAudioUnitFound);
161            }
162
163            // Create an instance of the default audio unit using the component.
164            let mut instance_uninit = mem::MaybeUninit::<InnerAudioUnit>::uninit();
165            try_os_status!(AudioComponentInstanceNew(
166                component,
167                NonNull::from(&mut instance_uninit).cast()
168            ));
169            let instance: InnerAudioUnit = instance_uninit.assume_init();
170
171            // Initialise the audio unit!
172            try_os_status!(AudioUnitInitialize(instance));
173            Ok(AudioUnit {
174                instance,
175                maybe_render_callback: None,
176                maybe_input_callback: None,
177            })
178        }
179    }
180
181    /// On successful initialization, the audio formats for input and output are valid
182    /// and the audio unit is ready to render. During initialization, an audio unit
183    /// allocates memory according to the maximum number of audio frames it can produce
184    /// in response to a single render call.
185    ///
186    /// Usually, the state of an audio unit (such as its I/O formats and memory allocations)
187    /// cannot be changed while an audio unit is initialized.
188    pub fn initialize(&mut self) -> Result<(), Error> {
189        unsafe {
190            try_os_status!(AudioUnitInitialize(self.instance));
191        }
192        Ok(())
193    }
194
195    /// Before you change an initialize audio unit’s processing characteristics,
196    /// such as its input or output audio data format or its sample rate, you must
197    /// first uninitialize it. Calling this function deallocates the audio unit’s resources.
198    ///
199    /// After calling this function, you can reconfigure the audio unit and then call
200    /// AudioUnitInitialize to reinitialize it.
201    pub fn uninitialize(&mut self) -> Result<(), Error> {
202        unsafe {
203            try_os_status!(AudioUnitUninitialize(self.instance));
204        }
205        Ok(())
206    }
207
208    /// Sets the value for some property of the **AudioUnit**.
209    ///
210    /// To clear an audio unit property value, set the data parameter with `None::<()>`.
211    ///
212    /// Clearing properties only works for those properties that do not have a default value.
213    ///
214    /// For more on "properties" see [the reference](https://developer.apple.com/library/ios/documentation/AudioUnit/Reference/AudioUnitPropertiesReference/index.html#//apple_ref/doc/uid/TP40007288).
215    ///
216    /// **Available** in iOS 2.0 and later.
217    ///
218    /// Parameters
219    /// ----------
220    ///
221    /// - **id**: The identifier of the property.
222    /// - **scope**: The audio unit scope for the property.
223    /// - **elem**: The audio unit element for the property.
224    /// - **maybe_data**: The value that you want to apply to the property.
225    pub fn set_property<T>(
226        &mut self,
227        id: u32,
228        scope: Scope,
229        elem: Element,
230        maybe_data: Option<&T>,
231    ) -> Result<(), Error> {
232        unsafe { set_property(self.instance, id, scope, elem, maybe_data) }
233    }
234
235    /// Gets the value of an **AudioUnit** property.
236    ///
237    /// **Available** in iOS 2.0 and later.
238    ///
239    /// Parameters
240    /// ----------
241    ///
242    /// - **id**: The identifier of the property.
243    /// - **scope**: The audio unit scope for the property.
244    /// - **elem**: The audio unit element for the property.
245    pub fn get_property<T>(&self, id: u32, scope: Scope, elem: Element) -> Result<T, Error> {
246        unsafe { get_property(self.instance, id, scope, elem) }
247    }
248
249    /// Starts an I/O **AudioUnit**, which in turn starts the audio unit processing graph that it is
250    /// connected to.
251    ///
252    /// **Available** in OS X v10.0 and later.
253    pub fn start(&mut self) -> Result<(), Error> {
254        unsafe {
255            try_os_status!(AudioOutputUnitStart(self.instance));
256        }
257        Ok(())
258    }
259
260    /// Stops an I/O **AudioUnit**, which in turn stops the audio unit processing graph that it is
261    /// connected to.
262    ///
263    /// **Available** in OS X v10.0 and later.
264    pub fn stop(&mut self) -> Result<(), Error> {
265        unsafe {
266            try_os_status!(AudioOutputUnitStop(self.instance));
267        }
268        Ok(())
269    }
270
271    /// Set the **AudioUnit**'s sample rate.
272    ///
273    /// **Available** in iOS 2.0 and later.
274    pub fn set_sample_rate(&mut self, sample_rate: f64) -> Result<(), Error> {
275        let id = kAudioUnitProperty_SampleRate;
276        self.set_property(id, Scope::Input, Element::Output, Some(&sample_rate))
277    }
278
279    /// Get the **AudioUnit**'s sample rate.
280    pub fn sample_rate(&self) -> Result<f64, Error> {
281        let id = kAudioUnitProperty_SampleRate;
282        self.get_property(id, Scope::Input, Element::Output)
283    }
284
285    /// Sets the current **StreamFormat** for the AudioUnit.
286    ///
287    /// Core Audio uses slightly different defaults depending on the platform.
288    ///
289    /// From the Core Audio Overview:
290    ///
291    /// > The canonical formats in Core Audio are as follows:
292    /// >
293    /// > - iOS input and output: Linear PCM with 16-bit integer samples.
294    /// > - iOS audio units and other audio processing: Noninterleaved linear PCM with 8.24-bit
295    /// >   fixed-point samples
296    /// > - Mac input and output: Linear PCM with 32-bit floating point samples.
297    /// > - Mac audio units and other audio processing: Noninterleaved linear PCM with 32-bit
298    /// >   floating-point
299    pub fn set_stream_format(
300        &mut self,
301        stream_format: StreamFormat,
302        scope: Scope,
303        element: Element,
304    ) -> Result<(), Error> {
305        let id = kAudioUnitProperty_StreamFormat;
306        let asbd = stream_format.to_asbd();
307        self.set_property(id, scope, element, Some(&asbd))
308    }
309
310    /// Return the current Stream Format for the AudioUnit.
311    pub fn stream_format(&self, scope: Scope, element: Element) -> Result<StreamFormat, Error> {
312        let id = kAudioUnitProperty_StreamFormat;
313        let asbd = self.get_property(id, scope, element)?;
314        StreamFormat::from_asbd(asbd)
315    }
316
317    /// Return the current output Stream Format for the AudioUnit.
318    pub fn output_stream_format(&self) -> Result<StreamFormat, Error> {
319        self.stream_format(Scope::Input, Element::Output)
320    }
321
322    /// Return the current input Stream Format for the AudioUnit.
323    pub fn input_stream_format(&self) -> Result<StreamFormat, Error> {
324        self.stream_format(Scope::Output, Element::Input)
325    }
326}
327
328impl AsRef<InnerAudioUnit> for AudioUnit {
329    fn as_ref(&self) -> &InnerAudioUnit {
330        &self.instance
331    }
332}
333
334impl AsMut<InnerAudioUnit> for AudioUnit {
335    fn as_mut(&mut self) -> &mut InnerAudioUnit {
336        &mut self.instance
337    }
338}
339
340unsafe impl Send for AudioUnit {}
341
342impl Drop for AudioUnit {
343    fn drop(&mut self) {
344        unsafe {
345            use crate::error;
346
347            // We don't want to panic in `drop`, so we'll ignore returned errors.
348            //
349            // A user should explicitly terminate the `AudioUnit` if they want to handle errors (we
350            // still need to provide a way to actually do that).
351            self.stop().ok();
352            error::Error::from_os_status(AudioUnitUninitialize(self.instance)).ok();
353
354            self.free_render_callback();
355            self.free_input_callback();
356
357            error::Error::from_os_status(AudioComponentInstanceDispose(self.instance)).ok();
358        }
359    }
360}
361
362/// Sets the value for some property of the **AudioUnit**.
363///
364/// To clear an audio unit property value, set the data parameter with `None::<()>`.
365///
366/// Clearing properties only works for those properties that do not have a default value.
367///
368/// For more on "properties" see [the reference](https://developer.apple.com/library/ios/documentation/AudioUnit/Reference/AudioUnitPropertiesReference/index.html#//apple_ref/doc/uid/TP40007288).
369///
370/// **Available** in iOS 2.0 and later.
371///
372/// Parameters
373/// ----------
374///
375/// - **au**: The AudioUnit instance.
376/// - **id**: The identifier of the property.
377/// - **scope**: The audio unit scope for the property.
378/// - **elem**: The audio unit element for the property.
379/// - **maybe_data**: The value that you want to apply to the property.
380///
381/// Safety
382/// ------
383/// This function is safe as long as the **au** parameter is a valid pointer to an AudioUnit instance.
384/// The caller is responsible for ensuring this.
385/// For a safer alternative, consider using an [AudioUnit] instance
386/// and calling the associated [AudioUnit::set_property] method.
387pub unsafe fn set_property<T>(
388    au: InnerAudioUnit,
389    id: u32,
390    scope: Scope,
391    elem: Element,
392    maybe_data: Option<&T>,
393) -> Result<(), Error> {
394    let (data_ptr, size) = maybe_data
395        .map(|data| {
396            let ptr = data as *const _ as *const c_void;
397            let size = ::std::mem::size_of::<T>() as u32;
398            (ptr, size)
399        })
400        .unwrap_or_else(|| (::std::ptr::null(), 0));
401    let scope = scope as c_uint;
402    let elem = elem as c_uint;
403    try_os_status!(AudioUnitSetProperty(au, id, scope, elem, data_ptr, size));
404    Ok(())
405}
406
407/// Gets the value of an **AudioUnit** property.
408///
409/// **Available** in iOS 2.0 and later.
410///
411/// Parameters
412/// ----------
413///
414/// - **au**: The AudioUnit instance.
415/// - **id**: The identifier of the property.
416/// - **scope**: The audio unit scope for the property.
417/// - **elem**: The audio unit element for the property.
418///
419/// Safety
420/// ------
421/// This function is safe as long as the **au** parameter is a valid pointer to an AudioUnit instance.
422/// The caller is responsible for ensuring this.
423/// For a safer alternative, consider using an [AudioUnit] instance
424/// and calling the associated [AudioUnit::get_property] method.
425pub unsafe fn get_property<T>(
426    au: InnerAudioUnit,
427    id: u32,
428    scope: Scope,
429    elem: Element,
430) -> Result<T, Error> {
431    let scope = scope as c_uint;
432    let elem = elem as c_uint;
433    let mut size = ::std::mem::size_of::<T>() as u32;
434    let mut data_uninit = ::std::mem::MaybeUninit::<T>::uninit();
435    let data_ptr = NonNull::from(&mut data_uninit).cast::<c_void>();
436    let size_ptr = NonNull::from(&mut size);
437    try_os_status!(AudioUnitGetProperty(
438        au, id, scope, elem, data_ptr, size_ptr
439    ));
440    let data: T = data_uninit.assume_init();
441    Ok(data)
442}
443
444/// Gets the value of a specified audio session property.
445///
446/// **Available** in iOS 2.0 and later, and tvOS 9.0 and later.
447///
448/// Parameters
449/// ----------
450///
451/// - **id**: The identifier of the property.
452#[cfg(any(target_os = "ios", target_os = "tvos", target_os = "visionos"))]
453pub fn audio_session_get_property<T>(id: u32) -> Result<T, Error> {
454    let mut size = ::std::mem::size_of::<T>() as u32;
455    #[allow(deprecated)]
456    unsafe {
457        let mut data_uninit = ::std::mem::MaybeUninit::<T>::uninit();
458        let data_ptr = data_uninit.as_mut_ptr() as *mut _ as *mut c_void;
459        let size_ptr = &mut size as *mut _;
460        try_os_status!(objc2_audio_toolbox::AudioSessionGetProperty(
461            id, size_ptr, data_ptr
462        ));
463        let data: T = data_uninit.assume_init();
464        Ok(data)
465    }
466}