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