diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 6ca25437..8f0f079f 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -817,14 +817,14 @@ fn get_default_device_id(devtype: DeviceType) -> std::result::Result Vec { +fn audiounit_convert_channel_layout(layout: &AudioChannelLayout) -> Result> { if layout.mChannelLayoutTag != kAudioChannelLayoutTag_UseChannelDescriptions { // kAudioChannelLayoutTag_UseChannelBitmap // kAudioChannelLayoutTag_Mono // kAudioChannelLayoutTag_Stereo // .... cubeb_log!("Only handling UseChannelDescriptions for now.\n"); - return Vec::new(); + return Err(Error::error()); } let channel_descriptions = unsafe { @@ -840,10 +840,10 @@ fn audiounit_convert_channel_layout(layout: &AudioChannelLayout) -> Vec Vec { +fn audiounit_get_preferred_channel_layout(output_unit: AudioUnit) -> Result> { let mut rv = NO_ERR; let mut size: usize = 0; rv = audio_unit_get_property_info( @@ -859,7 +859,7 @@ fn audiounit_get_preferred_channel_layout(output_unit: AudioUnit) -> Vec 0); @@ -877,7 +877,7 @@ fn audiounit_get_preferred_channel_layout(output_unit: AudioUnit) -> Vec Vec Vec { +fn audiounit_get_current_channel_layout(output_unit: AudioUnit) -> Result> { let mut rv = NO_ERR; let mut size: usize = 0; rv = audio_unit_get_property_info( @@ -901,8 +901,7 @@ fn audiounit_get_current_channel_layout(output_unit: AudioUnit) -> Vec 0); @@ -920,7 +919,7 @@ fn audiounit_get_current_channel_layout(output_unit: AudioUnit) -> Vec CoreStreamData<'ctx> { e })?; - // XXX - let device_layout = if using_voice_processing_unit { - let mut channels = Vec::with_capacity(output_hw_desc.mChannelsPerFrame as usize); - match output_hw_desc.mChannelsPerFrame { - 1 => channels.push(mixer::Channel::FrontCenter), - _ => { - channels.push(mixer::Channel::FrontLeft); - channels.push(mixer::Channel::FrontRight); + let device_layout = audiounit_get_current_channel_layout(self.unit) + .or_else(|_| { + // The VoiceProcessingIO unit is known to not support + // kAudioUnitProperty_AudioChannelLayout queries. If we're using + // VoiceProcessingIO, try standing up a regular AudioUnit and query that. + if !using_voice_processing_unit { + return Err(Error::error()); } - } - channels - } else { - audiounit_get_current_channel_layout(self.unit) - }; + cubeb_log!( + "({:p}) Could not get current channel layout for vpio unit. \ + Retrying with a dedicated unit.", + self.stm_ptr + ); + let mut blank_in_dev_info = self.input_device.clone(); + blank_in_dev_info.flags = device_flags::DEV_UNKNOWN; + let mut dedicated_unit = create_audiounit(&blank_in_dev_info, &self.output_device)?; + let res = audiounit_get_current_channel_layout(dedicated_unit).or_else(|_| { + cubeb_log!( + "({:p}) Could not get current channel layout for dedicated unit. \ + Trying to get preferred channel layout with the dedicated unit.", + self.stm_ptr + ); + audiounit_get_preferred_channel_layout(dedicated_unit) + }); + audio_unit_uninitialize(dedicated_unit); + dispose_audio_unit(dedicated_unit); + dedicated_unit = ptr::null_mut(); + res + }) + .or_else(|_| { + // The kAudioUnitProperty_AudioChannelLayout property isn't known before + // macOS 10.12, attempt another method. + cubeb_log!( + "({:p}) Could not get current channel layout. Trying preferred channel layout.", + self.stm_ptr + ); + audiounit_get_preferred_channel_layout(self.unit) + }) + .unwrap_or_else(|_| { + cubeb_log!( + "({:p}) Could not get any channel layout. Defaulting to no channels.", + self.stm_ptr + ); + Vec::new() + }); + + cubeb_log!( + "({:p} Using output device channel layout {:?}", + self.stm_ptr, + device_layout + ); // The mixer will be set up when // 1. using aggregate device whose input device has output channels diff --git a/src/backend/tests/api.rs b/src/backend/tests/api.rs index 1ee450a1..dd3f94f3 100644 --- a/src/backend/tests/api.rs +++ b/src/backend/tests/api.rs @@ -700,7 +700,7 @@ fn test_convert_channel_layout() { } let layout_ref = unsafe { &(*(&layout as *const TestLayout as *const AudioChannelLayout)) }; assert_eq!( - &audiounit_convert_channel_layout(layout_ref), + &audiounit_convert_channel_layout(layout_ref).unwrap(), expected_layout ); } @@ -711,7 +711,9 @@ fn test_convert_channel_layout() { #[test] fn test_get_preferred_channel_layout_output() { match test_get_default_audiounit(Scope::Output) { - Some(unit) => assert!(!audiounit_get_preferred_channel_layout(unit.get_inner()).is_empty()), + Some(unit) => assert!(!audiounit_get_preferred_channel_layout(unit.get_inner()) + .unwrap() + .is_empty()), None => println!("No output audiounit for test."), } } @@ -721,7 +723,9 @@ fn test_get_preferred_channel_layout_output() { #[test] fn test_get_current_channel_layout_output() { match test_get_default_audiounit(Scope::Output) { - Some(unit) => assert!(!audiounit_get_current_channel_layout(unit.get_inner()).is_empty()), + Some(unit) => assert!(!audiounit_get_current_channel_layout(unit.get_inner()) + .unwrap() + .is_empty()), None => println!("No output audiounit for test."), } }