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