1 extern crate core_foundation_sys;
2 extern crate coreaudio;
3 
4 use super::{asbd_from_config, check_os_status, frames_to_duration, host_time_to_stream_instant};
5 
6 use self::core_foundation_sys::string::{CFStringGetCString, CFStringGetCStringPtr, CFStringRef};
7 use self::coreaudio::audio_unit::render_callback::{self, data};
8 use self::coreaudio::audio_unit::{AudioUnit, Element, Scope};
9 use self::coreaudio::sys::{
10     kAudioDevicePropertyAvailableNominalSampleRates, kAudioDevicePropertyBufferFrameSize,
11     kAudioDevicePropertyBufferFrameSizeRange, kAudioDevicePropertyDeviceNameCFString,
12     kAudioDevicePropertyNominalSampleRate, kAudioDevicePropertyScopeOutput,
13     kAudioDevicePropertyStreamConfiguration, kAudioDevicePropertyStreamFormat,
14     kAudioObjectPropertyElementMaster, kAudioObjectPropertyScopeGlobal,
15     kAudioObjectPropertyScopeInput, kAudioObjectPropertyScopeOutput,
16     kAudioOutputUnitProperty_CurrentDevice, kAudioOutputUnitProperty_EnableIO,
17     kAudioUnitProperty_StreamFormat, kCFStringEncodingUTF8, AudioBuffer, AudioBufferList,
18     AudioDeviceID, AudioObjectAddPropertyListener, AudioObjectGetPropertyData,
19     AudioObjectGetPropertyDataSize, AudioObjectID, AudioObjectPropertyAddress,
20     AudioObjectPropertyScope, AudioObjectRemovePropertyListener, AudioObjectSetPropertyData,
21     AudioStreamBasicDescription, AudioValueRange, OSStatus,
22 };
23 use crate::traits::{DeviceTrait, HostTrait, StreamTrait};
24 use crate::{
25     BackendSpecificError, BufferSize, BuildStreamError, ChannelCount, Data,
26     DefaultStreamConfigError, DeviceNameError, DevicesError, InputCallbackInfo, OutputCallbackInfo,
27     PauseStreamError, PlayStreamError, SampleFormat, SampleRate, StreamConfig, StreamError,
28     SupportedBufferSize, SupportedStreamConfig, SupportedStreamConfigRange,
29     SupportedStreamConfigsError,
30 };
31 use std::cell::RefCell;
32 use std::ffi::CStr;
33 use std::fmt;
34 use std::mem;
35 use std::os::raw::c_char;
36 use std::ptr::null;
37 use std::slice;
38 use std::thread;
39 use std::time::Duration;
40 
41 pub use self::enumerate::{
42     default_input_device, default_output_device, Devices, SupportedInputConfigs,
43     SupportedOutputConfigs,
44 };
45 
46 pub mod enumerate;
47 
48 /// Coreaudio host, the default host on macOS.
49 #[derive(Debug)]
50 pub struct Host;
51 
52 impl Host {
new() -> Result<Self, crate::HostUnavailable>53     pub fn new() -> Result<Self, crate::HostUnavailable> {
54         Ok(Host)
55     }
56 }
57 
58 impl HostTrait for Host {
59     type Devices = Devices;
60     type Device = Device;
61 
is_available() -> bool62     fn is_available() -> bool {
63         // Assume coreaudio is always available
64         true
65     }
66 
devices(&self) -> Result<Self::Devices, DevicesError>67     fn devices(&self) -> Result<Self::Devices, DevicesError> {
68         Devices::new()
69     }
70 
default_input_device(&self) -> Option<Self::Device>71     fn default_input_device(&self) -> Option<Self::Device> {
72         default_input_device()
73     }
74 
default_output_device(&self) -> Option<Self::Device>75     fn default_output_device(&self) -> Option<Self::Device> {
76         default_output_device()
77     }
78 }
79 
80 impl DeviceTrait for Device {
81     type SupportedInputConfigs = SupportedInputConfigs;
82     type SupportedOutputConfigs = SupportedOutputConfigs;
83     type Stream = Stream;
84 
name(&self) -> Result<String, DeviceNameError>85     fn name(&self) -> Result<String, DeviceNameError> {
86         Device::name(self)
87     }
88 
supported_input_configs( &self, ) -> Result<Self::SupportedInputConfigs, SupportedStreamConfigsError>89     fn supported_input_configs(
90         &self,
91     ) -> Result<Self::SupportedInputConfigs, SupportedStreamConfigsError> {
92         Device::supported_input_configs(self)
93     }
94 
supported_output_configs( &self, ) -> Result<Self::SupportedOutputConfigs, SupportedStreamConfigsError>95     fn supported_output_configs(
96         &self,
97     ) -> Result<Self::SupportedOutputConfigs, SupportedStreamConfigsError> {
98         Device::supported_output_configs(self)
99     }
100 
default_input_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError>101     fn default_input_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError> {
102         Device::default_input_config(self)
103     }
104 
default_output_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError>105     fn default_output_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError> {
106         Device::default_output_config(self)
107     }
108 
build_input_stream_raw<D, E>( &self, config: &StreamConfig, sample_format: SampleFormat, data_callback: D, error_callback: E, ) -> Result<Self::Stream, BuildStreamError> where D: FnMut(&Data, &InputCallbackInfo) + Send + 'static, E: FnMut(StreamError) + Send + 'static,109     fn build_input_stream_raw<D, E>(
110         &self,
111         config: &StreamConfig,
112         sample_format: SampleFormat,
113         data_callback: D,
114         error_callback: E,
115     ) -> Result<Self::Stream, BuildStreamError>
116     where
117         D: FnMut(&Data, &InputCallbackInfo) + Send + 'static,
118         E: FnMut(StreamError) + Send + 'static,
119     {
120         Device::build_input_stream_raw(self, config, sample_format, data_callback, error_callback)
121     }
122 
build_output_stream_raw<D, E>( &self, config: &StreamConfig, sample_format: SampleFormat, data_callback: D, error_callback: E, ) -> Result<Self::Stream, BuildStreamError> where D: FnMut(&mut Data, &OutputCallbackInfo) + Send + 'static, E: FnMut(StreamError) + Send + 'static,123     fn build_output_stream_raw<D, E>(
124         &self,
125         config: &StreamConfig,
126         sample_format: SampleFormat,
127         data_callback: D,
128         error_callback: E,
129     ) -> Result<Self::Stream, BuildStreamError>
130     where
131         D: FnMut(&mut Data, &OutputCallbackInfo) + Send + 'static,
132         E: FnMut(StreamError) + Send + 'static,
133     {
134         Device::build_output_stream_raw(self, config, sample_format, data_callback, error_callback)
135     }
136 }
137 
138 #[derive(Clone, PartialEq, Eq)]
139 pub struct Device {
140     pub(crate) audio_device_id: AudioDeviceID,
141 }
142 
143 impl Device {
name(&self) -> Result<String, DeviceNameError>144     fn name(&self) -> Result<String, DeviceNameError> {
145         let property_address = AudioObjectPropertyAddress {
146             mSelector: kAudioDevicePropertyDeviceNameCFString,
147             mScope: kAudioDevicePropertyScopeOutput,
148             mElement: kAudioObjectPropertyElementMaster,
149         };
150         let device_name: CFStringRef = null();
151         let data_size = mem::size_of::<CFStringRef>();
152         let c_str = unsafe {
153             let status = AudioObjectGetPropertyData(
154                 self.audio_device_id,
155                 &property_address as *const _,
156                 0,
157                 null(),
158                 &data_size as *const _ as *mut _,
159                 &device_name as *const _ as *mut _,
160             );
161             check_os_status(status)?;
162 
163             let c_string: *const c_char = CFStringGetCStringPtr(device_name, kCFStringEncodingUTF8);
164             if c_string.is_null() {
165                 let status = AudioObjectGetPropertyData(
166                     self.audio_device_id,
167                     &property_address as *const _,
168                     0,
169                     null(),
170                     &data_size as *const _ as *mut _,
171                     &device_name as *const _ as *mut _,
172                 );
173                 check_os_status(status)?;
174                 let mut buf: [i8; 255] = [0; 255];
175                 let result = CFStringGetCString(
176                     device_name,
177                     buf.as_mut_ptr(),
178                     buf.len() as _,
179                     kCFStringEncodingUTF8,
180                 );
181                 if result == 0 {
182                     let description =
183                         "core foundation failed to return device name string".to_string();
184                     let err = BackendSpecificError { description };
185                     return Err(err.into());
186                 }
187                 let name: &CStr = CStr::from_ptr(buf.as_ptr());
188                 return Ok(name.to_str().unwrap().to_owned());
189             }
190             CStr::from_ptr(c_string as *mut _)
191         };
192         Ok(c_str.to_string_lossy().into_owned())
193     }
194 
195     // Logic re-used between `supported_input_configs` and `supported_output_configs`.
196     #[allow(clippy::cast_ptr_alignment)]
supported_configs( &self, scope: AudioObjectPropertyScope, ) -> Result<SupportedOutputConfigs, SupportedStreamConfigsError>197     fn supported_configs(
198         &self,
199         scope: AudioObjectPropertyScope,
200     ) -> Result<SupportedOutputConfigs, SupportedStreamConfigsError> {
201         let mut property_address = AudioObjectPropertyAddress {
202             mSelector: kAudioDevicePropertyStreamConfiguration,
203             mScope: scope,
204             mElement: kAudioObjectPropertyElementMaster,
205         };
206 
207         unsafe {
208             // Retrieve the devices audio buffer list.
209             let data_size = 0u32;
210             let status = AudioObjectGetPropertyDataSize(
211                 self.audio_device_id,
212                 &property_address as *const _,
213                 0,
214                 null(),
215                 &data_size as *const _ as *mut _,
216             );
217             check_os_status(status)?;
218 
219             let mut audio_buffer_list: Vec<u8> = vec![];
220             audio_buffer_list.reserve_exact(data_size as usize);
221             let status = AudioObjectGetPropertyData(
222                 self.audio_device_id,
223                 &property_address as *const _,
224                 0,
225                 null(),
226                 &data_size as *const _ as *mut _,
227                 audio_buffer_list.as_mut_ptr() as *mut _,
228             );
229             check_os_status(status)?;
230 
231             let audio_buffer_list = audio_buffer_list.as_mut_ptr() as *mut AudioBufferList;
232 
233             // If there's no buffers, skip.
234             if (*audio_buffer_list).mNumberBuffers == 0 {
235                 return Ok(vec![].into_iter());
236             }
237 
238             // Count the number of channels as the sum of all channels in all output buffers.
239             let n_buffers = (*audio_buffer_list).mNumberBuffers as usize;
240             let first: *const AudioBuffer = (*audio_buffer_list).mBuffers.as_ptr();
241             let buffers: &'static [AudioBuffer] = slice::from_raw_parts(first, n_buffers);
242             let mut n_channels = 0;
243             for buffer in buffers {
244                 n_channels += buffer.mNumberChannels as usize;
245             }
246 
247             // TODO: macOS should support U8, I16, I32, F32 and F64. This should allow for using
248             // I16 but just use F32 for now as it's the default anyway.
249             let sample_format = SampleFormat::F32;
250 
251             // Get available sample rate ranges.
252             property_address.mSelector = kAudioDevicePropertyAvailableNominalSampleRates;
253             let data_size = 0u32;
254             let status = AudioObjectGetPropertyDataSize(
255                 self.audio_device_id,
256                 &property_address as *const _,
257                 0,
258                 null(),
259                 &data_size as *const _ as *mut _,
260             );
261             check_os_status(status)?;
262 
263             let n_ranges = data_size as usize / mem::size_of::<AudioValueRange>();
264             let mut ranges: Vec<u8> = vec![];
265             ranges.reserve_exact(data_size as usize);
266             let status = AudioObjectGetPropertyData(
267                 self.audio_device_id,
268                 &property_address as *const _,
269                 0,
270                 null(),
271                 &data_size as *const _ as *mut _,
272                 ranges.as_mut_ptr() as *mut _,
273             );
274             check_os_status(status)?;
275 
276             let ranges: *mut AudioValueRange = ranges.as_mut_ptr() as *mut _;
277             let ranges: &'static [AudioValueRange] = slice::from_raw_parts(ranges, n_ranges);
278 
279             let audio_unit = audio_unit_from_device(self, true)?;
280             let buffer_size = get_io_buffer_frame_size_range(&audio_unit)?;
281 
282             // Collect the supported formats for the device.
283             let mut fmts = vec![];
284             for range in ranges {
285                 let fmt = SupportedStreamConfigRange {
286                     channels: n_channels as ChannelCount,
287                     min_sample_rate: SampleRate(range.mMinimum as _),
288                     max_sample_rate: SampleRate(range.mMaximum as _),
289                     buffer_size: buffer_size.clone(),
290                     sample_format,
291                 };
292                 fmts.push(fmt);
293             }
294 
295             Ok(fmts.into_iter())
296         }
297     }
298 
supported_input_configs( &self, ) -> Result<SupportedOutputConfigs, SupportedStreamConfigsError>299     fn supported_input_configs(
300         &self,
301     ) -> Result<SupportedOutputConfigs, SupportedStreamConfigsError> {
302         self.supported_configs(kAudioObjectPropertyScopeInput)
303     }
304 
supported_output_configs( &self, ) -> Result<SupportedOutputConfigs, SupportedStreamConfigsError>305     fn supported_output_configs(
306         &self,
307     ) -> Result<SupportedOutputConfigs, SupportedStreamConfigsError> {
308         self.supported_configs(kAudioObjectPropertyScopeOutput)
309     }
310 
default_config( &self, scope: AudioObjectPropertyScope, ) -> Result<SupportedStreamConfig, DefaultStreamConfigError>311     fn default_config(
312         &self,
313         scope: AudioObjectPropertyScope,
314     ) -> Result<SupportedStreamConfig, DefaultStreamConfigError> {
315         fn default_config_error_from_os_status(
316             status: OSStatus,
317         ) -> Result<(), DefaultStreamConfigError> {
318             let err = match coreaudio::Error::from_os_status(status) {
319                 Err(err) => err,
320                 Ok(_) => return Ok(()),
321             };
322             match err {
323                 coreaudio::Error::AudioUnit(
324                     coreaudio::error::AudioUnitError::FormatNotSupported,
325                 )
326                 | coreaudio::Error::AudioCodec(_)
327                 | coreaudio::Error::AudioFormat(_) => {
328                     Err(DefaultStreamConfigError::StreamTypeNotSupported)
329                 }
330                 coreaudio::Error::AudioUnit(coreaudio::error::AudioUnitError::NoConnection) => {
331                     Err(DefaultStreamConfigError::DeviceNotAvailable)
332                 }
333                 err => {
334                     let description = format!("{}", err);
335                     let err = BackendSpecificError { description };
336                     Err(err.into())
337                 }
338             }
339         }
340 
341         let property_address = AudioObjectPropertyAddress {
342             mSelector: kAudioDevicePropertyStreamFormat,
343             mScope: scope,
344             mElement: kAudioObjectPropertyElementMaster,
345         };
346 
347         unsafe {
348             let asbd: AudioStreamBasicDescription = mem::zeroed();
349             let data_size = mem::size_of::<AudioStreamBasicDescription>() as u32;
350             let status = AudioObjectGetPropertyData(
351                 self.audio_device_id,
352                 &property_address as *const _,
353                 0,
354                 null(),
355                 &data_size as *const _ as *mut _,
356                 &asbd as *const _ as *mut _,
357             );
358             default_config_error_from_os_status(status)?;
359 
360             let sample_format = {
361                 let audio_format = coreaudio::audio_unit::AudioFormat::from_format_and_flag(
362                     asbd.mFormatID,
363                     Some(asbd.mFormatFlags),
364                 );
365                 let flags = match audio_format {
366                     Some(coreaudio::audio_unit::AudioFormat::LinearPCM(flags)) => flags,
367                     _ => return Err(DefaultStreamConfigError::StreamTypeNotSupported),
368                 };
369                 let maybe_sample_format =
370                     coreaudio::audio_unit::SampleFormat::from_flags_and_bytes_per_frame(
371                         flags,
372                         asbd.mBytesPerFrame,
373                     );
374                 match maybe_sample_format {
375                     Some(coreaudio::audio_unit::SampleFormat::F32) => SampleFormat::F32,
376                     Some(coreaudio::audio_unit::SampleFormat::I16) => SampleFormat::I16,
377                     _ => return Err(DefaultStreamConfigError::StreamTypeNotSupported),
378                 }
379             };
380 
381             let audio_unit = audio_unit_from_device(self, true)?;
382             let buffer_size = get_io_buffer_frame_size_range(&audio_unit)?;
383 
384             let config = SupportedStreamConfig {
385                 sample_rate: SampleRate(asbd.mSampleRate as _),
386                 channels: asbd.mChannelsPerFrame as _,
387                 buffer_size,
388                 sample_format,
389             };
390             Ok(config)
391         }
392     }
393 
default_input_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError>394     fn default_input_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError> {
395         self.default_config(kAudioObjectPropertyScopeInput)
396     }
397 
default_output_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError>398     fn default_output_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError> {
399         self.default_config(kAudioObjectPropertyScopeOutput)
400     }
401 }
402 
403 impl fmt::Debug for Device {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result404     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
405         f.debug_struct("Device")
406             .field("audio_device_id", &self.audio_device_id)
407             .field("name", &self.name())
408             .finish()
409     }
410 }
411 
412 struct StreamInner {
413     playing: bool,
414     audio_unit: AudioUnit,
415     // Track the device with which the audio unit was spawned.
416     //
417     // We must do this so that we can avoid changing the device sample rate if there is already
418     // a stream associated with the device.
419     #[allow(dead_code)]
420     device_id: AudioDeviceID,
421 }
422 
audio_unit_from_device(device: &Device, input: bool) -> Result<AudioUnit, coreaudio::Error>423 fn audio_unit_from_device(device: &Device, input: bool) -> Result<AudioUnit, coreaudio::Error> {
424     let mut audio_unit = AudioUnit::new(coreaudio::audio_unit::IOType::HalOutput)?;
425 
426     if input {
427         // Enable input processing.
428         let enable_input = 1u32;
429         audio_unit.set_property(
430             kAudioOutputUnitProperty_EnableIO,
431             Scope::Input,
432             Element::Input,
433             Some(&enable_input),
434         )?;
435 
436         // Disable output processing.
437         let disable_output = 0u32;
438         audio_unit.set_property(
439             kAudioOutputUnitProperty_EnableIO,
440             Scope::Output,
441             Element::Output,
442             Some(&disable_output),
443         )?;
444     }
445 
446     audio_unit.set_property(
447         kAudioOutputUnitProperty_CurrentDevice,
448         Scope::Global,
449         Element::Output,
450         Some(&device.audio_device_id),
451     )?;
452 
453     Ok(audio_unit)
454 }
455 
456 impl Device {
457     #[allow(clippy::cast_ptr_alignment)]
458     #[allow(clippy::while_immutable_condition)]
459     #[allow(clippy::float_cmp)]
build_input_stream_raw<D, E>( &self, config: &StreamConfig, sample_format: SampleFormat, mut data_callback: D, mut error_callback: E, ) -> Result<Stream, BuildStreamError> where D: FnMut(&Data, &InputCallbackInfo) + Send + 'static, E: FnMut(StreamError) + Send + 'static,460     fn build_input_stream_raw<D, E>(
461         &self,
462         config: &StreamConfig,
463         sample_format: SampleFormat,
464         mut data_callback: D,
465         mut error_callback: E,
466     ) -> Result<Stream, BuildStreamError>
467     where
468         D: FnMut(&Data, &InputCallbackInfo) + Send + 'static,
469         E: FnMut(StreamError) + Send + 'static,
470     {
471         // The scope and element for working with a device's input stream.
472         let scope = Scope::Output;
473         let element = Element::Input;
474 
475         // Check whether or not we need to change the device sample rate to suit the one specified for the stream.
476         unsafe {
477             // Get the current sample rate.
478             let mut property_address = AudioObjectPropertyAddress {
479                 mSelector: kAudioDevicePropertyNominalSampleRate,
480                 mScope: kAudioObjectPropertyScopeGlobal,
481                 mElement: kAudioObjectPropertyElementMaster,
482             };
483             let sample_rate: f64 = 0.0;
484             let data_size = mem::size_of::<f64>() as u32;
485             let status = AudioObjectGetPropertyData(
486                 self.audio_device_id,
487                 &property_address as *const _,
488                 0,
489                 null(),
490                 &data_size as *const _ as *mut _,
491                 &sample_rate as *const _ as *mut _,
492             );
493             coreaudio::Error::from_os_status(status)?;
494 
495             // If the requested sample rate is different to the device sample rate, update the device.
496             if sample_rate as u32 != config.sample_rate.0 {
497                 // Get available sample rate ranges.
498                 property_address.mSelector = kAudioDevicePropertyAvailableNominalSampleRates;
499                 let data_size = 0u32;
500                 let status = AudioObjectGetPropertyDataSize(
501                     self.audio_device_id,
502                     &property_address as *const _,
503                     0,
504                     null(),
505                     &data_size as *const _ as *mut _,
506                 );
507                 coreaudio::Error::from_os_status(status)?;
508                 let n_ranges = data_size as usize / mem::size_of::<AudioValueRange>();
509                 let mut ranges: Vec<u8> = vec![];
510                 ranges.reserve_exact(data_size as usize);
511                 let status = AudioObjectGetPropertyData(
512                     self.audio_device_id,
513                     &property_address as *const _,
514                     0,
515                     null(),
516                     &data_size as *const _ as *mut _,
517                     ranges.as_mut_ptr() as *mut _,
518                 );
519                 coreaudio::Error::from_os_status(status)?;
520                 let ranges: *mut AudioValueRange = ranges.as_mut_ptr() as *mut _;
521                 let ranges: &'static [AudioValueRange] = slice::from_raw_parts(ranges, n_ranges);
522 
523                 // Now that we have the available ranges, pick the one matching the desired rate.
524                 let sample_rate = config.sample_rate.0;
525                 let maybe_index = ranges.iter().position(|r| {
526                     r.mMinimum as u32 == sample_rate && r.mMaximum as u32 == sample_rate
527                 });
528                 let range_index = match maybe_index {
529                     None => return Err(BuildStreamError::StreamConfigNotSupported),
530                     Some(i) => i,
531                 };
532 
533                 // Update the property selector to specify the nominal sample rate.
534                 property_address.mSelector = kAudioDevicePropertyNominalSampleRate;
535 
536                 // Setting the sample rate of a device is an asynchronous process in coreaudio.
537                 //
538                 // Thus, we are required to set a `listener` so that we may be notified when the
539                 // change occurs.
540                 unsafe extern "C" fn rate_listener(
541                     device_id: AudioObjectID,
542                     _n_addresses: u32,
543                     _properties: *const AudioObjectPropertyAddress,
544                     rate_ptr: *mut ::std::os::raw::c_void,
545                 ) -> OSStatus {
546                     let rate_ptr: *const f64 = rate_ptr as *const _;
547                     let data_size = mem::size_of::<f64>();
548                     let property_address = AudioObjectPropertyAddress {
549                         mSelector: kAudioDevicePropertyNominalSampleRate,
550                         mScope: kAudioObjectPropertyScopeGlobal,
551                         mElement: kAudioObjectPropertyElementMaster,
552                     };
553                     AudioObjectGetPropertyData(
554                         device_id,
555                         &property_address as *const _,
556                         0,
557                         null(),
558                         &data_size as *const _ as *mut _,
559                         rate_ptr as *const _ as *mut _,
560                     )
561                 }
562 
563                 // Add our sample rate change listener callback.
564                 let reported_rate: f64 = 0.0;
565                 let status = AudioObjectAddPropertyListener(
566                     self.audio_device_id,
567                     &property_address as *const _,
568                     Some(rate_listener),
569                     &reported_rate as *const _ as *mut _,
570                 );
571                 coreaudio::Error::from_os_status(status)?;
572 
573                 // Finally, set the sample rate.
574                 let sample_rate = sample_rate as f64;
575                 let status = AudioObjectSetPropertyData(
576                     self.audio_device_id,
577                     &property_address as *const _,
578                     0,
579                     null(),
580                     data_size,
581                     &ranges[range_index] as *const _ as *const _,
582                 );
583                 coreaudio::Error::from_os_status(status)?;
584 
585                 // Wait for the reported_rate to change.
586                 //
587                 // This should not take longer than a few ms, but we timeout after 1 sec just in case.
588                 //
589                 // WARNING: a reference to reported_rate is unsafely captured above,
590                 // and the loop below assumes it can change - but compiler does not know that!
591                 //
592                 let timer = ::std::time::Instant::now();
593                 while sample_rate != reported_rate {
594                     if timer.elapsed() > Duration::from_secs(1) {
595                         let description =
596                             "timeout waiting for sample rate update for device".into();
597                         let err = BackendSpecificError { description };
598                         return Err(err.into());
599                     }
600                     thread::sleep(Duration::from_millis(5));
601                 }
602 
603                 // Remove the `rate_listener` callback.
604                 let status = AudioObjectRemovePropertyListener(
605                     self.audio_device_id,
606                     &property_address as *const _,
607                     Some(rate_listener),
608                     &reported_rate as *const _ as *mut _,
609                 );
610                 coreaudio::Error::from_os_status(status)?;
611             }
612         }
613 
614         let mut audio_unit = audio_unit_from_device(self, true)?;
615 
616         // Set the stream in interleaved mode.
617         let asbd = asbd_from_config(config, sample_format);
618         audio_unit.set_property(kAudioUnitProperty_StreamFormat, scope, element, Some(&asbd))?;
619 
620         // Set the buffersize
621         match config.buffer_size {
622             BufferSize::Fixed(v) => {
623                 let buffer_size_range = get_io_buffer_frame_size_range(&audio_unit)?;
624                 match buffer_size_range {
625                     SupportedBufferSize::Range { min, max } => {
626                         if v >= min && v <= max {
627                             audio_unit.set_property(
628                                 kAudioDevicePropertyBufferFrameSize,
629                                 scope,
630                                 element,
631                                 Some(&v),
632                             )?
633                         } else {
634                             return Err(BuildStreamError::StreamConfigNotSupported);
635                         }
636                     }
637                     SupportedBufferSize::Unknown => (),
638                 }
639             }
640             BufferSize::Default => (),
641         }
642 
643         // Register the callback that is being called by coreaudio whenever it needs data to be
644         // fed to the audio buffer.
645         let bytes_per_channel = sample_format.sample_size();
646         let sample_rate = config.sample_rate;
647         type Args = render_callback::Args<data::Raw>;
648         audio_unit.set_input_callback(move |args: Args| unsafe {
649             let ptr = (*args.data.data).mBuffers.as_ptr() as *const AudioBuffer;
650             let len = (*args.data.data).mNumberBuffers as usize;
651             let buffers: &[AudioBuffer] = slice::from_raw_parts(ptr, len);
652 
653             // TODO: Perhaps loop over all buffers instead?
654             let AudioBuffer {
655                 mNumberChannels: channels,
656                 mDataByteSize: data_byte_size,
657                 mData: data,
658             } = buffers[0];
659 
660             let data = data as *mut ();
661             let len = (data_byte_size as usize / bytes_per_channel) as usize;
662             let data = Data::from_parts(data, len, sample_format);
663 
664             // TODO: Need a better way to get delay, for now we assume a double-buffer offset.
665             let callback = match host_time_to_stream_instant(args.time_stamp.mHostTime) {
666                 Err(err) => {
667                     error_callback(err.into());
668                     return Err(());
669                 }
670                 Ok(cb) => cb,
671             };
672             let buffer_frames = len / channels as usize;
673             let delay = frames_to_duration(buffer_frames, sample_rate);
674             let capture = callback
675                 .sub(delay)
676                 .expect("`capture` occurs before origin of alsa `StreamInstant`");
677             let timestamp = crate::InputStreamTimestamp { callback, capture };
678 
679             let info = InputCallbackInfo { timestamp };
680             data_callback(&data, &info);
681             Ok(())
682         })?;
683 
684         audio_unit.start()?;
685 
686         Ok(Stream::new(StreamInner {
687             playing: true,
688             audio_unit,
689             device_id: self.audio_device_id,
690         }))
691     }
692 
build_output_stream_raw<D, E>( &self, config: &StreamConfig, sample_format: SampleFormat, mut data_callback: D, mut error_callback: E, ) -> Result<Stream, BuildStreamError> where D: FnMut(&mut Data, &OutputCallbackInfo) + Send + 'static, E: FnMut(StreamError) + Send + 'static,693     fn build_output_stream_raw<D, E>(
694         &self,
695         config: &StreamConfig,
696         sample_format: SampleFormat,
697         mut data_callback: D,
698         mut error_callback: E,
699     ) -> Result<Stream, BuildStreamError>
700     where
701         D: FnMut(&mut Data, &OutputCallbackInfo) + Send + 'static,
702         E: FnMut(StreamError) + Send + 'static,
703     {
704         let mut audio_unit = audio_unit_from_device(self, false)?;
705 
706         // The scope and element for working with a device's output stream.
707         let scope = Scope::Input;
708         let element = Element::Output;
709 
710         // Set the stream in interleaved mode.
711         let asbd = asbd_from_config(config, sample_format);
712         audio_unit.set_property(kAudioUnitProperty_StreamFormat, scope, element, Some(&asbd))?;
713 
714         // Set the buffersize
715         match config.buffer_size {
716             BufferSize::Fixed(v) => {
717                 let buffer_size_range = get_io_buffer_frame_size_range(&audio_unit)?;
718                 match buffer_size_range {
719                     SupportedBufferSize::Range { min, max } => {
720                         if v >= min && v <= max {
721                             audio_unit.set_property(
722                                 kAudioDevicePropertyBufferFrameSize,
723                                 scope,
724                                 element,
725                                 Some(&v),
726                             )?
727                         } else {
728                             return Err(BuildStreamError::StreamConfigNotSupported);
729                         }
730                     }
731                     SupportedBufferSize::Unknown => (),
732                 }
733             }
734             BufferSize::Default => (),
735         }
736 
737         // Register the callback that is being called by coreaudio whenever it needs data to be
738         // fed to the audio buffer.
739         let bytes_per_channel = sample_format.sample_size();
740         let sample_rate = config.sample_rate;
741         type Args = render_callback::Args<data::Raw>;
742         audio_unit.set_render_callback(move |args: Args| unsafe {
743             // If `run()` is currently running, then a callback will be available from this list.
744             // Otherwise, we just fill the buffer with zeroes and return.
745 
746             let AudioBuffer {
747                 mNumberChannels: channels,
748                 mDataByteSize: data_byte_size,
749                 mData: data,
750             } = (*args.data.data).mBuffers[0];
751 
752             let data = data as *mut ();
753             let len = (data_byte_size as usize / bytes_per_channel) as usize;
754             let mut data = Data::from_parts(data, len, sample_format);
755 
756             let callback = match host_time_to_stream_instant(args.time_stamp.mHostTime) {
757                 Err(err) => {
758                     error_callback(err.into());
759                     return Err(());
760                 }
761                 Ok(cb) => cb,
762             };
763             // TODO: Need a better way to get delay, for now we assume a double-buffer offset.
764             let buffer_frames = len / channels as usize;
765             let delay = frames_to_duration(buffer_frames, sample_rate);
766             let playback = callback
767                 .add(delay)
768                 .expect("`playback` occurs beyond representation supported by `StreamInstant`");
769             let timestamp = crate::OutputStreamTimestamp { callback, playback };
770 
771             let info = OutputCallbackInfo { timestamp };
772             data_callback(&mut data, &info);
773             Ok(())
774         })?;
775 
776         audio_unit.start()?;
777 
778         Ok(Stream::new(StreamInner {
779             playing: true,
780             audio_unit,
781             device_id: self.audio_device_id,
782         }))
783     }
784 }
785 
786 pub struct Stream {
787     inner: RefCell<StreamInner>,
788 }
789 
790 impl Stream {
new(inner: StreamInner) -> Self791     fn new(inner: StreamInner) -> Self {
792         Self {
793             inner: RefCell::new(inner),
794         }
795     }
796 }
797 
798 impl StreamTrait for Stream {
play(&self) -> Result<(), PlayStreamError>799     fn play(&self) -> Result<(), PlayStreamError> {
800         let mut stream = self.inner.borrow_mut();
801 
802         if !stream.playing {
803             if let Err(e) = stream.audio_unit.start() {
804                 let description = format!("{}", e);
805                 let err = BackendSpecificError { description };
806                 return Err(err.into());
807             }
808             stream.playing = true;
809         }
810         Ok(())
811     }
812 
pause(&self) -> Result<(), PauseStreamError>813     fn pause(&self) -> Result<(), PauseStreamError> {
814         let mut stream = self.inner.borrow_mut();
815 
816         if stream.playing {
817             if let Err(e) = stream.audio_unit.stop() {
818                 let description = format!("{}", e);
819                 let err = BackendSpecificError { description };
820                 return Err(err.into());
821             }
822 
823             stream.playing = false;
824         }
825         Ok(())
826     }
827 }
828 
get_io_buffer_frame_size_range( audio_unit: &AudioUnit, ) -> Result<SupportedBufferSize, coreaudio::Error>829 fn get_io_buffer_frame_size_range(
830     audio_unit: &AudioUnit,
831 ) -> Result<SupportedBufferSize, coreaudio::Error> {
832     let buffer_size_range: AudioValueRange = audio_unit.get_property(
833         kAudioDevicePropertyBufferFrameSizeRange,
834         Scope::Global,
835         Element::Output,
836     )?;
837 
838     Ok(SupportedBufferSize::Range {
839         min: buffer_size_range.mMinimum as u32,
840         max: buffer_size_range.mMaximum as u32,
841     })
842 }
843