1 // Copyright © 2018 Mozilla Foundation
2 //
3 // This program is made available under an ISC-style license.  See the
4 // accompanying file LICENSE for details.
5 #![allow(unused_assignments)]
6 #![allow(unused_must_use)]
7 
8 extern crate coreaudio_sys_utils;
9 extern crate libc;
10 extern crate ringbuf;
11 
12 mod aggregate_device;
13 mod auto_release;
14 mod buffer_manager;
15 mod device_property;
16 mod mixer;
17 mod resampler;
18 mod utils;
19 
20 use self::aggregate_device::*;
21 use self::auto_release::*;
22 use self::buffer_manager::*;
23 use self::coreaudio_sys_utils::aggregate_device::*;
24 use self::coreaudio_sys_utils::audio_object::*;
25 use self::coreaudio_sys_utils::audio_unit::*;
26 use self::coreaudio_sys_utils::cf_mutable_dict::*;
27 use self::coreaudio_sys_utils::dispatch::*;
28 use self::coreaudio_sys_utils::string::*;
29 use self::coreaudio_sys_utils::sys::*;
30 use self::device_property::*;
31 use self::mixer::*;
32 use self::resampler::*;
33 use self::utils::*;
34 use atomic;
35 use cubeb_backend::{
36     ffi, Context, ContextOps, DeviceCollectionRef, DeviceId, DeviceRef, DeviceType, Error, Ops,
37     Result, SampleFormat, State, Stream, StreamOps, StreamParams, StreamParamsRef, StreamPrefs,
38 };
39 use mach::mach_time::{mach_absolute_time, mach_timebase_info};
40 use std::cmp;
41 use std::ffi::{CStr, CString};
42 use std::mem;
43 use std::os::raw::c_void;
44 use std::ptr;
45 use std::slice;
46 use std::sync::atomic::{AtomicBool, AtomicU32, AtomicUsize, Ordering};
47 use std::sync::{Arc, Condvar, Mutex};
48 use std::time::Duration;
49 const NO_ERR: OSStatus = 0;
50 
51 const AU_OUT_BUS: AudioUnitElement = 0;
52 const AU_IN_BUS: AudioUnitElement = 1;
53 
54 const DISPATCH_QUEUE_LABEL: &str = "org.mozilla.cubeb";
55 const PRIVATE_AGGREGATE_DEVICE_NAME: &str = "CubebAggregateDevice";
56 
57 // Testing empirically, some headsets report a minimal latency that is very low,
58 // but this does not work in practice. Lie and say the minimum is 256 frames.
59 const SAFE_MIN_LATENCY_FRAMES: u32 = 128;
60 const SAFE_MAX_LATENCY_FRAMES: u32 = 512;
61 
62 bitflags! {
63     #[allow(non_camel_case_types)]
64     struct device_flags: u32 {
65         const DEV_UNKNOWN           = 0b0000_0000; // Unknown
66         const DEV_INPUT             = 0b0000_0001; // Record device like mic
67         const DEV_OUTPUT            = 0b0000_0010; // Playback device like speakers
68         const DEV_SYSTEM_DEFAULT    = 0b0000_0100; // System default device
69         const DEV_SELECTED_DEFAULT  = 0b0000_1000; // User selected to use the system default device
70     }
71 }
72 
73 lazy_static! {
74     static ref HOST_TIME_TO_NS_RATIO: (u32, u32) = {
75         let mut timebase_info = mach_timebase_info { numer: 0, denom: 0 };
76         unsafe {
77             mach_timebase_info(&mut timebase_info);
78         }
79         (timebase_info.numer, timebase_info.denom)
80     };
81 }
82 
make_sized_audio_channel_layout(sz: usize) -> AutoRelease<AudioChannelLayout>83 fn make_sized_audio_channel_layout(sz: usize) -> AutoRelease<AudioChannelLayout> {
84     assert!(sz >= mem::size_of::<AudioChannelLayout>());
85     assert_eq!(
86         (sz - mem::size_of::<AudioChannelLayout>()) % mem::size_of::<AudioChannelDescription>(),
87         0
88     );
89     let acl = unsafe { libc::calloc(1, sz) } as *mut AudioChannelLayout;
90 
91     unsafe extern "C" fn free_acl(acl: *mut AudioChannelLayout) {
92         libc::free(acl as *mut libc::c_void);
93     }
94 
95     AutoRelease::new(acl, free_acl)
96 }
97 
98 #[allow(non_camel_case_types)]
99 #[derive(Clone, Debug)]
100 struct device_info {
101     id: AudioDeviceID,
102     flags: device_flags,
103 }
104 
105 impl Default for device_info {
default() -> Self106     fn default() -> Self {
107         Self {
108             id: kAudioObjectUnknown,
109             flags: device_flags::DEV_UNKNOWN,
110         }
111     }
112 }
113 
114 #[allow(non_camel_case_types)]
115 #[derive(Debug)]
116 struct device_property_listener {
117     device: AudioDeviceID,
118     property: AudioObjectPropertyAddress,
119     listener: audio_object_property_listener_proc,
120 }
121 
122 impl device_property_listener {
new( device: AudioDeviceID, property: AudioObjectPropertyAddress, listener: audio_object_property_listener_proc, ) -> Self123     fn new(
124         device: AudioDeviceID,
125         property: AudioObjectPropertyAddress,
126         listener: audio_object_property_listener_proc,
127     ) -> Self {
128         Self {
129             device,
130             property,
131             listener,
132         }
133     }
134 }
135 
136 #[derive(Debug, PartialEq)]
137 struct CAChannelLabel(AudioChannelLabel);
138 
139 impl Into<mixer::Channel> for CAChannelLabel {
into(self) -> mixer::Channel140     fn into(self) -> mixer::Channel {
141         use self::coreaudio_sys_utils::sys;
142         match self.0 {
143             sys::kAudioChannelLabel_Left => mixer::Channel::FrontLeft,
144             sys::kAudioChannelLabel_Right => mixer::Channel::FrontRight,
145             sys::kAudioChannelLabel_Center | sys::kAudioChannelLabel_Mono => {
146                 mixer::Channel::FrontCenter
147             }
148             sys::kAudioChannelLabel_LFEScreen => mixer::Channel::LowFrequency,
149             sys::kAudioChannelLabel_LeftSurround => mixer::Channel::BackLeft,
150             sys::kAudioChannelLabel_RightSurround => mixer::Channel::BackRight,
151             sys::kAudioChannelLabel_LeftCenter => mixer::Channel::FrontLeftOfCenter,
152             sys::kAudioChannelLabel_RightCenter => mixer::Channel::FrontRightOfCenter,
153             sys::kAudioChannelLabel_CenterSurround => mixer::Channel::BackCenter,
154             sys::kAudioChannelLabel_LeftSurroundDirect => mixer::Channel::SideLeft,
155             sys::kAudioChannelLabel_RightSurroundDirect => mixer::Channel::SideRight,
156             sys::kAudioChannelLabel_TopCenterSurround => mixer::Channel::TopCenter,
157             sys::kAudioChannelLabel_VerticalHeightLeft => mixer::Channel::TopFrontLeft,
158             sys::kAudioChannelLabel_VerticalHeightCenter => mixer::Channel::TopFrontCenter,
159             sys::kAudioChannelLabel_VerticalHeightRight => mixer::Channel::TopFrontRight,
160             sys::kAudioChannelLabel_TopBackLeft => mixer::Channel::TopBackLeft,
161             sys::kAudioChannelLabel_TopBackCenter => mixer::Channel::TopBackCenter,
162             sys::kAudioChannelLabel_TopBackRight => mixer::Channel::TopBackRight,
163             _ => mixer::Channel::Silence,
164         }
165     }
166 }
167 
set_notification_runloop()168 fn set_notification_runloop() {
169     let address = AudioObjectPropertyAddress {
170         mSelector: kAudioHardwarePropertyRunLoop,
171         mScope: kAudioObjectPropertyScopeGlobal,
172         mElement: kAudioObjectPropertyElementMaster,
173     };
174 
175     // Ask HAL to manage its own thread for notification by setting the run_loop to NULL.
176     // Otherwise HAL may use main thread to fire notifications.
177     let run_loop: CFRunLoopRef = ptr::null_mut();
178     let size = mem::size_of::<CFRunLoopRef>();
179     let status =
180         audio_object_set_property_data(kAudioObjectSystemObject, &address, size, &run_loop);
181     if status != NO_ERR {
182         cubeb_log!("Could not make global CoreAudio notifications use their own thread.");
183     }
184 }
185 
clamp_latency(latency_frames: u32) -> u32186 fn clamp_latency(latency_frames: u32) -> u32 {
187     cmp::max(
188         cmp::min(latency_frames, SAFE_MAX_LATENCY_FRAMES),
189         SAFE_MIN_LATENCY_FRAMES,
190     )
191 }
192 
create_device_info(id: AudioDeviceID, devtype: DeviceType) -> Result<device_info>193 fn create_device_info(id: AudioDeviceID, devtype: DeviceType) -> Result<device_info> {
194     assert_ne!(id, kAudioObjectSystemObject);
195 
196     let mut info = device_info {
197         id,
198         flags: match devtype {
199             DeviceType::INPUT => device_flags::DEV_INPUT,
200             DeviceType::OUTPUT => device_flags::DEV_OUTPUT,
201             _ => panic!("Only accept input or output type"),
202         },
203     };
204 
205     let default_device_id = audiounit_get_default_device_id(devtype);
206     if default_device_id == kAudioObjectUnknown {
207         cubeb_log!("Could not find default audio device for {:?}", devtype);
208         return Err(Error::error());
209     }
210 
211     if id == kAudioObjectUnknown {
212         info.id = default_device_id;
213         cubeb_log!("Creating a default device info.");
214         info.flags |= device_flags::DEV_SELECTED_DEFAULT;
215     }
216 
217     if info.id == default_device_id {
218         cubeb_log!("Requesting default system device.");
219         info.flags |= device_flags::DEV_SYSTEM_DEFAULT;
220     }
221 
222     Ok(info)
223 }
224 
create_stream_description(stream_params: &StreamParams) -> Result<AudioStreamBasicDescription>225 fn create_stream_description(stream_params: &StreamParams) -> Result<AudioStreamBasicDescription> {
226     assert!(stream_params.rate() > 0);
227     assert!(stream_params.channels() > 0);
228 
229     let mut desc = AudioStreamBasicDescription::default();
230 
231     match stream_params.format() {
232         SampleFormat::S16LE => {
233             desc.mBitsPerChannel = 16;
234             desc.mFormatFlags = kAudioFormatFlagIsSignedInteger;
235         }
236         SampleFormat::S16BE => {
237             desc.mBitsPerChannel = 16;
238             desc.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsBigEndian;
239         }
240         SampleFormat::Float32LE => {
241             desc.mBitsPerChannel = 32;
242             desc.mFormatFlags = kAudioFormatFlagIsFloat;
243         }
244         SampleFormat::Float32BE => {
245             desc.mBitsPerChannel = 32;
246             desc.mFormatFlags = kAudioFormatFlagIsFloat | kAudioFormatFlagIsBigEndian;
247         }
248         _ => {
249             return Err(Error::invalid_format());
250         }
251     }
252 
253     desc.mFormatID = kAudioFormatLinearPCM;
254     desc.mFormatFlags |= kLinearPCMFormatFlagIsPacked;
255     desc.mSampleRate = f64::from(stream_params.rate());
256     desc.mChannelsPerFrame = stream_params.channels();
257 
258     desc.mBytesPerFrame = (desc.mBitsPerChannel / 8) * desc.mChannelsPerFrame;
259     desc.mFramesPerPacket = 1;
260     desc.mBytesPerPacket = desc.mBytesPerFrame * desc.mFramesPerPacket;
261 
262     desc.mReserved = 0;
263 
264     Ok(desc)
265 }
266 
set_volume(unit: AudioUnit, volume: f32) -> Result<()>267 fn set_volume(unit: AudioUnit, volume: f32) -> Result<()> {
268     assert!(!unit.is_null());
269     let r = audio_unit_set_parameter(
270         unit,
271         kHALOutputParam_Volume,
272         kAudioUnitScope_Global,
273         0,
274         volume,
275         0,
276     );
277     if r == NO_ERR {
278         Ok(())
279     } else {
280         cubeb_log!("AudioUnitSetParameter/kHALOutputParam_Volume rv={}", r);
281         Err(Error::error())
282     }
283 }
284 
get_volume(unit: AudioUnit) -> Result<f32>285 fn get_volume(unit: AudioUnit) -> Result<f32> {
286     assert!(!unit.is_null());
287     let mut volume: f32 = 0.0;
288     let r = audio_unit_get_parameter(
289         unit,
290         kHALOutputParam_Volume,
291         kAudioUnitScope_Global,
292         0,
293         &mut volume,
294     );
295     if r == NO_ERR {
296         Ok(volume)
297     } else {
298         cubeb_log!("AudioUnitGetParameter/kHALOutputParam_Volume rv={}", r);
299         Err(Error::error())
300     }
301 }
302 
minimum_resampling_input_frames( input_rate: f64, output_rate: f64, output_frames: usize, ) -> usize303 fn minimum_resampling_input_frames(
304     input_rate: f64,
305     output_rate: f64,
306     output_frames: usize,
307 ) -> usize {
308     assert!(!approx_eq!(f64, input_rate, 0_f64));
309     assert!(!approx_eq!(f64, output_rate, 0_f64));
310     if approx_eq!(f64, input_rate, output_rate) {
311         return output_frames;
312     }
313     (input_rate * output_frames as f64 / output_rate).ceil() as usize
314 }
315 
audiounit_make_silent(io_data: &mut AudioBuffer)316 fn audiounit_make_silent(io_data: &mut AudioBuffer) {
317     assert!(!io_data.mData.is_null());
318     let bytes = unsafe {
319         let ptr = io_data.mData as *mut u8;
320         let len = io_data.mDataByteSize as usize;
321         slice::from_raw_parts_mut(ptr, len)
322     };
323     for data in bytes.iter_mut() {
324         *data = 0;
325     }
326 }
327 
audiounit_input_callback( user_ptr: *mut c_void, flags: *mut AudioUnitRenderActionFlags, tstamp: *const AudioTimeStamp, bus: u32, input_frames: u32, _: *mut AudioBufferList, ) -> OSStatus328 extern "C" fn audiounit_input_callback(
329     user_ptr: *mut c_void,
330     flags: *mut AudioUnitRenderActionFlags,
331     tstamp: *const AudioTimeStamp,
332     bus: u32,
333     input_frames: u32,
334     _: *mut AudioBufferList,
335 ) -> OSStatus {
336     enum ErrorHandle {
337         Return(OSStatus),
338         Reinit,
339     };
340 
341     assert!(input_frames > 0);
342     assert_eq!(bus, AU_IN_BUS);
343 
344     assert!(!user_ptr.is_null());
345     let stm = unsafe { &mut *(user_ptr as *mut AudioUnitStream) };
346 
347     if unsafe { *flags | kAudioTimeStampHostTimeValid } != 0 {
348         let now = unsafe { mach_absolute_time() };
349         let input_latency_frames = compute_input_latency(&stm, unsafe { (*tstamp).mHostTime }, now);
350         stm.total_input_latency_frames
351             .store(input_latency_frames, Ordering::SeqCst);
352     }
353 
354     if stm.stopped.load(Ordering::SeqCst) {
355         cubeb_log!("({:p}) input stopped", stm as *const AudioUnitStream);
356         return NO_ERR;
357     }
358 
359     let handler = |stm: &mut AudioUnitStream,
360                    flags: *mut AudioUnitRenderActionFlags,
361                    tstamp: *const AudioTimeStamp,
362                    bus: u32,
363                    input_frames: u32|
364      -> ErrorHandle {
365         let input_buffer_manager = stm.core_stream_data.input_buffer_manager.as_mut().unwrap();
366         assert_eq!(
367             stm.core_stream_data.stm_ptr,
368             user_ptr as *const AudioUnitStream
369         );
370 
371         // `flags` and `tstamp` must be non-null so they can be casted into the references.
372         assert!(!flags.is_null());
373         let flags = unsafe { &mut (*flags) };
374         assert!(!tstamp.is_null());
375         let tstamp = unsafe { &(*tstamp) };
376 
377         // Create the AudioBufferList to store input.
378         let mut input_buffer_list = AudioBufferList::default();
379         input_buffer_list.mBuffers[0].mDataByteSize =
380             stm.core_stream_data.input_desc.mBytesPerFrame * input_frames;
381         input_buffer_list.mBuffers[0].mData = ptr::null_mut();
382         input_buffer_list.mBuffers[0].mNumberChannels =
383             stm.core_stream_data.input_desc.mChannelsPerFrame;
384         input_buffer_list.mNumberBuffers = 1;
385 
386         debug_assert!(!stm.core_stream_data.input_unit.is_null());
387         let status = audio_unit_render(
388             stm.core_stream_data.input_unit,
389             flags,
390             tstamp,
391             bus,
392             input_frames,
393             &mut input_buffer_list,
394         );
395         if (status != NO_ERR)
396             && (status != kAudioUnitErr_CannotDoInCurrentContext
397                 || stm.core_stream_data.output_unit.is_null())
398         {
399             return ErrorHandle::Return(status);
400         }
401         let handle = if status == kAudioUnitErr_CannotDoInCurrentContext {
402             assert!(!stm.core_stream_data.output_unit.is_null());
403             // kAudioUnitErr_CannotDoInCurrentContext is returned when using a BT
404             // headset and the profile is changed from A2DP to HFP/HSP. The previous
405             // output device is no longer valid and must be reset.
406             // For now state that no error occurred and feed silence, stream will be
407             // resumed once reinit has completed.
408             cubeb_logv!(
409                 "({:p}) input: reinit pending, output will pull silence instead",
410                 stm.core_stream_data.stm_ptr
411             );
412             ErrorHandle::Reinit
413         } else {
414             assert_eq!(status, NO_ERR);
415             // Copy input data in linear buffer.
416             let elements =
417                 (input_frames * stm.core_stream_data.input_desc.mChannelsPerFrame) as usize;
418             input_buffer_manager.push_data(input_buffer_list.mBuffers[0].mData, elements);
419             ErrorHandle::Return(status)
420         };
421 
422         // Advance input frame counter.
423         stm.frames_read
424             .fetch_add(input_frames as usize, atomic::Ordering::SeqCst);
425 
426         cubeb_logv!(
427             "({:p}) input: buffers {}, size {}, channels {}, rendered frames {}, total frames {}.",
428             stm.core_stream_data.stm_ptr,
429             input_buffer_list.mNumberBuffers,
430             input_buffer_list.mBuffers[0].mDataByteSize,
431             input_buffer_list.mBuffers[0].mNumberChannels,
432             input_frames,
433             input_buffer_manager.available_samples()
434                 / stm.core_stream_data.input_desc.mChannelsPerFrame as usize
435         );
436 
437         // Full Duplex. We'll call data_callback in the AudioUnit output callback.
438         if !stm.core_stream_data.output_unit.is_null() {
439             return handle;
440         }
441 
442         // Input only. Call the user callback through resampler.
443         // Resampler will deliver input buffer in the correct rate.
444         let mut total_input_frames = (input_buffer_manager.available_samples()
445             / stm.core_stream_data.input_desc.mChannelsPerFrame as usize)
446             as i64;
447         assert!(input_frames as i64 <= total_input_frames);
448         let input_buffer = input_buffer_manager.get_linear_data(total_input_frames as usize);
449         let outframes = stm.core_stream_data.resampler.fill(
450             input_buffer,
451             &mut total_input_frames,
452             ptr::null_mut(),
453             0,
454         );
455         if outframes < total_input_frames {
456             stm.draining.store(true, Ordering::SeqCst);
457         }
458 
459         handle
460     };
461 
462     // If the stream is drained, do nothing.
463     let handle = if !stm.draining.load(Ordering::SeqCst) {
464         handler(stm, flags, tstamp, bus, input_frames)
465     } else {
466         ErrorHandle::Return(NO_ERR)
467     };
468 
469     // If the input (input-only stream) or the output is drained (duplex stream),
470     // cancel this callback.
471     if stm.draining.load(Ordering::SeqCst) {
472         let r = stop_audiounit(stm.core_stream_data.input_unit);
473         assert!(r.is_ok());
474         // Only fire state-changed callback for input-only stream.
475         // The state-changed callback for the duplex stream is fired in the output callback.
476         if stm.core_stream_data.output_unit.is_null() {
477             stm.notify_state_changed(State::Drained);
478         }
479     }
480 
481     match handle {
482         ErrorHandle::Reinit => {
483             stm.reinit_async();
484             NO_ERR
485         }
486         ErrorHandle::Return(s) => s,
487     }
488 }
489 
host_time_to_ns(host_time: u64) -> u64490 fn host_time_to_ns(host_time: u64) -> u64 {
491     let mut rv: f64 = host_time as f64;
492     rv *= HOST_TIME_TO_NS_RATIO.0 as f64;
493     rv /= HOST_TIME_TO_NS_RATIO.1 as f64;
494     rv as u64
495 }
496 
compute_output_latency(stm: &AudioUnitStream, audio_output_time: u64, now: u64) -> u32497 fn compute_output_latency(stm: &AudioUnitStream, audio_output_time: u64, now: u64) -> u32 {
498     const NS2S: u64 = 1_000_000_000;
499     let output_hw_rate = stm.core_stream_data.output_hw_rate as u64;
500     let fixed_latency_ns =
501         (stm.output_device_latency_frames.load(Ordering::SeqCst) as u64 * NS2S) / output_hw_rate;
502     // The total output latency is the timestamp difference + the stream latency + the hardware
503     // latency.
504     let total_output_latency_ns =
505         fixed_latency_ns + host_time_to_ns(audio_output_time.saturating_sub(now));
506 
507     (total_output_latency_ns * output_hw_rate / NS2S) as u32
508 }
509 
compute_input_latency(stm: &AudioUnitStream, audio_input_time: u64, now: u64) -> u32510 fn compute_input_latency(stm: &AudioUnitStream, audio_input_time: u64, now: u64) -> u32 {
511     const NS2S: u64 = 1_000_000_000;
512     let input_hw_rate = stm.core_stream_data.input_hw_rate as u64;
513     let fixed_latency_ns =
514         (stm.input_device_latency_frames.load(Ordering::SeqCst) as u64 * NS2S) / input_hw_rate;
515     // The total input latency is the timestamp difference + the stream latency +
516     // the hardware latency.
517     let total_input_latency_ns =
518         host_time_to_ns(now.saturating_sub(audio_input_time)) + fixed_latency_ns;
519 
520     (total_input_latency_ns * input_hw_rate / NS2S) as u32
521 }
522 
audiounit_output_callback( user_ptr: *mut c_void, flags: *mut AudioUnitRenderActionFlags, tstamp: *const AudioTimeStamp, bus: u32, output_frames: u32, out_buffer_list: *mut AudioBufferList, ) -> OSStatus523 extern "C" fn audiounit_output_callback(
524     user_ptr: *mut c_void,
525     flags: *mut AudioUnitRenderActionFlags,
526     tstamp: *const AudioTimeStamp,
527     bus: u32,
528     output_frames: u32,
529     out_buffer_list: *mut AudioBufferList,
530 ) -> OSStatus {
531     assert_eq!(bus, AU_OUT_BUS);
532     assert!(!out_buffer_list.is_null());
533 
534     assert!(!user_ptr.is_null());
535     let stm = unsafe { &mut *(user_ptr as *mut AudioUnitStream) };
536 
537     let out_buffer_list_ref = unsafe { &mut (*out_buffer_list) };
538     assert_eq!(out_buffer_list_ref.mNumberBuffers, 1);
539     let buffers = unsafe {
540         let ptr = out_buffer_list_ref.mBuffers.as_mut_ptr();
541         let len = out_buffer_list_ref.mNumberBuffers as usize;
542         slice::from_raw_parts_mut(ptr, len)
543     };
544 
545     if stm.stopped.load(Ordering::SeqCst) {
546         cubeb_log!("({:p}) output stopped.", stm as *const AudioUnitStream);
547         audiounit_make_silent(&mut buffers[0]);
548         return NO_ERR;
549     }
550 
551     if stm.draining.load(Ordering::SeqCst) {
552         // Cancel the output callback only. For duplex stream,
553         // the input callback will be cancelled in its own callback.
554         let r = stop_audiounit(stm.core_stream_data.output_unit);
555         assert!(r.is_ok());
556         stm.notify_state_changed(State::Drained);
557         audiounit_make_silent(&mut buffers[0]);
558         return NO_ERR;
559     }
560 
561     let now = unsafe { mach_absolute_time() };
562 
563     if unsafe { *flags | kAudioTimeStampHostTimeValid } != 0 {
564         let output_latency_frames =
565             compute_output_latency(&stm, unsafe { (*tstamp).mHostTime }, now);
566         stm.total_output_latency_frames
567             .store(output_latency_frames, Ordering::SeqCst);
568     }
569 
570     cubeb_logv!(
571         "({:p}) output: buffers {}, size {}, channels {}, frames {}.",
572         stm as *const AudioUnitStream,
573         buffers.len(),
574         buffers[0].mDataByteSize,
575         buffers[0].mNumberChannels,
576         output_frames
577     );
578 
579     // Get output buffer
580     let output_buffer = match stm.core_stream_data.mixer.as_mut() {
581         None => buffers[0].mData,
582         Some(mixer) => {
583             // If remixing needs to occur, we can't directly work in our final
584             // destination buffer as data may be overwritten or too small to start with.
585             mixer.update_buffer_size(output_frames as usize);
586             mixer.get_buffer_mut_ptr() as *mut c_void
587         }
588     };
589 
590     let prev_frames_written = stm.frames_written.load(Ordering::SeqCst);
591 
592     stm.frames_written
593         .fetch_add(output_frames as usize, Ordering::SeqCst);
594 
595     // Also get the input buffer if the stream is duplex
596     let (input_buffer, mut input_frames) = if !stm.core_stream_data.input_unit.is_null() {
597         let input_buffer_manager = stm.core_stream_data.input_buffer_manager.as_mut().unwrap();
598         assert_ne!(stm.core_stream_data.input_desc.mChannelsPerFrame, 0);
599         let input_channels = stm.core_stream_data.input_desc.mChannelsPerFrame as usize;
600         // If the output callback came first and this is a duplex stream, we need to
601         // fill in some additional silence in the resampler.
602         // Otherwise, if we had more than expected callbacks in a row, or we're
603         // currently switching, we add some silence as well to compensate for the
604         // fact that we're lacking some input data.
605         let input_frames_needed = minimum_resampling_input_frames(
606             stm.core_stream_data.input_hw_rate,
607             f64::from(stm.core_stream_data.output_stream_params.rate()),
608             output_frames as usize,
609         );
610         let buffered_input_frames = input_buffer_manager.available_samples() / input_channels;
611         // Else if the input has buffered a lot already because the output started late, we
612         // need to trim the input buffer
613         if prev_frames_written == 0 && buffered_input_frames > input_frames_needed as usize {
614             input_buffer_manager.trim(input_frames_needed * input_channels);
615             let popped_frames = buffered_input_frames - input_frames_needed as usize;
616             stm.frames_read.fetch_sub(popped_frames, Ordering::SeqCst);
617 
618             cubeb_log!("Dropping {} frames in input buffer.", popped_frames);
619         }
620 
621         let input_frames = if input_frames_needed > buffered_input_frames
622             && (stm.switching_device.load(Ordering::SeqCst)
623                 || stm.frames_read.load(Ordering::SeqCst) == 0)
624         {
625             // The silent frames will be inserted in `get_linear_data` below.
626             let silent_frames_to_push = input_frames_needed - buffered_input_frames;
627             cubeb_log!(
628                 "({:p}) Missing Frames: {} will append {} frames of input silence.",
629                 stm.core_stream_data.stm_ptr,
630                 if stm.frames_read.load(Ordering::SeqCst) == 0 {
631                     "input hasn't started,"
632                 } else {
633                     assert!(stm.switching_device.load(Ordering::SeqCst));
634                     "device switching,"
635                 },
636                 silent_frames_to_push
637             );
638             stm.frames_read
639                 .fetch_add(input_frames_needed, Ordering::SeqCst);
640             input_frames_needed
641         } else {
642             buffered_input_frames
643         };
644 
645         let input_samples_needed = input_frames * input_channels;
646         (
647             input_buffer_manager.get_linear_data(input_samples_needed),
648             input_frames as i64,
649         )
650     } else {
651         (ptr::null_mut::<c_void>(), 0)
652     };
653 
654     let outframes = stm.core_stream_data.resampler.fill(
655         input_buffer,
656         if input_buffer.is_null() {
657             ptr::null_mut()
658         } else {
659             &mut input_frames
660         },
661         output_buffer,
662         i64::from(output_frames),
663     );
664 
665     if outframes < 0 || outframes > i64::from(output_frames) {
666         stm.stopped.store(true, Ordering::SeqCst);
667         stm.core_stream_data.stop_audiounits();
668         audiounit_make_silent(&mut buffers[0]);
669         stm.notify_state_changed(State::Error);
670         return NO_ERR;
671     }
672 
673     stm.draining
674         .store(outframes < i64::from(output_frames), Ordering::SeqCst);
675     stm.output_callback_timing_data_write
676         .write(OutputCallbackTimingData {
677             frames_queued: stm.frames_queued,
678             timestamp: now,
679             buffer_size: outframes as u64,
680         });
681 
682     stm.frames_queued += outframes as u64;
683 
684     // Post process output samples.
685     if stm.draining.load(Ordering::SeqCst) {
686         // Clear missing frames (silence)
687         let frames_to_bytes = |frames: usize| -> usize {
688             let sample_size = cubeb_sample_size(stm.core_stream_data.output_stream_params.format());
689             let channel_count = stm.core_stream_data.output_stream_params.channels() as usize;
690             frames * sample_size * channel_count
691         };
692         let out_bytes = unsafe {
693             slice::from_raw_parts_mut(
694                 output_buffer as *mut u8,
695                 frames_to_bytes(output_frames as usize),
696             )
697         };
698         let start = frames_to_bytes(outframes as usize);
699         for byte in out_bytes.iter_mut().skip(start) {
700             *byte = 0;
701         }
702     }
703 
704     // Mixing
705     if stm.core_stream_data.mixer.is_some() {
706         assert!(
707             buffers[0].mDataByteSize
708                 >= stm.core_stream_data.output_desc.mBytesPerFrame * output_frames
709         );
710         stm.core_stream_data.mixer.as_mut().unwrap().mix(
711             output_frames as usize,
712             buffers[0].mData,
713             buffers[0].mDataByteSize as usize,
714         );
715     }
716     NO_ERR
717 }
718 
719 #[allow(clippy::cognitive_complexity)]
audiounit_property_listener_callback( id: AudioObjectID, address_count: u32, addresses: *const AudioObjectPropertyAddress, user: *mut c_void, ) -> OSStatus720 extern "C" fn audiounit_property_listener_callback(
721     id: AudioObjectID,
722     address_count: u32,
723     addresses: *const AudioObjectPropertyAddress,
724     user: *mut c_void,
725 ) -> OSStatus {
726     use self::coreaudio_sys_utils::sys;
727 
728     let stm = unsafe { &mut *(user as *mut AudioUnitStream) };
729     let addrs = unsafe { slice::from_raw_parts(addresses, address_count as usize) };
730     let property_selector = PropertySelector::new(addrs[0].mSelector);
731     if stm.switching_device.load(Ordering::SeqCst) {
732         cubeb_log!(
733             "Switching is already taking place. Skip Event {} for id={}",
734             property_selector,
735             id
736         );
737         return NO_ERR;
738     }
739     stm.switching_device.store(true, Ordering::SeqCst);
740 
741     cubeb_log!(
742         "({:p}) Audio device changed, {} events.",
743         stm as *const AudioUnitStream,
744         address_count
745     );
746     for (i, addr) in addrs.iter().enumerate() {
747         match addr.mSelector {
748             sys::kAudioHardwarePropertyDefaultOutputDevice => {
749                 cubeb_log!(
750                     "Event[{}] - mSelector == kAudioHardwarePropertyDefaultOutputDevice for id={}",
751                     i,
752                     id
753                 );
754             }
755             sys::kAudioHardwarePropertyDefaultInputDevice => {
756                 cubeb_log!(
757                     "Event[{}] - mSelector == kAudioHardwarePropertyDefaultInputDevice for id={}",
758                     i,
759                     id
760                 );
761             }
762             sys::kAudioDevicePropertyDeviceIsAlive => {
763                 cubeb_log!(
764                     "Event[{}] - mSelector == kAudioDevicePropertyDeviceIsAlive for id={}",
765                     i,
766                     id
767                 );
768                 // If this is the default input device ignore the event,
769                 // kAudioHardwarePropertyDefaultInputDevice will take care of the switch
770                 if stm
771                     .core_stream_data
772                     .input_device
773                     .flags
774                     .contains(device_flags::DEV_SYSTEM_DEFAULT)
775                 {
776                     cubeb_log!("It's the default input device, ignore the event");
777                     stm.switching_device.store(false, Ordering::SeqCst);
778                     return NO_ERR;
779                 }
780             }
781             sys::kAudioDevicePropertyDataSource => {
782                 cubeb_log!(
783                     "Event[{}] - mSelector == kAudioDevicePropertyDataSource for id={}",
784                     i,
785                     id
786                 );
787             }
788             _ => {
789                 cubeb_log!(
790                     "Event[{}] - mSelector == Unexpected Event id {}, return",
791                     i,
792                     addr.mSelector
793                 );
794                 stm.switching_device.store(false, Ordering::SeqCst);
795                 return NO_ERR;
796             }
797         }
798     }
799 
800     for _addr in addrs.iter() {
801         let callback = stm.device_changed_callback.lock().unwrap();
802         if let Some(device_changed_callback) = *callback {
803             unsafe {
804                 device_changed_callback(stm.user_ptr);
805             }
806         }
807     }
808 
809     stm.reinit_async();
810 
811     NO_ERR
812 }
813 
audiounit_get_default_device_id(devtype: DeviceType) -> AudioObjectID814 fn audiounit_get_default_device_id(devtype: DeviceType) -> AudioObjectID {
815     let address = get_property_address(
816         match devtype {
817             DeviceType::INPUT => Property::HardwareDefaultInputDevice,
818             DeviceType::OUTPUT => Property::HardwareDefaultOutputDevice,
819             _ => panic!("Unsupport type"),
820         },
821         DeviceType::INPUT | DeviceType::OUTPUT,
822     );
823 
824     let mut devid: AudioDeviceID = kAudioObjectUnknown;
825     let mut size = mem::size_of::<AudioDeviceID>();
826     if audio_object_get_property_data(kAudioObjectSystemObject, &address, &mut size, &mut devid)
827         != NO_ERR
828     {
829         return kAudioObjectUnknown;
830     }
831 
832     devid
833 }
834 
audiounit_convert_channel_layout(layout: &AudioChannelLayout) -> Vec<mixer::Channel>835 fn audiounit_convert_channel_layout(layout: &AudioChannelLayout) -> Vec<mixer::Channel> {
836     if layout.mChannelLayoutTag != kAudioChannelLayoutTag_UseChannelDescriptions {
837         // kAudioChannelLayoutTag_UseChannelBitmap
838         // kAudioChannelLayoutTag_Mono
839         // kAudioChannelLayoutTag_Stereo
840         // ....
841         cubeb_log!("Only handle UseChannelDescriptions for now.\n");
842         return Vec::new();
843     }
844 
845     let channel_descriptions = unsafe {
846         slice::from_raw_parts(
847             layout.mChannelDescriptions.as_ptr(),
848             layout.mNumberChannelDescriptions as usize,
849         )
850     };
851 
852     let mut channels = Vec::with_capacity(layout.mNumberChannelDescriptions as usize);
853     for description in channel_descriptions {
854         let label = CAChannelLabel(description.mChannelLabel);
855         channels.push(label.into());
856     }
857 
858     channels
859 }
860 
audiounit_get_preferred_channel_layout(output_unit: AudioUnit) -> Vec<mixer::Channel>861 fn audiounit_get_preferred_channel_layout(output_unit: AudioUnit) -> Vec<mixer::Channel> {
862     let mut rv = NO_ERR;
863     let mut size: usize = 0;
864     rv = audio_unit_get_property_info(
865         output_unit,
866         kAudioDevicePropertyPreferredChannelLayout,
867         kAudioUnitScope_Output,
868         AU_OUT_BUS,
869         &mut size,
870         None,
871     );
872     if rv != NO_ERR {
873         cubeb_log!(
874             "AudioUnitGetPropertyInfo/kAudioDevicePropertyPreferredChannelLayout rv={}",
875             rv
876         );
877         return Vec::new();
878     }
879     debug_assert!(size > 0);
880 
881     let mut layout = make_sized_audio_channel_layout(size);
882     rv = audio_unit_get_property(
883         output_unit,
884         kAudioDevicePropertyPreferredChannelLayout,
885         kAudioUnitScope_Output,
886         AU_OUT_BUS,
887         layout.as_mut(),
888         &mut size,
889     );
890     if rv != NO_ERR {
891         cubeb_log!(
892             "AudioUnitGetProperty/kAudioDevicePropertyPreferredChannelLayout rv={}",
893             rv
894         );
895         return Vec::new();
896     }
897 
898     audiounit_convert_channel_layout(layout.as_ref())
899 }
900 
901 // This is for output AudioUnit only. Calling this by input-only AudioUnit is prone
902 // to crash intermittently.
audiounit_get_current_channel_layout(output_unit: AudioUnit) -> Vec<mixer::Channel>903 fn audiounit_get_current_channel_layout(output_unit: AudioUnit) -> Vec<mixer::Channel> {
904     let mut rv = NO_ERR;
905     let mut size: usize = 0;
906     rv = audio_unit_get_property_info(
907         output_unit,
908         kAudioUnitProperty_AudioChannelLayout,
909         kAudioUnitScope_Output,
910         AU_OUT_BUS,
911         &mut size,
912         None,
913     );
914     if rv != NO_ERR {
915         cubeb_log!(
916             "AudioUnitGetPropertyInfo/kAudioUnitProperty_AudioChannelLayout rv={}",
917             rv
918         );
919         // This property isn't known before macOS 10.12, attempt another method.
920         return audiounit_get_preferred_channel_layout(output_unit);
921     }
922     debug_assert!(size > 0);
923 
924     let mut layout = make_sized_audio_channel_layout(size);
925     rv = audio_unit_get_property(
926         output_unit,
927         kAudioUnitProperty_AudioChannelLayout,
928         kAudioUnitScope_Output,
929         AU_OUT_BUS,
930         layout.as_mut(),
931         &mut size,
932     );
933     if rv != NO_ERR {
934         cubeb_log!(
935             "AudioUnitGetProperty/kAudioUnitProperty_AudioChannelLayout rv={}",
936             rv
937         );
938         return Vec::new();
939     }
940 
941     audiounit_convert_channel_layout(layout.as_ref())
942 }
943 
start_audiounit(unit: AudioUnit) -> Result<()>944 fn start_audiounit(unit: AudioUnit) -> Result<()> {
945     let status = audio_output_unit_start(unit);
946     if status == NO_ERR {
947         Ok(())
948     } else {
949         cubeb_log!("Cannot start audiounit @ {:p}. Error: {}", unit, status);
950         Err(Error::error())
951     }
952 }
953 
stop_audiounit(unit: AudioUnit) -> Result<()>954 fn stop_audiounit(unit: AudioUnit) -> Result<()> {
955     let status = audio_output_unit_stop(unit);
956     if status == NO_ERR {
957         Ok(())
958     } else {
959         cubeb_log!("Cannot stop audiounit @ {:p}. Error: {}", unit, status);
960         Err(Error::error())
961     }
962 }
963 
create_audiounit(device: &device_info) -> Result<AudioUnit>964 fn create_audiounit(device: &device_info) -> Result<AudioUnit> {
965     assert!(device
966         .flags
967         .intersects(device_flags::DEV_INPUT | device_flags::DEV_OUTPUT));
968     assert!(!device
969         .flags
970         .contains(device_flags::DEV_INPUT | device_flags::DEV_OUTPUT));
971 
972     let unit = create_default_audiounit(device.flags)?;
973     if device
974         .flags
975         .contains(device_flags::DEV_SYSTEM_DEFAULT | device_flags::DEV_OUTPUT)
976     {
977         return Ok(unit);
978     }
979 
980     if device.flags.contains(device_flags::DEV_INPUT) {
981         // Input only.
982         enable_audiounit_scope(unit, DeviceType::INPUT, true).map_err(|e| {
983             cubeb_log!("Fail to enable audiounit input scope. Error: {}", e);
984             Error::error()
985         })?;
986         enable_audiounit_scope(unit, DeviceType::OUTPUT, false).map_err(|e| {
987             cubeb_log!("Fail to disable audiounit output scope. Error: {}", e);
988             Error::error()
989         })?;
990     }
991 
992     if device.flags.contains(device_flags::DEV_OUTPUT) {
993         // Output only.
994         enable_audiounit_scope(unit, DeviceType::OUTPUT, true).map_err(|e| {
995             cubeb_log!("Fail to enable audiounit output scope. Error: {}", e);
996             Error::error()
997         })?;
998         enable_audiounit_scope(unit, DeviceType::INPUT, false).map_err(|e| {
999             cubeb_log!("Fail to disable audiounit input scope. Error: {}", e);
1000             Error::error()
1001         })?;
1002     }
1003 
1004     set_device_to_audiounit(unit, device.id).map_err(|e| {
1005         cubeb_log!(
1006             "Fail to set device {} to the created audiounit. Error: {}",
1007             device.id,
1008             e
1009         );
1010         Error::error()
1011     })?;
1012 
1013     Ok(unit)
1014 }
1015 
enable_audiounit_scope( unit: AudioUnit, devtype: DeviceType, enable_io: bool, ) -> std::result::Result<(), OSStatus>1016 fn enable_audiounit_scope(
1017     unit: AudioUnit,
1018     devtype: DeviceType,
1019     enable_io: bool,
1020 ) -> std::result::Result<(), OSStatus> {
1021     assert!(!unit.is_null());
1022 
1023     let enable: u32 = if enable_io { 1 } else { 0 };
1024     let (scope, element) = match devtype {
1025         DeviceType::INPUT => (kAudioUnitScope_Input, AU_IN_BUS),
1026         DeviceType::OUTPUT => (kAudioUnitScope_Output, AU_OUT_BUS),
1027         _ => panic!(
1028             "Enable AudioUnit {:?} with unsupported type: {:?}",
1029             unit, devtype
1030         ),
1031     };
1032     let status = audio_unit_set_property(
1033         unit,
1034         kAudioOutputUnitProperty_EnableIO,
1035         scope,
1036         element,
1037         &enable,
1038         mem::size_of::<u32>(),
1039     );
1040     if status == NO_ERR {
1041         Ok(())
1042     } else {
1043         Err(status)
1044     }
1045 }
1046 
set_device_to_audiounit( unit: AudioUnit, device_id: AudioObjectID, ) -> std::result::Result<(), OSStatus>1047 fn set_device_to_audiounit(
1048     unit: AudioUnit,
1049     device_id: AudioObjectID,
1050 ) -> std::result::Result<(), OSStatus> {
1051     assert!(!unit.is_null());
1052 
1053     let status = audio_unit_set_property(
1054         unit,
1055         kAudioOutputUnitProperty_CurrentDevice,
1056         kAudioUnitScope_Global,
1057         0,
1058         &device_id,
1059         mem::size_of::<AudioDeviceID>(),
1060     );
1061     if status == NO_ERR {
1062         Ok(())
1063     } else {
1064         Err(status)
1065     }
1066 }
1067 
create_default_audiounit(flags: device_flags) -> Result<AudioUnit>1068 fn create_default_audiounit(flags: device_flags) -> Result<AudioUnit> {
1069     let desc = get_audiounit_description(flags);
1070     create_audiounit_by_description(desc)
1071 }
1072 
get_audiounit_description(flags: device_flags) -> AudioComponentDescription1073 fn get_audiounit_description(flags: device_flags) -> AudioComponentDescription {
1074     AudioComponentDescription {
1075         componentType: kAudioUnitType_Output,
1076         // Use the DefaultOutputUnit for output when no device is specified
1077         // so we retain automatic output device switching when the default
1078         // changes. Once we have complete support for device notifications
1079         // and switching, we can use the AUHAL for everything.
1080         #[cfg(not(target_os = "ios"))]
1081         componentSubType: if flags
1082             .contains(device_flags::DEV_SYSTEM_DEFAULT | device_flags::DEV_OUTPUT)
1083         {
1084             kAudioUnitSubType_DefaultOutput
1085         } else {
1086             kAudioUnitSubType_HALOutput
1087         },
1088         #[cfg(target_os = "ios")]
1089         componentSubType: kAudioUnitSubType_RemoteIO,
1090         componentManufacturer: kAudioUnitManufacturer_Apple,
1091         componentFlags: 0,
1092         componentFlagsMask: 0,
1093     }
1094 }
1095 
create_audiounit_by_description(desc: AudioComponentDescription) -> Result<AudioUnit>1096 fn create_audiounit_by_description(desc: AudioComponentDescription) -> Result<AudioUnit> {
1097     let comp = unsafe { AudioComponentFindNext(ptr::null_mut(), &desc) };
1098     if comp.is_null() {
1099         cubeb_log!("Could not find matching audio hardware.");
1100         return Err(Error::error());
1101     }
1102     let mut unit: AudioUnit = ptr::null_mut();
1103     let status = unsafe { AudioComponentInstanceNew(comp, &mut unit) };
1104     if status == NO_ERR {
1105         assert!(!unit.is_null());
1106         Ok(unit)
1107     } else {
1108         cubeb_log!("Fail to get a new AudioUnit. Error: {}", status);
1109         Err(Error::error())
1110     }
1111 }
1112 
get_buffer_size(unit: AudioUnit, devtype: DeviceType) -> std::result::Result<u32, OSStatus>1113 fn get_buffer_size(unit: AudioUnit, devtype: DeviceType) -> std::result::Result<u32, OSStatus> {
1114     assert!(!unit.is_null());
1115     let (scope, element) = match devtype {
1116         DeviceType::INPUT => (kAudioUnitScope_Output, AU_IN_BUS),
1117         DeviceType::OUTPUT => (kAudioUnitScope_Input, AU_OUT_BUS),
1118         _ => panic!(
1119             "Get buffer size of AudioUnit {:?} with unsupported type: {:?}",
1120             unit, devtype
1121         ),
1122     };
1123     let mut frames: u32 = 0;
1124     let mut size = mem::size_of::<u32>();
1125     let status = audio_unit_get_property(
1126         unit,
1127         kAudioDevicePropertyBufferFrameSize,
1128         scope,
1129         element,
1130         &mut frames,
1131         &mut size,
1132     );
1133     if status == NO_ERR {
1134         Ok(frames)
1135     } else {
1136         Err(status)
1137     }
1138 }
1139 
set_buffer_size( unit: AudioUnit, devtype: DeviceType, frames: u32, ) -> std::result::Result<(), OSStatus>1140 fn set_buffer_size(
1141     unit: AudioUnit,
1142     devtype: DeviceType,
1143     frames: u32,
1144 ) -> std::result::Result<(), OSStatus> {
1145     assert!(!unit.is_null());
1146     let (scope, element) = match devtype {
1147         DeviceType::INPUT => (kAudioUnitScope_Output, AU_IN_BUS),
1148         DeviceType::OUTPUT => (kAudioUnitScope_Input, AU_OUT_BUS),
1149         _ => panic!(
1150             "Set buffer size of AudioUnit {:?} with unsupported type: {:?}",
1151             unit, devtype
1152         ),
1153     };
1154     let status = audio_unit_set_property(
1155         unit,
1156         kAudioDevicePropertyBufferFrameSize,
1157         scope,
1158         element,
1159         &frames,
1160         mem::size_of_val(&frames),
1161     );
1162     if status == NO_ERR {
1163         Ok(())
1164     } else {
1165         Err(status)
1166     }
1167 }
1168 
1169 #[allow(clippy::mutex_atomic)] // The mutex needs to be fed into Condvar::wait_timeout.
set_buffer_size_sync(unit: AudioUnit, devtype: DeviceType, frames: u32) -> Result<()>1170 fn set_buffer_size_sync(unit: AudioUnit, devtype: DeviceType, frames: u32) -> Result<()> {
1171     let current_frames = get_buffer_size(unit, devtype).map_err(|e| {
1172         cubeb_log!(
1173             "Cannot get buffer size of AudioUnit {:?} for {:?}. Error: {}",
1174             unit,
1175             devtype,
1176             e
1177         );
1178         Error::error()
1179     })?;
1180     if frames == current_frames {
1181         cubeb_log!(
1182             "The buffer frame size of AudioUnit {:?} for {:?} is already {}",
1183             unit,
1184             devtype,
1185             frames
1186         );
1187         return Ok(());
1188     }
1189 
1190     let waiting_time = Duration::from_millis(100);
1191     let pair = Arc::new((Mutex::new(false), Condvar::new()));
1192     let mut pair2 = pair.clone();
1193     let pair_ptr = &mut pair2;
1194 
1195     assert_eq!(
1196         audio_unit_add_property_listener(
1197             unit,
1198             kAudioDevicePropertyBufferFrameSize,
1199             buffer_size_changed_callback,
1200             pair_ptr,
1201         ),
1202         NO_ERR
1203     );
1204 
1205     let _teardown = finally(|| {
1206         assert_eq!(
1207             audio_unit_remove_property_listener_with_user_data(
1208                 unit,
1209                 kAudioDevicePropertyBufferFrameSize,
1210                 buffer_size_changed_callback,
1211                 pair_ptr,
1212             ),
1213             NO_ERR
1214         );
1215     });
1216 
1217     set_buffer_size(unit, devtype, frames).map_err(|e| {
1218         cubeb_log!(
1219             "Fail to set buffer size for AudioUnit {:?} for {:?}. Error: {}",
1220             unit,
1221             devtype,
1222             e
1223         );
1224         Error::error()
1225     })?;
1226 
1227     let &(ref lock, ref cvar) = &*pair;
1228     let changed = lock.lock().unwrap();
1229     if !*changed {
1230         let (chg, timeout_res) = cvar.wait_timeout(changed, waiting_time).unwrap();
1231         if timeout_res.timed_out() {
1232             cubeb_log!(
1233                 "Time out for waiting the buffer frame size setting of AudioUnit {:?} for {:?}",
1234                 unit,
1235                 devtype
1236             );
1237         }
1238         if !*chg {
1239             return Err(Error::error());
1240         }
1241     }
1242 
1243     let new_frames = get_buffer_size(unit, devtype).map_err(|e| {
1244         cubeb_log!(
1245             "Cannot get new buffer size of AudioUnit {:?} for {:?}. Error: {}",
1246             unit,
1247             devtype,
1248             e
1249         );
1250         Error::error()
1251     })?;
1252     cubeb_log!(
1253         "The new buffer frames size of AudioUnit {:?} for {:?} is {}",
1254         unit,
1255         devtype,
1256         new_frames
1257     );
1258 
1259     extern "C" fn buffer_size_changed_callback(
1260         in_client_data: *mut c_void,
1261         _in_unit: AudioUnit,
1262         in_property_id: AudioUnitPropertyID,
1263         in_scope: AudioUnitScope,
1264         in_element: AudioUnitElement,
1265     ) {
1266         if in_scope == 0 {
1267             // filter out the callback for global scope.
1268             return;
1269         }
1270         assert!(in_element == AU_IN_BUS || in_element == AU_OUT_BUS);
1271         assert_eq!(in_property_id, kAudioDevicePropertyBufferFrameSize);
1272         let pair = unsafe { &mut *(in_client_data as *mut Arc<(Mutex<bool>, Condvar)>) };
1273         let &(ref lock, ref cvar) = &**pair;
1274         let mut changed = lock.lock().unwrap();
1275         *changed = true;
1276         cvar.notify_one();
1277     }
1278 
1279     Ok(())
1280 }
1281 
convert_uint32_into_string(data: u32) -> CString1282 fn convert_uint32_into_string(data: u32) -> CString {
1283     let empty = CString::default();
1284     if data == 0 {
1285         return empty;
1286     }
1287 
1288     // Reverse 0xWXYZ into 0xZYXW.
1289     let mut buffer = vec![b'\x00'; 4]; // 4 bytes for uint32.
1290     buffer[0] = (data >> 24) as u8;
1291     buffer[1] = (data >> 16) as u8;
1292     buffer[2] = (data >> 8) as u8;
1293     buffer[3] = (data) as u8;
1294 
1295     // CString::new() will consume the input bytes vec and add a '\0' at the
1296     // end of the bytes. The input bytes vec must not contain any 0 bytes in
1297     // it in case causing memory leaks.
1298     CString::new(buffer).unwrap_or(empty)
1299 }
1300 
audiounit_get_default_datasource_string(devtype: DeviceType) -> Result<CString>1301 fn audiounit_get_default_datasource_string(devtype: DeviceType) -> Result<CString> {
1302     let id = audiounit_get_default_device_id(devtype);
1303     if id == kAudioObjectUnknown {
1304         return Err(Error::error());
1305     }
1306     let data = get_device_source(id, devtype).unwrap_or(0);
1307     Ok(convert_uint32_into_string(data))
1308 }
1309 
is_device_a_type_of(devid: AudioObjectID, devtype: DeviceType) -> bool1310 fn is_device_a_type_of(devid: AudioObjectID, devtype: DeviceType) -> bool {
1311     assert_ne!(devid, kAudioObjectUnknown);
1312     get_channel_count(devid, devtype).unwrap_or(0) > 0
1313 }
1314 
get_channel_count(devid: AudioObjectID, devtype: DeviceType) -> Result<u32>1315 fn get_channel_count(devid: AudioObjectID, devtype: DeviceType) -> Result<u32> {
1316     assert_ne!(devid, kAudioObjectUnknown);
1317 
1318     let buffers = get_device_stream_configuration(devid, devtype).map_err(|e| {
1319         cubeb_log!("Cannot get the stream configuration. Error: {}", e);
1320         Error::error()
1321     })?;
1322 
1323     let mut count = 0;
1324     for buffer in buffers {
1325         count += buffer.mNumberChannels;
1326     }
1327     Ok(count)
1328 }
1329 
get_range_of_sample_rates( devid: AudioObjectID, devtype: DeviceType, ) -> std::result::Result<(f64, f64), String>1330 fn get_range_of_sample_rates(
1331     devid: AudioObjectID,
1332     devtype: DeviceType,
1333 ) -> std::result::Result<(f64, f64), String> {
1334     let result = get_ranges_of_device_sample_rate(devid, devtype);
1335     if let Err(e) = result {
1336         return Err(format!("status {}", e));
1337     }
1338     let rates = result.unwrap();
1339     if rates.is_empty() {
1340         return Err(String::from("No data"));
1341     }
1342     let (mut min, mut max) = (std::f64::MAX, std::f64::MIN);
1343     for rate in rates {
1344         if rate.mMaximum > max {
1345             max = rate.mMaximum;
1346         }
1347         if rate.mMinimum < min {
1348             min = rate.mMinimum;
1349         }
1350     }
1351     Ok((min, max))
1352 }
1353 
get_fixed_latency(devid: AudioObjectID, devtype: DeviceType) -> u321354 fn get_fixed_latency(devid: AudioObjectID, devtype: DeviceType) -> u32 {
1355     let device_latency = match get_device_latency(devid, devtype) {
1356         Ok(latency) => latency,
1357         Err(e) => {
1358             cubeb_log!(
1359                 "Cannot get the device latency for device {} in {:?} scope. Error: {}",
1360                 devid,
1361                 devtype,
1362                 e
1363             );
1364             0 // default device latency
1365         }
1366     };
1367 
1368     let stream_latency = get_device_streams(devid, devtype).and_then(|streams| {
1369         if streams.is_empty() {
1370             cubeb_log!(
1371                 "No any stream on device {} in {:?} scope!",
1372                 devid,
1373                 devtype
1374             );
1375             Ok(0) // default stream latency
1376         } else {
1377             get_stream_latency(streams[0], devtype)
1378         }
1379     }).map_err(|e| {
1380         cubeb_log!(
1381             "Cannot get the stream, or the latency of the first stream on device {} in {:?} scope. Error: {}",
1382             devid,
1383             devtype,
1384             e
1385         );
1386         e
1387     }).unwrap_or(0); // default stream latency
1388 
1389     device_latency + stream_latency
1390 }
1391 
get_device_group_id( id: AudioDeviceID, devtype: DeviceType, ) -> std::result::Result<CString, OSStatus>1392 fn get_device_group_id(
1393     id: AudioDeviceID,
1394     devtype: DeviceType,
1395 ) -> std::result::Result<CString, OSStatus> {
1396     const BLTN: u32 = 0x626C_746E; // "bltn" (builtin)
1397 
1398     match get_device_transport_type(id, devtype) {
1399         Ok(BLTN) => {
1400             cubeb_log!(
1401                 "The transport type is {:?}",
1402                 convert_uint32_into_string(BLTN)
1403             );
1404             match get_custom_group_id(id, devtype) {
1405                 Some(id) => return Ok(id),
1406                 None => {
1407                     cubeb_log!("Get model uid instead.");
1408                 }
1409             };
1410         }
1411         Ok(trans_type) => {
1412             cubeb_log!(
1413                 "The transport type is {:?}. Get model uid instead.",
1414                 convert_uint32_into_string(trans_type)
1415             );
1416         }
1417         Err(e) => {
1418             cubeb_log!(
1419                 "Error: {} when getting transport type. Get model uid instead.",
1420                 e
1421             );
1422         }
1423     }
1424 
1425     // Some devices (e.g. AirPods) might only set the model-uid in the global scope.
1426     // The query might fail if the scope is input-only or output-only.
1427     get_device_model_uid(id, devtype)
1428         .or_else(|_| get_device_model_uid(id, DeviceType::INPUT | DeviceType::OUTPUT))
1429         .map(|uid| uid.into_cstring())
1430 }
1431 
get_custom_group_id(id: AudioDeviceID, devtype: DeviceType) -> Option<CString>1432 fn get_custom_group_id(id: AudioDeviceID, devtype: DeviceType) -> Option<CString> {
1433     const IMIC: u32 = 0x696D_6963; // "imic" (internal microphone)
1434     const ISPK: u32 = 0x6973_706B; // "ispk" (internal speaker)
1435     const EMIC: u32 = 0x656D_6963; // "emic" (external microphone)
1436     const HDPN: u32 = 0x6864_706E; // "hdpn" (headphone)
1437 
1438     match get_device_source(id, devtype) {
1439         s @ Ok(IMIC) | s @ Ok(ISPK) => {
1440             const GROUP_ID: &str = "builtin-internal-mic|spk";
1441             cubeb_log!(
1442                 "Use hardcode group id: {} when source is: {:?}.",
1443                 GROUP_ID,
1444                 convert_uint32_into_string(s.unwrap())
1445             );
1446             return Some(CString::new(GROUP_ID).unwrap());
1447         }
1448         s @ Ok(EMIC) | s @ Ok(HDPN) => {
1449             const GROUP_ID: &str = "builtin-external-mic|hdpn";
1450             cubeb_log!(
1451                 "Use hardcode group id: {} when source is: {:?}.",
1452                 GROUP_ID,
1453                 convert_uint32_into_string(s.unwrap())
1454             );
1455             return Some(CString::new(GROUP_ID).unwrap());
1456         }
1457         Ok(s) => {
1458             cubeb_log!(
1459                 "No custom group id when source is: {:?}.",
1460                 convert_uint32_into_string(s)
1461             );
1462         }
1463         Err(e) => {
1464             cubeb_log!("Error: {} when getting device source. ", e);
1465         }
1466     }
1467     None
1468 }
1469 
get_device_label( id: AudioDeviceID, devtype: DeviceType, ) -> std::result::Result<StringRef, OSStatus>1470 fn get_device_label(
1471     id: AudioDeviceID,
1472     devtype: DeviceType,
1473 ) -> std::result::Result<StringRef, OSStatus> {
1474     get_device_source_name(id, devtype).or_else(|_| get_device_name(id, devtype))
1475 }
1476 
get_device_global_uid(id: AudioDeviceID) -> std::result::Result<StringRef, OSStatus>1477 fn get_device_global_uid(id: AudioDeviceID) -> std::result::Result<StringRef, OSStatus> {
1478     get_device_uid(id, DeviceType::INPUT | DeviceType::OUTPUT)
1479 }
1480 
1481 #[allow(clippy::cognitive_complexity)]
create_cubeb_device_info( devid: AudioObjectID, devtype: DeviceType, ) -> Result<ffi::cubeb_device_info>1482 fn create_cubeb_device_info(
1483     devid: AudioObjectID,
1484     devtype: DeviceType,
1485 ) -> Result<ffi::cubeb_device_info> {
1486     let channels = get_channel_count(devid, devtype)?;
1487     if channels == 0 {
1488         // Invalid type for this device.
1489         return Err(Error::error());
1490     }
1491 
1492     let mut dev_info = ffi::cubeb_device_info::default();
1493     dev_info.max_channels = channels;
1494 
1495     assert!(
1496         mem::size_of::<ffi::cubeb_devid>() >= mem::size_of_val(&devid),
1497         "cubeb_devid can't represent devid"
1498     );
1499     dev_info.devid = devid as ffi::cubeb_devid;
1500 
1501     match get_device_uid(devid, devtype) {
1502         Ok(uid) => {
1503             let c_string = uid.into_cstring();
1504             dev_info.device_id = c_string.into_raw();
1505         }
1506         Err(e) => {
1507             cubeb_log!(
1508                 "Cannot get the uid for device {} in {:?} scope. Error: {}",
1509                 devid,
1510                 devtype,
1511                 e
1512             );
1513         }
1514     }
1515 
1516     match get_device_group_id(devid, devtype) {
1517         Ok(group_id) => {
1518             dev_info.group_id = group_id.into_raw();
1519         }
1520         Err(e) => {
1521             cubeb_log!(
1522                 "Cannot get the model uid for device {} in {:?} scope. Error: {}",
1523                 devid,
1524                 devtype,
1525                 e
1526             );
1527         }
1528     }
1529 
1530     let label = match get_device_label(devid, devtype) {
1531         Ok(label) => label.into_cstring(),
1532         Err(e) => {
1533             cubeb_log!(
1534                 "Cannot get the label for device {} in {:?} scope. Error: {}",
1535                 devid,
1536                 devtype,
1537                 e
1538             );
1539             CString::default()
1540         }
1541     };
1542     dev_info.friendly_name = label.into_raw();
1543 
1544     match get_device_manufacturer(devid, devtype) {
1545         Ok(vendor) => {
1546             let vendor = vendor.into_cstring();
1547             dev_info.vendor_name = vendor.into_raw();
1548         }
1549         Err(e) => {
1550             cubeb_log!(
1551                 "Cannot get the manufacturer for device {} in {:?} scope. Error: {}",
1552                 devid,
1553                 devtype,
1554                 e
1555             );
1556         }
1557     }
1558 
1559     dev_info.device_type = match devtype {
1560         DeviceType::INPUT => ffi::CUBEB_DEVICE_TYPE_INPUT,
1561         DeviceType::OUTPUT => ffi::CUBEB_DEVICE_TYPE_OUTPUT,
1562         _ => panic!("invalid type"),
1563     };
1564 
1565     dev_info.state = ffi::CUBEB_DEVICE_STATE_ENABLED;
1566     dev_info.preferred = if devid == audiounit_get_default_device_id(devtype) {
1567         ffi::CUBEB_DEVICE_PREF_ALL
1568     } else {
1569         ffi::CUBEB_DEVICE_PREF_NONE
1570     };
1571 
1572     dev_info.format = ffi::CUBEB_DEVICE_FMT_ALL;
1573     dev_info.default_format = ffi::CUBEB_DEVICE_FMT_F32NE;
1574 
1575     match get_device_sample_rate(devid, devtype) {
1576         Ok(rate) => {
1577             dev_info.default_rate = rate as u32;
1578         }
1579         Err(e) => {
1580             cubeb_log!(
1581                 "Cannot get the sample rate for device {} in {:?} scope. Error: {}",
1582                 devid,
1583                 devtype,
1584                 e
1585             );
1586         }
1587     }
1588 
1589     match get_range_of_sample_rates(devid, devtype) {
1590         Ok((min, max)) => {
1591             dev_info.min_rate = min as u32;
1592             dev_info.max_rate = max as u32;
1593         }
1594         Err(e) => {
1595             cubeb_log!(
1596                 "Cannot get the range of sample rate for device {} in {:?} scope. Error: {}",
1597                 devid,
1598                 devtype,
1599                 e
1600             );
1601         }
1602     }
1603 
1604     let latency = get_fixed_latency(devid, devtype);
1605 
1606     let (latency_low, latency_high) = match get_device_buffer_frame_size_range(devid, devtype) {
1607         Ok(range) => (
1608             latency + range.mMinimum as u32,
1609             latency + range.mMaximum as u32,
1610         ),
1611         Err(e) => {
1612             cubeb_log!("Cannot get the buffer frame size for device {} in {:?} scope. Use default value instead. Error: {}", devid, devtype, e);
1613             (
1614                 10 * dev_info.default_rate / 1000,
1615                 100 * dev_info.default_rate / 1000,
1616             )
1617         }
1618     };
1619     dev_info.latency_lo = latency_low;
1620     dev_info.latency_hi = latency_high;
1621 
1622     Ok(dev_info)
1623 }
1624 
is_aggregate_device(device_info: &ffi::cubeb_device_info) -> bool1625 fn is_aggregate_device(device_info: &ffi::cubeb_device_info) -> bool {
1626     assert!(!device_info.friendly_name.is_null());
1627     let private_name =
1628         CString::new(PRIVATE_AGGREGATE_DEVICE_NAME).expect("Fail to create a private name");
1629     unsafe {
1630         libc::strncmp(
1631             device_info.friendly_name,
1632             private_name.as_ptr(),
1633             libc::strlen(private_name.as_ptr()),
1634         ) == 0
1635     }
1636 }
1637 
destroy_cubeb_device_info(device: &mut ffi::cubeb_device_info)1638 fn destroy_cubeb_device_info(device: &mut ffi::cubeb_device_info) {
1639     // This should be mapped to the memory allocation in `create_cubeb_device_info`.
1640     // The `device_id`, `group_id`, `vendor_name` can be null pointer if the queries
1641     // failed, while `friendly_name` will be assigned to a default empty "" string.
1642     // Set the pointers to null in case it points to some released memory.
1643     unsafe {
1644         if !device.device_id.is_null() {
1645             let _ = CString::from_raw(device.device_id as *mut _);
1646             device.device_id = ptr::null();
1647         }
1648 
1649         if !device.group_id.is_null() {
1650             let _ = CString::from_raw(device.group_id as *mut _);
1651             device.group_id = ptr::null();
1652         }
1653 
1654         assert!(!device.friendly_name.is_null());
1655         let _ = CString::from_raw(device.friendly_name as *mut _);
1656         device.friendly_name = ptr::null();
1657 
1658         if !device.vendor_name.is_null() {
1659             let _ = CString::from_raw(device.vendor_name as *mut _);
1660             device.vendor_name = ptr::null();
1661         }
1662     }
1663 }
1664 
audiounit_get_devices() -> Vec<AudioObjectID>1665 fn audiounit_get_devices() -> Vec<AudioObjectID> {
1666     let mut size: usize = 0;
1667     let address = get_property_address(
1668         Property::HardwareDevices,
1669         DeviceType::INPUT | DeviceType::OUTPUT,
1670     );
1671     let mut ret =
1672         audio_object_get_property_data_size(kAudioObjectSystemObject, &address, &mut size);
1673     if ret != NO_ERR {
1674         return Vec::new();
1675     }
1676     // Total number of input and output devices.
1677     let mut devices: Vec<AudioObjectID> = allocate_array_by_size(size);
1678     ret = audio_object_get_property_data(
1679         kAudioObjectSystemObject,
1680         &address,
1681         &mut size,
1682         devices.as_mut_ptr(),
1683     );
1684     if ret != NO_ERR {
1685         return Vec::new();
1686     }
1687     devices
1688 }
1689 
audiounit_get_devices_of_type(devtype: DeviceType) -> Vec<AudioObjectID>1690 fn audiounit_get_devices_of_type(devtype: DeviceType) -> Vec<AudioObjectID> {
1691     assert!(devtype.intersects(DeviceType::INPUT | DeviceType::OUTPUT));
1692 
1693     let mut devices = audiounit_get_devices();
1694 
1695     // Remove the aggregate device from the list of devices (if any).
1696     devices.retain(|&device| {
1697         // TODO: (bug 1628411) Figure out when `device` is `kAudioObjectUnknown`.
1698         if device == kAudioObjectUnknown {
1699             false
1700         } else if let Ok(uid) = get_device_global_uid(device) {
1701             let uid = uid.into_string();
1702             !uid.contains(PRIVATE_AGGREGATE_DEVICE_NAME)
1703         } else {
1704             // Fail to get device uid.
1705             true
1706         }
1707     });
1708 
1709     // Expected sorted but did not find anything in the docs.
1710     devices.sort_unstable();
1711     if devtype.contains(DeviceType::INPUT | DeviceType::OUTPUT) {
1712         return devices;
1713     }
1714 
1715     let mut devices_in_scope = Vec::new();
1716     for device in devices {
1717         let label = match get_device_label(device, DeviceType::OUTPUT | DeviceType::INPUT) {
1718             Ok(label) => label.into_string(),
1719             Err(e) => format!("Unknown(error: {})", e),
1720         };
1721         let info = format!("{} ({})", device, label);
1722 
1723         if let Ok(channels) = get_channel_count(device, devtype) {
1724             cubeb_log!("device {} has {} {:?}-channels", info, channels, devtype);
1725             if channels > 0 {
1726                 devices_in_scope.push(device);
1727             }
1728         } else {
1729             cubeb_log!("Cannot get the channel count for device {}. Ignored.", info);
1730         }
1731     }
1732 
1733     devices_in_scope
1734 }
1735 
audiounit_collection_changed_callback( _in_object_id: AudioObjectID, _in_number_addresses: u32, _in_addresses: *const AudioObjectPropertyAddress, in_client_data: *mut c_void, ) -> OSStatus1736 extern "C" fn audiounit_collection_changed_callback(
1737     _in_object_id: AudioObjectID,
1738     _in_number_addresses: u32,
1739     _in_addresses: *const AudioObjectPropertyAddress,
1740     in_client_data: *mut c_void,
1741 ) -> OSStatus {
1742     let context = unsafe { &mut *(in_client_data as *mut AudioUnitContext) };
1743 
1744     let queue = context.serial_queue.clone();
1745     let mutexed_context = Arc::new(Mutex::new(context));
1746     let also_mutexed_context = Arc::clone(&mutexed_context);
1747 
1748     // This can be called from inside an AudioUnit function, dispatch to another queue.
1749     queue.run_async(move || {
1750         let ctx_guard = also_mutexed_context.lock().unwrap();
1751         let ctx_ptr = *ctx_guard as *const AudioUnitContext;
1752 
1753         let mut devices = ctx_guard.devices.lock().unwrap();
1754 
1755         if devices.input.changed_callback.is_none() && devices.output.changed_callback.is_none() {
1756             return;
1757         }
1758         if devices.input.changed_callback.is_some() {
1759             let input_devices = audiounit_get_devices_of_type(DeviceType::INPUT);
1760             if devices.input.update_devices(input_devices) {
1761                 unsafe {
1762                     devices.input.changed_callback.unwrap()(
1763                         ctx_ptr as *mut ffi::cubeb,
1764                         devices.input.callback_user_ptr,
1765                     );
1766                 }
1767             }
1768         }
1769         if devices.output.changed_callback.is_some() {
1770             let output_devices = audiounit_get_devices_of_type(DeviceType::OUTPUT);
1771             if devices.output.update_devices(output_devices) {
1772                 unsafe {
1773                     devices.output.changed_callback.unwrap()(
1774                         ctx_ptr as *mut ffi::cubeb,
1775                         devices.output.callback_user_ptr,
1776                     );
1777                 }
1778             }
1779         }
1780     });
1781 
1782     NO_ERR
1783 }
1784 
1785 #[derive(Debug)]
1786 struct DevicesData {
1787     changed_callback: ffi::cubeb_device_collection_changed_callback,
1788     callback_user_ptr: *mut c_void,
1789     devices: Vec<AudioObjectID>,
1790 }
1791 
1792 impl DevicesData {
set( &mut self, changed_callback: ffi::cubeb_device_collection_changed_callback, callback_user_ptr: *mut c_void, devices: Vec<AudioObjectID>, )1793     fn set(
1794         &mut self,
1795         changed_callback: ffi::cubeb_device_collection_changed_callback,
1796         callback_user_ptr: *mut c_void,
1797         devices: Vec<AudioObjectID>,
1798     ) {
1799         self.changed_callback = changed_callback;
1800         self.callback_user_ptr = callback_user_ptr;
1801         self.devices = devices;
1802     }
1803 
update_devices(&mut self, devices: Vec<AudioObjectID>) -> bool1804     fn update_devices(&mut self, devices: Vec<AudioObjectID>) -> bool {
1805         // Elements in the vector expected sorted.
1806         if self.devices == devices {
1807             return false;
1808         }
1809         self.devices = devices;
1810         true
1811     }
1812 
clear(&mut self)1813     fn clear(&mut self) {
1814         self.changed_callback = None;
1815         self.callback_user_ptr = ptr::null_mut();
1816         self.devices.clear();
1817     }
1818 
is_empty(&self) -> bool1819     fn is_empty(&self) -> bool {
1820         self.changed_callback == None && self.callback_user_ptr.is_null() && self.devices.is_empty()
1821     }
1822 }
1823 
1824 impl Default for DevicesData {
default() -> Self1825     fn default() -> Self {
1826         Self {
1827             changed_callback: None,
1828             callback_user_ptr: ptr::null_mut(),
1829             devices: Vec::new(),
1830         }
1831     }
1832 }
1833 
1834 #[derive(Debug)]
1835 struct SharedDevices {
1836     input: DevicesData,
1837     output: DevicesData,
1838 }
1839 
1840 impl Default for SharedDevices {
default() -> Self1841     fn default() -> Self {
1842         Self {
1843             input: DevicesData::default(),
1844             output: DevicesData::default(),
1845         }
1846     }
1847 }
1848 
1849 #[derive(Debug)]
1850 struct LatencyController {
1851     streams: u32,
1852     latency: Option<u32>,
1853 }
1854 
1855 impl LatencyController {
add_stream(&mut self, latency: u32) -> Option<u32>1856     fn add_stream(&mut self, latency: u32) -> Option<u32> {
1857         self.streams += 1;
1858         // For the 1st stream set anything within safe min-max
1859         if self.streams == 1 {
1860             assert!(self.latency.is_none());
1861             // Silently clamp the latency down to the platform default, because we
1862             // synthetize the clock from the callbacks, and we want the clock to update often.
1863             self.latency = Some(clamp_latency(latency));
1864         }
1865         self.latency
1866     }
1867 
subtract_stream(&mut self) -> Option<u32>1868     fn subtract_stream(&mut self) -> Option<u32> {
1869         self.streams -= 1;
1870         if self.streams == 0 {
1871             assert!(self.latency.is_some());
1872             self.latency = None;
1873         }
1874         self.latency
1875     }
1876 }
1877 
1878 impl Default for LatencyController {
default() -> Self1879     fn default() -> Self {
1880         Self {
1881             streams: 0,
1882             latency: None,
1883         }
1884     }
1885 }
1886 
1887 pub const OPS: Ops = capi_new!(AudioUnitContext, AudioUnitStream);
1888 
1889 // The fisrt member of the Cubeb context must be a pointer to a Ops struct. The Ops struct is an
1890 // interface to link to all the Cubeb APIs, and the Cubeb interface use this assumption to operate
1891 // the Cubeb APIs on different implementation.
1892 // #[repr(C)] is used to prevent any padding from being added in the beginning of the AudioUnitContext.
1893 #[repr(C)]
1894 #[derive(Debug)]
1895 pub struct AudioUnitContext {
1896     _ops: *const Ops,
1897     serial_queue: Queue,
1898     latency_controller: Mutex<LatencyController>,
1899     devices: Mutex<SharedDevices>,
1900 }
1901 
1902 impl AudioUnitContext {
new() -> Self1903     fn new() -> Self {
1904         Self {
1905             _ops: &OPS as *const _,
1906             serial_queue: Queue::new(DISPATCH_QUEUE_LABEL),
1907             latency_controller: Mutex::new(LatencyController::default()),
1908             devices: Mutex::new(SharedDevices::default()),
1909         }
1910     }
1911 
active_streams(&self) -> u321912     fn active_streams(&self) -> u32 {
1913         let controller = self.latency_controller.lock().unwrap();
1914         controller.streams
1915     }
1916 
update_latency_by_adding_stream(&self, latency_frames: u32) -> Option<u32>1917     fn update_latency_by_adding_stream(&self, latency_frames: u32) -> Option<u32> {
1918         let mut controller = self.latency_controller.lock().unwrap();
1919         controller.add_stream(latency_frames)
1920     }
1921 
update_latency_by_removing_stream(&self) -> Option<u32>1922     fn update_latency_by_removing_stream(&self) -> Option<u32> {
1923         let mut controller = self.latency_controller.lock().unwrap();
1924         controller.subtract_stream()
1925     }
1926 
add_devices_changed_listener( &mut self, devtype: DeviceType, collection_changed_callback: ffi::cubeb_device_collection_changed_callback, user_ptr: *mut c_void, ) -> Result<()>1927     fn add_devices_changed_listener(
1928         &mut self,
1929         devtype: DeviceType,
1930         collection_changed_callback: ffi::cubeb_device_collection_changed_callback,
1931         user_ptr: *mut c_void,
1932     ) -> Result<()> {
1933         assert!(devtype.intersects(DeviceType::INPUT | DeviceType::OUTPUT));
1934         assert!(collection_changed_callback.is_some());
1935 
1936         let context_ptr = self as *mut AudioUnitContext;
1937         let mut devices = self.devices.lock().unwrap();
1938 
1939         // Note: second register without unregister first causes 'nope' error.
1940         // Current implementation requires unregister before register a new cb.
1941         if devtype.contains(DeviceType::INPUT) && devices.input.changed_callback.is_some()
1942             || devtype.contains(DeviceType::OUTPUT) && devices.output.changed_callback.is_some()
1943         {
1944             return Err(Error::invalid_parameter());
1945         }
1946 
1947         if devices.input.changed_callback.is_none() && devices.output.changed_callback.is_none() {
1948             let address = get_property_address(
1949                 Property::HardwareDevices,
1950                 DeviceType::INPUT | DeviceType::OUTPUT,
1951             );
1952             let ret = audio_object_add_property_listener(
1953                 kAudioObjectSystemObject,
1954                 &address,
1955                 audiounit_collection_changed_callback,
1956                 context_ptr,
1957             );
1958             if ret != NO_ERR {
1959                 cubeb_log!(
1960                     "Cannot add devices-changed listener for {:?}, Error: {}",
1961                     devtype,
1962                     ret
1963                 );
1964                 return Err(Error::error());
1965             }
1966         }
1967 
1968         if devtype.contains(DeviceType::INPUT) {
1969             // Expected empty after unregister.
1970             assert!(devices.input.is_empty());
1971             devices.input.set(
1972                 collection_changed_callback,
1973                 user_ptr,
1974                 audiounit_get_devices_of_type(DeviceType::INPUT),
1975             );
1976         }
1977 
1978         if devtype.contains(DeviceType::OUTPUT) {
1979             // Expected empty after unregister.
1980             assert!(devices.output.is_empty());
1981             devices.output.set(
1982                 collection_changed_callback,
1983                 user_ptr,
1984                 audiounit_get_devices_of_type(DeviceType::OUTPUT),
1985             );
1986         }
1987 
1988         Ok(())
1989     }
1990 
remove_devices_changed_listener(&mut self, devtype: DeviceType) -> Result<()>1991     fn remove_devices_changed_listener(&mut self, devtype: DeviceType) -> Result<()> {
1992         if !devtype.intersects(DeviceType::INPUT | DeviceType::OUTPUT) {
1993             return Err(Error::invalid_parameter());
1994         }
1995 
1996         let context_ptr = self as *mut AudioUnitContext;
1997         let mut devices = self.devices.lock().unwrap();
1998 
1999         if devtype.contains(DeviceType::INPUT) {
2000             devices.input.clear();
2001         }
2002 
2003         if devtype.contains(DeviceType::OUTPUT) {
2004             devices.output.clear();
2005         }
2006 
2007         if devices.input.changed_callback.is_some() || devices.output.changed_callback.is_some() {
2008             return Ok(());
2009         }
2010 
2011         let address = get_property_address(
2012             Property::HardwareDevices,
2013             DeviceType::INPUT | DeviceType::OUTPUT,
2014         );
2015         // Note: unregister a non registered cb is not a problem, not checking.
2016         let r = audio_object_remove_property_listener(
2017             kAudioObjectSystemObject,
2018             &address,
2019             audiounit_collection_changed_callback,
2020             context_ptr,
2021         );
2022         if r == NO_ERR {
2023             Ok(())
2024         } else {
2025             cubeb_log!(
2026                 "Cannot remove devices-changed listener for {:?}, Error: {}",
2027                 devtype,
2028                 r
2029             );
2030             Err(Error::error())
2031         }
2032     }
2033 }
2034 
2035 impl ContextOps for AudioUnitContext {
init(_context_name: Option<&CStr>) -> Result<Context>2036     fn init(_context_name: Option<&CStr>) -> Result<Context> {
2037         set_notification_runloop();
2038         let ctx = Box::new(AudioUnitContext::new());
2039         Ok(unsafe { Context::from_ptr(Box::into_raw(ctx) as *mut _) })
2040     }
2041 
backend_id(&mut self) -> &'static CStr2042     fn backend_id(&mut self) -> &'static CStr {
2043         unsafe { CStr::from_ptr(b"audiounit-rust\0".as_ptr() as *const _) }
2044     }
2045     #[cfg(target_os = "ios")]
max_channel_count(&mut self) -> Result<u32>2046     fn max_channel_count(&mut self) -> Result<u32> {
2047         Ok(2u32)
2048     }
2049     #[cfg(not(target_os = "ios"))]
max_channel_count(&mut self) -> Result<u32>2050     fn max_channel_count(&mut self) -> Result<u32> {
2051         let device = audiounit_get_default_device_id(DeviceType::OUTPUT);
2052         if device == kAudioObjectUnknown {
2053             return Err(Error::error());
2054         }
2055 
2056         let format = get_device_stream_format(device, DeviceType::OUTPUT).map_err(|e| {
2057             cubeb_log!(
2058                 "Cannot get the stream format of the default output device. Error: {}",
2059                 e
2060             );
2061             Error::error()
2062         })?;
2063         Ok(format.mChannelsPerFrame)
2064     }
2065     #[cfg(target_os = "ios")]
min_latency(&mut self, _params: StreamParams) -> Result<u32>2066     fn min_latency(&mut self, _params: StreamParams) -> Result<u32> {
2067         Err(not_supported());
2068     }
2069     #[cfg(not(target_os = "ios"))]
min_latency(&mut self, _params: StreamParams) -> Result<u32>2070     fn min_latency(&mut self, _params: StreamParams) -> Result<u32> {
2071         let device = audiounit_get_default_device_id(DeviceType::OUTPUT);
2072         if device == kAudioObjectUnknown {
2073             cubeb_log!("Could not get default output device id.");
2074             return Err(Error::error());
2075         }
2076 
2077         let range =
2078             get_device_buffer_frame_size_range(device, DeviceType::OUTPUT).map_err(|e| {
2079                 cubeb_log!("Could not get acceptable latency range. Error: {}", e);
2080                 Error::error()
2081             })?;
2082 
2083         Ok(cmp::max(range.mMinimum as u32, SAFE_MIN_LATENCY_FRAMES))
2084     }
2085     #[cfg(target_os = "ios")]
preferred_sample_rate(&mut self) -> Result<u32>2086     fn preferred_sample_rate(&mut self) -> Result<u32> {
2087         Err(not_supported());
2088     }
2089     #[cfg(not(target_os = "ios"))]
preferred_sample_rate(&mut self) -> Result<u32>2090     fn preferred_sample_rate(&mut self) -> Result<u32> {
2091         let device = audiounit_get_default_device_id(DeviceType::OUTPUT);
2092         if device == kAudioObjectUnknown {
2093             return Err(Error::error());
2094         }
2095         let rate = get_device_sample_rate(device, DeviceType::OUTPUT).map_err(|e| {
2096             cubeb_log!(
2097                 "Cannot get the sample rate of the default output device. Error: {}",
2098                 e
2099             );
2100             Error::error()
2101         })?;
2102         Ok(rate as u32)
2103     }
enumerate_devices( &mut self, devtype: DeviceType, collection: &DeviceCollectionRef, ) -> Result<()>2104     fn enumerate_devices(
2105         &mut self,
2106         devtype: DeviceType,
2107         collection: &DeviceCollectionRef,
2108     ) -> Result<()> {
2109         let mut device_infos = Vec::new();
2110         let dev_types = [DeviceType::INPUT, DeviceType::OUTPUT];
2111         for dev_type in dev_types.iter() {
2112             if !devtype.contains(*dev_type) {
2113                 continue;
2114             }
2115             let devices = audiounit_get_devices_of_type(*dev_type);
2116             for device in devices {
2117                 if let Ok(info) = create_cubeb_device_info(device, *dev_type) {
2118                     if !is_aggregate_device(&info) {
2119                         device_infos.push(info);
2120                     }
2121                 }
2122             }
2123         }
2124         let (ptr, len) = if device_infos.is_empty() {
2125             (ptr::null_mut(), 0)
2126         } else {
2127             forget_vec(device_infos)
2128         };
2129         let coll = unsafe { &mut *collection.as_ptr() };
2130         coll.device = ptr;
2131         coll.count = len;
2132         Ok(())
2133     }
device_collection_destroy(&mut self, collection: &mut DeviceCollectionRef) -> Result<()>2134     fn device_collection_destroy(&mut self, collection: &mut DeviceCollectionRef) -> Result<()> {
2135         assert!(!collection.as_ptr().is_null());
2136         let coll = unsafe { &mut *collection.as_ptr() };
2137         if coll.device.is_null() {
2138             return Ok(());
2139         }
2140 
2141         let mut devices = retake_forgotten_vec(coll.device, coll.count);
2142         for device in &mut devices {
2143             destroy_cubeb_device_info(device);
2144         }
2145         drop(devices); // Release the memory.
2146         coll.device = ptr::null_mut();
2147         coll.count = 0;
2148         Ok(())
2149     }
stream_init( &mut self, _stream_name: Option<&CStr>, input_device: DeviceId, input_stream_params: Option<&StreamParamsRef>, output_device: DeviceId, output_stream_params: Option<&StreamParamsRef>, latency_frames: u32, data_callback: ffi::cubeb_data_callback, state_callback: ffi::cubeb_state_callback, user_ptr: *mut c_void, ) -> Result<Stream>2150     fn stream_init(
2151         &mut self,
2152         _stream_name: Option<&CStr>,
2153         input_device: DeviceId,
2154         input_stream_params: Option<&StreamParamsRef>,
2155         output_device: DeviceId,
2156         output_stream_params: Option<&StreamParamsRef>,
2157         latency_frames: u32,
2158         data_callback: ffi::cubeb_data_callback,
2159         state_callback: ffi::cubeb_state_callback,
2160         user_ptr: *mut c_void,
2161     ) -> Result<Stream> {
2162         if (!input_device.is_null() && input_stream_params.is_none())
2163             || (!output_device.is_null() && output_stream_params.is_none())
2164         {
2165             return Err(Error::invalid_parameter());
2166         }
2167 
2168         // Latency cannot change if another stream is operating in parallel. In this case
2169         // latency is set to the other stream value.
2170         let global_latency_frames = self
2171             .update_latency_by_adding_stream(latency_frames)
2172             .unwrap();
2173         if global_latency_frames != latency_frames {
2174             cubeb_log!(
2175                 "Use global latency {} instead of the requested latency {}.",
2176                 global_latency_frames,
2177                 latency_frames
2178             );
2179         }
2180 
2181         let in_stm_settings = if let Some(params) = input_stream_params {
2182             let in_device = create_device_info(input_device as AudioDeviceID, DeviceType::INPUT)
2183                 .map_err(|e| {
2184                     cubeb_log!("Fail to create device info for input.");
2185                     e
2186                 })?;
2187             let stm_params = StreamParams::from(unsafe { *params.as_ptr() });
2188             Some((stm_params, in_device))
2189         } else {
2190             None
2191         };
2192 
2193         let out_stm_settings = if let Some(params) = output_stream_params {
2194             let out_device = create_device_info(output_device as AudioDeviceID, DeviceType::OUTPUT)
2195                 .map_err(|e| {
2196                     cubeb_log!("Fail to create device info for output.");
2197                     e
2198                 })?;
2199             let stm_params = StreamParams::from(unsafe { *params.as_ptr() });
2200             Some((stm_params, out_device))
2201         } else {
2202             None
2203         };
2204 
2205         let mut boxed_stream = Box::new(AudioUnitStream::new(
2206             self,
2207             user_ptr,
2208             data_callback,
2209             state_callback,
2210             global_latency_frames,
2211         ));
2212 
2213         // Rename the task queue to be an unique label.
2214         let queue_label = format!("{}.{:p}", DISPATCH_QUEUE_LABEL, boxed_stream.as_ref());
2215         boxed_stream.queue = Queue::new(queue_label.as_str());
2216 
2217         boxed_stream.core_stream_data =
2218             CoreStreamData::new(boxed_stream.as_ref(), in_stm_settings, out_stm_settings);
2219 
2220         if let Err(r) = boxed_stream.core_stream_data.setup() {
2221             cubeb_log!(
2222                 "({:p}) Could not setup the audiounit stream.",
2223                 boxed_stream.as_ref()
2224             );
2225             return Err(r);
2226         }
2227 
2228         let cubeb_stream = unsafe { Stream::from_ptr(Box::into_raw(boxed_stream) as *mut _) };
2229         cubeb_log!(
2230             "({:p}) Cubeb stream init successful.",
2231             cubeb_stream.as_ref()
2232         );
2233         Ok(cubeb_stream)
2234     }
register_device_collection_changed( &mut self, devtype: DeviceType, collection_changed_callback: ffi::cubeb_device_collection_changed_callback, user_ptr: *mut c_void, ) -> Result<()>2235     fn register_device_collection_changed(
2236         &mut self,
2237         devtype: DeviceType,
2238         collection_changed_callback: ffi::cubeb_device_collection_changed_callback,
2239         user_ptr: *mut c_void,
2240     ) -> Result<()> {
2241         if devtype == DeviceType::UNKNOWN {
2242             return Err(Error::invalid_parameter());
2243         }
2244         if collection_changed_callback.is_some() {
2245             self.add_devices_changed_listener(devtype, collection_changed_callback, user_ptr)
2246         } else {
2247             self.remove_devices_changed_listener(devtype)
2248         }
2249     }
2250 }
2251 
2252 impl Drop for AudioUnitContext {
drop(&mut self)2253     fn drop(&mut self) {
2254         {
2255             let controller = self.latency_controller.lock().unwrap();
2256             // Disabling this assert for bug 1083664 -- we seem to leak a stream
2257             // assert(controller.streams == 0);
2258             if controller.streams > 0 {
2259                 cubeb_log!(
2260                     "({:p}) API misuse, {} streams active when context destroyed!",
2261                     self as *const AudioUnitContext,
2262                     controller.streams
2263                 );
2264             }
2265         }
2266 
2267         // Make sure all the pending (device-collection-changed-callback) tasks
2268         // in queue are done, and cancel all the tasks appended after `drop` is executed.
2269         let queue = self.serial_queue.clone();
2270         queue.run_final(|| {
2271             // Unregister the callback if necessary.
2272             self.remove_devices_changed_listener(DeviceType::INPUT);
2273             self.remove_devices_changed_listener(DeviceType::OUTPUT);
2274         });
2275     }
2276 }
2277 
2278 unsafe impl Send for AudioUnitContext {}
2279 unsafe impl Sync for AudioUnitContext {}
2280 
2281 #[derive(Debug)]
2282 struct CoreStreamData<'ctx> {
2283     stm_ptr: *const AudioUnitStream<'ctx>,
2284     aggregate_device: AggregateDevice,
2285     mixer: Option<Mixer>,
2286     resampler: Resampler,
2287     // Stream creation parameters.
2288     input_stream_params: StreamParams,
2289     output_stream_params: StreamParams,
2290     // Format descriptions.
2291     input_desc: AudioStreamBasicDescription,
2292     output_desc: AudioStreamBasicDescription,
2293     // I/O AudioUnits.
2294     input_unit: AudioUnit,
2295     output_unit: AudioUnit,
2296     // Info of the I/O devices.
2297     input_device: device_info,
2298     output_device: device_info,
2299     // Sample rates of the I/O devices.
2300     input_hw_rate: f64,
2301     output_hw_rate: f64,
2302     // Channel layout of the output AudioUnit.
2303     device_layout: Vec<mixer::Channel>,
2304     input_buffer_manager: Option<BufferManager>,
2305     // Listeners indicating what system events are monitored.
2306     default_input_listener: Option<device_property_listener>,
2307     default_output_listener: Option<device_property_listener>,
2308     input_alive_listener: Option<device_property_listener>,
2309     input_source_listener: Option<device_property_listener>,
2310     output_source_listener: Option<device_property_listener>,
2311 }
2312 
2313 impl<'ctx> Default for CoreStreamData<'ctx> {
default() -> Self2314     fn default() -> Self {
2315         Self {
2316             stm_ptr: ptr::null(),
2317             aggregate_device: AggregateDevice::default(),
2318             mixer: None,
2319             resampler: Resampler::default(),
2320             input_stream_params: StreamParams::from(ffi::cubeb_stream_params {
2321                 format: ffi::CUBEB_SAMPLE_FLOAT32NE,
2322                 rate: 0,
2323                 channels: 0,
2324                 layout: ffi::CUBEB_LAYOUT_UNDEFINED,
2325                 prefs: ffi::CUBEB_STREAM_PREF_NONE,
2326             }),
2327             output_stream_params: StreamParams::from(ffi::cubeb_stream_params {
2328                 format: ffi::CUBEB_SAMPLE_FLOAT32NE,
2329                 rate: 0,
2330                 channels: 0,
2331                 layout: ffi::CUBEB_LAYOUT_UNDEFINED,
2332                 prefs: ffi::CUBEB_STREAM_PREF_NONE,
2333             }),
2334             input_desc: AudioStreamBasicDescription::default(),
2335             output_desc: AudioStreamBasicDescription::default(),
2336             input_unit: ptr::null_mut(),
2337             output_unit: ptr::null_mut(),
2338             input_device: device_info::default(),
2339             output_device: device_info::default(),
2340             input_hw_rate: 0_f64,
2341             output_hw_rate: 0_f64,
2342             device_layout: Vec::new(),
2343             input_buffer_manager: None,
2344             default_input_listener: None,
2345             default_output_listener: None,
2346             input_alive_listener: None,
2347             input_source_listener: None,
2348             output_source_listener: None,
2349         }
2350     }
2351 }
2352 
2353 impl<'ctx> CoreStreamData<'ctx> {
new( stm: &AudioUnitStream<'ctx>, input_stream_settings: Option<(StreamParams, device_info)>, output_stream_settings: Option<(StreamParams, device_info)>, ) -> Self2354     fn new(
2355         stm: &AudioUnitStream<'ctx>,
2356         input_stream_settings: Option<(StreamParams, device_info)>,
2357         output_stream_settings: Option<(StreamParams, device_info)>,
2358     ) -> Self {
2359         fn get_default_sttream_params() -> StreamParams {
2360             StreamParams::from(ffi::cubeb_stream_params {
2361                 format: ffi::CUBEB_SAMPLE_FLOAT32NE,
2362                 rate: 0,
2363                 channels: 0,
2364                 layout: ffi::CUBEB_LAYOUT_UNDEFINED,
2365                 prefs: ffi::CUBEB_STREAM_PREF_NONE,
2366             })
2367         }
2368         let (in_stm_params, in_dev) =
2369             input_stream_settings.unwrap_or((get_default_sttream_params(), device_info::default()));
2370         let (out_stm_params, out_dev) = output_stream_settings
2371             .unwrap_or((get_default_sttream_params(), device_info::default()));
2372         Self {
2373             stm_ptr: stm,
2374             aggregate_device: AggregateDevice::default(),
2375             mixer: None,
2376             resampler: Resampler::default(),
2377             input_stream_params: in_stm_params,
2378             output_stream_params: out_stm_params,
2379             input_desc: AudioStreamBasicDescription::default(),
2380             output_desc: AudioStreamBasicDescription::default(),
2381             input_unit: ptr::null_mut(),
2382             output_unit: ptr::null_mut(),
2383             input_device: in_dev,
2384             output_device: out_dev,
2385             input_hw_rate: 0_f64,
2386             output_hw_rate: 0_f64,
2387             device_layout: Vec::new(),
2388             input_buffer_manager: None,
2389             default_input_listener: None,
2390             default_output_listener: None,
2391             input_alive_listener: None,
2392             input_source_listener: None,
2393             output_source_listener: None,
2394         }
2395     }
2396 
start_audiounits(&self) -> Result<()>2397     fn start_audiounits(&self) -> Result<()> {
2398         // Only allowed to be called after the stream is initialized
2399         // and before the stream is destroyed.
2400         debug_assert!(!self.input_unit.is_null() || !self.output_unit.is_null());
2401 
2402         if !self.input_unit.is_null() {
2403             start_audiounit(self.input_unit)?;
2404         }
2405         if !self.output_unit.is_null() {
2406             start_audiounit(self.output_unit)?;
2407         }
2408         Ok(())
2409     }
2410 
stop_audiounits(&self)2411     fn stop_audiounits(&self) {
2412         if !self.input_unit.is_null() {
2413             let r = stop_audiounit(self.input_unit);
2414             assert!(r.is_ok());
2415         }
2416         if !self.output_unit.is_null() {
2417             let r = stop_audiounit(self.output_unit);
2418             assert!(r.is_ok());
2419         }
2420     }
2421 
has_input(&self) -> bool2422     fn has_input(&self) -> bool {
2423         self.input_stream_params.rate() > 0
2424     }
2425 
has_output(&self) -> bool2426     fn has_output(&self) -> bool {
2427         self.output_stream_params.rate() > 0
2428     }
2429 
should_use_aggregate_device(&self) -> bool2430     fn should_use_aggregate_device(&self) -> bool {
2431         // Only using aggregate device when the input is a mic-only device and the output is a
2432         // speaker-only device. Otherwise, the mic on the output device may become the main
2433         // microphone of the aggregate device for this duplex stream.
2434         self.has_input()
2435             && self.has_output()
2436             && self.input_device.id != kAudioObjectUnknown
2437             && self.input_device.flags.contains(device_flags::DEV_INPUT)
2438             && self.output_device.id != kAudioObjectUnknown
2439             && self.output_device.flags.contains(device_flags::DEV_OUTPUT)
2440             && self.input_device.id != self.output_device.id
2441             && !is_device_a_type_of(self.input_device.id, DeviceType::OUTPUT)
2442             && !is_device_a_type_of(self.output_device.id, DeviceType::INPUT)
2443     }
2444 
2445     #[allow(clippy::cognitive_complexity)] // TODO: Refactoring.
setup(&mut self) -> Result<()>2446     fn setup(&mut self) -> Result<()> {
2447         if self
2448             .input_stream_params
2449             .prefs()
2450             .contains(StreamPrefs::LOOPBACK)
2451             || self
2452                 .output_stream_params
2453                 .prefs()
2454                 .contains(StreamPrefs::LOOPBACK)
2455         {
2456             cubeb_log!("({:p}) Loopback not supported for audiounit.", self.stm_ptr);
2457             return Err(Error::not_supported());
2458         }
2459 
2460         let mut in_dev_info = self.input_device.clone();
2461         let mut out_dev_info = self.output_device.clone();
2462 
2463         if self.should_use_aggregate_device() {
2464             match AggregateDevice::new(in_dev_info.id, out_dev_info.id) {
2465                 Ok(device) => {
2466                     in_dev_info.id = device.get_device_id();
2467                     out_dev_info.id = device.get_device_id();
2468                     in_dev_info.flags = device_flags::DEV_INPUT;
2469                     out_dev_info.flags = device_flags::DEV_OUTPUT;
2470                     self.aggregate_device = device;
2471                     cubeb_log!(
2472                         "({:p}) Use aggregate device {} for input and output.",
2473                         self.stm_ptr,
2474                         self.aggregate_device.get_device_id()
2475                     );
2476                 }
2477                 Err(e) => {
2478                     cubeb_log!(
2479                         "({:p}) Create aggregate devices failed. Error: {}.\
2480                          Use assigned devices directly instead.",
2481                         self.stm_ptr,
2482                         e
2483                     );
2484                 }
2485             }
2486         }
2487 
2488         assert!(!self.stm_ptr.is_null());
2489         let stream = unsafe { &(*self.stm_ptr) };
2490 
2491         // Configure I/O stream
2492         if self.has_input() {
2493             cubeb_log!(
2494                 "({:p}) Initialize input by device info: {:?}",
2495                 self.stm_ptr,
2496                 in_dev_info
2497             );
2498 
2499             self.input_unit = create_audiounit(&in_dev_info).map_err(|e| {
2500                 cubeb_log!("({:p}) AudioUnit creation for input failed.", self.stm_ptr);
2501                 e
2502             })?;
2503 
2504             cubeb_log!(
2505                 "({:p}) Opening input side: rate {}, channels {}, format {:?}, layout {:?}, prefs {:?}, latency in frames {}.",
2506                 self.stm_ptr,
2507                 self.input_stream_params.rate(),
2508                 self.input_stream_params.channels(),
2509                 self.input_stream_params.format(),
2510                 self.input_stream_params.layout(),
2511                 self.input_stream_params.prefs(),
2512                 stream.latency_frames
2513             );
2514 
2515             // Get input device sample rate.
2516             let mut input_hw_desc = AudioStreamBasicDescription::default();
2517             let mut size = mem::size_of::<AudioStreamBasicDescription>();
2518             let r = audio_unit_get_property(
2519                 self.input_unit,
2520                 kAudioUnitProperty_StreamFormat,
2521                 kAudioUnitScope_Input,
2522                 AU_IN_BUS,
2523                 &mut input_hw_desc,
2524                 &mut size,
2525             );
2526             if r != NO_ERR {
2527                 cubeb_log!(
2528                     "AudioUnitGetProperty/input/kAudioUnitProperty_StreamFormat rv={}",
2529                     r
2530                 );
2531                 return Err(Error::error());
2532             }
2533             cubeb_log!(
2534                 "({:p}) Input hardware description: {:?}",
2535                 self.stm_ptr,
2536                 input_hw_desc
2537             );
2538             self.input_hw_rate = input_hw_desc.mSampleRate;
2539 
2540             // Set format description according to the input params.
2541             self.input_desc =
2542                 create_stream_description(&self.input_stream_params).map_err(|e| {
2543                     cubeb_log!(
2544                         "({:p}) Setting format description for input failed.",
2545                         self.stm_ptr
2546                     );
2547                     e
2548                 })?;
2549 
2550             // Use latency to set buffer size
2551             assert_ne!(stream.latency_frames, 0);
2552             if let Err(r) =
2553                 set_buffer_size_sync(self.input_unit, DeviceType::INPUT, stream.latency_frames)
2554             {
2555                 cubeb_log!("({:p}) Error in change input buffer size.", self.stm_ptr);
2556                 return Err(r);
2557             }
2558 
2559             let mut src_desc = self.input_desc;
2560             // Input AudioUnit must be configured with device's sample rate.
2561             // we will resample inside input callback.
2562             src_desc.mSampleRate = self.input_hw_rate;
2563             let r = audio_unit_set_property(
2564                 self.input_unit,
2565                 kAudioUnitProperty_StreamFormat,
2566                 kAudioUnitScope_Output,
2567                 AU_IN_BUS,
2568                 &src_desc,
2569                 mem::size_of::<AudioStreamBasicDescription>(),
2570             );
2571             if r != NO_ERR {
2572                 cubeb_log!(
2573                     "AudioUnitSetProperty/input/kAudioUnitProperty_StreamFormat rv={}",
2574                     r
2575                 );
2576                 return Err(Error::error());
2577             }
2578 
2579             // Frames per buffer in the input callback.
2580             let r = audio_unit_set_property(
2581                 self.input_unit,
2582                 kAudioUnitProperty_MaximumFramesPerSlice,
2583                 kAudioUnitScope_Global,
2584                 AU_IN_BUS,
2585                 &stream.latency_frames,
2586                 mem::size_of::<u32>(),
2587             );
2588             if r != NO_ERR {
2589                 cubeb_log!(
2590                     "AudioUnitSetProperty/input/kAudioUnitProperty_MaximumFramesPerSlice rv={}",
2591                     r
2592                 );
2593                 return Err(Error::error());
2594             }
2595 
2596             self.input_buffer_manager = Some(BufferManager::new(self.input_stream_params.format()));
2597 
2598             let aurcbs_in = AURenderCallbackStruct {
2599                 inputProc: Some(audiounit_input_callback),
2600                 inputProcRefCon: self.stm_ptr as *mut c_void,
2601             };
2602 
2603             let r = audio_unit_set_property(
2604                 self.input_unit,
2605                 kAudioOutputUnitProperty_SetInputCallback,
2606                 kAudioUnitScope_Global,
2607                 AU_OUT_BUS,
2608                 &aurcbs_in,
2609                 mem::size_of_val(&aurcbs_in),
2610             );
2611             if r != NO_ERR {
2612                 cubeb_log!(
2613                     "AudioUnitSetProperty/input/kAudioOutputUnitProperty_SetInputCallback rv={}",
2614                     r
2615                 );
2616                 return Err(Error::error());
2617             }
2618 
2619             stream.frames_read.store(0, Ordering::SeqCst);
2620 
2621             cubeb_log!(
2622                 "({:p}) Input audiounit init with device {} successfully.",
2623                 self.stm_ptr,
2624                 in_dev_info.id
2625             );
2626         }
2627 
2628         if self.has_output() {
2629             cubeb_log!(
2630                 "({:p}) Initialize output by device info: {:?}",
2631                 self.stm_ptr,
2632                 out_dev_info
2633             );
2634 
2635             self.output_unit = create_audiounit(&out_dev_info).map_err(|e| {
2636                 cubeb_log!("({:p}) AudioUnit creation for output failed.", self.stm_ptr);
2637                 e
2638             })?;
2639 
2640             cubeb_log!(
2641                 "({:p}) Opening output side: rate {}, channels {}, format {:?}, layout {:?}, prefs {:?}, latency in frames {}.",
2642                 self.stm_ptr,
2643                 self.output_stream_params.rate(),
2644                 self.output_stream_params.channels(),
2645                 self.output_stream_params.format(),
2646                 self.output_stream_params.layout(),
2647                 self.output_stream_params.prefs(),
2648                 stream.latency_frames
2649             );
2650 
2651             self.output_desc =
2652                 create_stream_description(&self.output_stream_params).map_err(|e| {
2653                     cubeb_log!(
2654                         "({:p}) Could not initialize the audio stream description.",
2655                         self.stm_ptr
2656                     );
2657                     e
2658                 })?;
2659 
2660             // Get output device sample rate.
2661             let mut output_hw_desc = AudioStreamBasicDescription::default();
2662             let mut size = mem::size_of::<AudioStreamBasicDescription>();
2663             let r = audio_unit_get_property(
2664                 self.output_unit,
2665                 kAudioUnitProperty_StreamFormat,
2666                 kAudioUnitScope_Output,
2667                 AU_OUT_BUS,
2668                 &mut output_hw_desc,
2669                 &mut size,
2670             );
2671             if r != NO_ERR {
2672                 cubeb_log!(
2673                     "AudioUnitGetProperty/output/kAudioUnitProperty_StreamFormat rv={}",
2674                     r
2675                 );
2676                 return Err(Error::error());
2677             }
2678             cubeb_log!(
2679                 "({:p}) Output hardware description: {:?}",
2680                 self.stm_ptr,
2681                 output_hw_desc
2682             );
2683             self.output_hw_rate = output_hw_desc.mSampleRate;
2684             let hw_channels = output_hw_desc.mChannelsPerFrame;
2685             if hw_channels == 0 {
2686                 cubeb_log!(
2687                     "({:p}) Output hardware has no output channel! Bail out.",
2688                     self.stm_ptr
2689                 );
2690                 return Err(Error::device_unavailable());
2691             }
2692 
2693             self.device_layout = audiounit_get_current_channel_layout(self.output_unit);
2694 
2695             self.mixer = if hw_channels != self.output_stream_params.channels()
2696                 || self.device_layout
2697                     != mixer::get_channel_order(self.output_stream_params.layout())
2698             {
2699                 cubeb_log!("Incompatible channel layouts detected, setting up remixer");
2700                 // We will be remixing the data before it reaches the output device.
2701                 // We need to adjust the number of channels and other
2702                 // AudioStreamDescription details.
2703                 self.output_desc.mChannelsPerFrame = hw_channels;
2704                 self.output_desc.mBytesPerFrame =
2705                     (self.output_desc.mBitsPerChannel / 8) * self.output_desc.mChannelsPerFrame;
2706                 self.output_desc.mBytesPerPacket =
2707                     self.output_desc.mBytesPerFrame * self.output_desc.mFramesPerPacket;
2708                 Some(Mixer::new(
2709                     self.output_stream_params.format(),
2710                     self.output_stream_params.channels() as usize,
2711                     self.output_stream_params.layout(),
2712                     hw_channels as usize,
2713                     self.device_layout.clone(),
2714                 ))
2715             } else {
2716                 None
2717             };
2718 
2719             let r = audio_unit_set_property(
2720                 self.output_unit,
2721                 kAudioUnitProperty_StreamFormat,
2722                 kAudioUnitScope_Input,
2723                 AU_OUT_BUS,
2724                 &self.output_desc,
2725                 mem::size_of::<AudioStreamBasicDescription>(),
2726             );
2727             if r != NO_ERR {
2728                 cubeb_log!(
2729                     "AudioUnitSetProperty/output/kAudioUnitProperty_StreamFormat rv={}",
2730                     r
2731                 );
2732                 return Err(Error::error());
2733             }
2734 
2735             // Use latency to set buffer size
2736             assert_ne!(stream.latency_frames, 0);
2737             if let Err(r) =
2738                 set_buffer_size_sync(self.output_unit, DeviceType::OUTPUT, stream.latency_frames)
2739             {
2740                 cubeb_log!("({:p}) Error in change output buffer size.", self.stm_ptr);
2741                 return Err(r);
2742             }
2743 
2744             // Frames per buffer in the input callback.
2745             let r = audio_unit_set_property(
2746                 self.output_unit,
2747                 kAudioUnitProperty_MaximumFramesPerSlice,
2748                 kAudioUnitScope_Global,
2749                 AU_OUT_BUS,
2750                 &stream.latency_frames,
2751                 mem::size_of::<u32>(),
2752             );
2753             if r != NO_ERR {
2754                 cubeb_log!(
2755                     "AudioUnitSetProperty/output/kAudioUnitProperty_MaximumFramesPerSlice rv={}",
2756                     r
2757                 );
2758                 return Err(Error::error());
2759             }
2760 
2761             let aurcbs_out = AURenderCallbackStruct {
2762                 inputProc: Some(audiounit_output_callback),
2763                 inputProcRefCon: self.stm_ptr as *mut c_void,
2764             };
2765             let r = audio_unit_set_property(
2766                 self.output_unit,
2767                 kAudioUnitProperty_SetRenderCallback,
2768                 kAudioUnitScope_Global,
2769                 AU_OUT_BUS,
2770                 &aurcbs_out,
2771                 mem::size_of_val(&aurcbs_out),
2772             );
2773             if r != NO_ERR {
2774                 cubeb_log!(
2775                     "AudioUnitSetProperty/output/kAudioUnitProperty_SetRenderCallback rv={}",
2776                     r
2777                 );
2778                 return Err(Error::error());
2779             }
2780 
2781             stream.frames_written.store(0, Ordering::SeqCst);
2782 
2783             cubeb_log!(
2784                 "({:p}) Output audiounit init with device {} successfully.",
2785                 self.stm_ptr,
2786                 out_dev_info.id
2787             );
2788         }
2789 
2790         // We use a resampler because input AudioUnit operates
2791         // reliable only in the capture device sample rate.
2792         // Resampler will convert it to the user sample rate
2793         // and deliver it to the callback.
2794         let target_sample_rate = if self.has_input() {
2795             self.input_stream_params.rate()
2796         } else {
2797             assert!(self.has_output());
2798             self.output_stream_params.rate()
2799         };
2800 
2801         let resampler_input_params = if self.has_input() {
2802             let mut params = unsafe { *(self.input_stream_params.as_ptr()) };
2803             params.rate = self.input_hw_rate as u32;
2804             Some(params)
2805         } else {
2806             None
2807         };
2808         let resampler_output_params = if self.has_output() {
2809             let params = unsafe { *(self.output_stream_params.as_ptr()) };
2810             Some(params)
2811         } else {
2812             None
2813         };
2814 
2815         self.resampler = Resampler::new(
2816             self.stm_ptr as *mut ffi::cubeb_stream,
2817             resampler_input_params,
2818             resampler_output_params,
2819             target_sample_rate,
2820             stream.data_callback,
2821             stream.user_ptr,
2822         );
2823 
2824         if !self.input_unit.is_null() {
2825             let r = audio_unit_initialize(self.input_unit);
2826             if r != NO_ERR {
2827                 cubeb_log!("AudioUnitInitialize/input rv={}", r);
2828                 return Err(Error::error());
2829             }
2830 
2831             stream.input_device_latency_frames.store(
2832                 get_fixed_latency(self.input_device.id, DeviceType::INPUT),
2833                 Ordering::SeqCst,
2834             );
2835         }
2836 
2837         if !self.output_unit.is_null() {
2838             let r = audio_unit_initialize(self.output_unit);
2839             if r != NO_ERR {
2840                 cubeb_log!("AudioUnitInitialize/output rv={}", r);
2841                 return Err(Error::error());
2842             }
2843 
2844             stream.output_device_latency_frames.store(
2845                 get_fixed_latency(self.output_device.id, DeviceType::OUTPUT),
2846                 Ordering::SeqCst,
2847             );
2848 
2849             let mut unit_s: f64 = 0.0;
2850             let mut size = mem::size_of_val(&unit_s);
2851             if audio_unit_get_property(
2852                 self.output_unit,
2853                 kAudioUnitProperty_Latency,
2854                 kAudioUnitScope_Global,
2855                 0,
2856                 &mut unit_s,
2857                 &mut size,
2858             ) == NO_ERR
2859             {
2860                 stream.output_device_latency_frames.fetch_add(
2861                     (unit_s * self.output_desc.mSampleRate) as u32,
2862                     Ordering::SeqCst,
2863                 );
2864             }
2865         }
2866 
2867         if let Err(r) = self.install_system_changed_callback() {
2868             cubeb_log!(
2869                 "({:p}) Could not install the device change callback.",
2870                 self.stm_ptr
2871             );
2872             return Err(r);
2873         }
2874 
2875         if let Err(r) = self.install_device_changed_callback() {
2876             cubeb_log!(
2877                 "({:p}) Could not install all device change callback.",
2878                 self.stm_ptr
2879             );
2880             return Err(r);
2881         }
2882 
2883         Ok(())
2884     }
2885 
close(&mut self)2886     fn close(&mut self) {
2887         if !self.input_unit.is_null() {
2888             audio_unit_uninitialize(self.input_unit);
2889             dispose_audio_unit(self.input_unit);
2890             self.input_unit = ptr::null_mut();
2891         }
2892 
2893         if !self.output_unit.is_null() {
2894             audio_unit_uninitialize(self.output_unit);
2895             dispose_audio_unit(self.output_unit);
2896             self.output_unit = ptr::null_mut();
2897         }
2898 
2899         self.resampler.destroy();
2900         self.mixer = None;
2901         self.aggregate_device = AggregateDevice::default();
2902 
2903         if self.uninstall_system_changed_callback().is_err() {
2904             cubeb_log!(
2905                 "({:p}) Could not uninstall the system changed callback",
2906                 self.stm_ptr
2907             );
2908         }
2909 
2910         if self.uninstall_device_changed_callback().is_err() {
2911             cubeb_log!(
2912                 "({:p}) Could not uninstall all device change listeners",
2913                 self.stm_ptr
2914             );
2915         }
2916     }
2917 
install_device_changed_callback(&mut self) -> Result<()>2918     fn install_device_changed_callback(&mut self) -> Result<()> {
2919         assert!(!self.stm_ptr.is_null());
2920         let stm = unsafe { &(*self.stm_ptr) };
2921 
2922         if !self.output_unit.is_null() {
2923             assert_ne!(self.output_device.id, kAudioObjectUnknown);
2924             assert_ne!(self.output_device.id, kAudioObjectSystemObject);
2925             assert!(
2926                 self.output_source_listener.is_none(),
2927                 "register output_source_listener without unregistering the one in use"
2928             );
2929 
2930             // This event will notify us when the data source on the same device changes,
2931             // for example when the user plugs in a normal (non-usb) headset in the
2932             // headphone jack.
2933             self.output_source_listener = Some(device_property_listener::new(
2934                 self.output_device.id,
2935                 get_property_address(Property::DeviceSource, DeviceType::OUTPUT),
2936                 audiounit_property_listener_callback,
2937             ));
2938             let rv = stm.add_device_listener(self.output_source_listener.as_ref().unwrap());
2939             if rv != NO_ERR {
2940                 self.output_source_listener = None;
2941                 cubeb_log!("AudioObjectAddPropertyListener/output/kAudioDevicePropertyDataSource rv={}, device id={}", rv, self.output_device.id);
2942                 return Err(Error::error());
2943             }
2944         }
2945 
2946         if !self.input_unit.is_null() {
2947             assert_ne!(self.input_device.id, kAudioObjectUnknown);
2948             assert_ne!(self.input_device.id, kAudioObjectSystemObject);
2949             assert!(
2950                 self.input_source_listener.is_none(),
2951                 "register input_source_listener without unregistering the one in use"
2952             );
2953             assert!(
2954                 self.input_alive_listener.is_none(),
2955                 "register input_alive_listener without unregistering the one in use"
2956             );
2957 
2958             // This event will notify us when the data source on the input device changes.
2959             self.input_source_listener = Some(device_property_listener::new(
2960                 self.input_device.id,
2961                 get_property_address(Property::DeviceSource, DeviceType::INPUT),
2962                 audiounit_property_listener_callback,
2963             ));
2964             let rv = stm.add_device_listener(self.input_source_listener.as_ref().unwrap());
2965             if rv != NO_ERR {
2966                 self.input_source_listener = None;
2967                 cubeb_log!("AudioObjectAddPropertyListener/input/kAudioDevicePropertyDataSource rv={}, device id={}", rv, self.input_device.id);
2968                 return Err(Error::error());
2969             }
2970 
2971             // Event to notify when the input is going away.
2972             self.input_alive_listener = Some(device_property_listener::new(
2973                 self.input_device.id,
2974                 get_property_address(
2975                     Property::DeviceIsAlive,
2976                     DeviceType::INPUT | DeviceType::OUTPUT,
2977                 ),
2978                 audiounit_property_listener_callback,
2979             ));
2980             let rv = stm.add_device_listener(self.input_alive_listener.as_ref().unwrap());
2981             if rv != NO_ERR {
2982                 self.input_alive_listener = None;
2983                 cubeb_log!("AudioObjectAddPropertyListener/input/kAudioDevicePropertyDeviceIsAlive rv={}, device id ={}", rv, self.input_device.id);
2984                 return Err(Error::error());
2985             }
2986         }
2987 
2988         Ok(())
2989     }
2990 
install_system_changed_callback(&mut self) -> Result<()>2991     fn install_system_changed_callback(&mut self) -> Result<()> {
2992         assert!(!self.stm_ptr.is_null());
2993         let stm = unsafe { &(*self.stm_ptr) };
2994 
2995         if !self.output_unit.is_null() {
2996             assert!(
2997                 self.default_output_listener.is_none(),
2998                 "register default_output_listener without unregistering the one in use"
2999             );
3000 
3001             // This event will notify us when the default audio device changes,
3002             // for example when the user plugs in a USB headset and the system chooses it
3003             // automatically as the default, or when another device is chosen in the
3004             // dropdown list.
3005             self.default_output_listener = Some(device_property_listener::new(
3006                 kAudioObjectSystemObject,
3007                 get_property_address(
3008                     Property::HardwareDefaultOutputDevice,
3009                     DeviceType::INPUT | DeviceType::OUTPUT,
3010                 ),
3011                 audiounit_property_listener_callback,
3012             ));
3013             let r = stm.add_device_listener(self.default_output_listener.as_ref().unwrap());
3014             if r != NO_ERR {
3015                 self.default_output_listener = None;
3016                 cubeb_log!("AudioObjectAddPropertyListener/output/kAudioHardwarePropertyDefaultOutputDevice rv={}", r);
3017                 return Err(Error::error());
3018             }
3019         }
3020 
3021         if !self.input_unit.is_null() {
3022             assert!(
3023                 self.default_input_listener.is_none(),
3024                 "register default_input_listener without unregistering the one in use"
3025             );
3026 
3027             // This event will notify us when the default input device changes.
3028             self.default_input_listener = Some(device_property_listener::new(
3029                 kAudioObjectSystemObject,
3030                 get_property_address(
3031                     Property::HardwareDefaultInputDevice,
3032                     DeviceType::INPUT | DeviceType::OUTPUT,
3033                 ),
3034                 audiounit_property_listener_callback,
3035             ));
3036             let r = stm.add_device_listener(self.default_input_listener.as_ref().unwrap());
3037             if r != NO_ERR {
3038                 self.default_input_listener = None;
3039                 cubeb_log!("AudioObjectAddPropertyListener/input/kAudioHardwarePropertyDefaultInputDevice rv={}", r);
3040                 return Err(Error::error());
3041             }
3042         }
3043 
3044         Ok(())
3045     }
3046 
uninstall_device_changed_callback(&mut self) -> Result<()>3047     fn uninstall_device_changed_callback(&mut self) -> Result<()> {
3048         if self.stm_ptr.is_null() {
3049             assert!(
3050                 self.output_source_listener.is_none()
3051                     && self.input_source_listener.is_none()
3052                     && self.input_alive_listener.is_none()
3053             );
3054             return Ok(());
3055         }
3056 
3057         let stm = unsafe { &(*self.stm_ptr) };
3058 
3059         // Failing to uninstall listeners is not a fatal error.
3060         let mut r = Ok(());
3061 
3062         if self.output_source_listener.is_some() {
3063             let rv = stm.remove_device_listener(self.output_source_listener.as_ref().unwrap());
3064             if rv != NO_ERR {
3065                 cubeb_log!("AudioObjectRemovePropertyListener/output/kAudioDevicePropertyDataSource rv={}, device id={}", rv, self.output_device.id);
3066                 r = Err(Error::error());
3067             }
3068             self.output_source_listener = None;
3069         }
3070 
3071         if self.input_source_listener.is_some() {
3072             let rv = stm.remove_device_listener(self.input_source_listener.as_ref().unwrap());
3073             if rv != NO_ERR {
3074                 cubeb_log!("AudioObjectRemovePropertyListener/input/kAudioDevicePropertyDataSource rv={}, device id={}", rv, self.input_device.id);
3075                 r = Err(Error::error());
3076             }
3077             self.input_source_listener = None;
3078         }
3079 
3080         if self.input_alive_listener.is_some() {
3081             let rv = stm.remove_device_listener(self.input_alive_listener.as_ref().unwrap());
3082             if rv != NO_ERR {
3083                 cubeb_log!("AudioObjectRemovePropertyListener/input/kAudioDevicePropertyDeviceIsAlive rv={}, device id={}", rv, self.input_device.id);
3084                 r = Err(Error::error());
3085             }
3086             self.input_alive_listener = None;
3087         }
3088 
3089         r
3090     }
3091 
uninstall_system_changed_callback(&mut self) -> Result<()>3092     fn uninstall_system_changed_callback(&mut self) -> Result<()> {
3093         if self.stm_ptr.is_null() {
3094             assert!(
3095                 self.default_output_listener.is_none() && self.default_input_listener.is_none()
3096             );
3097             return Ok(());
3098         }
3099 
3100         let stm = unsafe { &(*self.stm_ptr) };
3101 
3102         if self.default_output_listener.is_some() {
3103             let r = stm.remove_device_listener(self.default_output_listener.as_ref().unwrap());
3104             if r != NO_ERR {
3105                 return Err(Error::error());
3106             }
3107             self.default_output_listener = None;
3108         }
3109 
3110         if self.default_input_listener.is_some() {
3111             let r = stm.remove_device_listener(self.default_input_listener.as_ref().unwrap());
3112             if r != NO_ERR {
3113                 return Err(Error::error());
3114             }
3115             self.default_input_listener = None;
3116         }
3117 
3118         Ok(())
3119     }
3120 }
3121 
3122 impl<'ctx> Drop for CoreStreamData<'ctx> {
drop(&mut self)3123     fn drop(&mut self) {
3124         self.stop_audiounits();
3125         self.close();
3126     }
3127 }
3128 
3129 #[derive(Debug, Clone)]
3130 struct OutputCallbackTimingData {
3131     frames_queued: u64,
3132     timestamp: u64,
3133     buffer_size: u64,
3134 }
3135 
3136 // The fisrt two members of the Cubeb stream must be a pointer to its Cubeb context and a void user
3137 // defined pointer. The Cubeb interface use this assumption to operate the Cubeb APIs.
3138 // #[repr(C)] is used to prevent any padding from being added in the beginning of the AudioUnitStream.
3139 #[repr(C)]
3140 #[derive(Debug)]
3141 // Allow exposing this private struct in public interfaces when running tests.
3142 #[cfg_attr(test, allow(private_in_public))]
3143 struct AudioUnitStream<'ctx> {
3144     context: &'ctx mut AudioUnitContext,
3145     user_ptr: *mut c_void,
3146     // Task queue for the stream.
3147     queue: Queue,
3148 
3149     data_callback: ffi::cubeb_data_callback,
3150     state_callback: ffi::cubeb_state_callback,
3151     device_changed_callback: Mutex<ffi::cubeb_device_changed_callback>,
3152     // Frame counters
3153     frames_queued: u64,
3154     // How many frames got read from the input since the stream started (includes
3155     // padded silence)
3156     frames_read: AtomicUsize,
3157     // How many frames got written to the output device since the stream started
3158     frames_written: AtomicUsize,
3159     stopped: AtomicBool,
3160     draining: AtomicBool,
3161     reinit_pending: AtomicBool,
3162     destroy_pending: AtomicBool,
3163     // Latency requested by the user.
3164     latency_frames: u32,
3165     // Fixed latency, characteristic of the device.
3166     output_device_latency_frames: AtomicU32,
3167     input_device_latency_frames: AtomicU32,
3168     // Total latency: the latency of the device + the OS latency
3169     total_output_latency_frames: AtomicU32,
3170     total_input_latency_frames: AtomicU32,
3171     output_callback_timing_data_read: triple_buffer::Output<OutputCallbackTimingData>,
3172     output_callback_timing_data_write: triple_buffer::Input<OutputCallbackTimingData>,
3173     prev_position: u64,
3174     // This is true if a device change callback is currently running.
3175     switching_device: AtomicBool,
3176     core_stream_data: CoreStreamData<'ctx>,
3177 }
3178 
3179 impl<'ctx> AudioUnitStream<'ctx> {
new( context: &'ctx mut AudioUnitContext, user_ptr: *mut c_void, data_callback: ffi::cubeb_data_callback, state_callback: ffi::cubeb_state_callback, latency_frames: u32, ) -> Self3180     fn new(
3181         context: &'ctx mut AudioUnitContext,
3182         user_ptr: *mut c_void,
3183         data_callback: ffi::cubeb_data_callback,
3184         state_callback: ffi::cubeb_state_callback,
3185         latency_frames: u32,
3186     ) -> Self {
3187         let output_callback_timing_data =
3188             triple_buffer::TripleBuffer::new(OutputCallbackTimingData {
3189                 frames_queued: 0,
3190                 timestamp: 0,
3191                 buffer_size: 0,
3192             });
3193         let (output_callback_timing_data_write, output_callback_timing_data_read) =
3194             output_callback_timing_data.split();
3195         AudioUnitStream {
3196             context,
3197             user_ptr,
3198             queue: Queue::new(DISPATCH_QUEUE_LABEL),
3199             data_callback,
3200             state_callback,
3201             device_changed_callback: Mutex::new(None),
3202             frames_queued: 0,
3203             frames_read: AtomicUsize::new(0),
3204             frames_written: AtomicUsize::new(0),
3205             stopped: AtomicBool::new(true),
3206             draining: AtomicBool::new(false),
3207             reinit_pending: AtomicBool::new(false),
3208             destroy_pending: AtomicBool::new(false),
3209             latency_frames,
3210             output_device_latency_frames: AtomicU32::new(0),
3211             input_device_latency_frames: AtomicU32::new(0),
3212             total_output_latency_frames: AtomicU32::new(0),
3213             total_input_latency_frames: AtomicU32::new(0),
3214             output_callback_timing_data_write,
3215             output_callback_timing_data_read,
3216             prev_position: 0,
3217             switching_device: AtomicBool::new(false),
3218             core_stream_data: CoreStreamData::default(),
3219         }
3220     }
3221 
add_device_listener(&self, listener: &device_property_listener) -> OSStatus3222     fn add_device_listener(&self, listener: &device_property_listener) -> OSStatus {
3223         audio_object_add_property_listener(
3224             listener.device,
3225             &listener.property,
3226             listener.listener,
3227             self as *const Self as *mut c_void,
3228         )
3229     }
3230 
remove_device_listener(&self, listener: &device_property_listener) -> OSStatus3231     fn remove_device_listener(&self, listener: &device_property_listener) -> OSStatus {
3232         audio_object_remove_property_listener(
3233             listener.device,
3234             &listener.property,
3235             listener.listener,
3236             self as *const Self as *mut c_void,
3237         )
3238     }
3239 
notify_state_changed(&self, state: State)3240     fn notify_state_changed(&self, state: State) {
3241         if self.state_callback.is_none() {
3242             return;
3243         }
3244         let callback = self.state_callback.unwrap();
3245         unsafe {
3246             callback(
3247                 self as *const AudioUnitStream as *mut ffi::cubeb_stream,
3248                 self.user_ptr,
3249                 state.into(),
3250             );
3251         }
3252     }
3253 
reinit(&mut self) -> Result<()>3254     fn reinit(&mut self) -> Result<()> {
3255         // Call stop_audiounits to avoid potential data race. If there is a running data callback,
3256         // which locks a mutex inside CoreAudio framework, then this call will block the current
3257         // thread until the callback is finished since this call asks to lock a mutex inside
3258         // CoreAudio framework that is used by the data callback.
3259         if !self.stopped.load(Ordering::SeqCst) {
3260             self.core_stream_data.stop_audiounits();
3261         }
3262 
3263         debug_assert!(
3264             !self.core_stream_data.input_unit.is_null()
3265                 || !self.core_stream_data.output_unit.is_null()
3266         );
3267         let vol_rv = if self.core_stream_data.output_unit.is_null() {
3268             Err(Error::error())
3269         } else {
3270             get_volume(self.core_stream_data.output_unit)
3271         };
3272 
3273         let has_input = !self.core_stream_data.input_unit.is_null();
3274         let input_device = if has_input {
3275             self.core_stream_data.input_device.id
3276         } else {
3277             kAudioObjectUnknown
3278         };
3279 
3280         self.core_stream_data.close();
3281 
3282         // Reinit occurs in one of the following case:
3283         // - When the device is not alive any more
3284         // - When the default system device change.
3285         // - The bluetooth device changed from A2DP to/from HFP/HSP profile
3286         // We first attempt to re-use the same device id, should that fail we will
3287         // default to the (potentially new) default device.
3288         if has_input {
3289             self.core_stream_data.input_device = create_device_info(input_device, DeviceType::INPUT).map_err(|e| {
3290                 cubeb_log!(
3291                     "({:p}) Create input device info failed. This can happen when last media device is unplugged",
3292                     self.core_stream_data.stm_ptr
3293                 );
3294                 e
3295             })?;
3296         }
3297 
3298         // Always use the default output on reinit. This is not correct in every
3299         // case but it is sufficient for Firefox and prevent reinit from reporting
3300         // failures. It will change soon when reinit mechanism will be updated.
3301         self.core_stream_data.output_device = create_device_info(kAudioObjectUnknown, DeviceType::OUTPUT).map_err(|e| {
3302             cubeb_log!(
3303                 "({:p}) Create output device info failed. This can happen when last media device is unplugged",
3304                 self.core_stream_data.stm_ptr
3305             );
3306             e
3307         })?;
3308 
3309         if self.core_stream_data.setup().is_err() {
3310             cubeb_log!(
3311                 "({:p}) Stream reinit failed.",
3312                 self.core_stream_data.stm_ptr
3313             );
3314             if has_input && input_device != kAudioObjectUnknown {
3315                 // Attempt to re-use the same device-id failed, so attempt again with
3316                 // default input device.
3317                 self.core_stream_data.input_device = create_device_info(kAudioObjectUnknown, DeviceType::INPUT).map_err(|e| {
3318                     cubeb_log!(
3319                         "({:p}) Create input device info failed. This can happen when last media device is unplugged",
3320                         self.core_stream_data.stm_ptr
3321                     );
3322                     e
3323                 })?;
3324                 self.core_stream_data.setup().map_err(|e| {
3325                     cubeb_log!(
3326                         "({:p}) Second stream reinit failed.",
3327                         self.core_stream_data.stm_ptr
3328                     );
3329                     e
3330                 })?;
3331             }
3332         }
3333 
3334         if let Ok(volume) = vol_rv {
3335             set_volume(self.core_stream_data.output_unit, volume);
3336         }
3337 
3338         // If the stream was running, start it again.
3339         if !self.stopped.load(Ordering::SeqCst) {
3340             self.core_stream_data.start_audiounits().map_err(|e| {
3341                 cubeb_log!(
3342                     "({:p}) Start audiounit failed.",
3343                     self.core_stream_data.stm_ptr
3344                 );
3345                 e
3346             })?;
3347         }
3348 
3349         Ok(())
3350     }
3351 
reinit_async(&mut self)3352     fn reinit_async(&mut self) {
3353         if self.reinit_pending.swap(true, Ordering::SeqCst) {
3354             // A reinit task is already pending, nothing more to do.
3355             cubeb_log!(
3356                 "({:p}) re-init stream task already pending, cancelling request",
3357                 self as *const AudioUnitStream
3358             );
3359             return;
3360         }
3361 
3362         let queue = self.queue.clone();
3363         let mutexed_stm = Arc::new(Mutex::new(self));
3364         let also_mutexed_stm = Arc::clone(&mutexed_stm);
3365         // Use a new thread, through the queue, to avoid deadlock when calling
3366         // Get/SetProperties method from inside notify callback
3367         queue.run_async(move || {
3368             let mut stm_guard = also_mutexed_stm.lock().unwrap();
3369             let stm_ptr = *stm_guard as *const AudioUnitStream;
3370             if stm_guard.destroy_pending.load(Ordering::SeqCst) {
3371                 cubeb_log!(
3372                     "({:p}) stream pending destroy, cancelling reinit task",
3373                     stm_ptr
3374                 );
3375                 return;
3376             }
3377 
3378             if stm_guard.reinit().is_err() {
3379                 stm_guard.core_stream_data.close();
3380                 stm_guard.notify_state_changed(State::Error);
3381                 cubeb_log!(
3382                     "({:p}) Could not reopen the stream after switching.",
3383                     stm_ptr
3384                 );
3385             }
3386             stm_guard.switching_device.store(false, Ordering::SeqCst);
3387             stm_guard.reinit_pending.store(false, Ordering::SeqCst);
3388         });
3389     }
3390 
destroy_internal(&mut self)3391     fn destroy_internal(&mut self) {
3392         self.core_stream_data.close();
3393         assert!(self.context.active_streams() >= 1);
3394         self.context.update_latency_by_removing_stream();
3395     }
3396 
destroy(&mut self)3397     fn destroy(&mut self) {
3398         if self
3399             .core_stream_data
3400             .uninstall_system_changed_callback()
3401             .is_err()
3402         {
3403             cubeb_log!(
3404                 "({:p}) Could not uninstall the system changed callback",
3405                 self as *const AudioUnitStream
3406             );
3407         }
3408 
3409         if self
3410             .core_stream_data
3411             .uninstall_device_changed_callback()
3412             .is_err()
3413         {
3414             cubeb_log!(
3415                 "({:p}) Could not uninstall all device change listeners",
3416                 self as *const AudioUnitStream
3417             );
3418         }
3419 
3420         // Execute the stream destroy work.
3421         self.destroy_pending.store(true, Ordering::SeqCst);
3422 
3423         let queue = self.queue.clone();
3424 
3425         let stream_ptr = self as *const AudioUnitStream;
3426         // Execute close in serial queue to avoid collision
3427         // with reinit when un/plug devices
3428         queue.run_final(move || {
3429             // Call stop_audiounits to avoid potential data race. If there is a running data callback,
3430             // which locks a mutex inside CoreAudio framework, then this call will block the current
3431             // thread until the callback is finished since this call asks to lock a mutex inside
3432             // CoreAudio framework that is used by the data callback.
3433             if !self.stopped.load(Ordering::SeqCst) {
3434                 self.core_stream_data.stop_audiounits();
3435                 self.stopped.store(true, Ordering::SeqCst);
3436             }
3437 
3438             self.destroy_internal();
3439         });
3440 
3441         cubeb_log!("Cubeb stream ({:p}) destroyed successful.", stream_ptr);
3442     }
3443 }
3444 
3445 impl<'ctx> Drop for AudioUnitStream<'ctx> {
drop(&mut self)3446     fn drop(&mut self) {
3447         self.destroy();
3448     }
3449 }
3450 
3451 impl<'ctx> StreamOps for AudioUnitStream<'ctx> {
start(&mut self) -> Result<()>3452     fn start(&mut self) -> Result<()> {
3453         self.stopped.store(false, Ordering::SeqCst);
3454         self.draining.store(false, Ordering::SeqCst);
3455 
3456         // Execute start in serial queue to avoid racing with destroy or reinit.
3457         let mut result = Err(Error::error());
3458         let started = &mut result;
3459         let stream = &self;
3460         self.queue.run_sync(move || {
3461             *started = stream.core_stream_data.start_audiounits();
3462         });
3463 
3464         if result.is_err() {
3465             return result;
3466         }
3467 
3468         self.notify_state_changed(State::Started);
3469 
3470         cubeb_log!(
3471             "Cubeb stream ({:p}) started successfully.",
3472             self as *const AudioUnitStream
3473         );
3474         Ok(())
3475     }
stop(&mut self) -> Result<()>3476     fn stop(&mut self) -> Result<()> {
3477         self.stopped.store(true, Ordering::SeqCst);
3478 
3479         // Execute stop in serial queue to avoid racing with destroy or reinit.
3480         let stream = &self;
3481         self.queue.run_sync(move || {
3482             stream.core_stream_data.stop_audiounits();
3483         });
3484 
3485         self.notify_state_changed(State::Stopped);
3486 
3487         cubeb_log!(
3488             "Cubeb stream ({:p}) stopped successfully.",
3489             self as *const AudioUnitStream
3490         );
3491         Ok(())
3492     }
position(&mut self) -> Result<u64>3493     fn position(&mut self) -> Result<u64> {
3494         let OutputCallbackTimingData {
3495             frames_queued,
3496             timestamp,
3497             buffer_size,
3498         } = self.output_callback_timing_data_read.read().clone();
3499         let total_output_latency_frames =
3500             u64::from(self.total_output_latency_frames.load(Ordering::SeqCst));
3501         // If output latency is available, take it into account. Otherwise, use the number of
3502         // frames played.
3503         let position = if total_output_latency_frames != 0 {
3504             if total_output_latency_frames > frames_queued {
3505                 0
3506             } else {
3507                 // Interpolate here to match other cubeb backends. Only return an interpolated time
3508                 // if we've played enough frames. If the stream is paused, clamp the interpolated
3509                 // number of frames to the buffer size.
3510                 const NS2S: u64 = 1_000_000_000;
3511                 let now = unsafe { mach_absolute_time() };
3512                 let diff = now - timestamp;
3513                 let interpolated_frames = cmp::min(
3514                     host_time_to_ns(diff)
3515                         * self.core_stream_data.output_stream_params.rate() as u64
3516                         / NS2S,
3517                     buffer_size,
3518                 );
3519                 (frames_queued - total_output_latency_frames) + interpolated_frames
3520             }
3521         } else {
3522             frames_queued
3523         };
3524 
3525         // Ensure mononicity of the clock even when changing output device.
3526         if position > self.prev_position {
3527             self.prev_position = position;
3528         }
3529         Ok(self.prev_position)
3530     }
3531     #[cfg(target_os = "ios")]
latency(&mut self) -> Result<u32>3532     fn latency(&mut self) -> Result<u32> {
3533         Err(not_supported())
3534     }
3535     #[cfg(not(target_os = "ios"))]
latency(&mut self) -> Result<u32>3536     fn latency(&mut self) -> Result<u32> {
3537         Ok(self.total_output_latency_frames.load(Ordering::SeqCst))
3538     }
3539     #[cfg(target_os = "ios")]
input_latency(&mut self) -> Result<u32>3540     fn input_latency(&mut self) -> Result<u32> {
3541         Err(not_supported())
3542     }
3543     #[cfg(not(target_os = "ios"))]
input_latency(&mut self) -> Result<u32>3544     fn input_latency(&mut self) -> Result<u32> {
3545         let user_rate = self.core_stream_data.input_stream_params.rate();
3546         let hw_rate = self.core_stream_data.input_hw_rate as u32;
3547         let frames = self.total_input_latency_frames.load(Ordering::SeqCst);
3548         if frames != 0 {
3549             if hw_rate == user_rate {
3550                 Ok(frames)
3551             } else {
3552                 Ok(frames * (user_rate / hw_rate))
3553             }
3554         } else {
3555             Err(Error::error())
3556         }
3557     }
set_volume(&mut self, volume: f32) -> Result<()>3558     fn set_volume(&mut self, volume: f32) -> Result<()> {
3559         // Execute set_volume in serial queue to avoid racing with destroy or reinit.
3560         let mut result = Err(Error::error());
3561         let set = &mut result;
3562         let stream = &self;
3563         self.queue.run_sync(move || {
3564             *set = set_volume(stream.core_stream_data.output_unit, volume);
3565         });
3566 
3567         if result.is_err() {
3568             return result;
3569         }
3570 
3571         cubeb_log!(
3572             "Cubeb stream ({:p}) set volume to {}.",
3573             self as *const AudioUnitStream,
3574             volume
3575         );
3576         Ok(())
3577     }
set_name(&mut self, _: &CStr) -> Result<()>3578     fn set_name(&mut self, _: &CStr) -> Result<()> {
3579         Err(Error::not_supported())
3580     }
3581     #[cfg(target_os = "ios")]
current_device(&mut self) -> Result<&DeviceRef>3582     fn current_device(&mut self) -> Result<&DeviceRef> {
3583         Err(not_supported())
3584     }
3585     #[cfg(not(target_os = "ios"))]
current_device(&mut self) -> Result<&DeviceRef>3586     fn current_device(&mut self) -> Result<&DeviceRef> {
3587         let input_name = audiounit_get_default_datasource_string(DeviceType::INPUT);
3588         let output_name = audiounit_get_default_datasource_string(DeviceType::OUTPUT);
3589         if input_name.is_err() && output_name.is_err() {
3590             return Err(Error::error());
3591         }
3592 
3593         let mut device: Box<ffi::cubeb_device> = Box::new(ffi::cubeb_device::default());
3594 
3595         let input_name = input_name.unwrap_or_default();
3596         device.input_name = input_name.into_raw();
3597 
3598         let output_name = output_name.unwrap_or_default();
3599         device.output_name = output_name.into_raw();
3600 
3601         Ok(unsafe { DeviceRef::from_ptr(Box::into_raw(device)) })
3602     }
3603     #[cfg(target_os = "ios")]
device_destroy(&mut self, device: &DeviceRef) -> Result<()>3604     fn device_destroy(&mut self, device: &DeviceRef) -> Result<()> {
3605         Err(not_supported())
3606     }
3607     #[cfg(not(target_os = "ios"))]
device_destroy(&mut self, device: &DeviceRef) -> Result<()>3608     fn device_destroy(&mut self, device: &DeviceRef) -> Result<()> {
3609         if device.as_ptr().is_null() {
3610             Err(Error::error())
3611         } else {
3612             unsafe {
3613                 let mut dev: Box<ffi::cubeb_device> = Box::from_raw(device.as_ptr() as *mut _);
3614                 if !dev.output_name.is_null() {
3615                     let _ = CString::from_raw(dev.output_name as *mut _);
3616                     dev.output_name = ptr::null_mut();
3617                 }
3618                 if !dev.input_name.is_null() {
3619                     let _ = CString::from_raw(dev.input_name as *mut _);
3620                     dev.input_name = ptr::null_mut();
3621                 }
3622                 drop(dev);
3623             }
3624             Ok(())
3625         }
3626     }
register_device_changed_callback( &mut self, device_changed_callback: ffi::cubeb_device_changed_callback, ) -> Result<()>3627     fn register_device_changed_callback(
3628         &mut self,
3629         device_changed_callback: ffi::cubeb_device_changed_callback,
3630     ) -> Result<()> {
3631         let mut callback = self.device_changed_callback.lock().unwrap();
3632         // Note: second register without unregister first causes 'nope' error.
3633         // Current implementation requires unregister before register a new cb.
3634         if device_changed_callback.is_some() && callback.is_some() {
3635             Err(Error::invalid_parameter())
3636         } else {
3637             *callback = device_changed_callback;
3638             Ok(())
3639         }
3640     }
3641 }
3642 
3643 unsafe impl<'ctx> Send for AudioUnitStream<'ctx> {}
3644 unsafe impl<'ctx> Sync for AudioUnitStream<'ctx> {}
3645 
3646 #[cfg(test)]
3647 mod tests;
3648