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