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