diff --git a/.cargo/config.in b/.cargo/config.in index 1c4008d9a49a..bc6741b3f3be 100644 --- a/.cargo/config.in +++ b/.cargo/config.in @@ -35,7 +35,7 @@ rev = "df4dc0288b07b865440f4c7e41ca49ca9ccffc63" [source."https://github.com/mozilla/cubeb-coreaudio-rs"] git = "https://github.com/mozilla/cubeb-coreaudio-rs" replace-with = "vendored-sources" -rev = "e012b2151fb6f0ffd50e91baa7756e77a3c416d9" +rev = "39f7e696c11ff45503b50a49a36cd9f39900c27b" [source."https://github.com/mozilla/audioipc-2"] git = "https://github.com/mozilla/audioipc-2" diff --git a/Cargo.lock b/Cargo.lock index 7ed4c0b49a76..b3338e203ed5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -844,7 +844,7 @@ dependencies = [ [[package]] name = "coreaudio-sys-utils" version = "0.1.0" -source = "git+https://github.com/mozilla/cubeb-coreaudio-rs?rev=e012b2151fb6f0ffd50e91baa7756e77a3c416d9#e012b2151fb6f0ffd50e91baa7756e77a3c416d9" +source = "git+https://github.com/mozilla/cubeb-coreaudio-rs?rev=39f7e696c11ff45503b50a49a36cd9f39900c27b#39f7e696c11ff45503b50a49a36cd9f39900c27b" dependencies = [ "core-foundation-sys", "coreaudio-sys", @@ -1145,7 +1145,7 @@ dependencies = [ [[package]] name = "cubeb-coreaudio" version = "0.1.0" -source = "git+https://github.com/mozilla/cubeb-coreaudio-rs?rev=e012b2151fb6f0ffd50e91baa7756e77a3c416d9#e012b2151fb6f0ffd50e91baa7756e77a3c416d9" +source = "git+https://github.com/mozilla/cubeb-coreaudio-rs?rev=39f7e696c11ff45503b50a49a36cd9f39900c27b#39f7e696c11ff45503b50a49a36cd9f39900c27b" dependencies = [ "atomic", "audio-mixer", diff --git a/third_party/rust/cubeb-coreaudio/.cargo-checksum.json b/third_party/rust/cubeb-coreaudio/.cargo-checksum.json index 1686cb80d116..98a37d441e49 100644 --- a/third_party/rust/cubeb-coreaudio/.cargo-checksum.json +++ b/third_party/rust/cubeb-coreaudio/.cargo-checksum.json @@ -1 +1 @@ -{"files":{".circleci/config.yml":"7f3dc865105ca8f33965a7958b1fe2e627ae2d5a703f3b2a4ab6e2e796018597",".editorconfig":"4e53b182bcc78b83d7e1b5c03efa14d22d4955c4ed2514d1ba4e99c1eb1a50ba",".githooks/pre-push":"8b8b26544cd56f54c0c33812551f786bb25cb08c86dbfeb6bf3daad881c826a1",".github/workflows/test.yml":"aa1998a3b104ad131805ca3513832cef3f65300192824f8b1efc9a5a0cc108f6",".travis.yml":"dc07bac53f70f16c9bdf52264bdc58500ae6018c1b4c567bc7642f6b4ca3cc35","Cargo.toml":"4671b9a0fbf47773cf01e40592ac5b5fe5cd93722f425f249e6c8b432ce3871c","LICENSE":"6e6f56aff5bbf3cbc60747e152fb1a719bd0716aaf6d711c554f57d92e96297c","README.md":"0007782a05a5330f739ad789c19c82562c82e32386b0447000fc72c0d48405bc","build-audiounit-rust-in-cubeb.sh":"d228a05985dcd02ec1ecac66a2b64dae5a530804a25a7054ccc95905aedfb7ef","install_git_hook.sh":"d38c8e51e636f6b90b489621ac34ccd1d1b1f40dccce3d178ed1da1c5068f16d","install_rustfmt_clippy.sh":"4ae90d8dcb9757cb3ae4ae142ef80e5377c0dde61c63f4a3c32418646e80ca7b","run_device_tests.sh":"cac9a7d588c2be0efa842c15d24c8cf0573bc9f9d73011662ba764dc9f6245e8","run_sanitizers.sh":"8828c73439dfd540cd21fc713c4a1011ec05baca6f282f285743f310ace39563","run_tests.sh":"916a7ae4a406d2274417d6eca939a878db5adcb6144e5680d9d148bf90178f1c","src/backend/aggregate_device.rs":"6faa5ed4f4ab378fd452105a655cd64d2459edec0cf9b3d70375df22cd79c7e8","src/backend/auto_release.rs":"050fdcee74cf46b9a8a85a877e166d72a853d33220f59cf734cbb6ea09daa441","src/backend/buffer_manager.rs":"12490043d978d3902927e739cf33905a3c756888a8ff991c2bae4c3792db02fd","src/backend/device_property.rs":"2a63837b98b9b6bfb314b4aa6dce919412b71e13e18c7b8f3477aa1482f70b29","src/backend/mixer.rs":"949c34927ba72b3365bc733a63b2f7950aef707ee08363f97242a4de6b7d4818","src/backend/mod.rs":"a4ea99bb92e42471db44801cec83833fa17c1b10bb606366e3cfdadaff4325dd","src/backend/resampler.rs":"8641c672d00f77be287d64f6cd4a2b2cd36f8630e2ded1eff6b39834b1b7ddc3","src/backend/tests/aggregate_device.rs":"d0b863fb67d3533501b3266f9fa944ec872efb02a457728b2fe7e92c47abb261","src/backend/tests/api.rs":"a6cd4e7c89be3fa820402714bbd1d792404fe2915928f70d626f887c9e2d7685","src/backend/tests/backlog.rs":"3b189a7e036543c467cc242af0ed3332721179ee2b1c8847a6db563546f1ac52","src/backend/tests/device_change.rs":"97555244a8081251f1447c6a677609d1e91f33c9c0f4fb3f8a4082005c68ae0c","src/backend/tests/device_property.rs":"373f76d3bee83b263db3f02be3b94b408bdf852d84e4b5153273fda34b11a374","src/backend/tests/interfaces.rs":"b48d646b6ea06ca1bf7ce4b0ada59a164bc094e40b0cd66bb63b269f9032b022","src/backend/tests/manual.rs":"8d485a6666a3f4518b03e39dab80bf2acfd760af2d2f43bad99023cb135b38ca","src/backend/tests/mod.rs":"8dba770023d7f9c4228f0e11915347f0e07da5fd818e3ee4478c4b197af9aa2a","src/backend/tests/parallel.rs":"f9e1883660d6146b6e5075806561f5f689810e25c5e7764dfd28c9b939821a49","src/backend/tests/tone.rs":"779cc14fc2a362bf7f26ce66ad70c0639501176175655a99b7fefb3c59d56c7a","src/backend/tests/utils.rs":"38f78f79758d43ca1b8ec41dd4b918c72eaacc4da7e94cf3b2629ba621497e55","src/backend/utils.rs":"6c3ffbcd602e6cc9f56deb9ecb07b2eef2e6f074ef924178e466f380aae5c595","src/capi.rs":"21b66b70545bf04ec719928004d1d9adb45b24ced51288f5b2993d79aaf78f5f","src/lib.rs":"5e586d45cd6b3722f0a6736d9252593299269817a153eef1930a5fb9bfbb56f5","todo.md":"e79e442241c5346737e7d52a9a7a1f824d2657855e8c44b42840f85956d8bfe7"},"package":null} \ No newline at end of file +{"files":{".circleci/config.yml":"7f3dc865105ca8f33965a7958b1fe2e627ae2d5a703f3b2a4ab6e2e796018597",".editorconfig":"4e53b182bcc78b83d7e1b5c03efa14d22d4955c4ed2514d1ba4e99c1eb1a50ba",".githooks/pre-push":"8b8b26544cd56f54c0c33812551f786bb25cb08c86dbfeb6bf3daad881c826a1",".github/workflows/test.yml":"aa1998a3b104ad131805ca3513832cef3f65300192824f8b1efc9a5a0cc108f6",".travis.yml":"dc07bac53f70f16c9bdf52264bdc58500ae6018c1b4c567bc7642f6b4ca3cc35","Cargo.toml":"4671b9a0fbf47773cf01e40592ac5b5fe5cd93722f425f249e6c8b432ce3871c","LICENSE":"6e6f56aff5bbf3cbc60747e152fb1a719bd0716aaf6d711c554f57d92e96297c","README.md":"0007782a05a5330f739ad789c19c82562c82e32386b0447000fc72c0d48405bc","build-audiounit-rust-in-cubeb.sh":"d228a05985dcd02ec1ecac66a2b64dae5a530804a25a7054ccc95905aedfb7ef","install_git_hook.sh":"d38c8e51e636f6b90b489621ac34ccd1d1b1f40dccce3d178ed1da1c5068f16d","install_rustfmt_clippy.sh":"4ae90d8dcb9757cb3ae4ae142ef80e5377c0dde61c63f4a3c32418646e80ca7b","run_device_tests.sh":"cac9a7d588c2be0efa842c15d24c8cf0573bc9f9d73011662ba764dc9f6245e8","run_sanitizers.sh":"8828c73439dfd540cd21fc713c4a1011ec05baca6f282f285743f310ace39563","run_tests.sh":"916a7ae4a406d2274417d6eca939a878db5adcb6144e5680d9d148bf90178f1c","src/backend/aggregate_device.rs":"e822b4496e2ea5c6e1a288c6e92f57e598abf67cb0bdff813f859d57c63be5f9","src/backend/auto_release.rs":"050fdcee74cf46b9a8a85a877e166d72a853d33220f59cf734cbb6ea09daa441","src/backend/buffer_manager.rs":"12490043d978d3902927e739cf33905a3c756888a8ff991c2bae4c3792db02fd","src/backend/device_property.rs":"2a63837b98b9b6bfb314b4aa6dce919412b71e13e18c7b8f3477aa1482f70b29","src/backend/mixer.rs":"949c34927ba72b3365bc733a63b2f7950aef707ee08363f97242a4de6b7d4818","src/backend/mod.rs":"922d09452d9900b2578683cf47389d824d29bcb8a222f194f0d69cfbb1d28f76","src/backend/resampler.rs":"8641c672d00f77be287d64f6cd4a2b2cd36f8630e2ded1eff6b39834b1b7ddc3","src/backend/tests/aggregate_device.rs":"7542cbb1c82398d00a5cba5b335842c517af2cda887946ebb5aaf512fd06b527","src/backend/tests/api.rs":"6eafca24d61729cad108b34c01e339130f9c479ebbe1026dc9c65778c1d9cfe0","src/backend/tests/backlog.rs":"3b189a7e036543c467cc242af0ed3332721179ee2b1c8847a6db563546f1ac52","src/backend/tests/device_change.rs":"97555244a8081251f1447c6a677609d1e91f33c9c0f4fb3f8a4082005c68ae0c","src/backend/tests/device_property.rs":"373f76d3bee83b263db3f02be3b94b408bdf852d84e4b5153273fda34b11a374","src/backend/tests/interfaces.rs":"b48d646b6ea06ca1bf7ce4b0ada59a164bc094e40b0cd66bb63b269f9032b022","src/backend/tests/manual.rs":"8d485a6666a3f4518b03e39dab80bf2acfd760af2d2f43bad99023cb135b38ca","src/backend/tests/mod.rs":"8dba770023d7f9c4228f0e11915347f0e07da5fd818e3ee4478c4b197af9aa2a","src/backend/tests/parallel.rs":"f9e1883660d6146b6e5075806561f5f689810e25c5e7764dfd28c9b939821a49","src/backend/tests/tone.rs":"779cc14fc2a362bf7f26ce66ad70c0639501176175655a99b7fefb3c59d56c7a","src/backend/tests/utils.rs":"3c430e519c0e7a17dda6b57c110fab725a846da39606fd99274bad20a637cf35","src/backend/utils.rs":"6c3ffbcd602e6cc9f56deb9ecb07b2eef2e6f074ef924178e466f380aae5c595","src/capi.rs":"21b66b70545bf04ec719928004d1d9adb45b24ced51288f5b2993d79aaf78f5f","src/lib.rs":"5e586d45cd6b3722f0a6736d9252593299269817a153eef1930a5fb9bfbb56f5","todo.md":"efc1f012eb9a331a040cad4ac03aa79307f25885f71b6fb38f3ad7af8d7d515c"},"package":null} \ No newline at end of file diff --git a/third_party/rust/cubeb-coreaudio/src/backend/aggregate_device.rs b/third_party/rust/cubeb-coreaudio/src/backend/aggregate_device.rs index 1e89cf5627b4..5dc4a17fbfd4 100644 --- a/third_party/rust/cubeb-coreaudio/src/backend/aggregate_device.rs +++ b/third_party/rust/cubeb-coreaudio/src/backend/aggregate_device.rs @@ -78,7 +78,7 @@ impl AggregateDevice { }); Self::set_sub_devices_sync(device_id, input_id, output_id)?; - Self::set_master_device(device_id)?; + Self::set_master_device(device_id, output_id)?; Self::activate_clock_drift_compensation(device_id)?; Self::workaround_for_airpod(device_id, input_id, output_id)?; @@ -466,18 +466,27 @@ impl AggregateDevice { } } - pub fn set_master_device(device_id: AudioDeviceID) -> std::result::Result<(), Error> { + pub fn set_master_device( + device_id: AudioDeviceID, + primary_id: AudioDeviceID, + ) -> std::result::Result<(), Error> { assert_ne!(device_id, kAudioObjectUnknown); + assert_ne!(primary_id, kAudioObjectUnknown); + + cubeb_log!( + "Set master device of the aggregate device {} to device {}", + device_id, + primary_id + ); + let address = AudioObjectPropertyAddress { mSelector: kAudioAggregateDevicePropertyMasterSubDevice, mScope: kAudioObjectPropertyScopeGlobal, mElement: kAudioObjectPropertyElementMaster, }; - // Master become the 1st output sub device - let output_device_id = audiounit_get_default_device_id(DeviceType::OUTPUT); - assert_ne!(output_device_id, kAudioObjectUnknown); - let output_sub_devices = Self::get_sub_devices(output_device_id)?; + // Master become the 1st sub device of the primary device + let output_sub_devices = Self::get_sub_devices(primary_id)?; assert!(!output_sub_devices.is_empty()); let master_sub_device_uid = get_device_global_uid(output_sub_devices[0]).unwrap(); let master_sub_device = master_sub_device_uid.get_raw(); diff --git a/third_party/rust/cubeb-coreaudio/src/backend/mod.rs b/third_party/rust/cubeb-coreaudio/src/backend/mod.rs index ea638652f8f8..07f504a10137 100644 --- a/third_party/rust/cubeb-coreaudio/src/backend/mod.rs +++ b/third_party/rust/cubeb-coreaudio/src/backend/mod.rs @@ -189,31 +189,22 @@ fn clamp_latency(latency_frames: u32) -> u32 { ) } -fn create_device_info(id: AudioDeviceID, devtype: DeviceType) -> Result { - assert_ne!(id, kAudioObjectSystemObject); +fn create_device_info(devid: AudioDeviceID, devtype: DeviceType) -> Option { + assert_ne!(devid, kAudioObjectSystemObject); - let mut info = device_info { - id, - flags: match devtype { - DeviceType::INPUT => device_flags::DEV_INPUT, - DeviceType::OUTPUT => device_flags::DEV_OUTPUT, - _ => panic!("Only accept input or output type"), - }, + let mut flags = match devtype { + DeviceType::INPUT => device_flags::DEV_INPUT, + DeviceType::OUTPUT => device_flags::DEV_OUTPUT, + _ => panic!("Only accept input or output type"), }; - let default_device_id = audiounit_get_default_device_id(devtype); - if default_device_id == kAudioObjectUnknown { - cubeb_log!("Could not find default audio device for {:?}", devtype); - return Err(Error::error()); + if devid == kAudioObjectUnknown { + cubeb_log!("Use the system default device"); + flags |= device_flags::DEV_SELECTED_DEFAULT; + get_default_device(devtype).map(|id| device_info { id, flags }) + } else { + Some(device_info { id: devid, flags }) } - - if id == kAudioObjectUnknown { - info.id = default_device_id; - cubeb_log!("Creating a default device info."); - info.flags |= device_flags::DEV_SELECTED_DEFAULT; - } - - Ok(info) } fn create_stream_description(stream_params: &StreamParams) -> Result { @@ -443,6 +434,12 @@ extern "C" fn audiounit_input_callback( ptr::null_mut(), 0, ); + if outframes < 0 { + stm.stopped.store(true, Ordering::SeqCst); + stm.core_stream_data.stop_audiounits(); + stm.notify_state_changed(State::Error); + return handle; + } if outframes < total_input_frames { stm.draining.store(true, Ordering::SeqCst); } @@ -768,7 +765,21 @@ extern "C" fn audiounit_property_listener_callback( NO_ERR } -fn audiounit_get_default_device_id(devtype: DeviceType) -> AudioObjectID { +fn get_default_device(devtype: DeviceType) -> Option { + match get_default_device_id(devtype) { + Err(e) => { + cubeb_log!("Cannot get default {:?} device. Error: {}", devtype, e); + None + } + Ok(id) if id == kAudioObjectUnknown => { + cubeb_log!("Get an invalid default {:?} device: {}", devtype, id); + None + } + Ok(id) => Some(id), + } +} + +fn get_default_device_id(devtype: DeviceType) -> std::result::Result { let address = get_property_address( match devtype { DeviceType::INPUT => Property::HardwareDefaultInputDevice, @@ -780,13 +791,13 @@ fn audiounit_get_default_device_id(devtype: DeviceType) -> AudioObjectID { let mut devid: AudioDeviceID = kAudioObjectUnknown; let mut size = mem::size_of::(); - if audio_object_get_property_data(kAudioObjectSystemObject, &address, &mut size, &mut devid) - != NO_ERR - { - return kAudioObjectUnknown; + let status = + audio_object_get_property_data(kAudioObjectSystemObject, &address, &mut size, &mut devid); + if status == NO_ERR { + Ok(devid) + } else { + Err(status) } - - devid } fn audiounit_convert_channel_layout(layout: &AudioChannelLayout) -> Vec { @@ -1232,23 +1243,21 @@ fn convert_uint32_into_string(data: u32) -> CString { CString::new(buffer).unwrap_or(empty) } -fn audiounit_get_default_datasource_string(devtype: DeviceType) -> Result { - let id = audiounit_get_default_device_id(devtype); - if id == kAudioObjectUnknown { - return Err(Error::error()); - } - let data = get_device_source(id, devtype).unwrap_or(0); +fn get_device_source_string( + id: AudioDeviceID, + devtype: DeviceType, +) -> std::result::Result { + let data = get_device_source(id, devtype)?; Ok(convert_uint32_into_string(data)) } -fn get_channel_count(devid: AudioObjectID, devtype: DeviceType) -> Result { +fn get_channel_count( + devid: AudioObjectID, + devtype: DeviceType, +) -> std::result::Result { assert_ne!(devid, kAudioObjectUnknown); - let buffers = get_device_stream_configuration(devid, devtype).map_err(|e| { - cubeb_log!("Cannot get the stream configuration. Error: {}", e); - Error::error() - })?; - + let buffers = get_device_stream_configuration(devid, devtype)?; let mut count = 0; for buffer in buffers { count += buffer.mNumberChannels; @@ -1411,7 +1420,10 @@ fn create_cubeb_device_info( devid: AudioObjectID, devtype: DeviceType, ) -> Result { - let channels = get_channel_count(devid, devtype)?; + let channels = get_channel_count(devid, devtype).map_err(|e| { + cubeb_log!("Cannot get the channel count. Error: {}", e); + Error::error() + })?; if channels == 0 { // Invalid type for this device. return Err(Error::error()); @@ -1493,10 +1505,9 @@ fn create_cubeb_device_info( }; dev_info.state = ffi::CUBEB_DEVICE_STATE_ENABLED; - dev_info.preferred = if devid == audiounit_get_default_device_id(devtype) { - ffi::CUBEB_DEVICE_PREF_ALL - } else { - ffi::CUBEB_DEVICE_PREF_NONE + dev_info.preferred = match get_default_device(devtype) { + Some(id) if id == devid => ffi::CUBEB_DEVICE_PREF_ALL, + _ => ffi::CUBEB_DEVICE_PREF_NONE, }; dev_info.format = ffi::CUBEB_DEVICE_FMT_ALL; @@ -1960,19 +1971,17 @@ impl ContextOps for AudioUnitContext { } #[cfg(not(target_os = "ios"))] fn max_channel_count(&mut self) -> Result { - let device = audiounit_get_default_device_id(DeviceType::OUTPUT); - if device == kAudioObjectUnknown { - return Err(Error::error()); - } - - let format = get_device_stream_format(device, DeviceType::OUTPUT).map_err(|e| { - cubeb_log!( - "Cannot get the stream format of the default output device. Error: {}", - e - ); + let device = match get_default_device(DeviceType::OUTPUT) { + None => { + cubeb_log!("Could not get default output device"); + return Err(Error::error()); + } + Some(id) => id, + }; + get_channel_count(device, DeviceType::OUTPUT).map_err(|e| { + cubeb_log!("Cannot get the channel count. Error: {}", e); Error::error() - })?; - Ok(format.mChannelsPerFrame) + }) } #[cfg(target_os = "ios")] fn min_latency(&mut self, _params: StreamParams) -> Result { @@ -1980,11 +1989,13 @@ impl ContextOps for AudioUnitContext { } #[cfg(not(target_os = "ios"))] fn min_latency(&mut self, _params: StreamParams) -> Result { - let device = audiounit_get_default_device_id(DeviceType::OUTPUT); - if device == kAudioObjectUnknown { - cubeb_log!("Could not get default output device id."); - return Err(Error::error()); - } + let device = match get_default_device(DeviceType::OUTPUT) { + None => { + cubeb_log!("Could not get default output device"); + return Err(Error::error()); + } + Some(id) => id, + }; let range = get_device_buffer_frame_size_range(device, DeviceType::OUTPUT).map_err(|e| { @@ -2000,10 +2011,13 @@ impl ContextOps for AudioUnitContext { } #[cfg(not(target_os = "ios"))] fn preferred_sample_rate(&mut self) -> Result { - let device = audiounit_get_default_device_id(DeviceType::OUTPUT); - if device == kAudioObjectUnknown { - return Err(Error::error()); - } + let device = match get_default_device(DeviceType::OUTPUT) { + None => { + cubeb_log!("Could not get default output device"); + return Err(Error::error()); + } + Some(id) => id, + }; let rate = get_device_sample_rate(device, DeviceType::OUTPUT).map_err(|e| { cubeb_log!( "Cannot get the sample rate of the default output device. Error: {}", @@ -2091,11 +2105,14 @@ impl ContextOps for AudioUnitContext { } let in_stm_settings = if let Some(params) = input_stream_params { - let in_device = create_device_info(input_device as AudioDeviceID, DeviceType::INPUT) - .map_err(|e| { - cubeb_log!("Fail to create device info for input."); - e - })?; + let in_device = + match create_device_info(input_device as AudioDeviceID, DeviceType::INPUT) { + None => { + cubeb_log!("Fail to create device info for input"); + return Err(Error::error()); + } + Some(d) => d, + }; let stm_params = StreamParams::from(unsafe { *params.as_ptr() }); Some((stm_params, in_device)) } else { @@ -2103,11 +2120,14 @@ impl ContextOps for AudioUnitContext { }; let out_stm_settings = if let Some(params) = output_stream_params { - let out_device = create_device_info(output_device as AudioDeviceID, DeviceType::OUTPUT) - .map_err(|e| { - cubeb_log!("Fail to create device info for output."); - e - })?; + let out_device = + match create_device_info(output_device as AudioDeviceID, DeviceType::OUTPUT) { + None => { + cubeb_log!("Fail to create device info for output"); + return Err(Error::error()); + } + Some(d) => d, + }; let stm_params = StreamParams::from(unsafe { *params.as_ptr() }); Some((stm_params, out_device)) } else { @@ -3294,16 +3314,16 @@ impl<'ctx> AudioUnitStream<'ctx> { .flags .contains(device_flags::DEV_SELECTED_DEFAULT) { - self.core_stream_data.output_device = create_device_info(kAudioObjectUnknown, DeviceType::OUTPUT).map_err(|e| { + self.core_stream_data.output_device.id = get_default_device_id(DeviceType::OUTPUT).map_err(|e| { cubeb_log!( - "({:p}) Create output device info failed. This can happen when last media device is unplugged", - self.core_stream_data.stm_ptr + "({:p}) Cannot get default output device. Error: {}. This can happen when last media device is unplugged", + self.core_stream_data.stm_ptr, e ); - e + Error::error() })?; } - // Likewise, for the input seid + // Likewise, for the input side if self.core_stream_data.has_input() && self .core_stream_data @@ -3311,12 +3331,12 @@ impl<'ctx> AudioUnitStream<'ctx> { .flags .contains(device_flags::DEV_SELECTED_DEFAULT) { - self.core_stream_data.input_device = create_device_info(kAudioObjectUnknown, DeviceType::INPUT).map_err(|e| { + self.core_stream_data.input_device.id = get_default_device_id(DeviceType::INPUT).map_err(|e| { cubeb_log!( - "({:p}) Create input device info failed. This can happen when last media device is unplugged", - self.core_stream_data.stm_ptr + "({:p}) Cannot get default input device. Error: {}. This can happen when last media device is unplugged", + self.core_stream_data.stm_ptr, e ); - e + Error::error() })?; } @@ -3593,18 +3613,41 @@ impl<'ctx> StreamOps for AudioUnitStream<'ctx> { } #[cfg(not(target_os = "ios"))] fn current_device(&mut self) -> Result<&DeviceRef> { - let input_name = audiounit_get_default_datasource_string(DeviceType::INPUT); - let output_name = audiounit_get_default_datasource_string(DeviceType::OUTPUT); - if input_name.is_err() && output_name.is_err() { - return Err(Error::error()); - } + let output_device = match get_default_device(DeviceType::OUTPUT) { + None => { + cubeb_log!("Could not get default output device"); + return Err(Error::error()); + } + Some(id) => id, + }; + let output_name = + get_device_source_string(output_device, DeviceType::OUTPUT).map_err(|e| { + cubeb_log!( + "Could not get device source string for default output device. Error: {}", + e + ); + Error::error() + })?; + + let input_device = match get_default_device(DeviceType::INPUT) { + None => { + cubeb_log!("Could not get default input device"); + return Err(Error::error()); + } + Some(id) => id, + }; + let input_name = + get_device_source_string(input_device, DeviceType::INPUT).map_err(|e| { + cubeb_log!( + "Could not get device source string for default input device. Error: {}", + e + ); + Error::error() + })?; let mut device: Box = Box::new(ffi::cubeb_device::default()); - let input_name = input_name.unwrap_or_default(); device.input_name = input_name.into_raw(); - - let output_name = output_name.unwrap_or_default(); device.output_name = output_name.into_raw(); Ok(unsafe { DeviceRef::from_ptr(Box::into_raw(device)) }) diff --git a/third_party/rust/cubeb-coreaudio/src/backend/tests/aggregate_device.rs b/third_party/rust/cubeb-coreaudio/src/backend/tests/aggregate_device.rs index 9df3e55a9991..49726f2613da 100644 --- a/third_party/rust/cubeb-coreaudio/src/backend/tests/aggregate_device.rs +++ b/third_party/rust/cubeb-coreaudio/src/backend/tests/aggregate_device.rs @@ -66,7 +66,7 @@ fn test_aggregate_get_sub_devices_for_a_unknown_device() { #[test] #[should_panic] fn test_aggregate_set_master_device_for_an_unknown_aggregate_device() { - assert!(AggregateDevice::set_master_device(kAudioObjectUnknown).is_err()); + assert!(AggregateDevice::set_master_device(kAudioObjectUnknown, kAudioObjectUnknown).is_err()); } // AggregateDevice::activate_clock_drift_compensation @@ -243,10 +243,9 @@ fn test_aggregate_set_master_device() { let plugin = AggregateDevice::get_system_plugin_id().unwrap(); let device = AggregateDevice::create_blank_device_sync(plugin).unwrap(); assert!(AggregateDevice::set_sub_devices_sync(device, input_device, output_device).is_ok()); - assert!(AggregateDevice::set_master_device(device).is_ok()); + assert!(AggregateDevice::set_master_device(device, output_device).is_ok()); // Check if master is set to the first sub device of the default output device. - // TODO: What if the output device in the aggregate device is not the default output device? let first_output_sub_device_uid = get_device_uid(AggregateDevice::get_sub_devices(device).unwrap()[0]); let master_device_uid = test_get_master_device(device); @@ -266,7 +265,7 @@ fn test_aggregate_set_master_device_for_a_blank_aggregate_device() { let plugin = AggregateDevice::get_system_plugin_id().unwrap(); let device = AggregateDevice::create_blank_device_sync(plugin).unwrap(); - assert!(AggregateDevice::set_master_device(device).is_ok()); + assert!(AggregateDevice::set_master_device(device, output_device.unwrap()).is_ok()); // TODO: it's really weird the aggregate device actually own nothing // but its master device can be set successfully! @@ -301,7 +300,7 @@ fn test_aggregate_activate_clock_drift_compensation() { let plugin = AggregateDevice::get_system_plugin_id().unwrap(); let device = AggregateDevice::create_blank_device_sync(plugin).unwrap(); assert!(AggregateDevice::set_sub_devices_sync(device, input_device, output_device).is_ok()); - assert!(AggregateDevice::set_master_device(device).is_ok()); + assert!(AggregateDevice::set_master_device(device, output_device).is_ok()); assert!(AggregateDevice::activate_clock_drift_compensation(device).is_ok()); // Check the compensations. diff --git a/third_party/rust/cubeb-coreaudio/src/backend/tests/api.rs b/third_party/rust/cubeb-coreaudio/src/backend/tests/api.rs index 525e624ec85c..402a16354a65 100644 --- a/third_party/rust/cubeb-coreaudio/src/backend/tests/api.rs +++ b/third_party/rust/cubeb-coreaudio/src/backend/tests/api.rs @@ -2,8 +2,8 @@ use super::utils::{ test_audiounit_get_buffer_frame_size, test_audiounit_scope_is_enabled, test_create_audiounit, test_device_channels_in_scope, test_device_in_scope, test_get_all_devices, test_get_default_audiounit, test_get_default_device, test_get_default_raw_stream, - test_get_default_source_name, test_get_devices_in_scope, test_get_raw_context, - ComponentSubType, DeviceFilter, PropertyScope, Scope, + test_get_devices_in_scope, test_get_raw_context, test_get_source_name, ComponentSubType, + DeviceFilter, PropertyScope, Scope, }; use super::*; @@ -321,14 +321,14 @@ fn test_remove_listener_unknown_device() { fn test_get_default_device_id() { if test_get_default_device(Scope::Input).is_some() { assert_ne!( - audiounit_get_default_device_id(DeviceType::INPUT), + get_default_device_id(DeviceType::INPUT).unwrap(), kAudioObjectUnknown, ); } if test_get_default_device(Scope::Output).is_some() { assert_ne!( - audiounit_get_default_device_id(DeviceType::OUTPUT), + get_default_device_id(DeviceType::OUTPUT).unwrap(), kAudioObjectUnknown, ); } @@ -337,19 +337,13 @@ fn test_get_default_device_id() { #[test] #[should_panic] fn test_get_default_device_id_with_unknown_type() { - assert_eq!( - audiounit_get_default_device_id(DeviceType::UNKNOWN), - kAudioObjectUnknown, - ); + assert!(get_default_device_id(DeviceType::UNKNOWN).is_err()); } #[test] #[should_panic] fn test_get_default_device_id_with_inout_type() { - assert_eq!( - audiounit_get_default_device_id(DeviceType::INPUT | DeviceType::OUTPUT), - kAudioObjectUnknown, - ); + assert!(get_default_device_id(DeviceType::INPUT | DeviceType::OUTPUT).is_err()); } // convert_channel_layout @@ -982,22 +976,26 @@ fn test_convert_uint32_into_string() { assert_eq!(data_string, CString::new("RUST").unwrap()); } -// get_default_datasource_string +// get_device_source_string // ------------------------------------ #[test] -fn test_get_default_device_name() { - test_get_default_device_name_in_scope(Scope::Input); - test_get_default_device_name_in_scope(Scope::Output); +fn test_get_device_source_string() { + test_get_source_name_in_scope(Scope::Input); + test_get_source_name_in_scope(Scope::Output); - fn test_get_default_device_name_in_scope(scope: Scope) { - if let Some(name) = test_get_default_source_name(scope.clone()) { - let source = audiounit_get_default_datasource_string(scope.into()) - .unwrap() - .into_string() - .unwrap(); - assert_eq!(name, source); + fn test_get_source_name_in_scope(scope: Scope) { + if let Some(dev) = test_get_default_device(scope.clone()) { + if let Some(name) = test_get_source_name(dev, scope.clone()) { + let source = get_device_source_string(dev, scope.into()) + .unwrap() + .into_string() + .unwrap(); + assert_eq!(name, source); + } else { + println!("No source name for default {:?} device ", scope); + } } else { - println!("No source name for {:?}", scope); + println!("No default {:?} device", scope); } } } @@ -1052,10 +1050,7 @@ fn test_get_channel_count_of_output_for_a_input_only_deivce() { #[test] #[should_panic] fn test_get_channel_count_of_unknown_device() { - assert_eq!( - get_channel_count(kAudioObjectUnknown, DeviceType::OUTPUT).unwrap_err(), - Error::error() - ); + assert!(get_channel_count(kAudioObjectUnknown, DeviceType::OUTPUT).is_err()); } #[test] @@ -1066,9 +1061,8 @@ fn test_get_channel_count_of_inout_type() { fn test_channel_count(scope: Scope) { if let Some(device) = test_get_default_device(scope.clone()) { assert_eq!( - // Get a kAudioHardwareUnknownPropertyError in get_channel_count actually. get_channel_count(device, DeviceType::INPUT | DeviceType::OUTPUT).unwrap_err(), - Error::error() + kAudioHardwareUnknownPropertyError as OSStatus ); } else { println!("No device for {:?}.", scope); @@ -1084,10 +1078,7 @@ fn test_get_channel_count_of_unknwon_type() { fn test_channel_count(scope: Scope) { if let Some(device) = test_get_default_device(scope.clone()) { - assert_eq!( - get_channel_count(device, DeviceType::UNKNOWN).unwrap_err(), - Error::error() - ); + assert!(get_channel_count(device, DeviceType::UNKNOWN).is_err()); } else { panic!("Panic by default: No device for {:?}.", scope); } diff --git a/third_party/rust/cubeb-coreaudio/src/backend/tests/utils.rs b/third_party/rust/cubeb-coreaudio/src/backend/tests/utils.rs index e5377a586e13..1c2c0683afb5 100644 --- a/third_party/rust/cubeb-coreaudio/src/backend/tests/utils.rs +++ b/third_party/rust/cubeb-coreaudio/src/backend/tests/utils.rs @@ -188,21 +188,15 @@ fn test_enable_audiounit_in_scope( } } -pub fn test_get_default_source_name(scope: Scope) -> Option { - if let Some(source) = test_get_default_source_data(scope) { +pub fn test_get_source_name(device: AudioObjectID, scope: Scope) -> Option { + if let Some(source) = test_get_source_data(device, scope) { Some(u32_to_string(source)) } else { None } } -pub fn test_get_default_source_data(scope: Scope) -> Option { - let device = test_get_default_device(scope.clone()); - if device.is_none() { - return None; - } - - let device = device.unwrap(); +pub fn test_get_source_data(device: AudioObjectID, scope: Scope) -> Option { let address = AudioObjectPropertyAddress { mSelector: kAudioDevicePropertyDataSource, mScope: match scope { diff --git a/third_party/rust/cubeb-coreaudio/todo.md b/third_party/rust/cubeb-coreaudio/todo.md index 5700541576c8..7e07476bd247 100644 --- a/third_party/rust/cubeb-coreaudio/todo.md +++ b/third_party/rust/cubeb-coreaudio/todo.md @@ -77,8 +77,6 @@ and create a new one. It's easier than the current implementation. ### Setting master device -- We always set the master device to the first subdevice of the default output device - but the output device (forming the aggregate device) may not be the default output device - Check if the first subdevice of the default output device is in the list of sub devices list of the aggregate device - Check the `name: CFStringRef` of the master device is not `NULL` @@ -102,6 +100,7 @@ and create a new one. It's easier than the current implementation. ## [Cubeb Interface][cubeb-rs] +- `current_device` should be the in-use device of the current stream rather than default input and output device. - Implement `From` trait for `enum cubeb_device_type` so we can use `devtype.into()` to get `ffi::CUBEB_DEVICE_TYPE_*`. - Implement `to_owned` in [`StreamParamsRef`][cubeb-rs-stmparamsref] - Check the passed parameters like what [cubeb.c does][cubeb-stm-check]!