1 //! A basic input + output stream example, copying the mic input stream to the default output stream
2 
3 extern crate coreaudio;
4 
5 use std::collections::VecDeque;
6 use std::mem;
7 use std::ptr::null;
8 use std::sync::{Arc, Mutex};
9 
10 use coreaudio::audio_unit::audio_format::LinearPcmFlags;
11 use coreaudio::audio_unit::render_callback::{self, data};
12 use coreaudio::audio_unit::{AudioUnit, Element, SampleFormat, Scope, StreamFormat};
13 use coreaudio::sys::*;
14 
15 const SAMPLE_RATE: f64 = 44100.0;
16 
17 type S = f32; const SAMPLE_FORMAT: SampleFormat = SampleFormat::F32;
18 // type S = i32; const SAMPLE_FORMAT: SampleFormat = SampleFormat::I32;
19 // type S = i16; const SAMPLE_FORMAT: SampleFormat = SampleFormat::I16;
20 // type S = i8; const SAMPLE_FORMAT: SampleFormat = SampleFormat::I8;
21 
main() -> Result<(), coreaudio::Error>22 fn main() -> Result<(), coreaudio::Error> {
23     let mut input_audio_unit = audio_unit_from_device(default_input_device().unwrap(), true)?;
24     let mut output_audio_unit = audio_unit_from_device(default_output_device().unwrap(), false)?;
25 
26     let format_flag = match SAMPLE_FORMAT {
27         SampleFormat::F32 => LinearPcmFlags::IS_FLOAT,
28         SampleFormat::I32 | SampleFormat::I16 | SampleFormat::I8 => LinearPcmFlags::IS_SIGNED_INTEGER,
29     };
30 
31     // Using IS_NON_INTERLEAVED everywhere because data::Interleaved is commented out / not implemented
32     let in_stream_format = StreamFormat {
33         sample_rate: SAMPLE_RATE,
34         sample_format: SAMPLE_FORMAT,
35         flags: format_flag | LinearPcmFlags::IS_PACKED | LinearPcmFlags::IS_NON_INTERLEAVED,
36         // audio_unit.set_input_callback is hardcoded to 1 buffer, and when using non_interleaved
37         // we are forced to 1 channel
38         channels_per_frame: 1,
39     };
40 
41     let out_stream_format = StreamFormat {
42         sample_rate: SAMPLE_RATE,
43         sample_format: SAMPLE_FORMAT,
44         flags: format_flag | LinearPcmFlags::IS_PACKED | LinearPcmFlags::IS_NON_INTERLEAVED,
45         // you can change this to 1
46         channels_per_frame: 2,
47     };
48 
49     println!("input={:#?}", &in_stream_format);
50     println!("output={:#?}", &out_stream_format);
51     println!("input_asbd={:#?}", &in_stream_format.to_asbd());
52     println!("output_asbd={:#?}", &out_stream_format.to_asbd());
53 
54     let id = kAudioUnitProperty_StreamFormat;
55     let asbd = in_stream_format.to_asbd();
56     input_audio_unit.set_property(id, Scope::Output, Element::Input, Some(&asbd))?;
57 
58     let asbd = out_stream_format.to_asbd();
59     output_audio_unit.set_property(id, Scope::Input, Element::Output, Some(&asbd))?;
60 
61     let buffer_left = Arc::new(Mutex::new(VecDeque::<S>::new()));
62     let producer_left = buffer_left.clone();
63     let consumer_left = buffer_left.clone();
64     let buffer_right = Arc::new(Mutex::new(VecDeque::<S>::new()));
65     let producer_right = buffer_right.clone();
66     let consumer_right = buffer_right.clone();
67 
68     // seed roughly 1 second of data to create a delay in the feedback loop for easier testing
69     for buffer in vec![buffer_left, buffer_right] {
70         let mut buffer = buffer.lock().unwrap();
71         for _ in 0..(out_stream_format.sample_rate as i32) {
72             buffer.push_back(0 as S);
73         }
74     }
75 
76     type Args = render_callback::Args<data::NonInterleaved<S>>;
77 
78     input_audio_unit.set_input_callback(move |args| {
79         let Args {
80             num_frames,
81             mut data,
82             ..
83         } = args;
84         let buffer_left = producer_left.lock().unwrap();
85         let buffer_right = producer_right.lock().unwrap();
86         let mut buffers = vec![buffer_left, buffer_right];
87         for i in 0..num_frames {
88             for (ch, channel) in data.channels_mut().enumerate() {
89                 let value: S = channel[i];
90                 buffers[ch].push_back(value);
91             }
92         }
93         Ok(())
94     })?;
95     input_audio_unit.start()?;
96 
97     output_audio_unit.set_render_callback(move |args: Args| {
98         let Args {
99             num_frames,
100             mut data,
101             ..
102         } = args;
103 
104         let buffer_left = consumer_left.lock().unwrap();
105         let buffer_right = consumer_right.lock().unwrap();
106         let mut buffers = vec![buffer_left, buffer_right];
107         for i in 0..num_frames {
108             // Default other channels to copy value from first channel as a fallback
109             let zero: S = 0 as S;
110             let f: S = *buffers[0].front().unwrap_or(&zero);
111             for (ch, channel) in data.channels_mut().enumerate() {
112                 let sample: S = buffers[ch].pop_front().unwrap_or(f);
113                 channel[i] = sample;
114             }
115         }
116         Ok(())
117     })?;
118     output_audio_unit.start()?;
119 
120     std::thread::sleep(std::time::Duration::from_millis(100000));
121 
122     Ok(())
123 }
124 
125 /// Copied from cpal
default_input_device() -> Option<AudioDeviceID>126 pub fn default_input_device() -> Option<AudioDeviceID> {
127     let property_address = AudioObjectPropertyAddress {
128         mSelector: kAudioHardwarePropertyDefaultInputDevice,
129         mScope: kAudioObjectPropertyScopeGlobal,
130         mElement: kAudioObjectPropertyElementMaster,
131     };
132 
133     let audio_device_id: AudioDeviceID = 0;
134     let data_size = mem::size_of::<AudioDeviceID>();
135     let status = unsafe {
136         AudioObjectGetPropertyData(
137             kAudioObjectSystemObject,
138             &property_address as *const _,
139             0,
140             null(),
141             &data_size as *const _ as *mut _,
142             &audio_device_id as *const _ as *mut _,
143         )
144     };
145     if status != kAudioHardwareNoError as i32 {
146         return None;
147     }
148 
149     Some(audio_device_id)
150 }
151 
152 /// Copied from cpal
default_output_device() -> Option<AudioDeviceID>153 pub fn default_output_device() -> Option<AudioDeviceID> {
154     let property_address = AudioObjectPropertyAddress {
155         mSelector: kAudioHardwarePropertyDefaultOutputDevice,
156         mScope: kAudioObjectPropertyScopeGlobal,
157         mElement: kAudioObjectPropertyElementMaster,
158     };
159 
160     let audio_device_id: AudioDeviceID = 0;
161     let data_size = mem::size_of::<AudioDeviceID>();
162     let status = unsafe {
163         AudioObjectGetPropertyData(
164             kAudioObjectSystemObject,
165             &property_address as *const _,
166             0,
167             null(),
168             &data_size as *const _ as *mut _,
169             &audio_device_id as *const _ as *mut _,
170         )
171     };
172     if status != kAudioHardwareNoError as i32 {
173         return None;
174     }
175 
176     Some(audio_device_id)
177 }
178 
179 /// Copied from cpal
audio_unit_from_device( device_id: AudioDeviceID, input: bool, ) -> Result<AudioUnit, coreaudio::Error>180 fn audio_unit_from_device(
181     device_id: AudioDeviceID,
182     input: bool,
183 ) -> Result<AudioUnit, coreaudio::Error> {
184     let mut audio_unit = AudioUnit::new(coreaudio::audio_unit::IOType::HalOutput)?;
185 
186     if input {
187         // Enable input processing.
188         let enable_input = 1u32;
189         audio_unit.set_property(
190             kAudioOutputUnitProperty_EnableIO,
191             Scope::Input,
192             Element::Input,
193             Some(&enable_input),
194         )?;
195 
196         // Disable output processing.
197         let disable_output = 0u32;
198         audio_unit.set_property(
199             kAudioOutputUnitProperty_EnableIO,
200             Scope::Output,
201             Element::Output,
202             Some(&disable_output),
203         )?;
204     }
205 
206     audio_unit.set_property(
207         kAudioOutputUnitProperty_CurrentDevice,
208         Scope::Global,
209         Element::Output,
210         Some(&device_id),
211     )?;
212 
213     Ok(audio_unit)
214 }
215