diff --git a/.cargo/config.in b/.cargo/config.in index 05a0dc5b7358..b2bb67a7b811 100644 --- a/.cargo/config.in +++ b/.cargo/config.in @@ -65,9 +65,9 @@ git = "https://github.com/mozilla/audioipc" rev = "596bdb7fbb5745ea415726e16bd497e6c850a540" replace-with = "vendored-sources" -[source."git+https://github.com/mozilla/cubeb-coreaudio-rs?rev=d23ab55eab684b46f46e1da177c8814f6103a009"] +[source."git+https://github.com/mozilla/cubeb-coreaudio-rs?rev=4ba39ca14bbb5bb0274843701cd958717a0fe293"] git = "https://github.com/mozilla/cubeb-coreaudio-rs" -rev = "d23ab55eab684b46f46e1da177c8814f6103a009" +rev = "4ba39ca14bbb5bb0274843701cd958717a0fe293" replace-with = "vendored-sources" [source."git+https://github.com/mozilla/cubeb-pulse-rs?rev=8ff972c8e2ec1782ff262ac4071c0415e69b1367"] diff --git a/Cargo.lock b/Cargo.lock index 426c4ffd00c3..d37659ac0ec8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -899,7 +899,7 @@ dependencies = [ [[package]] name = "coreaudio-sys-utils" version = "0.1.0" -source = "git+https://github.com/mozilla/cubeb-coreaudio-rs?rev=d23ab55eab684b46f46e1da177c8814f6103a009#d23ab55eab684b46f46e1da177c8814f6103a009" +source = "git+https://github.com/mozilla/cubeb-coreaudio-rs?rev=4ba39ca14bbb5bb0274843701cd958717a0fe293#4ba39ca14bbb5bb0274843701cd958717a0fe293" dependencies = [ "core-foundation-sys", "coreaudio-sys", @@ -1110,7 +1110,7 @@ dependencies = [ [[package]] name = "cubeb-coreaudio" version = "0.1.0" -source = "git+https://github.com/mozilla/cubeb-coreaudio-rs?rev=d23ab55eab684b46f46e1da177c8814f6103a009#d23ab55eab684b46f46e1da177c8814f6103a009" +source = "git+https://github.com/mozilla/cubeb-coreaudio-rs?rev=4ba39ca14bbb5bb0274843701cd958717a0fe293#4ba39ca14bbb5bb0274843701cd958717a0fe293" dependencies = [ "atomic", "audio-mixer", diff --git a/dom/media/GraphDriver.cpp b/dom/media/GraphDriver.cpp index 7357b411d91f..b9469900da2d 100644 --- a/dom/media/GraphDriver.cpp +++ b/dom/media/GraphDriver.cpp @@ -482,12 +482,11 @@ AudioCallbackDriver::AudioCallbackDriver( "Invalid output channel count"); MOZ_ASSERT(mOutputChannelCount <= 8); - bool allowVoice = StaticPrefs:: - media_getusermedia_microphone_prefer_voice_stream_with_processing_enabled(); + bool allowVoice = true; #ifdef MOZ_WIDGET_COCOA // Using the VoiceProcessingIO audio unit on MacOS 12 causes crashes in - // OS code. - allowVoice = allowVoice && nsCocoaFeatures::macOSVersionMajor() != 12; + // platform code. + allowVoice = nsCocoaFeatures::macOSVersionMajor() != 12; #endif if (aAudioInputType == AudioInputType::Voice && allowVoice) { diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml index 8481c6790cb1..4942fc5a331f 100644 --- a/modules/libpref/init/StaticPrefList.yaml +++ b/modules/libpref/init/StaticPrefList.yaml @@ -10682,14 +10682,6 @@ value: true mirror: once -# Tell the audio backend to prefer a stream adapted for voice when processing is -# enabled through constraints (possibly defaults). Whether it has any effect -# depends on the backend. -- name: media.getusermedia.microphone.prefer_voice_stream_with_processing.enabled - type: bool - value: True - mirror: always - # This pref turns on legacy (non-spec) exposure of camera and microphone # information from enumerateDevices and devicechange ahead of successful # getUserMedia calls. Should only be turned on to resolve web compat issues, diff --git a/third_party/rust/cubeb-coreaudio/.cargo-checksum.json b/third_party/rust/cubeb-coreaudio/.cargo-checksum.json index 5c8366f60a5a..cf501afdca55 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":"d7e757e664c23fae52028f1dfc5917f92523c08702e3a1f95e1fd38ed714416c","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":"d717e598c96e4911d9494b18382d6bd3a8d5038b7d68d3166ad4336e237a97d8","run_sanitizers.sh":"84e93a0da137803018f37403511e8c92760be730426bf6cea34419d93d1a7ff8","run_tests.sh":"916a7ae4a406d2274417d6eca939a878db5adcb6144e5680d9d148bf90178f1c","src/backend/aggregate_device.rs":"43511107ba2a75a19340ac663c981362ca1b75b679b6c295d88b5035bd7e3619","src/backend/auto_release.rs":"050fdcee74cf46b9a8a85a877e166d72a853d33220f59cf734cbb6ea09daa441","src/backend/buffer_manager.rs":"e9bcf964347daa8952f98caa2746e34a31ea8908375204896593f56e4b6147ca","src/backend/device_property.rs":"a7622feaa41db1cd76fd35a85a022e44f4894e396a104a59008d5b8757d2ab4e","src/backend/mixer.rs":"ed299d3954e2a823060c870a8244673a7d4bca530830cb66b964d047a80ee3af","src/backend/mod.rs":"1591669c30a3d07754bfb39c9cb042cdd101f0ab89be13f6cdf74d376e441cf8","src/backend/resampler.rs":"48bf8f56ae8d60dbabca6417b768000619abee8731ac3902164b45651ac08a4d","src/backend/tests/aggregate_device.rs":"e3f94e118e1dd47941fbba4417de40bddc4254d9f06b1e938f58d8f1aa566a5c","src/backend/tests/api.rs":"cd7e7551e2e82b19da883621a494d2a6779c373f3ff2d12ee52fae8efec1e7b8","src/backend/tests/backlog.rs":"3b189a7e036543c467cc242af0ed3332721179ee2b1c8847a6db563546f1ac52","src/backend/tests/device_change.rs":"f68c2eaa55c3ec2a58894832fbca1e2a2e79e740b145f76a0f45452af465a934","src/backend/tests/device_property.rs":"ea0be5f8834be494cb33f854ce9d334b5763dc5287f949bcb4bd025d8a8b2d3b","src/backend/tests/interfaces.rs":"af8e3fdeb58226621699b29f1a90621b2260e3f17292dac54860cd05fe4eec71","src/backend/tests/manual.rs":"4a1634e86beb145d2703722a8be057a762953241329c82ee09acf7dc0f0d9d0c","src/backend/tests/mod.rs":"8dba770023d7f9c4228f0e11915347f0e07da5fd818e3ee4478c4b197af9aa2a","src/backend/tests/parallel.rs":"59632744e70616ab7037facb0787db339b96800c8cc397d203241548c5cfb7f5","src/backend/tests/tone.rs":"779cc14fc2a362bf7f26ce66ad70c0639501176175655a99b7fefb3c59d56c7a","src/backend/tests/utils.rs":"efb8b3709aff7ed5e2923566084de3e0709f3bd9c18a04f3310d7a3b86fa4b71","src/backend/utils.rs":"6c3ffbcd602e6cc9f56deb9ecb07b2eef2e6f074ef924178e466f380aae5c595","src/capi.rs":"21b66b70545bf04ec719928004d1d9adb45b24ced51288f5b2993d79aaf78f5f","src/lib.rs":"5e586d45cd6b3722f0a6736d9252593299269817a153eef1930a5fb9bfbb56f5","todo.md":"efc1f012eb9a331a040cad4ac03aa79307f25885f71b6fb38f3ad7af8d7d515c"},"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":"d7e757e664c23fae52028f1dfc5917f92523c08702e3a1f95e1fd38ed714416c","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":"d717e598c96e4911d9494b18382d6bd3a8d5038b7d68d3166ad4336e237a97d8","run_sanitizers.sh":"84e93a0da137803018f37403511e8c92760be730426bf6cea34419d93d1a7ff8","run_tests.sh":"916a7ae4a406d2274417d6eca939a878db5adcb6144e5680d9d148bf90178f1c","src/backend/aggregate_device.rs":"43511107ba2a75a19340ac663c981362ca1b75b679b6c295d88b5035bd7e3619","src/backend/auto_release.rs":"050fdcee74cf46b9a8a85a877e166d72a853d33220f59cf734cbb6ea09daa441","src/backend/buffer_manager.rs":"e9bcf964347daa8952f98caa2746e34a31ea8908375204896593f56e4b6147ca","src/backend/device_property.rs":"a7622feaa41db1cd76fd35a85a022e44f4894e396a104a59008d5b8757d2ab4e","src/backend/mixer.rs":"ed299d3954e2a823060c870a8244673a7d4bca530830cb66b964d047a80ee3af","src/backend/mod.rs":"4f07743a46a4b908c9e23b31d0bc8f3a0983b943e0bb824b9154272b2673ae90","src/backend/resampler.rs":"48bf8f56ae8d60dbabca6417b768000619abee8731ac3902164b45651ac08a4d","src/backend/tests/aggregate_device.rs":"e3f94e118e1dd47941fbba4417de40bddc4254d9f06b1e938f58d8f1aa566a5c","src/backend/tests/api.rs":"cd7e7551e2e82b19da883621a494d2a6779c373f3ff2d12ee52fae8efec1e7b8","src/backend/tests/backlog.rs":"3b189a7e036543c467cc242af0ed3332721179ee2b1c8847a6db563546f1ac52","src/backend/tests/device_change.rs":"f68c2eaa55c3ec2a58894832fbca1e2a2e79e740b145f76a0f45452af465a934","src/backend/tests/device_property.rs":"ea0be5f8834be494cb33f854ce9d334b5763dc5287f949bcb4bd025d8a8b2d3b","src/backend/tests/interfaces.rs":"2f192d08a5b2cbf678e0fea38b7061b1f0e83aa6b8f443bd92b70fee67c35516","src/backend/tests/manual.rs":"0c1bbd9b6137bbc484974c4bf7ea965872b8f52f86055f07916b85a3d715e0a6","src/backend/tests/mod.rs":"8dba770023d7f9c4228f0e11915347f0e07da5fd818e3ee4478c4b197af9aa2a","src/backend/tests/parallel.rs":"59632744e70616ab7037facb0787db339b96800c8cc397d203241548c5cfb7f5","src/backend/tests/tone.rs":"779cc14fc2a362bf7f26ce66ad70c0639501176175655a99b7fefb3c59d56c7a","src/backend/tests/utils.rs":"efb8b3709aff7ed5e2923566084de3e0709f3bd9c18a04f3310d7a3b86fa4b71","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/mod.rs b/third_party/rust/cubeb-coreaudio/src/backend/mod.rs index 61ae44fea1d3..4516342aaf1b 100644 --- a/third_party/rust/cubeb-coreaudio/src/backend/mod.rs +++ b/third_party/rust/cubeb-coreaudio/src/backend/mod.rs @@ -32,11 +32,12 @@ use self::device_property::*; use self::mixer::*; use self::resampler::*; use self::utils::*; +use atomic; use backend::ringbuf::RingBuffer; use cubeb_backend::{ - ffi, ChannelLayout, Context, ContextOps, DeviceCollectionRef, DeviceId, DeviceRef, DeviceType, - Error, InputProcessingParams, Ops, Result, SampleFormat, State, Stream, StreamOps, - StreamParams, StreamParamsRef, StreamPrefs, + ffi, Context, ContextOps, DeviceCollectionRef, DeviceId, DeviceRef, DeviceType, Error, + InputProcessingParams, Ops, Result, SampleFormat, State, Stream, StreamOps, StreamParams, + StreamParamsRef, StreamPrefs, }; use mach::mach_time::{mach_absolute_time, mach_timebase_info}; use std::cmp; @@ -58,8 +59,6 @@ const DISPATCH_QUEUE_LABEL: &str = "org.mozilla.cubeb"; const PRIVATE_AGGREGATE_DEVICE_NAME: &str = "CubebAggregateDevice"; const VOICEPROCESSING_AGGREGATE_DEVICE_NAME: &str = "VPAUAggregateAudioDevice"; -const APPLE_STUDIO_DISPLAY_USB_ID: &str = "05AC:1114"; - // Testing empirically, some headsets report a minimal latency that is very low, // but this does not work in practice. Lie and say the minimum is 128 frames. const SAFE_MIN_LATENCY_FRAMES: u32 = 128; @@ -287,26 +286,7 @@ fn get_volume(unit: AudioUnit) -> Result { fn set_input_mute(unit: AudioUnit, mute: bool) -> Result<()> { assert!(!unit.is_null()); - let mute: u32 = mute.into(); - let mut old_mute: u32 = 0; - let r = audio_unit_get_property( - unit, - kAUVoiceIOProperty_MuteOutput, - kAudioUnitScope_Global, - AU_IN_BUS, - &mut old_mute, - &mut mem::size_of::(), - ); - if r != NO_ERR { - cubeb_log!( - "AudioUnitGetProperty/kAUVoiceIOProperty_MuteOutput rv={}", - r - ); - return Err(Error::error()); - } - if old_mute == mute { - return Ok(()); - } + let mute: UInt32 = mute.into(); let r = audio_unit_set_property( unit, kAUVoiceIOProperty_MuteOutput, @@ -330,85 +310,52 @@ fn set_input_processing_params(unit: AudioUnit, params: InputProcessingParams) - assert!(!unit.is_null()); let aec = params.contains(InputProcessingParams::ECHO_CANCELLATION); let ns = params.contains(InputProcessingParams::NOISE_SUPPRESSION); - let agc = params.contains(InputProcessingParams::AUTOMATIC_GAIN_CONTROL); - // AEC and NS are active as soon as VPIO is not bypassed, therefore the only combinations - // of those we can explicitly support are {} and {aec, ns}. + // We don't use AGC, but keep it here for reference. + // See the comment in supported_input_processing_params. + let agc = params.contains(InputProcessingParams::AUTOMATIC_GAIN_CONTROL); + assert!(!agc); + + // AEC and NS are active as soon as VPIO is not bypassed. + // Therefore the only modes we can explicitly support are {} and {aec, ns}. + if aec != ns { // No control to turn on AEC without NS or vice versa. return Err(Error::error()); } - let mut old_agc: u32 = 0; - let r = audio_unit_get_property( + let agc = u32::from(agc); + let r = audio_unit_set_property( unit, kAUVoiceIOProperty_VoiceProcessingEnableAGC, kAudioUnitScope_Global, AU_IN_BUS, - &mut old_agc, - &mut mem::size_of::(), + &agc, + mem::size_of::(), ); if r != NO_ERR { cubeb_log!( - "AudioUnitGetProperty/kAUVoiceIOProperty_VoiceProcessingEnableAGC rv={}", - r - ); - return Err(Error::error()); - } - - if (old_agc == 1) != agc { - let agc = u32::from(agc); - let r = audio_unit_set_property( - unit, - kAUVoiceIOProperty_VoiceProcessingEnableAGC, - kAudioUnitScope_Global, - AU_IN_BUS, - &agc, - mem::size_of::(), - ); - if r != NO_ERR { - cubeb_log!( - "AudioUnitSetProperty/kAUVoiceIOProperty_VoiceProcessingEnableAGC rv={}", - r - ); - return Err(Error::error()); - } - } - - let mut old_bypass: u32 = 0; - let r = audio_unit_get_property( - unit, - kAUVoiceIOProperty_BypassVoiceProcessing, - kAudioUnitScope_Global, - AU_IN_BUS, - &mut old_bypass, - &mut mem::size_of::(), - ); - if r != NO_ERR { - cubeb_log!( - "AudioUnitGetProperty/kAUVoiceIOProperty_BypassVoiceProcessing rv={}", + "AudioUnitSetProperty/kAUVoiceIOProperty_VoiceProcessingEnableAGC rv={}", r ); return Err(Error::error()); } let bypass = u32::from(!aec); - if old_bypass != bypass { - let r = audio_unit_set_property( - unit, - kAUVoiceIOProperty_BypassVoiceProcessing, - kAudioUnitScope_Global, - AU_IN_BUS, - &bypass, - mem::size_of::(), + let r = audio_unit_set_property( + unit, + kAUVoiceIOProperty_BypassVoiceProcessing, + kAudioUnitScope_Global, + AU_IN_BUS, + &bypass, + mem::size_of::(), + ); + if r != NO_ERR { + cubeb_log!( + "AudioUnitSetProperty/kAUVoiceIOProperty_BypassVoiceProcessing rv={}", + r ); - if r != NO_ERR { - cubeb_log!( - "AudioUnitSetProperty/kAUVoiceIOProperty_BypassVoiceProcessing rv={}", - r - ); - return Err(Error::error()); - } + return Err(Error::error()); } Ok(()) @@ -1471,8 +1418,6 @@ fn get_channel_count( assert_ne!(devid, kAudioObjectUnknown); let mut streams = get_device_streams(devid, devtype)?; - let model_uid = - get_device_model_uid(devid, devtype).map_or_else(|_| String::new(), |s| s.into_string()); if devtype == DeviceType::INPUT { // With VPIO, output devices will/may get a Tap that appears as input channels on the @@ -1517,13 +1462,6 @@ fn get_channel_count( ); false } - // The input tap stream on the Studio Display Speakers has a terminal type that - // is not clearly output-specific. We special-case it here. - EXTERNAL_DIGITAL_AUDIO_INTERFACE - if model_uid.contains(APPLE_STUDIO_DISPLAY_USB_ID) => - { - false - } // Note INPUT_UNDEFINED is 0x200 and INPUT_MICROPHONE is 0x201 t if (INPUT_MICROPHONE..OUTPUT_UNDEFINED).contains(&t) => true, t if (OUTPUT_UNDEFINED..BIDIRECTIONAL_UNDEFINED).contains(&t) => false, @@ -2299,9 +2237,11 @@ impl ContextOps for AudioUnitContext { Ok(rate as u32) } fn supported_input_processing_params(&mut self) -> Result { - Ok(InputProcessingParams::ECHO_CANCELLATION - | InputProcessingParams::NOISE_SUPPRESSION - | InputProcessingParams::AUTOMATIC_GAIN_CONTROL) + // The VoiceProcessingIO AudioUnit has the + // kAUVoiceIOProperty_VoiceProcessingEnableAGC property to enable AGC on + // the input signal, but some simple manual tests on MacOS 14.0 suggest + // it doesn't have any effect. + Ok(InputProcessingParams::ECHO_CANCELLATION | InputProcessingParams::NOISE_SUPPRESSION) } fn enumerate_devices( &mut self, @@ -2565,8 +2505,6 @@ struct CoreStreamData<'ctx> { // Info of the I/O devices. input_device: device_info, output_device: device_info, - input_processing_params: InputProcessingParams, - input_mute: bool, input_buffer_manager: Option, // Listeners indicating what system events are monitored. default_input_listener: Option, @@ -2605,8 +2543,6 @@ impl<'ctx> Default for CoreStreamData<'ctx> { output_unit: ptr::null_mut(), input_device: device_info::default(), output_device: device_info::default(), - input_processing_params: InputProcessingParams::NONE, - input_mute: false, input_buffer_manager: None, default_input_listener: None, default_output_listener: None, @@ -2651,8 +2587,6 @@ impl<'ctx> CoreStreamData<'ctx> { output_unit: ptr::null_mut(), input_device: in_dev, output_device: out_dev, - input_processing_params: InputProcessingParams::NONE, - input_mute: false, input_buffer_manager: None, default_input_listener: None, default_output_listener: None, @@ -2744,50 +2678,6 @@ impl<'ctx> CoreStreamData<'ctx> { input_domain == output_domain } - fn should_block_vpio_for_device_pair( - &self, - in_device: &device_info, - out_device: &device_info, - ) -> bool { - self.debug_assert_is_on_stream_queue(); - cubeb_log!("Evaluating device pair against VPIO block list"); - let log_device = |id, devtype| -> std::result::Result<(), OSStatus> { - cubeb_log!("{} uid=\"{}\", model_uid=\"{}\", transport_type={:?}, source={:?}, source_name=\"{}\", name=\"{}\", manufacturer=\"{}\"", - if devtype == DeviceType::INPUT { - "Input" - } else { - debug_assert_eq!(devtype, DeviceType::OUTPUT); - "Output" - }, - get_device_uid(id, devtype).map(|s| s.into_string()).unwrap_or_default(), - get_device_model_uid(id, devtype).map(|s| s.into_string()).unwrap_or_default(), - convert_uint32_into_string(get_device_transport_type(id, devtype).unwrap_or(0)), - convert_uint32_into_string(get_device_source(id, devtype).unwrap_or(0)), - get_device_source_name(id, devtype).map(|s| s.into_string()).unwrap_or_default(), - get_device_name(id, devtype).map(|s| s.into_string()).unwrap_or_default(), - get_device_manufacturer(id, devtype).map(|s| s.into_string()).unwrap_or_default()); - Ok(()) - }; - log_device(in_device.id, DeviceType::INPUT); - log_device(out_device.id, DeviceType::OUTPUT); - match ( - get_device_model_uid(in_device.id, DeviceType::INPUT).map(|s| s.to_string()), - get_device_model_uid(out_device.id, DeviceType::OUTPUT).map(|s| s.to_string()), - ) { - (Ok(in_model_uid), Ok(out_model_uid)) - if in_model_uid.contains(APPLE_STUDIO_DISPLAY_USB_ID) - && out_model_uid.contains(APPLE_STUDIO_DISPLAY_USB_ID) => - { - cubeb_log!("Both input and output device is an Apple Studio Display. BLOCKED"); - true - } - _ => { - cubeb_log!("Device pair is not blocked"); - false - } - } - } - fn create_audiounits(&mut self) -> Result<(device_info, device_info)> { self.debug_assert_is_on_stream_queue(); let should_use_voice_processing_unit = self.has_input() @@ -2795,8 +2685,7 @@ impl<'ctx> CoreStreamData<'ctx> { && self .input_stream_params .prefs() - .contains(StreamPrefs::VOICE) - && !self.should_block_vpio_for_device_pair(&self.input_device, &self.output_device); + .contains(StreamPrefs::VOICE); let should_use_aggregate_device = { // It's impossible to create an aggregate device from an aggregate device, and it's @@ -2826,7 +2715,7 @@ impl<'ctx> CoreStreamData<'ctx> { } cubeb_log!( "Output device ID: {} (aggregate: {:?})", - self.output_device.id, + self.input_device.id, output_is_aggregate ); } @@ -3046,7 +2935,8 @@ impl<'ctx> CoreStreamData<'ctx> { let params = unsafe { let mut p = *self.input_stream_params.as_ptr(); p.channels = if using_voice_processing_unit { - // VPIO is always MONO. + // With VPIO, stereo input devices configured for stereo have been observed to + // spit out only a single mono channel. 1 } else { input_hw_desc.mChannelsPerFrame @@ -3164,6 +3054,9 @@ impl<'ctx> CoreStreamData<'ctx> { out_dev_info ); + let device_channel_count = + get_channel_count(self.output_device.id, DeviceType::OUTPUT).unwrap_or(0); + cubeb_log!( "({:p}) Opening output side: rate {}, channels {}, format {:?}, layout {:?}, prefs {:?}, latency in frames {}, voice processing {}.", self.stm_ptr, @@ -3200,10 +3093,9 @@ impl<'ctx> CoreStreamData<'ctx> { output_hw_desc ); - // In some cases with (other streams using) VPIO the stream format's mChannelsPerFrame - // is higher than expected. Use get_channel_count as source of truth. - output_hw_desc.mChannelsPerFrame = - get_channel_count(self.output_device.id, DeviceType::OUTPUT).unwrap_or(0); + // In some cases with VPIO the stream format's mChannelsPerFrame is higher than + // expected. Use get_channel_count as source of truth. + output_hw_desc.mChannelsPerFrame = device_channel_count; // This has been observed in the wild. if output_hw_desc.mChannelsPerFrame == 0 { @@ -3220,12 +3112,7 @@ impl<'ctx> CoreStreamData<'ctx> { // channels will be appended at the end of the raw data given by the output callback. let params = unsafe { let mut p = *self.output_stream_params.as_ptr(); - p.channels = if using_voice_processing_unit { - // VPIO is always MONO. - 1 - } else { - output_hw_desc.mChannelsPerFrame - }; + p.channels = output_hw_desc.mChannelsPerFrame; if using_voice_processing_unit { // VPIO will always use the sample rate of the input hw for both input and output, // as reported to us. (We can override it but we cannot improve quality this way). @@ -3473,26 +3360,12 @@ impl<'ctx> CoreStreamData<'ctx> { ); } - // Always try to remember the applied input mute state. If it cannot be applied - // to the new device pair, we notify the client of an error and it will have to - // open a new stream. - if let Err(r) = set_input_mute(self.input_unit, self.input_mute) { - cubeb_log!( - "({:p}) Failed to set mute state of voiceprocessing. Error: {}", - self.stm_ptr, - r - ); - return Err(r); - } - - // Always try to remember the applied input processing params. If they cannot - // be applied in the new device pair, we notify the client of an error and it - // will have to open a new stream. + // Always initiate to not use input processing. if let Err(r) = - set_input_processing_params(self.input_unit, self.input_processing_params) + set_input_processing_params(self.input_unit, InputProcessingParams::NONE) { cubeb_log!( - "({:p}) Failed to set params of voiceprocessing. Error: {}", + "({:p}) Failed to enable bypass of voiceprocessing. Error: {}", self.stm_ptr, r ); @@ -3846,10 +3719,23 @@ impl<'ctx> CoreStreamData<'ctx> { fn get_output_channel_layout(&self) -> Result> { self.debug_assert_is_on_stream_queue(); assert!(!self.output_unit.is_null()); - if self.using_voice_processing_unit() { - return Ok(get_channel_order(ChannelLayout::MONO)); + if !self.using_voice_processing_unit() { + return get_channel_layout(self.output_unit); } - get_channel_layout(self.output_unit) + + // The VoiceProcessingIO unit (as tried on MacOS 14) is known to not support + // kAudioUnitProperty_AudioChannelLayout queries, and to lie about + // kAudioDevicePropertyPreferredChannelLayout. If we're using + // VoiceProcessingIO, try standing up a regular AudioUnit and query that. + cubeb_log!( + "({:p}) get_output_channel_layout with a VoiceProcessingIO output unit. Trying a dedicated unit.", + self.stm_ptr + ); + let mut dedicated_unit = create_audiounit(&self.output_device)?; + let res = get_channel_layout(dedicated_unit); + dispose_audio_unit(dedicated_unit); + dedicated_unit = ptr::null_mut(); + res } } @@ -4331,7 +4217,6 @@ impl<'ctx> StreamOps for AudioUnitStream<'ctx> { self as *const AudioUnitStream, mute ); - self.core_stream_data.input_mute = mute; Ok(()) } fn set_input_processing_params(&mut self, params: InputProcessingParams) -> Result<()> { @@ -4372,7 +4257,6 @@ impl<'ctx> StreamOps for AudioUnitStream<'ctx> { self as *const AudioUnitStream, params ); - self.core_stream_data.input_processing_params = params; Ok(()) } #[cfg(target_os = "ios")] diff --git a/third_party/rust/cubeb-coreaudio/src/backend/tests/interfaces.rs b/third_party/rust/cubeb-coreaudio/src/backend/tests/interfaces.rs index 340fec002dd6..8e6168f75720 100644 --- a/third_party/rust/cubeb-coreaudio/src/backend/tests/interfaces.rs +++ b/third_party/rust/cubeb-coreaudio/src/backend/tests/interfaces.rs @@ -90,7 +90,6 @@ fn test_ops_context_supported_input_processing_params() { params, ffi::CUBEB_INPUT_PROCESSING_PARAM_ECHO_CANCELLATION | ffi::CUBEB_INPUT_PROCESSING_PARAM_NOISE_SUPPRESSION - | ffi::CUBEB_INPUT_PROCESSING_PARAM_AUTOMATIC_GAIN_CONTROL ); }, ); @@ -1018,54 +1017,6 @@ fn test_ops_duplex_voice_stream_set_input_mute() { }); } -#[test] -fn test_ops_duplex_voice_stream_set_input_mute_before_start() { - test_default_duplex_voice_stream_operation( - "duplex voice stream: mute before start", - |stream| { - assert_eq!( - unsafe { OPS.stream_set_input_mute.unwrap()(stream, 1) }, - ffi::CUBEB_OK - ); - assert_eq!(unsafe { OPS.stream_start.unwrap()(stream) }, ffi::CUBEB_OK); - }, - ); -} - -#[test] -fn test_ops_duplex_voice_stream_set_input_mute_before_start_with_reinit() { - test_default_duplex_voice_stream_operation( - "duplex voice stream: mute before start with reinit", - |stream| { - assert_eq!( - unsafe { OPS.stream_set_input_mute.unwrap()(stream, 1) }, - ffi::CUBEB_OK - ); - assert_eq!(unsafe { OPS.stream_start.unwrap()(stream) }, ffi::CUBEB_OK); - - // Hacky cast, but testing this here was simplest for now. - let stm = unsafe { &mut *(stream as *mut AudioUnitStream) }; - stm.reinit_async(); - let queue = stm.queue.clone(); - let mut mute_after_reinit = false; - queue.run_sync(|| { - let mut mute: u32 = 0; - let r = audio_unit_get_property( - stm.core_stream_data.input_unit, - kAUVoiceIOProperty_MuteOutput, - kAudioUnitScope_Global, - AU_IN_BUS, - &mut mute, - &mut mem::size_of::(), - ); - assert_eq!(r, NO_ERR); - mute_after_reinit = mute == 1; - }); - assert_eq!(mute_after_reinit, true); - }, - ); -} - #[test] fn test_ops_duplex_voice_stream_set_input_mute_after_start() { test_default_duplex_voice_stream_operation("duplex voice stream: mute after start", |stream| { @@ -1082,8 +1033,7 @@ fn test_ops_duplex_voice_stream_set_input_processing_params() { test_default_duplex_voice_stream_operation("duplex voice stream: processing", |stream| { let params: ffi::cubeb_input_processing_params = ffi::CUBEB_INPUT_PROCESSING_PARAM_ECHO_CANCELLATION - | ffi::CUBEB_INPUT_PROCESSING_PARAM_NOISE_SUPPRESSION - | ffi::CUBEB_INPUT_PROCESSING_PARAM_AUTOMATIC_GAIN_CONTROL; + | ffi::CUBEB_INPUT_PROCESSING_PARAM_NOISE_SUPPRESSION; assert_eq!( unsafe { OPS.stream_set_input_processing_params.unwrap()(stream, params) }, ffi::CUBEB_OK @@ -1098,8 +1048,7 @@ fn test_ops_duplex_voice_stream_set_input_processing_params_before_start() { |stream| { let params: ffi::cubeb_input_processing_params = ffi::CUBEB_INPUT_PROCESSING_PARAM_ECHO_CANCELLATION - | ffi::CUBEB_INPUT_PROCESSING_PARAM_NOISE_SUPPRESSION - | ffi::CUBEB_INPUT_PROCESSING_PARAM_AUTOMATIC_GAIN_CONTROL; + | ffi::CUBEB_INPUT_PROCESSING_PARAM_NOISE_SUPPRESSION; assert_eq!( unsafe { OPS.stream_set_input_processing_params.unwrap()(stream, params) }, ffi::CUBEB_OK @@ -1109,65 +1058,6 @@ fn test_ops_duplex_voice_stream_set_input_processing_params_before_start() { ); } -#[test] -fn test_ops_duplex_voice_stream_set_input_processing_params_before_start_with_reinit() { - test_default_duplex_voice_stream_operation( - "duplex voice stream: processing before start with reinit", - |stream| { - let params: ffi::cubeb_input_processing_params = - ffi::CUBEB_INPUT_PROCESSING_PARAM_ECHO_CANCELLATION - | ffi::CUBEB_INPUT_PROCESSING_PARAM_NOISE_SUPPRESSION - | ffi::CUBEB_INPUT_PROCESSING_PARAM_AUTOMATIC_GAIN_CONTROL; - assert_eq!( - unsafe { OPS.stream_set_input_processing_params.unwrap()(stream, params) }, - ffi::CUBEB_OK - ); - assert_eq!(unsafe { OPS.stream_start.unwrap()(stream) }, ffi::CUBEB_OK); - - // Hacky cast, but testing this here was simplest for now. - let stm = unsafe { &mut *(stream as *mut AudioUnitStream) }; - stm.reinit_async(); - let queue = stm.queue.clone(); - let mut params_after_reinit: ffi::cubeb_input_processing_params = - ffi::CUBEB_INPUT_PROCESSING_PARAM_NONE; - queue.run_sync(|| { - let mut params: ffi::cubeb_input_processing_params = - ffi::CUBEB_INPUT_PROCESSING_PARAM_NONE; - let mut agc: u32 = 0; - let r = audio_unit_get_property( - stm.core_stream_data.input_unit, - kAUVoiceIOProperty_VoiceProcessingEnableAGC, - kAudioUnitScope_Global, - AU_IN_BUS, - &mut agc, - &mut mem::size_of::(), - ); - assert_eq!(r, NO_ERR); - if agc == 1 { - params = params | ffi::CUBEB_INPUT_PROCESSING_PARAM_AUTOMATIC_GAIN_CONTROL; - } - let mut bypass: u32 = 0; - let r = audio_unit_get_property( - stm.core_stream_data.input_unit, - kAUVoiceIOProperty_BypassVoiceProcessing, - kAudioUnitScope_Global, - AU_IN_BUS, - &mut bypass, - &mut mem::size_of::(), - ); - assert_eq!(r, NO_ERR); - if bypass == 0 { - params = params - | ffi::CUBEB_INPUT_PROCESSING_PARAM_ECHO_CANCELLATION - | ffi::CUBEB_INPUT_PROCESSING_PARAM_NOISE_SUPPRESSION; - } - params_after_reinit = params; - }); - assert_eq!(params, params_after_reinit); - }, - ); -} - #[test] fn test_ops_duplex_voice_stream_set_input_processing_params_after_start() { test_default_duplex_voice_stream_operation( @@ -1176,8 +1066,7 @@ fn test_ops_duplex_voice_stream_set_input_processing_params_after_start() { assert_eq!(unsafe { OPS.stream_start.unwrap()(stream) }, ffi::CUBEB_OK); let params: ffi::cubeb_input_processing_params = ffi::CUBEB_INPUT_PROCESSING_PARAM_ECHO_CANCELLATION - | ffi::CUBEB_INPUT_PROCESSING_PARAM_NOISE_SUPPRESSION - | ffi::CUBEB_INPUT_PROCESSING_PARAM_AUTOMATIC_GAIN_CONTROL; + | ffi::CUBEB_INPUT_PROCESSING_PARAM_NOISE_SUPPRESSION; assert_eq!( unsafe { OPS.stream_set_input_processing_params.unwrap()(stream, params) }, ffi::CUBEB_OK diff --git a/third_party/rust/cubeb-coreaudio/src/backend/tests/manual.rs b/third_party/rust/cubeb-coreaudio/src/backend/tests/manual.rs index b2b2241cc951..aa1dc3c34e79 100644 --- a/third_party/rust/cubeb-coreaudio/src/backend/tests/manual.rs +++ b/third_party/rust/cubeb-coreaudio/src/backend/tests/manual.rs @@ -338,6 +338,23 @@ fn test_stream_tester() { params.set(InputProcessingParams::ECHO_CANCELLATION, true); params.set(InputProcessingParams::NOISE_SUPPRESSION, true); } + let mut agc = u32::from(false); + let mut size: usize = mem::size_of::(); + assert_eq!( + audio_unit_get_property( + stm.core_stream_data.input_unit, + kAUVoiceIOProperty_VoiceProcessingEnableAGC, + kAudioUnitScope_Global, + AU_IN_BUS, + &mut agc, + &mut size, + ), + NO_ERR + ); + assert_eq!(size, mem::size_of::()); + if agc == 1 { + params.set(InputProcessingParams::AUTOMATIC_GAIN_CONTROL, true); + } } let mut done = false; while !done { diff --git a/toolkit/library/rust/shared/Cargo.toml b/toolkit/library/rust/shared/Cargo.toml index 4e7ab800a21e..181381b4d3c8 100644 --- a/toolkit/library/rust/shared/Cargo.toml +++ b/toolkit/library/rust/shared/Cargo.toml @@ -22,7 +22,7 @@ static_prefs = { path = "../../../../modules/libpref/init/static_prefs" } profiler_helper = { path = "../../../../tools/profiler/rust-helper", optional = true } mozurl = { path = "../../../../netwerk/base/mozurl" } webrender_bindings = { path = "../../../../gfx/webrender_bindings" } -cubeb-coreaudio = { git = "https://github.com/mozilla/cubeb-coreaudio-rs", rev = "d23ab55eab684b46f46e1da177c8814f6103a009", optional = true } +cubeb-coreaudio = { git = "https://github.com/mozilla/cubeb-coreaudio-rs", rev = "4ba39ca14bbb5bb0274843701cd958717a0fe293", optional = true } cubeb-pulse = { git = "https://github.com/mozilla/cubeb-pulse-rs", rev="8ff972c8e2ec1782ff262ac4071c0415e69b1367", optional = true, features=["pulse-dlopen"] } cubeb-sys = { version = "0.12.0", optional = true, features=["gecko-in-tree"] } audioipc2-client = { git = "https://github.com/mozilla/audioipc", rev = "596bdb7fbb5745ea415726e16bd497e6c850a540", optional = true }