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