diff --git a/third_party/rust/coreaudio-sys-utils/.cargo-checksum.json b/third_party/rust/coreaudio-sys-utils/.cargo-checksum.json index 114eecd0e169e..a2b80ca0e074e 100644 --- a/third_party/rust/coreaudio-sys-utils/.cargo-checksum.json +++ b/third_party/rust/coreaudio-sys-utils/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"87292d055a2fc0f070f54abd549a5f79ec8ac33611ecde80ba394f256b88294c","src/aggregate_device.rs":"7d2bd5f5fd7f3d008ebb69ad81f522ca0cb73db6d7b3e50ed1a63ea26ff721f4","src/audio_object.rs":"5447179330a862659a25bceedfdc5d29a1296f63490908d1c868c6b21c5f95a1","src/audio_unit.rs":"d783878930df4923b57ad230138c0f3fd6b0b9bb80a39725092ff4c6615162d8","src/cf_mutable_dict.rs":"fc42edd270c6dfb02f123214d2d8e487bbd62b5bd923b71eec13190fd0104d2a","src/dispatch.rs":"f6267fe587217c3d3ad5fe7f3a35955221c936103bf853c477a2e44eba5f1e46","src/lib.rs":"bcc559d69ef6ed0cbea5b2a36fec89d8c011eb9da70e2f26c00f881ad97a2546","src/string.rs":"28f88b816c768bcfcc674a60d962b93f1c94e5e0f4cc8ed2a1301138b91039e7"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"87292d055a2fc0f070f54abd549a5f79ec8ac33611ecde80ba394f256b88294c","src/aggregate_device.rs":"7d2bd5f5fd7f3d008ebb69ad81f522ca0cb73db6d7b3e50ed1a63ea26ff721f4","src/audio_device_extensions.rs":"44ae6cd160987ecb6dae4ac8752fca7ed43fa6921ddc5525b051fe20dbd61fb8","src/audio_object.rs":"5447179330a862659a25bceedfdc5d29a1296f63490908d1c868c6b21c5f95a1","src/audio_unit.rs":"d783878930df4923b57ad230138c0f3fd6b0b9bb80a39725092ff4c6615162d8","src/cf_mutable_dict.rs":"fc42edd270c6dfb02f123214d2d8e487bbd62b5bd923b71eec13190fd0104d2a","src/dispatch.rs":"f6267fe587217c3d3ad5fe7f3a35955221c936103bf853c477a2e44eba5f1e46","src/lib.rs":"c93ed1411dd6cc39db44f57e0d7683bbc54745f84a3c9f9533a088895ec97abe","src/string.rs":"28f88b816c768bcfcc674a60d962b93f1c94e5e0f4cc8ed2a1301138b91039e7"},"package":null} diff --git a/third_party/rust/coreaudio-sys-utils/src/audio_device_extensions.rs b/third_party/rust/coreaudio-sys-utils/src/audio_device_extensions.rs index 8224d87c285ee..9566d2f08a446 100644 --- a/third_party/rust/coreaudio-sys-utils/src/audio_device_extensions.rs +++ b/third_party/rust/coreaudio-sys-utils/src/audio_device_extensions.rs @@ -19,6 +19,7 @@ pub fn audio_device_duck( in_start_time: *const AudioTimeStamp, in_ramp_duration: f32, ) -> OSStatus { - debug_assert_running_serially(); + // can't use this unless we rework queue, if someone wants to do that + //debug_assert_running_serially(); unsafe { AudioDeviceDuck(in_device, in_ducked_level, in_start_time, in_ramp_duration) } } diff --git a/third_party/rust/coreaudio-sys-utils/src/lib.rs b/third_party/rust/coreaudio-sys-utils/src/lib.rs index 04efde0bbdfa8..5a6179604b036 100644 --- a/third_party/rust/coreaudio-sys-utils/src/lib.rs +++ b/third_party/rust/coreaudio-sys-utils/src/lib.rs @@ -2,6 +2,7 @@ extern crate core_foundation_sys; extern crate coreaudio_sys; pub mod aggregate_device; +pub mod audio_device_extensions; pub mod audio_object; pub mod audio_unit; pub mod cf_mutable_dict; diff --git a/third_party/rust/cubeb-coreaudio/.cargo-checksum.json b/third_party/rust/cubeb-coreaudio/.cargo-checksum.json index 81b1fe6287d8b..4a4111f9b0bbc 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":"a16b883e4fb41bdbbe5f68158040f181aeeffb4573ab0d493e9452f7c6f00541","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":"d6c3cde105ae0759e753cc31cab691eb417c4d0ad68f20da5e87fe0138a0d92f","run_tests.sh":"916a7ae4a406d2274417d6eca939a878db5adcb6144e5680d9d148bf90178f1c","src/backend/aggregate_device.rs":"43511107ba2a75a19340ac663c981362ca1b75b679b6c295d88b5035bd7e3619","src/backend/auto_release.rs":"050fdcee74cf46b9a8a85a877e166d72a853d33220f59cf734cbb6ea09daa441","src/backend/buffer_manager.rs":"314c3404f1a44f8c23856f96510779e7e64ebb7dde5abe444946c16d04af7c29","src/backend/device_property.rs":"a7622feaa41db1cd76fd35a85a022e44f4894e396a104a59008d5b8757d2ab4e","src/backend/mixer.rs":"c7c08cab5ad59c3903c2c5de3839b7a50bb64edbebdb6a50f48b58314a4bbd2b","src/backend/mod.rs":"87775f304d4b5258c5818fd67bc162e99c12da4ef70a956203f18e4b7aba0b86","src/backend/resampler.rs":"48bf8f56ae8d60dbabca6417b768000619abee8731ac3902164b45651ac08a4d","src/backend/tests/aggregate_device.rs":"e3f94e118e1dd47941fbba4417de40bddc4254d9f06b1e938f58d8f1aa566a5c","src/backend/tests/api.rs":"566546bec17220641960342374516da3baf6032a8843ac7a6c1f0b1cb8911594","src/backend/tests/backlog.rs":"3b189a7e036543c467cc242af0ed3332721179ee2b1c8847a6db563546f1ac52","src/backend/tests/device_change.rs":"b1b4f7f71de99d07406a8a38dc67e46a43b883d4a845daaf356e72fbe0d5a08b","src/backend/tests/device_property.rs":"ea0be5f8834be494cb33f854ce9d334b5763dc5287f949bcb4bd025d8a8b2d3b","src/backend/tests/interfaces.rs":"c8ca26d0fd098b8a230d9aa8d67a062da2ab3ac0f868739485c793618fc75700","src/backend/tests/manual.rs":"8d485a6666a3f4518b03e39dab80bf2acfd760af2d2f43bad99023cb135b38ca","src/backend/tests/mod.rs":"8dba770023d7f9c4228f0e11915347f0e07da5fd818e3ee4478c4b197af9aa2a","src/backend/tests/parallel.rs":"504613b1b5fa4d67cbb2560cb8d8cef0a4e8929c28b31d9d4695ac5286969f38","src/backend/tests/tone.rs":"779cc14fc2a362bf7f26ce66ad70c0639501176175655a99b7fefb3c59d56c7a","src/backend/tests/utils.rs":"7d74298435260566838ece9a84ee42e4a02c16683f5434d7ba2671a9acf4424f","src/backend/utils.rs":"6c3ffbcd602e6cc9f56deb9ecb07b2eef2e6f074ef924178e466f380aae5c595","src/capi.rs":"21b66b70545bf04ec719928004d1d9adb45b24ced51288f5b2993d79aaf78f5f","src/lib.rs":"5e586d45cd6b3722f0a6736d9252593299269817a153eef1930a5fb9bfbb56f5","todo.md":"efc1f012eb9a331a040cad4ac03aa79307f25885f71b6fb38f3ad7af8d7d515c"},"package":null} +{"files":{".circleci/config.yml":"7f3dc865105ca8f33965a7958b1fe2e627ae2d5a703f3b2a4ab6e2e796018597",".editorconfig":"4e53b182bcc78b83d7e1b5c03efa14d22d4955c4ed2514d1ba4e99c1eb1a50ba",".githooks/pre-push":"8b8b26544cd56f54c0c33812551f786bb25cb08c86dbfeb6bf3daad881c826a1",".github/workflows/test.yml":"cf6ebe6d41b022897360866b526d19ba8843aa82ae99a1d28393985576b6a782",".travis.yml":"dc07bac53f70f16c9bdf52264bdc58500ae6018c1b4c567bc7642f6b4ca3cc35","Cargo.toml":"2698cf87581d8d551ed3ac5875564720ed23d7b788e8d145d4281c8026203cd2","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":"d6c3cde105ae0759e753cc31cab691eb417c4d0ad68f20da5e87fe0138a0d92f","run_tests.sh":"916a7ae4a406d2274417d6eca939a878db5adcb6144e5680d9d148bf90178f1c","src/backend/aggregate_device.rs":"0ab2c09549925e76389f7bc99320a7bd3685c743df91f2f998ba6e4643166944","src/backend/auto_release.rs":"050fdcee74cf46b9a8a85a877e166d72a853d33220f59cf734cbb6ea09daa441","src/backend/buffer_manager.rs":"314c3404f1a44f8c23856f96510779e7e64ebb7dde5abe444946c16d04af7c29","src/backend/device_property.rs":"f186017c7b4dc439250e5e3370ec052732907009f378b3ed09fc4770f9b4e4a9","src/backend/mixer.rs":"c7c08cab5ad59c3903c2c5de3839b7a50bb64edbebdb6a50f48b58314a4bbd2b","src/backend/mod.rs":"81a87a667e2abce5f4cc15bf4aad4a40e32008ba9ba2e5448fe86f4fa4c56a41","src/backend/resampler.rs":"48bf8f56ae8d60dbabca6417b768000619abee8731ac3902164b45651ac08a4d","src/backend/tests/aggregate_device.rs":"d61ca263bb6fe893b10561a0ba1519f667d91e083ea9c7f732c63cbe09914e12","src/backend/tests/api.rs":"35939515799c0642b5df0fccadd46d6aa0e20372de2d98827dcde24ee3ad8eb1","src/backend/tests/backlog.rs":"3b189a7e036543c467cc242af0ed3332721179ee2b1c8847a6db563546f1ac52","src/backend/tests/device_change.rs":"b1b4f7f71de99d07406a8a38dc67e46a43b883d4a845daaf356e72fbe0d5a08b","src/backend/tests/device_property.rs":"ea0be5f8834be494cb33f854ce9d334b5763dc5287f949bcb4bd025d8a8b2d3b","src/backend/tests/interfaces.rs":"cd58614435574444d8a1f039dc201cf371cccacd58efbae8ed8fbff919550d0a","src/backend/tests/manual.rs":"632026f25a003d053ab69ddd1000fba10dfd4a679cb853d98fa83365e33e2b28","src/backend/tests/mod.rs":"8dba770023d7f9c4228f0e11915347f0e07da5fd818e3ee4478c4b197af9aa2a","src/backend/tests/parallel.rs":"504613b1b5fa4d67cbb2560cb8d8cef0a4e8929c28b31d9d4695ac5286969f38","src/backend/tests/tone.rs":"779cc14fc2a362bf7f26ce66ad70c0639501176175655a99b7fefb3c59d56c7a","src/backend/tests/utils.rs":"15d17b5078ad725d429685a4c7898beb58f21f08a7016a743dca4b015f3fc280","src/backend/utils.rs":"6c3ffbcd602e6cc9f56deb9ecb07b2eef2e6f074ef924178e466f380aae5c595","src/capi.rs":"21b66b70545bf04ec719928004d1d9adb45b24ced51288f5b2993d79aaf78f5f","src/lib.rs":"5e586d45cd6b3722f0a6736d9252593299269817a153eef1930a5fb9bfbb56f5","todo.md":"efc1f012eb9a331a040cad4ac03aa79307f25885f71b6fb38f3ad7af8d7d515c"},"package":null} 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 d0f71a73a1813..8e39144edc311 100644 --- a/third_party/rust/cubeb-coreaudio/src/backend/aggregate_device.rs +++ b/third_party/rust/cubeb-coreaudio/src/backend/aggregate_device.rs @@ -69,7 +69,7 @@ impl AggregateDevice { input_id: AudioObjectID, output_id: AudioObjectID, ) -> std::result::Result { - debug_assert_running_serially(); + //debug_assert_running_serially(); let plugin_id = Self::get_system_plugin_id()?; let device_id = Self::create_blank_device_sync(plugin_id)?; @@ -149,7 +149,7 @@ impl AggregateDevice { pub fn create_blank_device_sync( plugin_id: AudioObjectID, ) -> std::result::Result { - debug_assert_running_serially(); + //debug_assert_running_serially(); let waiting_time = Duration::new(5, 0); let condvar_pair = Arc::new((Mutex::new(()), Condvar::new())); @@ -218,7 +218,7 @@ impl AggregateDevice { plugin_id: AudioObjectID, ) -> std::result::Result { assert_ne!(plugin_id, kAudioObjectUnknown); - debug_assert_running_serially(); + //debug_assert_running_serially(); let address = AudioObjectPropertyAddress { mSelector: kAudioPlugInCreateAggregateDevice, @@ -307,7 +307,7 @@ impl AggregateDevice { input_id: AudioDeviceID, output_id: AudioDeviceID, ) -> std::result::Result<(), Error> { - debug_assert_running_serially(); + //debug_assert_running_serially(); let address = AudioObjectPropertyAddress { mSelector: kAudioAggregateDevicePropertyFullSubDeviceList, mScope: kAudioObjectPropertyScopeGlobal, @@ -394,7 +394,7 @@ impl AggregateDevice { assert_ne!(input_id, kAudioObjectUnknown); assert_ne!(output_id, kAudioObjectUnknown); assert_ne!(input_id, output_id); - debug_assert_running_serially(); + //debug_assert_running_serially(); let output_sub_devices = Self::get_sub_devices(output_id)?; let input_sub_devices = Self::get_sub_devices(input_id)?; @@ -434,7 +434,7 @@ impl AggregateDevice { device_id: AudioDeviceID, ) -> std::result::Result, Error> { assert_ne!(device_id, kAudioObjectUnknown); - debug_assert_running_serially(); + //debug_assert_running_serially(); let mut sub_devices = Vec::new(); let address = AudioObjectPropertyAddress { @@ -472,7 +472,7 @@ impl AggregateDevice { } pub fn get_master_device_uid(device_id: AudioDeviceID) -> std::result::Result { - debug_assert_running_serially(); + //debug_assert_running_serially(); let address = AudioObjectPropertyAddress { mSelector: kAudioAggregateDevicePropertyMainSubDevice, mScope: kAudioObjectPropertyScopeGlobal, @@ -500,7 +500,7 @@ impl AggregateDevice { ) -> std::result::Result<(), Error> { assert_ne!(device_id, kAudioObjectUnknown); assert_ne!(primary_id, kAudioObjectUnknown); - debug_assert_running_serially(); + //debug_assert_running_serially(); cubeb_log!( "Set master device of the aggregate device {} to device {}", @@ -532,7 +532,7 @@ impl AggregateDevice { device_id: AudioObjectID, ) -> std::result::Result<(), Error> { assert_ne!(device_id, kAudioObjectUnknown); - debug_assert_running_serially(); + //debug_assert_running_serially(); let address = AudioObjectPropertyAddress { mSelector: kAudioObjectPropertyOwnedObjects, mScope: kAudioObjectPropertyScopeGlobal, @@ -616,7 +616,7 @@ impl AggregateDevice { ) -> std::result::Result<(), Error> { assert_ne!(plugin_id, kAudioObjectUnknown); assert_ne!(device_id, kAudioObjectUnknown); - debug_assert_running_serially(); + //debug_assert_running_serially(); let address = AudioObjectPropertyAddress { mSelector: kAudioPlugInDestroyAggregateDevice, @@ -648,7 +648,7 @@ impl AggregateDevice { assert_ne!(input_id, kAudioObjectUnknown); assert_ne!(output_id, kAudioObjectUnknown); assert_ne!(input_id, output_id); - debug_assert_running_serially(); + //debug_assert_running_serially(); let label = get_device_label(input_id, DeviceType::INPUT)?; let input_label = label.into_string(); @@ -710,7 +710,7 @@ impl Default for AggregateDevice { impl Drop for AggregateDevice { fn drop(&mut self) { - debug_assert_running_serially(); + //debug_assert_running_serially(); if self.plugin_id != kAudioObjectUnknown && self.device_id != kAudioObjectUnknown { if let Err(r) = Self::destroy_device(self.plugin_id, self.device_id) { cubeb_log!( diff --git a/third_party/rust/cubeb-coreaudio/src/backend/device_property.rs b/third_party/rust/cubeb-coreaudio/src/backend/device_property.rs index 6a85f22359aa2..e9cb53c7a09a4 100644 --- a/third_party/rust/cubeb-coreaudio/src/backend/device_property.rs +++ b/third_party/rust/cubeb-coreaudio/src/backend/device_property.rs @@ -5,7 +5,7 @@ pub fn get_device_uid( devtype: DeviceType, ) -> std::result::Result { assert_ne!(id, kAudioObjectUnknown); - debug_assert_running_serially(); + //debug_assert_running_serially(); let address = get_property_address(Property::DeviceUID, devtype); let mut size = mem::size_of::(); @@ -23,7 +23,7 @@ pub fn get_device_model_uid( devtype: DeviceType, ) -> std::result::Result { assert_ne!(id, kAudioObjectUnknown); - debug_assert_running_serially(); + //debug_assert_running_serially(); let address = get_property_address(Property::ModelUID, devtype); let mut size = mem::size_of::(); @@ -41,7 +41,7 @@ pub fn get_device_transport_type( devtype: DeviceType, ) -> std::result::Result { assert_ne!(id, kAudioObjectUnknown); - debug_assert_running_serially(); + //debug_assert_running_serially(); let address = get_property_address(Property::TransportType, devtype); let mut size = mem::size_of::(); @@ -59,7 +59,7 @@ pub fn get_device_source( devtype: DeviceType, ) -> std::result::Result { assert_ne!(id, kAudioObjectUnknown); - debug_assert_running_serially(); + //debug_assert_running_serially(); let address = get_property_address(Property::DeviceSource, devtype); let mut size = mem::size_of::(); @@ -77,7 +77,7 @@ pub fn get_device_source_name( devtype: DeviceType, ) -> std::result::Result { assert_ne!(id, kAudioObjectUnknown); - debug_assert_running_serially(); + //debug_assert_running_serially(); let mut source: u32 = get_device_source(id, devtype)?; let address = get_property_address(Property::DeviceSourceName, devtype); @@ -102,7 +102,7 @@ pub fn get_device_name( devtype: DeviceType, ) -> std::result::Result { assert_ne!(id, kAudioObjectUnknown); - debug_assert_running_serially(); + //debug_assert_running_serially(); let address = get_property_address(Property::DeviceName, devtype); let mut size = mem::size_of::(); @@ -120,7 +120,7 @@ pub fn get_device_manufacturer( devtype: DeviceType, ) -> std::result::Result { assert_ne!(id, kAudioObjectUnknown); - debug_assert_running_serially(); + //debug_assert_running_serially(); let address = get_property_address(Property::DeviceManufacturer, devtype); let mut size = mem::size_of::(); @@ -138,7 +138,7 @@ pub fn get_device_buffer_frame_size_range( devtype: DeviceType, ) -> std::result::Result { assert_ne!(id, kAudioObjectUnknown); - debug_assert_running_serially(); + //debug_assert_running_serially(); let address = get_property_address(Property::DeviceBufferFrameSizeRange, devtype); let mut size = mem::size_of::(); @@ -156,7 +156,7 @@ pub fn get_device_latency( devtype: DeviceType, ) -> std::result::Result { assert_ne!(id, kAudioObjectUnknown); - debug_assert_running_serially(); + //debug_assert_running_serially(); let address = get_property_address(Property::DeviceLatency, devtype); let mut size = mem::size_of::(); @@ -174,7 +174,7 @@ pub fn get_device_streams( devtype: DeviceType, ) -> std::result::Result, OSStatus> { assert_ne!(id, kAudioObjectUnknown); - debug_assert_running_serially(); + //debug_assert_running_serially(); let address = get_property_address(Property::DeviceStreams, devtype); @@ -198,7 +198,7 @@ pub fn get_device_sample_rate( devtype: DeviceType, ) -> std::result::Result { assert_ne!(id, kAudioObjectUnknown); - debug_assert_running_serially(); + //debug_assert_running_serially(); let address = get_property_address(Property::DeviceSampleRate, devtype); let mut size = mem::size_of::(); @@ -216,7 +216,7 @@ pub fn get_ranges_of_device_sample_rate( devtype: DeviceType, ) -> std::result::Result, OSStatus> { assert_ne!(id, kAudioObjectUnknown); - debug_assert_running_serially(); + //debug_assert_running_serially(); let address = get_property_address(Property::DeviceSampleRates, devtype); @@ -237,7 +237,7 @@ pub fn get_ranges_of_device_sample_rate( pub fn get_stream_latency(id: AudioStreamID) -> std::result::Result { assert_ne!(id, kAudioObjectUnknown); - debug_assert_running_serially(); + //debug_assert_running_serially(); let address = get_property_address( Property::StreamLatency, @@ -255,7 +255,7 @@ pub fn get_stream_latency(id: AudioStreamID) -> std::result::Result std::result::Result { assert_ne!(id, kAudioObjectUnknown); - debug_assert_running_serially(); + //debug_assert_running_serially(); let address = get_property_address( Property::StreamTerminalType, @@ -275,7 +275,7 @@ pub fn get_stream_virtual_format( id: AudioStreamID, ) -> std::result::Result { assert_ne!(id, kAudioObjectUnknown); - debug_assert_running_serially(); + //debug_assert_running_serially(); let address = get_property_address( Property::StreamVirtualFormat, @@ -296,7 +296,7 @@ pub fn get_clock_domain( devtype: DeviceType, ) -> std::result::Result { assert_ne!(id, kAudioObjectUnknown); - debug_assert_running_serially(); + //debug_assert_running_serially(); let address = get_property_address(Property::ClockDomain, devtype); let mut size = mem::size_of::(); diff --git a/third_party/rust/cubeb-coreaudio/src/backend/mod.rs b/third_party/rust/cubeb-coreaudio/src/backend/mod.rs index cbffb0300bab8..930a8dfbdea45 100644 --- a/third_party/rust/cubeb-coreaudio/src/backend/mod.rs +++ b/third_party/rust/cubeb-coreaudio/src/backend/mod.rs @@ -37,7 +37,7 @@ use backend::ringbuf::RingBuffer; #[cfg(feature = "audio-dump")] use cubeb_backend::ffi::cubeb_audio_dump_stream_t; use cubeb_backend::{ - ffi, Context, ContextOps, DeviceCollectionRef, DeviceId, DeviceRef, DeviceType, Error, + ffi, ChannelLayout, Context, ContextOps, DeviceCollectionRef, DeviceId, DeviceRef, DeviceType, Error, InputProcessingParams, Ops, Result, SampleFormat, State, Stream, StreamOps, StreamParams, StreamParamsRef, StreamPrefs, }; @@ -49,9 +49,10 @@ use std::mem; use std::os::raw::{c_uint, c_void}; use std::ptr; use std::slice; +use std::str::FromStr; use std::sync::atomic::{AtomicBool, AtomicU32, AtomicUsize, Ordering}; -use std::sync::{Arc, Condvar, Mutex}; -use std::time::Duration; +use std::sync::{Arc, Condvar, Mutex, MutexGuard, Weak}; +use std::time::{Duration, Instant}; const NO_ERR: OSStatus = 0; const AU_OUT_BUS: AudioUnitElement = 0; @@ -61,11 +62,41 @@ 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; const SAFE_MAX_LATENCY_FRAMES: u32 = 512; +const VPIO_IDLE_TIMEOUT: Duration = Duration::from_secs(10); + +const MACOS_KERNEL_MAJOR_VERSION_MONTEREY: u32 = 21; + +#[derive(Debug, PartialEq)] +enum ParseMacOSKernelVersionError { + SysCtl, + Malformed, + Parsing, +} + +fn macos_kernel_major_version() -> std::result::Result { + let ver = whatsys::kernel_version(); + if ver.is_none() { + return Err(ParseMacOSKernelVersionError::SysCtl); + } + let ver = ver.unwrap(); + let major = ver.split('.').next(); + if major.is_none() { + return Err(ParseMacOSKernelVersionError::Malformed); + } + let parsed_major = u32::from_str(major.unwrap()); + if parsed_major.is_err() { + return Err(ParseMacOSKernelVersionError::Parsing); + } + Ok(parsed_major.unwrap()) +} + bitflags! { #[allow(non_camel_case_types)] #[derive(Clone, Debug, PartialEq, Copy)] @@ -868,7 +899,7 @@ extern "C" fn audiounit_property_listener_callback( } fn get_default_device(devtype: DeviceType) -> Option { - debug_assert_running_serially(); + //debug_assert_running_serially(); match get_default_device_id(devtype) { Err(e) => { cubeb_log!("Cannot get default {:?} device. Error: {}", devtype, e); @@ -883,7 +914,7 @@ fn get_default_device(devtype: DeviceType) -> Option { } fn get_default_device_id(devtype: DeviceType) -> std::result::Result { - debug_assert_running_serially(); + //debug_assert_running_serially(); let address = get_property_address( match devtype { DeviceType::INPUT => Property::HardwareDefaultInputDevice, @@ -931,7 +962,7 @@ fn audiounit_convert_channel_layout(layout: &AudioChannelLayout) -> Result Result> { - debug_assert_running_serially(); + //debug_assert_running_serially(); let mut rv = NO_ERR; let mut size: usize = 0; rv = audio_unit_get_property_info( @@ -974,7 +1005,7 @@ fn audiounit_get_preferred_channel_layout(output_unit: AudioUnit) -> Result Result> { - debug_assert_running_serially(); + //debug_assert_running_serially(); let mut rv = NO_ERR; let mut size: usize = 0; rv = audio_unit_get_property_info( @@ -1015,7 +1046,7 @@ fn audiounit_get_current_channel_layout(output_unit: AudioUnit) -> Result Result> { - debug_assert_running_serially(); + //debug_assert_running_serially(); audiounit_get_current_channel_layout(output_unit) .or_else(|_| { // The kAudioUnitProperty_AudioChannelLayout property isn't known before @@ -1055,7 +1086,7 @@ fn create_audiounit(device: &device_info) -> Result { assert!(!device .flags .contains(device_flags::DEV_INPUT | device_flags::DEV_OUTPUT)); - debug_assert_running_serially(); + //debug_assert_running_serially(); let unit = create_blank_audiounit()?; let mut bus = AU_OUT_BUS; @@ -1103,53 +1134,81 @@ fn create_audiounit(device: &device_info) -> Result { Ok(unit) } -fn create_voiceprocessing_audiounit( + +fn create_voiceprocessing_audiounit() -> Result { + let res = create_typed_audiounit(kAudioUnitSubType_VoiceProcessingIO); + if res.is_err() { + return Err(Error::error()); + } + + match get_default_device(DeviceType::OUTPUT) { + None => { + cubeb_log!("Could not get default output device in order to undo vpio ducking"); + } + Some(id) => { + let r = audio_device_duck(id, 1.0, ptr::null_mut(), 0.5); + if r != NO_ERR { + cubeb_log!( + "Failed to undo ducking of voiceprocessing on output device {}. Proceeding... Error: {}", + id, + r + ); + } + } + }; + + res.map(|unit| VoiceProcessingUnit { unit }) +} +fn get_voiceprocessing_audiounit( + shared_voice_processing_unit: &mut SharedVoiceProcessingUnitManager, in_device: &device_info, out_device: &device_info, -) -> Result { +) -> Result> { + //debug_assert_running_serially(); assert!(in_device.flags.contains(device_flags::DEV_INPUT)); assert!(!in_device.flags.contains(device_flags::DEV_OUTPUT)); assert!(!out_device.flags.contains(device_flags::DEV_INPUT)); - assert!(out_device.flags.contains(device_flags::DEV_OUTPUT)); - - let unit = create_typed_audiounit(kAudioUnitSubType_VoiceProcessingIO)?; - if let Err(e) = set_device_to_audiounit(unit, in_device.id, AU_IN_BUS) { + let unit_handle = shared_voice_processing_unit.take_or_create(); + if let Err(e) = unit_handle { cubeb_log!( - "Failed to set in device {} to the created audiounit. Error: {}", - in_device.id, + "Failed to create shared voiceprocessing audiounit. Error: {}", e ); - dispose_audio_unit(unit); return Err(Error::error()); } + let mut unit_handle = unit_handle.unwrap(); - if let Err(e) = set_device_to_audiounit(unit, out_device.id, AU_OUT_BUS) { + if let Err(e) = set_device_to_audiounit(unit_handle.as_mut().unit, in_device.id, AU_IN_BUS) { cubeb_log!( - "Failed to set out device {} to the created audiounit. Error: {}", - out_device.id, + "Failed to set in device {} to the created audiounit. Error: {}", + in_device.id, e ); - dispose_audio_unit(unit); return Err(Error::error()); } - let bypass = u32::from(true); - let r = audio_unit_set_property( - unit, - kAudioUnitProperty_BypassEffect, - kAudioUnitScope_Global, - AU_IN_BUS, - &bypass, - mem::size_of::(), - ); - if r != NO_ERR { - cubeb_log!("Failed to enable bypass of voiceprocessing. Error: {}", r); - dispose_audio_unit(unit); + let has_output = out_device.id != kAudioObjectUnknown; + if let Err(e) = + enable_audiounit_scope(unit_handle.as_mut().unit, DeviceType::OUTPUT, has_output) + { + cubeb_log!("Failed to enable audiounit input scope. Error: {}", e); return Err(Error::error()); } + if has_output { + if let Err(e) = + set_device_to_audiounit(unit_handle.as_mut().unit, out_device.id, AU_OUT_BUS) + { + cubeb_log!( + "Failed to set out device {} to the created audiounit. Error: {}", + out_device.id, + e + ); + return Err(Error::error()); + } + } - Ok(unit) + Ok(unit_handle) } fn enable_audiounit_scope( @@ -1438,7 +1497,7 @@ fn get_channel_count( devtype: DeviceType, ) -> std::result::Result { assert_ne!(devid, kAudioObjectUnknown); - debug_assert_running_serially(); + //debug_assert_running_serially(); let mut streams = get_device_streams(devid, devtype)?; @@ -1490,7 +1549,7 @@ fn get_range_of_sample_rates( devid: AudioObjectID, devtype: DeviceType, ) -> std::result::Result<(f64, f64), String> { - debug_assert_running_serially(); + //debug_assert_running_serially(); let result = get_ranges_of_device_sample_rate(devid, devtype); if let Err(e) = result { return Err(format!("status {}", e)); @@ -1512,7 +1571,7 @@ fn get_range_of_sample_rates( } fn get_fixed_latency(devid: AudioObjectID, devtype: DeviceType) -> u32 { - debug_assert_running_serially(); + //debug_assert_running_serially(); let device_latency = match get_device_latency(devid, devtype) { Ok(latency) => latency, Err(e) => { @@ -1555,7 +1614,7 @@ fn get_device_group_id( id: AudioDeviceID, devtype: DeviceType, ) -> std::result::Result { - debug_assert_running_serially(); + //debug_assert_running_serially(); match get_device_transport_type(id, devtype) { Ok(kAudioDeviceTransportTypeBuiltIn) => { cubeb_log!( @@ -1591,7 +1650,7 @@ fn get_device_group_id( } fn get_custom_group_id(id: AudioDeviceID, devtype: DeviceType) -> Option { - debug_assert_running_serially(); + //debug_assert_running_serially(); const IMIC: u32 = 0x696D_6963; // "imic" (internal microphone) const ISPK: u32 = 0x6973_706B; // "ispk" (internal speaker) @@ -1634,12 +1693,12 @@ fn get_device_label( id: AudioDeviceID, devtype: DeviceType, ) -> std::result::Result { - debug_assert_running_serially(); + //debug_assert_running_serially(); get_device_source_name(id, devtype).or_else(|_| get_device_name(id, devtype)) } fn get_device_global_uid(id: AudioDeviceID) -> std::result::Result { - debug_assert_running_serially(); + //debug_assert_running_serially(); get_device_uid(id, DeviceType::INPUT | DeviceType::OUTPUT) } @@ -1822,7 +1881,7 @@ fn destroy_cubeb_device_info(device: &mut ffi::cubeb_device_info) { } fn audiounit_get_devices() -> Vec { - debug_assert_running_serially(); + //debug_assert_running_serially(); let mut size: usize = 0; let address = get_property_address( Property::HardwareDevices, @@ -1849,7 +1908,7 @@ fn audiounit_get_devices() -> Vec { fn audiounit_get_devices_of_type(devtype: DeviceType) -> Vec { assert!(devtype.intersects(DeviceType::INPUT | DeviceType::OUTPUT)); - debug_assert_running_serially(); + //debug_assert_running_serially(); let mut devices = audiounit_get_devices(); @@ -2027,6 +2086,316 @@ impl LatencyController { } } + +// SharedStorage below looks generic but has evolved to be pretty tailored +// the observed behavior of VoiceProcessingIO audio units on macOS 14. +// Some key points are: +// - Creating the first VoiceProcessingIO unit in a process takes a long time, often > 3s. +// - Creating a second VoiceProcessingIO unit in a process is significantly faster, < 1s. +// - Disposing of a VoiceProcessingIO unit when all other VoiceProcessingIO units are +// uninitialized will take significantly longer than disposing the remaining +// VoiceProcessingIO units, and will have other side effects: starting another +// VoiceProcessingIO unit after this is on par with creating the first one in the +// process, bluetooth devices will move away from the handsfree profile, etc. +// The takeaway is that there is something internal to the VoiceProcessingIO audio unit +// that is costly to create and dispose of and its creation is triggered by creation of +// the first VoiceProcessingIO unit, and its disposal is triggered by the disposal of +// the first VoiceProcessingIO unit when no other VoiceProcessingIO units are initialized. +// +// The intended behavior of SharedStorage and SharedVoiceProcessingUnitManager is therefore: +// - Retain ideally just one VoiceProcessingIO unit after stream destruction, so device +// switching is fast. The benefit of retaining more than one is unclear. +// - Dispose of either all VoiceProcessingIO units, or none at all, such that the retained +// VoiceProcessingIO unit really helps speed up creating and starting the next. In practice +// this means we retain all VoiceProcessingIO units until they can all be disposed of. + +#[derive(Debug)] +struct SharedStorageInternal { + // Storage for shared elements. + elements: Vec, + // Number of elements in use, i.e. all elements created/taken and not recycled. + outstanding_element_count: usize, + // Used for invalidation of in-flight tasks to clear elements. + // Incremented when something takes a shared element. + generation: usize, +} + +#[derive(Debug)] +struct SharedStorage { + queue: Queue, + idle_timeout: Duration, + storage: Mutex>, +} + +impl SharedStorage { + fn with_idle_timeout(queue: Queue, idle_timeout: Duration) -> Self { + Self { + queue, + idle_timeout, + storage: Mutex::new(SharedStorageInternal:: { + elements: Vec::default(), + outstanding_element_count: 0, + generation: 0, + }), + } + } + + fn take_locked(guard: &mut MutexGuard<'_, SharedStorageInternal>) -> Result { + if let Some(e) = guard.elements.pop() { + cubeb_log!("Taking shared element #{}.", guard.elements.len()); + guard.outstanding_element_count += 1; + guard.generation += 1; + return Ok(e); + } + + Err(Error::not_supported()) + } + + fn create_with_locked( + guard: &mut MutexGuard<'_, SharedStorageInternal>, + f: F, + ) -> Result + where + F: FnOnce() -> Result, + { + let start = Instant::now(); + match f() { + Ok(obj) => { + cubeb_log!( + "Just created shared element #{}. Took {}s.", + guard.outstanding_element_count, + (Instant::now() - start).as_secs_f32() + ); + guard.outstanding_element_count += 1; + guard.generation += 1; + Ok(obj) + } + Err(_) => { + cubeb_log!("Creating shared element failed"); + Err(Error::error()) + } + } + } + + #[cfg(test)] + fn take(&self) -> Result { + let mut guard = self.storage.lock().unwrap(); + SharedStorage::take_locked(&mut guard) + } + + fn take_or_create_with(&self, f: F) -> Result + where + F: FnOnce() -> Result, + { + let mut guard = self.storage.lock().unwrap(); + SharedStorage::take_locked(&mut guard) + .or_else(|_| SharedStorage::create_with_locked(&mut guard, f)) + } + + fn recycle(&self, obj: T) { + let mut guard = self.storage.lock().unwrap(); + guard.outstanding_element_count -= 1; + cubeb_log!( + "Recycling shared element #{}. Nr of live elements now {}.", + guard.elements.len(), + guard.outstanding_element_count + ); + guard.elements.push(obj); + } + + fn clear_locked(guard: &mut MutexGuard<'_, SharedStorageInternal>) { + let count = guard.elements.len(); + let start = Instant::now(); + guard.elements.clear(); + cubeb_log!( + "Cleared {} shared element{}. Took {}s.", + count, + if count == 1 { "" } else { "s" }, + (Instant::now() - start).as_secs_f32() + ); + } + + fn clear(&self) { + //debug_assert_running_serially(); + let mut guard = self.storage.lock().unwrap(); + SharedStorage::clear_locked(&mut guard); + } + + fn clear_if_all_idle_async(storage: &Arc>) { + let (queue, outstanding_element_count, generation) = { + let guard = storage.storage.lock().unwrap(); + ( + storage.queue.clone(), + guard.outstanding_element_count, + guard.generation, + ) + }; + if outstanding_element_count > 0 { + cubeb_log!( + "Not clearing shared voiceprocessing unit storage because {} elements are in use. Generation={}.", + outstanding_element_count, + generation + ); + return; + } + cubeb_log!( + "Clearing shared voiceprocessing unit storage in {}s if still at generation {}.", + storage.idle_timeout.as_secs_f32(), + generation + ); + let storage = storage.clone(); + /* we don't use this anyways on older macs + * queue.run_after(Instant::now() + storage.idle_timeout, move || { + let mut guard = storage.storage.lock().unwrap(); + if generation != guard.generation { + cubeb_log!( + "Not clearing shared voiceprocessing unit storage for generation {} as we're now at {}.", + generation, + guard.generation + ); + return; + } + SharedStorage::clear_locked(&mut guard); + });*/ + } +} + +#[derive(Debug)] +struct OwningHandle +where + T: Send, +{ + storage: Weak>, + obj: Option, +} + +impl OwningHandle { + fn new(storage: Weak>, obj: T) -> Self { + Self { + storage, + obj: Some(obj), + } + } +} + +impl AsRef for OwningHandle { + fn as_ref(&self) -> &T { + self.obj.as_ref().unwrap() + } +} + +impl AsMut for OwningHandle { + fn as_mut(&mut self) -> &mut T { + self.obj.as_mut().unwrap() + } +} + +impl Drop for OwningHandle { + fn drop(&mut self) { + let storage = self.storage.upgrade(); + assert!( + storage.is_some(), + "Storage must outlive the handle, but didn't" + ); + let storage = storage.unwrap(); + if self.obj.is_none() { + return; + } + let obj = self.obj.take().unwrap(); + storage.recycle(obj); + SharedStorage::clear_if_all_idle_async(&storage); + } +} + +#[derive(Debug)] +struct VoiceProcessingUnit { + unit: AudioUnit, +} + +impl Drop for VoiceProcessingUnit { + fn drop(&mut self) { + assert!(!self.unit.is_null()); + dispose_audio_unit(self.unit); + } +} + +unsafe impl Send for VoiceProcessingUnit {} + +#[derive(Debug)] +struct SharedVoiceProcessingUnitManager { + sync_storage: Mutex>>>, + queue: Queue, + idle_timeout: Duration, +} + +impl SharedVoiceProcessingUnitManager { + fn with_idle_timeout(queue: Queue, idle_timeout: Duration) -> Self { + Self { + sync_storage: Mutex::new(None), + queue, + idle_timeout, + } + } + + fn new(queue: Queue) -> Self { + SharedVoiceProcessingUnitManager::with_idle_timeout(queue, VPIO_IDLE_TIMEOUT) + } + + fn ensure_storage_locked( + &self, + guard: &mut MutexGuard>>>, + ) { + if guard.is_some() { + return; + } + cubeb_log!("Creating shared voiceprocessing storage."); + let storage = SharedStorage::::with_idle_timeout( + self.queue.clone(), + self.idle_timeout, + ); + let old_storage = guard.replace(Arc::from(storage)); + assert!(old_storage.is_none()); + } + + // Take an already existing, shared, vpio unit, if one is available. + #[cfg(test)] + fn take(&mut self) -> Result> { + //debug_assert_running_serially(); + let mut guard = self.sync_storage.lock().unwrap(); + self.ensure_storage_locked(&mut guard); + let storage = guard.as_mut().unwrap(); + let res = storage.take(); + res.map(|u| OwningHandle::new(Arc::downgrade(storage), u)) + } + + // Take an already existing, shared, vpio unit, or create one if none are available. + fn take_or_create(&mut self) -> Result> { + //debug_assert_running_serially(); + let mut guard = self.sync_storage.lock().unwrap(); + self.ensure_storage_locked(&mut guard); + let storage = guard.as_mut().unwrap(); + //bug. wrong argument. who cares. we don't use this anyways for older macs + let res = storage.take_or_create_with(create_voiceprocessing_audiounit); + res.map(|u| OwningHandle::new(Arc::downgrade(storage), u)) + } +} + +unsafe impl Send for SharedVoiceProcessingUnitManager {} +unsafe impl Sync for SharedVoiceProcessingUnitManager {} + +impl Drop for SharedVoiceProcessingUnitManager { + fn drop(&mut self) { + //debug_assert_not_running_serially(); + self.queue.run_final(|| { + let mut guard = self.sync_storage.lock().unwrap(); + if guard.is_none() { + return; + } + guard.as_mut().unwrap().clear(); + }); + } + +} pub const OPS: Ops = capi_new!(AudioUnitContext, AudioUnitStream); // The fisrt member of the Cubeb context must be a pointer to a Ops struct. The Ops struct is an @@ -2040,15 +2409,22 @@ pub struct AudioUnitContext { serial_queue: Queue, latency_controller: Mutex, devices: Mutex, + // Storage for a context-global vpio unit. Duplex streams that need one will take this + // and return it when done. + shared_voice_processing_unit: SharedVoiceProcessingUnitManager, } impl AudioUnitContext { fn new() -> Self { + let shared_vp_queue = Queue::new( + format!("{}.context.shared_vpio", DISPATCH_QUEUE_LABEL).as_str() + ); Self { _ops: &OPS as *const _, serial_queue: Queue::new(DISPATCH_QUEUE_LABEL), latency_controller: Mutex::new(LatencyController::default()), devices: Mutex::new(SharedDevices::default()), + shared_voice_processing_unit: SharedVoiceProcessingUnitManager::new(shared_vp_queue), } } @@ -2191,8 +2567,10 @@ impl ContextOps for AudioUnitContext { } #[cfg(not(target_os = "ios"))] fn max_channel_count(&mut self) -> Result { - self.serial_queue - .run_sync(|| { + //we have to figure out a way to backport the serial_queue declaration without + //dispatch_with_target. until we do, comment this out. + //self.serial_queue + // .run_sync(|| { let device = match get_default_device(DeviceType::OUTPUT) { None => { cubeb_log!("Could not get default output device"); @@ -2204,8 +2582,8 @@ impl ContextOps for AudioUnitContext { cubeb_log!("Cannot get the channel count. Error: {}", e); Error::error() }) - }) - .unwrap() + //}) + //.unwrap() } #[cfg(target_os = "ios")] fn min_latency(&mut self, _params: StreamParams) -> Result { @@ -2213,8 +2591,8 @@ impl ContextOps for AudioUnitContext { } #[cfg(not(target_os = "ios"))] fn min_latency(&mut self, _params: StreamParams) -> Result { - self.serial_queue - .run_sync(|| { + // self.serial_queue + // .run_sync(|| { let device = match get_default_device(DeviceType::OUTPUT) { None => { cubeb_log!("Could not get default output device"); @@ -2230,8 +2608,8 @@ impl ContextOps for AudioUnitContext { })?; Ok(cmp::max(range.mMinimum as u32, SAFE_MIN_LATENCY_FRAMES)) - }) - .unwrap() + // }) + // .unwrap() } #[cfg(target_os = "ios")] fn preferred_sample_rate(&mut self) -> Result { @@ -2239,8 +2617,8 @@ impl ContextOps for AudioUnitContext { } #[cfg(not(target_os = "ios"))] fn preferred_sample_rate(&mut self) -> Result { - self.serial_queue - .run_sync(|| { + //self.serial_queue + // .run_sync(|| { let device = match get_default_device(DeviceType::OUTPUT) { None => { cubeb_log!("Could not get default output device"); @@ -2256,8 +2634,8 @@ impl ContextOps for AudioUnitContext { Error::error() })?; Ok(rate as u32) - }) - .unwrap() + // }) + // .unwrap() } fn supported_input_processing_params(&mut self) -> Result { Ok(InputProcessingParams::NONE) @@ -2267,7 +2645,7 @@ impl ContextOps for AudioUnitContext { devtype: DeviceType, collection: &DeviceCollectionRef, ) -> Result<()> { - let device_infos = self + /*let device_infos = self .serial_queue .run_sync(|| { let mut dev_types = vec![DeviceType::INPUT, DeviceType::OUTPUT]; @@ -2288,6 +2666,20 @@ impl ContextOps for AudioUnitContext { device_infos }) .unwrap(); + */ + let mut device_infos = Vec::new(); + let dev_types = [DeviceType::INPUT, DeviceType::OUTPUT]; + for dev_type in dev_types.iter() { + if !devtype.contains(*dev_type) { + continue; + } + let devices = audiounit_get_devices_of_type(*dev_type); + for device in devices { + if let Ok(info) = create_cubeb_device_info(device, *dev_type) { + device_infos.push(info); + } + } + } let (ptr, len) = if device_infos.is_empty() { (ptr::null_mut(), 0) } else { @@ -2296,6 +2688,7 @@ impl ContextOps for AudioUnitContext { let coll = unsafe { &mut *collection.as_ptr() }; coll.device = ptr; coll.count = len; + Ok(()) } fn device_collection_destroy(&mut self, collection: &mut DeviceCollectionRef) -> Result<()> { @@ -2404,16 +2797,15 @@ impl ContextOps for AudioUnitContext { boxed_stream.core_stream_data = CoreStreamData::new(boxed_stream.as_ref(), in_stm_settings, out_stm_settings); - let mut result = Ok(()); - boxed_stream.queue.clone().run_sync(|| { - result = boxed_stream.core_stream_data.setup(); - }); - if let Err(r) = result { + if let Err(r) = boxed_stream.core_stream_data.setup( + &mut boxed_stream.context.shared_voice_processing_unit + ) { cubeb_log!( "({:p}) Could not setup the audiounit stream.", boxed_stream.as_ref() ); return Err(r); + } let cubeb_stream = unsafe { Stream::from_ptr(Box::into_raw(boxed_stream) as *mut _) }; @@ -2529,6 +2921,8 @@ struct CoreStreamData<'ctx> { // I/O AudioUnits. input_unit: AudioUnit, output_unit: AudioUnit, + // Handle to shared voiceprocessing AudioUnit, if in use. + voiceprocessing_unit_handle: Option>, // Info of the I/O devices. input_device: device_info, output_device: device_info, @@ -2576,6 +2970,7 @@ impl<'ctx> Default for CoreStreamData<'ctx> { output_dev_desc: AudioStreamBasicDescription::default(), input_unit: ptr::null_mut(), output_unit: ptr::null_mut(), + voiceprocessing_unit_handle: None, input_device: device_info::default(), output_device: device_info::default(), input_buffer_manager: None, @@ -2628,6 +3023,7 @@ impl<'ctx> CoreStreamData<'ctx> { output_dev_desc: AudioStreamBasicDescription::default(), input_unit: ptr::null_mut(), output_unit: ptr::null_mut(), + voiceprocessing_unit_handle: None, input_device: in_dev, output_device: out_dev, input_buffer_manager: None, @@ -2729,9 +3125,94 @@ impl<'ctx> CoreStreamData<'ctx> { input_domain == output_domain } - fn create_audiounits(&mut self) -> Result<(device_info, device_info)> { + #[allow(non_upper_case_globals)] + fn should_force_vpio_for_input_device(&self, in_device: &device_info) -> bool { + assert!(in_device.id != kAudioObjectUnknown); + self.debug_assert_is_on_stream_queue(); + match get_device_transport_type(in_device.id, DeviceType::INPUT) { + Ok(kAudioDeviceTransportTypeBuiltIn) => { + cubeb_log!( + "Forcing VPIO because input device is built in, and its volume \ + is known to be very low without VPIO whenever VPIO is hooked up to it elsewhere." + ); + true + } + _ => false, + } + } + + 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_and_get_model_uid = |id, devtype| -> String { + let device_model_uid = get_device_model_uid(id, devtype) + .map(|s| s.into_string()) + .unwrap_or_default(); + 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(), + device_model_uid, + 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()); + device_model_uid + }; + + #[allow(non_upper_case_globals)] + let in_id = match in_device.id { + kAudioObjectUnknown => None, + id => Some(id), + }; + #[allow(non_upper_case_globals)] + let out_id = match out_device.id { + kAudioObjectUnknown => None, + id => Some(id), + }; + + let (in_model_uid, out_model_uid) = ( + in_id + .map(|id| log_device_and_get_model_uid(id, DeviceType::INPUT)) + .unwrap_or_default(), + out_id + .map(|id| log_device_and_get_model_uid(id, DeviceType::OUTPUT)) + .unwrap_or_default(), + ); + + 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"); + return true; + } + + cubeb_log!("Device pair is not blocked"); + false + } + + fn create_audiounits( + &mut self, + shared_voice_processing_unit: &mut SharedVoiceProcessingUnitManager, + ) -> Result<(device_info, device_info)> { self.debug_assert_is_on_stream_queue(); - let should_use_voice_processing_unit = self.has_input() && self.has_output(); + let should_use_voice_processing_unit = self.has_input() + && (self + .input_stream_params + .prefs() + .contains(StreamPrefs::VOICE) + || self.should_force_vpio_for_input_device(&self.input_device)) + && !self.should_block_vpio_for_device_pair(&self.input_device, &self.output_device) + && macos_kernel_major_version() != Ok(MACOS_KERNEL_MAJOR_VERSION_MONTEREY); let should_use_aggregate_device = { // It's impossible to create an aggregate device from an aggregate device, and it's @@ -2778,16 +3259,20 @@ impl<'ctx> CoreStreamData<'ctx> { // - As last resort, create regular AudioUnits. This is also the normal non-duplex path. if should_use_voice_processing_unit { - if let Ok(au) = - create_voiceprocessing_audiounit(&self.input_device, &self.output_device) - { - cubeb_log!("({:p}) Using VoiceProcessingIO AudioUnit", self.stm_ptr); - self.input_unit = au; - self.output_unit = au; + if let Ok(mut au_handle) = get_voiceprocessing_audiounit( + shared_voice_processing_unit, + &self.input_device, + &self.output_device, + ) { + self.input_unit = au_handle.as_mut().unit; + if self.has_output() { + self.output_unit = au_handle.as_mut().unit; + } + self.voiceprocessing_unit_handle = Some(au_handle); return Ok((self.input_device.clone(), self.output_device.clone())); } cubeb_log!( - "({:p}) Failed to create VoiceProcessingIO AudioUnit. Trying a regular one.", + "({:p}) Failed to get VoiceProcessingIO AudioUnit. Trying a regular one.", self.stm_ptr ); } @@ -2889,7 +3374,10 @@ impl<'ctx> CoreStreamData<'ctx> { } #[allow(clippy::cognitive_complexity)] // TODO: Refactoring. - fn setup(&mut self) -> Result<()> { + fn setup( + &mut self, + shared_voice_processing_unit: &mut SharedVoiceProcessingUnitManager, + ) -> Result<()> { self.debug_assert_is_on_stream_queue(); if self .input_stream_params @@ -2905,7 +3393,7 @@ impl<'ctx> CoreStreamData<'ctx> { } let same_clock_domain = self.same_clock_domain(); - let (in_dev_info, out_dev_info) = self.create_audiounits()?; + let (in_dev_info, out_dev_info) = self.create_audiounits(shared_voice_processing_unit)?; let using_voice_processing_unit = self.using_voice_processing_unit(); assert!(!self.stm_ptr.is_null()); @@ -4051,10 +4539,12 @@ impl<'ctx> AudioUnitStream<'ctx> { } } - self.core_stream_data.setup().map_err(|e| { - cubeb_log!("({:p}) Setup failed.", self.core_stream_data.stm_ptr); - e - })?; + self.core_stream_data + .setup(&mut self.context.shared_voice_processing_unit) + .map_err(|e| { + cubeb_log!("({:p}) Setup failed.", self.core_stream_data.stm_ptr); + e + })?; if let Ok(volume) = vol_rv { set_volume(self.core_stream_data.output_unit, volume); 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 e14c5851958db..88389dbbf69e0 100644 --- a/third_party/rust/cubeb-coreaudio/src/backend/tests/utils.rs +++ b/third_party/rust/cubeb-coreaudio/src/backend/tests/utils.rs @@ -526,7 +526,7 @@ pub fn test_device_in_scope(id: AudioObjectID, scope: Scope) -> bool { pub fn test_get_all_onwed_devices(id: AudioDeviceID) -> Vec { assert_ne!(id, kAudioObjectUnknown); - debug_assert_running_serially(); + //debug_assert_running_serially(); let address = AudioObjectPropertyAddress { mSelector: kAudioObjectPropertyOwnedObjects, @@ -575,7 +575,7 @@ pub fn test_get_all_onwed_devices(id: AudioDeviceID) -> Vec { pub fn test_get_master_device(id: AudioObjectID) -> String { assert_ne!(id, kAudioObjectUnknown); - debug_assert_running_serially(); + //debug_assert_running_serially(); let address = AudioObjectPropertyAddress { mSelector: kAudioAggregateDevicePropertyMainSubDevice, @@ -596,7 +596,7 @@ pub fn test_get_master_device(id: AudioObjectID) -> String { } pub fn test_get_drift_compensations(id: AudioObjectID) -> std::result::Result { - debug_assert_running_serially(); + //debug_assert_running_serially(); let address = AudioObjectPropertyAddress { mSelector: kAudioSubDevicePropertyDriftCompensation, mScope: kAudioObjectPropertyScopeGlobal, @@ -779,7 +779,7 @@ pub fn test_create_device_change_listener(scope: Scope, listener: F) -> TestP where F: Fn(&[AudioObjectPropertyAddress]) -> OSStatus, { - debug_assert_running_serially(); + //debug_assert_running_serially(); let address = AudioObjectPropertyAddress { mSelector: match scope { Scope::Input => kAudioHardwarePropertyDefaultInputDevice, @@ -814,7 +814,7 @@ where } pub fn start(&self) -> std::result::Result<(), OSStatus> { - debug_assert_running_serially(); + //debug_assert_running_serially(); let status = unsafe { AudioObjectAddPropertyListener( self.device, @@ -831,7 +831,7 @@ where } pub fn stop(&self) -> std::result::Result<(), OSStatus> { - debug_assert_running_serially(); + //debug_assert_running_serially(); let status = unsafe { AudioObjectRemovePropertyListener( self.device,