Bug 1670633 - Update cubeb-coreaudio-rs to 964e1462. r=cubeb-reviewers,padenot

Differential Revision: https://phabricator.services.mozilla.com/D193900
This commit is contained in:
Andreas Pehrson 2023-11-24 11:33:56 +00:00
Родитель 6bb8230ea7
Коммит fd20da1468
21 изменённых файлов: 1259 добавлений и 604 удалений

Просмотреть файл

@ -65,9 +65,9 @@ git = "https://github.com/mozilla/audioipc"
rev = "6be424d75f1367e70f2f5ddcacd6d0237e81a6a9"
replace-with = "vendored-sources"
[source."git+https://github.com/mozilla/cubeb-coreaudio-rs?rev=93b5c01a131f65c83c11aeb317f4583405c5eb79"]
[source."git+https://github.com/mozilla/cubeb-coreaudio-rs?rev=964e14628f285ad44522bdeeb566c1864ecd2fd8"]
git = "https://github.com/mozilla/cubeb-coreaudio-rs"
rev = "93b5c01a131f65c83c11aeb317f4583405c5eb79"
rev = "964e14628f285ad44522bdeeb566c1864ecd2fd8"
replace-with = "vendored-sources"
[source."git+https://github.com/mozilla/cubeb-pulse-rs?rev=cf48897be5cbe147d051ebbbe1eaf5fd8fb6bbc9"]

6
Cargo.lock сгенерированный
Просмотреть файл

@ -895,7 +895,7 @@ dependencies = [
[[package]]
name = "coreaudio-sys-utils"
version = "0.1.0"
source = "git+https://github.com/mozilla/cubeb-coreaudio-rs?rev=93b5c01a131f65c83c11aeb317f4583405c5eb79#93b5c01a131f65c83c11aeb317f4583405c5eb79"
source = "git+https://github.com/mozilla/cubeb-coreaudio-rs?rev=964e14628f285ad44522bdeeb566c1864ecd2fd8#964e14628f285ad44522bdeeb566c1864ecd2fd8"
dependencies = [
"core-foundation-sys",
"coreaudio-sys",
@ -1106,11 +1106,11 @@ dependencies = [
[[package]]
name = "cubeb-coreaudio"
version = "0.1.0"
source = "git+https://github.com/mozilla/cubeb-coreaudio-rs?rev=93b5c01a131f65c83c11aeb317f4583405c5eb79#93b5c01a131f65c83c11aeb317f4583405c5eb79"
source = "git+https://github.com/mozilla/cubeb-coreaudio-rs?rev=964e14628f285ad44522bdeeb566c1864ecd2fd8#964e14628f285ad44522bdeeb566c1864ecd2fd8"
dependencies = [
"atomic",
"audio-mixer",
"bitflags 1.999.999",
"bitflags 2.4.0",
"coreaudio-sys-utils",
"cubeb-backend",
"float-cmp",

Просмотреть файл

@ -1 +1 @@
{"files":{"Cargo.toml":"d15a17e76eddf5088ad0b09544704479b3269ef1bc9060118bda7e87ed499eab","src/aggregate_device.rs":"7d2bd5f5fd7f3d008ebb69ad81f522ca0cb73db6d7b3e50ed1a63ea26ff721f4","src/audio_object.rs":"5447179330a862659a25bceedfdc5d29a1296f63490908d1c868c6b21c5f95a1","src/audio_unit.rs":"d783878930df4923b57ad230138c0f3fd6b0b9bb80a39725092ff4c6615162d8","src/cf_mutable_dict.rs":"fc42edd270c6dfb02f123214d2d8e487bbd62b5bd923b71eec13190fd0104d2a","src/dispatch.rs":"82ca429be8f930db730c7c571d6f2246e59e82ecb220b5290a3cf4a53e997053","src/lib.rs":"bcc559d69ef6ed0cbea5b2a36fec89d8c011eb9da70e2f26c00f881ad97a2546","src/string.rs":"28f88b816c768bcfcc674a60d962b93f1c94e5e0f4cc8ed2a1301138b91039e7"},"package":null}
{"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}

Просмотреть файл

@ -20,9 +20,10 @@ license = "ISC"
version = "0.8"
[dependencies.coreaudio-sys]
version = "0.2"
version = "0.2.14"
features = [
"audio_unit",
"core_audio",
"io_kit_audio",
]
default-features = false

Просмотреть файл

@ -22,6 +22,16 @@ impl Queue {
queue
}
#[cfg(debug_assertions)]
pub fn debug_assert_is_current(&self) {
unsafe {
dispatch_assert_queue(self.0);
}
}
#[cfg(not(debug_assertions))]
pub fn debug_assert_is_current(&self) {}
pub fn run_async<F>(&self, work: F)
where
F: Send + FnOnce(),

Просмотреть файл

@ -1 +1 @@
{"files":{".circleci/config.yml":"7f3dc865105ca8f33965a7958b1fe2e627ae2d5a703f3b2a4ab6e2e796018597",".editorconfig":"4e53b182bcc78b83d7e1b5c03efa14d22d4955c4ed2514d1ba4e99c1eb1a50ba",".githooks/pre-push":"8b8b26544cd56f54c0c33812551f786bb25cb08c86dbfeb6bf3daad881c826a1",".github/workflows/test.yml":"aa1998a3b104ad131805ca3513832cef3f65300192824f8b1efc9a5a0cc108f6",".travis.yml":"dc07bac53f70f16c9bdf52264bdc58500ae6018c1b4c567bc7642f6b4ca3cc35","Cargo.toml":"b82f0d73e2afde65c328c9263c7e4ff3f53fe1671e5fc9a96ced50fb12698933","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":"314c3404f1a44f8c23856f96510779e7e64ebb7dde5abe444946c16d04af7c29","src/backend/device_property.rs":"2a63837b98b9b6bfb314b4aa6dce919412b71e13e18c7b8f3477aa1482f70b29","src/backend/mixer.rs":"ed299d3954e2a823060c870a8244673a7d4bca530830cb66b964d047a80ee3af","src/backend/mod.rs":"c1d4c753d30fc5e6f2aafcd5d34c3ae2393e0bae4aeb5bc477af396014ec1877","src/backend/resampler.rs":"8641c672d00f77be287d64f6cd4a2b2cd36f8630e2ded1eff6b39834b1b7ddc3","src/backend/tests/aggregate_device.rs":"7542cbb1c82398d00a5cba5b335842c517af2cda887946ebb5aaf512fd06b527","src/backend/tests/api.rs":"2cbae3a49f39fc78ec379c8c0c0266ad3e3552ef22b42168ac9d62d9d983a4a7","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":"9ed857625147c3d13c1458e630db8a78362612e6ef679d918bfdafa6e927fe75","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}
{"files":{".circleci/config.yml":"7f3dc865105ca8f33965a7958b1fe2e627ae2d5a703f3b2a4ab6e2e796018597",".editorconfig":"4e53b182bcc78b83d7e1b5c03efa14d22d4955c4ed2514d1ba4e99c1eb1a50ba",".githooks/pre-push":"8b8b26544cd56f54c0c33812551f786bb25cb08c86dbfeb6bf3daad881c826a1",".github/workflows/test.yml":"aa1998a3b104ad131805ca3513832cef3f65300192824f8b1efc9a5a0cc108f6",".travis.yml":"dc07bac53f70f16c9bdf52264bdc58500ae6018c1b4c567bc7642f6b4ca3cc35","Cargo.toml":"4d868f1f8698945fb84b9700926f5d6800d003d289d5ae773bcfaaaeb436b45e","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":"ed299d3954e2a823060c870a8244673a7d4bca530830cb66b964d047a80ee3af","src/backend/mod.rs":"21ca892ccd925991e7f4877a5ac1b8e70a5f4785e7d498024965c46eabdd3033","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}

5
third_party/rust/cubeb-coreaudio/Cargo.toml поставляемый
Просмотреть файл

@ -28,7 +28,7 @@ crate-type = [
[dependencies]
atomic = "0.4"
audio-mixer = "0.1"
bitflags = "1.0"
bitflags = "2"
cubeb-backend = "0.10.3"
float-cmp = "0.6"
lazy_static = "1.2"
@ -39,3 +39,6 @@ triple_buffer = "5.0.5"
[dependencies.coreaudio-sys-utils]
path = "coreaudio-sys-utils"
[dev-dependencies]
itertools = "0.11"

Просмотреть файл

@ -24,21 +24,17 @@ cargo test test_suspend_input_stream_by_unplugging_a_nondefault_input_device --
cargo test test_destroy_input_stream_after_unplugging_a_default_input_device -- --ignored --nocapture
cargo test test_reinit_input_stream_by_unplugging_a_default_input_device -- --ignored --nocapture
# FIXME: We don't monitor the alive-status for output device currently
# cargo test test_destroy_output_stream_after_unplugging_a_nondefault_output_device -- --ignored --nocapture
# FIXME: We don't monitor the alive-status for output device currently
# cargo test test_suspend_output_stream_by_unplugging_a_nondefault_output_device -- --ignored --nocapture
cargo test test_destroy_output_stream_after_unplugging_a_nondefault_output_device -- --ignored --nocapture
cargo test test_suspend_output_stream_by_unplugging_a_nondefault_output_device -- --ignored --nocapture
cargo test test_destroy_output_stream_after_unplugging_a_default_output_device -- --ignored --nocapture
cargo test test_reinit_output_stream_by_unplugging_a_default_output_device -- --ignored --nocapture
cargo test test_destroy_duplex_stream_after_unplugging_a_nondefault_input_device -- --ignored --nocapture
cargo test test_suspend_duplex_stream_by_unplugging_a_nondefault_input_device
cargo test test_suspend_duplex_stream_by_unplugging_a_nondefault_input_device -- --ignored --nocapture
# FIXME: We don't monitor the alive-status for output device currently
# cargo test test_destroy_duplex_stream_after_unplugging_a_nondefault_output_device -- --ignored --nocapture
# FIXME: We don't monitor the alive-status for output device currently
# cargo test test_suspend_duplex_stream_by_unplugging_a_nondefault_output_device -- --ignored --nocapture
cargo test test_destroy_duplex_stream_after_unplugging_a_nondefault_output_device -- --ignored --nocapture
cargo test test_suspend_duplex_stream_by_unplugging_a_nondefault_output_device -- --ignored --nocapture
cargo test test_destroy_duplex_stream_after_unplugging_a_default_input_device -- --ignored --nocapture
cargo test test_reinit_duplex_stream_by_unplugging_a_default_input_device -- --ignored --nocapture

Просмотреть файл

@ -15,8 +15,7 @@ fi
# - `memory`: It doesn't works with target x86_64-apple-darwin
# - `leak`: Get some errors that are out of our control. See:
# https://github.com/mozilla/cubeb-coreaudio-rs/issues/45#issuecomment-591642931
# - `thread`: It's blocked by #129
sanitizers=("address")
sanitizers=("address" "thread")
for san in "${sanitizers[@]}"
do
San="$(tr '[:lower:]' '[:upper:]' <<< ${san:0:1})${san:1}"

Просмотреть файл

@ -180,7 +180,7 @@ impl AggregateDevice {
let device = Self::create_blank_device(plugin_id)?;
// Wait until the aggregate is created.
let &(ref lock, ref cvar) = &*condvar_pair;
let (lock, cvar) = &*condvar_pair;
let devices = lock.lock().unwrap();
if !devices.contains(&device) {
let (devs, timeout_res) = cvar.wait_timeout(devices, waiting_time).unwrap();
@ -203,7 +203,7 @@ impl AggregateDevice {
) -> OSStatus {
assert_eq!(id, kAudioObjectSystemObject);
let pair = unsafe { &mut *(data as *mut Arc<(Mutex<Vec<AudioObjectID>>, Condvar)>) };
let &(ref lock, ref cvar) = &**pair;
let (lock, cvar) = &**pair;
let mut devices = lock.lock().unwrap();
*devices = audiounit_get_devices();
cvar.notify_one();
@ -339,7 +339,7 @@ impl AggregateDevice {
Self::set_sub_devices(device_id, input_id, output_id)?;
// Wait until the sub devices are added.
let &(ref lock, ref cvar) = &*condvar_pair;
let (lock, cvar) = &*condvar_pair;
let device = lock.lock().unwrap();
if *device != device_id {
let (dev, timeout_res) = cvar.wait_timeout(device, waiting_time).unwrap();
@ -370,7 +370,7 @@ impl AggregateDevice {
data: *mut c_void,
) -> OSStatus {
let pair = unsafe { &mut *(data as *mut Arc<(Mutex<AudioObjectID>, Condvar)>) };
let &(ref lock, ref cvar) = &**pair;
let (lock, cvar) = &**pair;
let mut device = lock.lock().unwrap();
*device = id;
cvar.notify_one();

Просмотреть файл

@ -223,58 +223,13 @@ pub fn get_ranges_of_device_sample_rate(
}
}
pub fn get_device_stream_format(
id: AudioDeviceID,
devtype: DeviceType,
) -> std::result::Result<AudioStreamBasicDescription, OSStatus> {
pub fn get_stream_latency(id: AudioStreamID) -> std::result::Result<u32, OSStatus> {
assert_ne!(id, kAudioObjectUnknown);
let address = get_property_address(Property::DeviceStreamFormat, devtype);
let mut size = mem::size_of::<AudioStreamBasicDescription>();
let mut format = AudioStreamBasicDescription::default();
let err = audio_object_get_property_data(id, &address, &mut size, &mut format);
if err == NO_ERR {
Ok(format)
} else {
Err(err)
}
}
#[allow(clippy::cast_ptr_alignment)] // Allow casting *mut u8 to *mut AudioBufferList
pub fn get_device_stream_configuration(
id: AudioDeviceID,
devtype: DeviceType,
) -> std::result::Result<Vec<AudioBuffer>, OSStatus> {
assert_ne!(id, kAudioObjectUnknown);
let address = get_property_address(Property::DeviceStreamConfiguration, devtype);
let mut size: usize = 0;
let err = audio_object_get_property_data_size(id, &address, &mut size);
if err != NO_ERR {
return Err(err);
}
let mut data: Vec<u8> = allocate_array_by_size(size);
let ptr = data.as_mut_ptr() as *mut AudioBufferList;
let err = audio_object_get_property_data(id, &address, &mut size, ptr);
if err != NO_ERR {
return Err(err);
}
let list = unsafe { &(*ptr) };
let ptr = list.mBuffers.as_ptr() as *const AudioBuffer;
let len = list.mNumberBuffers as usize;
let buffers = unsafe { slice::from_raw_parts(ptr, len) };
Ok(buffers.to_vec())
}
pub fn get_stream_latency(
id: AudioStreamID,
devtype: DeviceType,
) -> std::result::Result<u32, OSStatus> {
assert_ne!(id, kAudioObjectUnknown);
let address = get_property_address(Property::StreamLatency, devtype);
let address = get_property_address(
Property::StreamLatency,
DeviceType::INPUT | DeviceType::OUTPUT,
);
let mut size = mem::size_of::<u32>();
let mut latency: u32 = 0;
let err = audio_object_get_property_data(id, &address, &mut size, &mut latency);
@ -285,6 +240,42 @@ pub fn get_stream_latency(
}
}
pub fn get_stream_terminal_type(id: AudioStreamID) -> std::result::Result<u32, OSStatus> {
assert_ne!(id, kAudioObjectUnknown);
let address = get_property_address(
Property::StreamTerminalType,
DeviceType::INPUT | DeviceType::OUTPUT,
);
let mut size = mem::size_of::<u32>();
let mut terminal_type: u32 = 0;
let err = audio_object_get_property_data(id, &address, &mut size, &mut terminal_type);
if err == NO_ERR {
Ok(terminal_type)
} else {
Err(err)
}
}
pub fn get_stream_virtual_format(
id: AudioStreamID,
) -> std::result::Result<AudioStreamBasicDescription, OSStatus> {
assert_ne!(id, kAudioObjectUnknown);
let address = get_property_address(
Property::StreamVirtualFormat,
DeviceType::INPUT | DeviceType::OUTPUT,
);
let mut size = mem::size_of::<AudioStreamBasicDescription>();
let mut format = AudioStreamBasicDescription::default();
let err = audio_object_get_property_data(id, &address, &mut size, &mut format);
if err == NO_ERR {
Ok(format)
} else {
Err(err)
}
}
pub fn get_clock_domain(
id: AudioStreamID,
devtype: DeviceType,
@ -312,8 +303,6 @@ pub enum Property {
DeviceSampleRates,
DeviceSource,
DeviceSourceName,
DeviceStreamConfiguration,
DeviceStreamFormat,
DeviceStreams,
DeviceUID,
HardwareDefaultInputDevice,
@ -321,6 +310,8 @@ pub enum Property {
HardwareDevices,
ModelUID,
StreamLatency,
StreamTerminalType,
StreamVirtualFormat,
TransportType,
ClockDomain,
}
@ -337,8 +328,6 @@ impl From<Property> for AudioObjectPropertySelector {
Property::DeviceSampleRates => kAudioDevicePropertyAvailableNominalSampleRates,
Property::DeviceSource => kAudioDevicePropertyDataSource,
Property::DeviceSourceName => kAudioDevicePropertyDataSourceNameForIDCFString,
Property::DeviceStreamConfiguration => kAudioDevicePropertyStreamConfiguration,
Property::DeviceStreamFormat => kAudioDevicePropertyStreamFormat,
Property::DeviceStreams => kAudioDevicePropertyStreams,
Property::DeviceUID => kAudioDevicePropertyDeviceUID,
Property::HardwareDefaultInputDevice => kAudioHardwarePropertyDefaultInputDevice,
@ -346,6 +335,8 @@ impl From<Property> for AudioObjectPropertySelector {
Property::HardwareDevices => kAudioHardwarePropertyDevices,
Property::ModelUID => kAudioDevicePropertyModelUID,
Property::StreamLatency => kAudioStreamPropertyLatency,
Property::StreamTerminalType => kAudioStreamPropertyTerminalType,
Property::StreamVirtualFormat => kAudioStreamPropertyVirtualFormat,
Property::TransportType => kAudioDevicePropertyTransportType,
Property::ClockDomain => kAudioDevicePropertyClockDomain,
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -19,15 +19,13 @@ impl Resampler {
reclock: ffi::cubeb_resampler_reclock,
) -> Self {
let raw_resampler = unsafe {
let in_params = if input_params.is_some() {
input_params.as_mut().unwrap() as *mut ffi::cubeb_stream_params
} else {
ptr::null_mut()
let in_params = match &mut input_params {
Some(p) => p,
None => ptr::null_mut(),
};
let out_params = if output_params.is_some() {
output_params.as_mut().unwrap() as *mut ffi::cubeb_stream_params
} else {
ptr::null_mut()
let out_params = match &mut output_params {
Some(p) => p,
None => ptr::null_mut(),
};
ffi::cubeb_resampler_create(
stream,

Просмотреть файл

@ -42,7 +42,7 @@ fn test_aggregate_set_sub_devices_for_unknown_devices() {
// application and print out the sub devices of them!
#[test]
fn test_aggregate_get_sub_devices() {
let devices = test_get_all_devices(DeviceFilter::ExcludeCubebAggregate);
let devices = test_get_all_devices(DeviceFilter::ExcludeCubebAggregateAndVPIO);
for device in devices {
// `AggregateDevice::get_sub_devices(device)` will return a single-element vector
// containing `device` itself if it's not an aggregate device. This test assumes devices
@ -108,7 +108,7 @@ fn test_aggregate_create_blank_device() {
// TODO: Test this when there is no available devices.
let plugin = AggregateDevice::get_system_plugin_id().unwrap();
let device = AggregateDevice::create_blank_device_sync(plugin).unwrap();
let devices = test_get_all_devices(DeviceFilter::IncludeCubebAggregate);
let devices = test_get_all_devices(DeviceFilter::IncludeAll);
let device = devices.into_iter().find(|dev| dev == &device).unwrap();
let uid = get_device_global_uid(device).unwrap().into_string();
assert!(uid.contains(PRIVATE_AGGREGATE_DEVICE_NAME));

Просмотреть файл

@ -45,8 +45,8 @@ fn test_increase_and_decrease_context_streams() {
for i in 0..STREAMS {
join_handles.push(thread::spawn(move || {
let context = unsafe { &*(context_ptr_value as *const AudioUnitContext) };
let global_latency = context.update_latency_by_adding_stream(i);
global_latency
context.update_latency_by_adding_stream(i)
}));
}
let mut latencies = vec![];
@ -227,10 +227,11 @@ fn test_add_listener_unknown_device() {
),
callback,
);
assert_eq!(
stream.add_device_listener(&listener),
kAudioHardwareBadObjectError as OSStatus
);
let mut res: OSStatus = 0;
stream
.queue
.run_sync(|| res = stream.add_device_listener(&listener));
assert_eq!(res, kAudioHardwareBadObjectError as OSStatus);
});
}
@ -257,8 +258,15 @@ fn test_add_listener_then_remove_system_device() {
),
callback,
);
assert_eq!(stream.add_device_listener(&listener), NO_ERR);
assert_eq!(stream.remove_device_listener(&listener), NO_ERR);
let mut res: OSStatus = 0;
stream
.queue
.run_sync(|| res = stream.add_device_listener(&listener));
assert_eq!(res, NO_ERR);
stream
.queue
.run_sync(|| res = stream.remove_device_listener(&listener));
assert_eq!(res, NO_ERR);
});
}
@ -283,7 +291,11 @@ fn test_remove_listener_without_adding_any_listener_before_system_device() {
),
callback,
);
assert_eq!(stream.remove_device_listener(&listener), NO_ERR);
let mut res: OSStatus = 0;
stream
.queue
.run_sync(|| res = stream.remove_device_listener(&listener));
assert_eq!(res, NO_ERR);
});
}
@ -308,10 +320,11 @@ fn test_remove_listener_unknown_device() {
),
callback,
);
assert_eq!(
stream.remove_device_listener(&listener),
kAudioHardwareBadObjectError as OSStatus
);
let mut res: OSStatus = 0;
stream
.queue
.run_sync(|| res = stream.remove_device_listener(&listener));
assert_eq!(res, kAudioHardwareBadObjectError as OSStatus);
});
}
@ -700,7 +713,7 @@ fn test_convert_channel_layout() {
}
let layout_ref = unsafe { &(*(&layout as *const TestLayout as *const AudioChannelLayout)) };
assert_eq!(
&audiounit_convert_channel_layout(layout_ref),
&audiounit_convert_channel_layout(layout_ref).unwrap(),
expected_layout
);
}
@ -711,7 +724,9 @@ fn test_convert_channel_layout() {
#[test]
fn test_get_preferred_channel_layout_output() {
match test_get_default_audiounit(Scope::Output) {
Some(unit) => assert!(!audiounit_get_preferred_channel_layout(unit.get_inner()).is_empty()),
Some(unit) => assert!(!audiounit_get_preferred_channel_layout(unit.get_inner())
.unwrap()
.is_empty()),
None => println!("No output audiounit for test."),
}
}
@ -721,7 +736,9 @@ fn test_get_preferred_channel_layout_output() {
#[test]
fn test_get_current_channel_layout_output() {
match test_get_default_audiounit(Scope::Output) {
Some(unit) => assert!(!audiounit_get_current_channel_layout(unit.get_inner()).is_empty()),
Some(unit) => assert!(!audiounit_get_current_channel_layout(unit.get_inner())
.unwrap()
.is_empty()),
None => println!("No output audiounit for test."),
}
}
@ -850,7 +867,7 @@ fn test_for_create_audiounit() {
// Check the output scope is enabled.
if device.flags.contains(device_flags::DEV_OUTPUT) && default_output.is_some() {
device.id = default_output.clone().unwrap();
device.id = default_output.unwrap();
let unit = create_audiounit(&device).unwrap();
assert!(!unit.is_null());
assert!(test_audiounit_scope_is_enabled(unit, Scope::Output));
@ -864,7 +881,7 @@ fn test_for_create_audiounit() {
// Check the input scope is enabled.
if device.flags.contains(device_flags::DEV_INPUT) && default_input.is_some() {
let device_id = default_input.clone().unwrap();
let device_id = default_input.unwrap();
device.id = device_id;
let unit = create_audiounit(&device).unwrap();
assert!(!unit.is_null());
@ -1047,8 +1064,12 @@ 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_channel_count(device, DeviceType::INPUT | DeviceType::OUTPUT).unwrap_err(),
kAudioHardwareUnknownPropertyError as OSStatus
get_channel_count(device, DeviceType::INPUT | DeviceType::OUTPUT),
get_channel_count(device, DeviceType::INPUT).map(|c| c + get_channel_count(
device,
DeviceType::OUTPUT
)
.unwrap_or(0))
);
} else {
println!("No device for {:?}.", scope);
@ -1366,7 +1387,6 @@ fn test_create_device_info_by_unknown_device() {
}
#[test]
#[should_panic]
fn test_create_device_info_with_unknown_type() {
test_create_device_info_with_unknown_type_by_scope(Scope::Input);
test_create_device_info_with_unknown_type_by_scope(Scope::Output);
@ -1374,8 +1394,6 @@ fn test_create_device_info_with_unknown_type() {
fn test_create_device_info_with_unknown_type_by_scope(scope: Scope) {
if let Some(device) = test_get_default_device(scope.clone()) {
assert!(create_cubeb_device_info(device, DeviceType::UNKNOWN).is_err());
} else {
panic!("Panic by default: No device for {:?}.", scope);
}
}
}
@ -1416,23 +1434,6 @@ fn test_create_device_from_hwdev_with_inout_type() {
}
}
// is_aggregate_device
// ------------------------------------
#[test]
fn test_is_aggregate_device() {
let mut aggregate_name = String::from(PRIVATE_AGGREGATE_DEVICE_NAME);
aggregate_name.push_str("_something");
let aggregate_name_cstring = CString::new(aggregate_name).unwrap();
let mut info = ffi::cubeb_device_info::default();
info.friendly_name = aggregate_name_cstring.as_ptr();
assert!(is_aggregate_device(&info));
let non_aggregate_name_cstring = CString::new("Hello World!").unwrap();
info.friendly_name = non_aggregate_name_cstring.as_ptr();
assert!(!is_aggregate_device(&info));
}
// get_devices_of_type
// ------------------------------------
#[test]
@ -1443,7 +1444,7 @@ fn test_get_devices_of_type() {
let input_devices = audiounit_get_devices_of_type(DeviceType::INPUT);
let output_devices = audiounit_get_devices_of_type(DeviceType::OUTPUT);
let mut expected_all = test_get_all_devices(DeviceFilter::ExcludeCubebAggregate);
let mut expected_all = test_get_all_devices(DeviceFilter::ExcludeCubebAggregateAndVPIO);
expected_all.sort();
assert_eq!(all_devices, expected_all);
for device in all_devices.iter() {

Просмотреть файл

@ -21,8 +21,7 @@ use super::utils::{
test_set_default_device, Scope, StreamType, TestDevicePlugger, TestDeviceSwitcher,
};
use super::*;
use std::fmt::Debug;
use std::thread;
use std::sync::{LockResult, MutexGuard, WaitTimeoutResult};
// Switch default devices used by the active streams, to test stream reinitialization
// ================================================================================================
@ -48,22 +47,25 @@ fn test_switch_device_in_scope(scope: Scope) {
let mut device_switcher = TestDeviceSwitcher::new(scope.clone());
let count = Arc::new(Mutex::new(0));
let also_count = Arc::clone(&count);
let notifier = Arc::new(Notifier::new(0));
let also_notifier = notifier.clone();
let listener = test_create_device_change_listener(scope.clone(), move |_addresses| {
let mut cnt = also_count.lock().unwrap();
let mut cnt = notifier.lock().unwrap();
*cnt += 1;
notifier.notify(cnt);
NO_ERR
});
listener.start();
let mut changed_watcher = Watcher::new(&count);
let changed_watcher = Watcher::new(&also_notifier);
test_get_started_stream_in_scope(scope.clone(), move |_stream| loop {
thread::sleep(Duration::from_millis(500));
changed_watcher.prepare();
let mut guard = changed_watcher.lock().unwrap();
let start_cnt = guard.clone();
device_switcher.next();
changed_watcher.wait_for_change();
if changed_watcher.current_result() >= devices.len() {
guard = changed_watcher
.wait_while(guard, |cnt| *cnt == start_cnt)
.unwrap();
if *guard >= devices.len() {
break;
}
});
@ -204,77 +206,90 @@ fn test_plug_and_unplug_device_in_scope(scope: Scope) {
let mut context = AudioUnitContext::new();
// Register the devices-changed callbacks.
let input_count = Arc::new(Mutex::new(0u32));
let also_input_count = Arc::clone(&input_count);
let input_mtx_ptr = also_input_count.as_ref() as *const Mutex<u32>;
#[derive(Clone, PartialEq)]
struct Counts {
input: u32,
output: u32,
}
impl Counts {
fn new() -> Self {
Self {
input: 0,
output: 0,
}
}
}
let counts = Arc::new(Notifier::new(Counts::new()));
let counts_notifier_ptr = counts.as_ref() as *const Notifier<Counts>;
assert!(context
.register_device_collection_changed(
DeviceType::INPUT,
Some(input_changed_callback),
input_mtx_ptr as *mut c_void,
counts_notifier_ptr as *mut c_void,
)
.is_ok());
let output_count = Arc::new(Mutex::new(0u32));
let also_output_count = Arc::clone(&output_count);
let output_mtx_ptr = also_output_count.as_ref() as *const Mutex<u32>;
assert!(context
.register_device_collection_changed(
DeviceType::OUTPUT,
Some(output_changed_callback),
output_mtx_ptr as *mut c_void,
counts_notifier_ptr as *mut c_void,
)
.is_ok());
let mut input_watcher = Watcher::new(&input_count);
let mut output_watcher = Watcher::new(&output_count);
let counts_watcher = Watcher::new(&counts);
let mut device_plugger = TestDevicePlugger::new(scope).unwrap();
// Simulate adding devices and monitor the devices-changed callbacks.
input_watcher.prepare();
output_watcher.prepare();
{
// Simulate adding devices and monitor the devices-changed callbacks.
let mut counts_guard = counts.lock().unwrap();
let counts_start = counts_guard.clone();
assert!(device_plugger.plug().is_ok());
assert!(device_plugger.plug().is_ok());
if is_input {
input_watcher.wait_for_change();
}
if is_output {
output_watcher.wait_for_change();
counts_guard = counts_watcher
.wait_while(counts_guard, |counts| {
(is_input && counts.input == counts_start.input)
|| (is_output && counts.output == counts_start.output)
})
.unwrap();
// Check changed count.
assert_eq!(counts_guard.input, if is_input { 1 } else { 0 });
assert_eq!(counts_guard.output, if is_output { 1 } else { 0 });
}
// Check changed count.
check_result(is_input, (1, 0), &input_watcher);
check_result(is_output, (1, 0), &output_watcher);
{
// Simulate removing devices and monitor the devices-changed callbacks.
let mut counts_guard = counts.lock().unwrap();
let counts_start = counts_guard.clone();
// Simulate removing devices and monitor the devices-changed callbacks.
input_watcher.prepare();
output_watcher.prepare();
assert!(device_plugger.unplug().is_ok());
assert!(device_plugger.unplug().is_ok());
counts_guard = counts_watcher
.wait_while(counts_guard, |counts| {
(is_input && counts.input == counts_start.input)
|| (is_output && counts.output == counts_start.output)
})
.unwrap();
if is_input {
input_watcher.wait_for_change();
// Check changed count.
assert_eq!(counts_guard.input, if is_input { 2 } else { 0 });
assert_eq!(counts_guard.output, if is_output { 2 } else { 0 });
}
if is_output {
output_watcher.wait_for_change();
}
check_result(is_input, (2, 0), &input_watcher);
check_result(is_output, (2, 0), &output_watcher);
extern "C" fn input_changed_callback(context: *mut ffi::cubeb, data: *mut c_void) {
println!(
"Input device collection @ {:p} is changed. Data @ {:p}",
context, data
);
let count = unsafe { &*(data as *const Mutex<u32>) };
let notifier = unsafe { &*(data as *const Notifier<Counts>) };
{
let mut guard = count.lock().unwrap();
*guard += 1;
let mut counts = notifier.lock().unwrap();
counts.input += 1;
notifier.notify(counts);
}
}
@ -283,23 +298,13 @@ fn test_plug_and_unplug_device_in_scope(scope: Scope) {
"output device collection @ {:p} is changed. Data @ {:p}",
context, data
);
let count = unsafe { &*(data as *const Mutex<u32>) };
let notifier = unsafe { &*(data as *const Notifier<Counts>) };
{
let mut guard = count.lock().unwrap();
*guard += 1;
let mut counts = notifier.lock().unwrap();
counts.output += 1;
notifier.notify(counts);
}
}
fn check_result<T: Clone + Debug + PartialEq>(
in_scope: bool,
expected: (T, T),
watcher: &Watcher<T>,
) {
assert_eq!(
watcher.current_result(),
if in_scope { expected.0 } else { expected.1 }
);
}
}
// Switch default devices used by the active streams, to test device changed callback
@ -352,16 +357,15 @@ fn test_register_device_changed_callback_to_check_default_device_changed(stm_typ
return;
}
let changed_count = Arc::new(Mutex::new(0u32));
let also_changed_count = Arc::clone(&changed_count);
let mtx_ptr = also_changed_count.as_ref() as *const Mutex<u32>;
let changed_count = Arc::new(Notifier::new(0u32));
let notifier_ptr = changed_count.as_ref() as *const Notifier<u32>;
test_get_stream_with_device_changed_callback(
"stream: test callback for default device changed",
stm_type,
None, // Use default input device.
None, // Use default output device.
mtx_ptr as *mut c_void,
notifier_ptr as *mut c_void,
state_callback,
device_changed_callback,
|stream| {
@ -371,17 +375,22 @@ fn test_register_device_changed_callback_to_check_default_device_changed(stm_typ
// be assigned to the default device, since the device list for setting
// default device is cached upon {input, output}_device_switcher is initialized.
let mut changed_watcher = Watcher::new(&changed_count);
let changed_watcher = Watcher::new(&changed_count);
if let Some(devices) = inputs {
let mut device_switcher = TestDeviceSwitcher::new(Scope::Input);
for _ in 0..devices {
// While the stream is re-initializing for the default device switch,
// switching for the default device again will be ignored.
while stream.switching_device.load(atomic::Ordering::SeqCst) {}
changed_watcher.prepare();
while stream.switching_device.load(atomic::Ordering::SeqCst) {
std::hint::spin_loop()
}
let guard = changed_watcher.lock().unwrap();
let start_cnt = guard.clone();
device_switcher.next();
changed_watcher.wait_for_change();
changed_watcher
.wait_while(guard, |cnt| *cnt == start_cnt)
.unwrap();
}
}
@ -390,10 +399,15 @@ fn test_register_device_changed_callback_to_check_default_device_changed(stm_typ
for _ in 0..devices {
// While the stream is re-initializing for the default device switch,
// switching for the default device again will be ignored.
while stream.switching_device.load(atomic::Ordering::SeqCst) {}
changed_watcher.prepare();
while stream.switching_device.load(atomic::Ordering::SeqCst) {
std::hint::spin_loop()
}
let guard = changed_watcher.lock().unwrap();
let start_cnt = guard.clone();
device_switcher.next();
changed_watcher.wait_for_change();
changed_watcher
.wait_while(guard, |cnt| *cnt == start_cnt)
.unwrap();
}
}
},
@ -410,11 +424,10 @@ fn test_register_device_changed_callback_to_check_default_device_changed(stm_typ
extern "C" fn device_changed_callback(data: *mut c_void) {
println!("Device change callback. data @ {:p}", data);
let count = unsafe { &*(data as *const Mutex<u32>) };
{
let mut guard = count.lock().unwrap();
*guard += 1;
}
let notifier = unsafe { &*(data as *const Notifier<u32>) };
let mut count_guard = notifier.lock().unwrap();
*count_guard += 1;
notifier.notify(count_guard);
}
}
@ -440,7 +453,7 @@ fn test_destroy_input_stream_after_unplugging_a_nondefault_input_device() {
#[test]
fn test_suspend_input_stream_by_unplugging_a_nondefault_input_device() {
// Expect to get an error state callback by device-changed event handler
test_unplug_a_device_on_an_active_stream(StreamType::INPUT, Scope::Input, false, 500);
test_unplug_a_device_on_an_active_stream(StreamType::INPUT, Scope::Input, false, 2000);
}
// Unplug the default input device for an input stream
@ -459,7 +472,7 @@ fn test_destroy_input_stream_after_unplugging_a_default_input_device() {
fn test_reinit_input_stream_by_unplugging_a_default_input_device() {
// Expect to get an device-changed callback by device-changed event handler,
// which will reinitialize the stream behind the scenes
test_unplug_a_device_on_an_active_stream(StreamType::INPUT, Scope::Input, true, 500);
test_unplug_a_device_on_an_active_stream(StreamType::INPUT, Scope::Input, true, 2000);
}
// Output-only stream
@ -467,18 +480,16 @@ fn test_reinit_input_stream_by_unplugging_a_default_input_device() {
// Unplug the non-default output device for an output stream
// ------------------------------------------------------------------------------------------------
// FIXME: We don't monitor the alive-status for output device currently
#[ignore]
#[test]
fn test_destroy_output_stream_after_unplugging_a_nondefault_output_device() {
test_unplug_a_device_on_an_active_stream(StreamType::OUTPUT, Scope::Output, false, 0);
}
// FIXME: We don't monitor the alive-status for output device currently
#[ignore]
#[test]
fn test_suspend_output_stream_by_unplugging_a_nondefault_output_device() {
test_unplug_a_device_on_an_active_stream(StreamType::OUTPUT, Scope::Output, false, 500);
test_unplug_a_device_on_an_active_stream(StreamType::OUTPUT, Scope::Output, false, 2000);
}
// Unplug the default output device for an output stream
@ -498,7 +509,7 @@ fn test_destroy_output_stream_after_unplugging_a_default_output_device() {
fn test_reinit_output_stream_by_unplugging_a_default_output_device() {
// Expect to get an device-changed callback by device-changed event handler,
// which will reinitialize the stream behind the scenes
test_unplug_a_device_on_an_active_stream(StreamType::OUTPUT, Scope::Output, true, 500);
test_unplug_a_device_on_an_active_stream(StreamType::OUTPUT, Scope::Output, true, 2000);
}
// Duplex stream
@ -518,24 +529,22 @@ fn test_destroy_duplex_stream_after_unplugging_a_nondefault_input_device() {
#[test]
fn test_suspend_duplex_stream_by_unplugging_a_nondefault_input_device() {
// Expect to get an error state callback by device-changed event handler
test_unplug_a_device_on_an_active_stream(StreamType::DUPLEX, Scope::Input, false, 500);
test_unplug_a_device_on_an_active_stream(StreamType::DUPLEX, Scope::Input, false, 2000);
}
// Unplug the non-default output device for a duplex stream
// ------------------------------------------------------------------------------------------------
// FIXME: We don't monitor the alive-status for output device currently
#[ignore]
#[test]
fn test_destroy_duplex_stream_after_unplugging_a_nondefault_output_device() {
test_unplug_a_device_on_an_active_stream(StreamType::DUPLEX, Scope::Output, false, 0);
}
// FIXME: We don't monitor the alive-status for output device currently
#[ignore]
#[test]
fn test_suspend_duplex_stream_by_unplugging_a_nondefault_output_device() {
test_unplug_a_device_on_an_active_stream(StreamType::DUPLEX, Scope::Output, false, 500);
test_unplug_a_device_on_an_active_stream(StreamType::DUPLEX, Scope::Output, false, 2000);
}
// Unplug the non-default in-out device for a duplex stream
@ -559,7 +568,7 @@ fn test_destroy_duplex_stream_after_unplugging_a_default_input_device() {
fn test_reinit_duplex_stream_by_unplugging_a_default_input_device() {
// Expect to get an device-changed callback by device-changed event handler,
// which will reinitialize the stream behind the scenes
test_unplug_a_device_on_an_active_stream(StreamType::DUPLEX, Scope::Input, true, 500);
test_unplug_a_device_on_an_active_stream(StreamType::DUPLEX, Scope::Input, true, 2000);
}
// Unplug the default ouput device for a duplex stream
@ -579,14 +588,14 @@ fn test_destroy_duplex_stream_after_unplugging_a_default_output_device() {
fn test_reinit_duplex_stream_by_unplugging_a_default_output_device() {
// Expect to get an device-changed callback by device-changed event handler,
// which will reinitialize the stream behind the scenes
test_unplug_a_device_on_an_active_stream(StreamType::DUPLEX, Scope::Output, true, 500);
test_unplug_a_device_on_an_active_stream(StreamType::DUPLEX, Scope::Output, true, 2000);
}
fn test_unplug_a_device_on_an_active_stream(
stream_type: StreamType,
device_scope: Scope,
set_device_to_default: bool,
sleep: u64,
wait_up_to_ms: u64,
) {
let has_input = test_get_default_device(Scope::Input).is_some();
let has_output = test_get_default_device(Scope::Output).is_some();
@ -670,62 +679,72 @@ fn test_unplug_a_device_on_an_active_stream(
),
};
struct SharedData {
changed_count: Arc<Mutex<u32>>,
states: Arc<Mutex<Vec<ffi::cubeb_state>>>,
#[derive(Clone, PartialEq)]
struct Data {
changed_count: u32,
states: Vec<ffi::cubeb_state>,
}
let mut shared_data = SharedData {
changed_count: Arc::new(Mutex::new(0u32)),
states: Arc::new(Mutex::new(vec![])),
};
impl Data {
fn new() -> Self {
Self {
changed_count: 0,
states: vec![],
}
}
}
let notifier = Arc::new(Notifier::new(Data::new()));
let notifier_ptr = notifier.as_ref() as *const Notifier<Data>;
test_get_stream_with_device_changed_callback(
"stream: test stream reinit/destroy after unplugging a device",
stream_type,
input_device,
output_device,
&mut shared_data as *mut SharedData as *mut c_void,
notifier_ptr as *mut c_void,
state_callback,
device_changed_callback,
|stream| {
let mut changed_watcher = Watcher::new(&shared_data.changed_count);
changed_watcher.prepare();
stream.start();
// Wait for stream data callback.
thread::sleep(Duration::from_millis(200));
let changed_watcher = Watcher::new(&notifier);
let mut data_guard = notifier.lock().unwrap();
assert_eq!(data_guard.states.last().unwrap(), &ffi::CUBEB_STATE_STARTED);
println!(
"Stream runs on the device {} for {:?}",
plugger.get_device_id(),
device_scope
);
let dev = plugger.get_device_id();
let start_changed_count = data_guard.changed_count.clone();
assert!(plugger.unplug().is_ok());
if set_device_to_default {
// The stream will be reinitialized if it follows the default input or output device.
changed_watcher.wait_for_change();
}
if sleep > 0 {
println!(
"Wait {} ms for stream re-initialization, or state callback",
sleep
);
thread::sleep(Duration::from_millis(sleep));
if !set_device_to_default {
// stream can be dropped immediately before device-changed callback
// so we only check the states if we wait for it explicitly.
let guard = shared_data.states.lock().unwrap();
assert!(guard.last().is_some());
assert_eq!(guard.last().unwrap(), &ffi::CUBEB_STATE_ERROR);
}
} else {
println!("Destroy the stream immediately");
if set_device_to_default {
println!("Stream re-initialization may run at the same time when stream is being destroyed");
}
println!("Waiting for default device to change and reinit");
data_guard = changed_watcher
.wait_while(data_guard, |data| {
data.changed_count == start_changed_count
|| data.states.last().unwrap_or(&ffi::CUBEB_STATE_ERROR)
!= &ffi::CUBEB_STATE_STARTED
})
.unwrap();
} else if wait_up_to_ms > 0 {
// stream can be dropped immediately before device-changed callback
// so we only check the states if we wait for it explicitly.
println!("Waiting for non-default device to enter error state");
let (new_guard, timeout_res) = changed_watcher
.wait_timeout_while(data_guard, Duration::from_millis(wait_up_to_ms), |data| {
data.states.last().unwrap_or(&ffi::CUBEB_STATE_STARTED)
!= &ffi::CUBEB_STATE_ERROR
})
.unwrap();
assert!(!timeout_res.timed_out());
data_guard = new_guard;
}
println!(
@ -745,6 +764,7 @@ fn test_unplug_a_device_on_an_active_stream(
user_ptr: *mut c_void,
state: ffi::cubeb_state,
) {
println!("Device change callback. user_ptr @ {:p}", user_ptr);
assert!(!stream.is_null());
println!(
"state: {}",
@ -756,52 +776,79 @@ fn test_unplug_a_device_on_an_active_stream(
_ => "unknown",
}
);
let shared_data = unsafe { &mut *(user_ptr as *mut SharedData) };
{
let mut guard = shared_data.states.lock().unwrap();
guard.push(state);
let notifier = unsafe { &mut *(user_ptr as *mut Notifier<Data>) };
let mut data_guard = notifier.lock().unwrap();
data_guard.states.push(state);
notifier.notify(data_guard);
}
extern "C" fn device_changed_callback(user_ptr: *mut c_void) {
println!("Device change callback. user_ptr @ {:p}", user_ptr);
let notifier = unsafe { &mut *(user_ptr as *mut Notifier<Data>) };
let mut data_guard = notifier.lock().unwrap();
data_guard.changed_count += 1;
notifier.notify(data_guard);
}
}
struct Notifier<T> {
value: Mutex<T>,
cvar: Condvar,
}
impl<T> Notifier<T> {
fn new(value: T) -> Self {
Self {
value: Mutex::new(value),
cvar: Condvar::new(),
}
}
extern "C" fn device_changed_callback(data: *mut c_void) {
println!("Device change callback. data @ {:p}", data);
let shared_data = unsafe { &mut *(data as *mut SharedData) };
{
let mut guard = shared_data.changed_count.lock().unwrap();
*guard += 1;
}
fn lock(&self) -> LockResult<MutexGuard<'_, T>> {
self.value.lock()
}
fn notify(&self, _guard: MutexGuard<'_, T>) {
self.cvar.notify_all();
}
}
struct Watcher<T: Clone + PartialEq> {
watching: Arc<Mutex<T>>,
current: Option<T>,
notifier: Arc<Notifier<T>>,
}
impl<T: Clone + PartialEq> Watcher<T> {
fn new(value: &Arc<Mutex<T>>) -> Self {
fn new(value: &Arc<Notifier<T>>) -> Self {
Self {
watching: Arc::clone(value),
current: None,
notifier: Arc::clone(value),
}
}
fn prepare(&mut self) {
self.current = Some(self.current_result());
fn lock(&self) -> LockResult<MutexGuard<'_, T>> {
self.notifier.lock()
}
fn wait_for_change(&self) {
loop {
if self.current_result() != self.current.clone().unwrap() {
break;
}
thread::sleep(Duration::from_millis(1));
}
fn wait_while<'a, F>(
&self,
guard: MutexGuard<'a, T>,
condition: F,
) -> LockResult<MutexGuard<'a, T>>
where
F: FnMut(&mut T) -> bool,
{
self.notifier.cvar.wait_while(guard, condition)
}
fn current_result(&self) -> T {
let guard = self.watching.lock().unwrap();
guard.clone()
fn wait_timeout_while<'a, F>(
&self,
guard: MutexGuard<'a, T>,
dur: Duration,
condition: F,
) -> LockResult<(MutexGuard<'a, T>, WaitTimeoutResult)>
where
F: FnMut(&mut T) -> bool,
{
self.notifier.cvar.wait_timeout_while(guard, dur, condition)
}
}

Просмотреть файл

@ -282,6 +282,7 @@ fn test_get_device_streams() {
if let Some(device) = test_get_default_device(Scope::Input) {
let streams = get_device_streams(device, DeviceType::INPUT).unwrap();
println!("streams on the input device: {:?}", streams);
assert!(!streams.is_empty());
} else {
println!("No input device.");
}
@ -289,6 +290,7 @@ fn test_get_device_streams() {
if let Some(device) = test_get_default_device(Scope::Output) {
let streams = get_device_streams(device, DeviceType::OUTPUT).unwrap();
println!("streams on the output device: {:?}", streams);
assert!(!streams.is_empty());
} else {
println!("No output device.");
}
@ -350,56 +352,6 @@ fn test_get_ranges_of_device_sample_rate_by_unknown_device() {
assert!(get_ranges_of_device_sample_rate(kAudioObjectUnknown, DeviceType::INPUT).is_err());
}
// get_device_stream_format
// ------------------------------------
#[test]
fn test_get_device_stream_format() {
if let Some(device) = test_get_default_device(Scope::Input) {
let format = get_device_stream_format(device, DeviceType::INPUT).unwrap();
println!("input stream format: {:?}", format);
} else {
println!("No input device.");
}
if let Some(device) = test_get_default_device(Scope::Output) {
let format = get_device_stream_format(device, DeviceType::OUTPUT).unwrap();
println!("output stream format: {:?}", format);
} else {
println!("No output device.");
}
}
#[test]
#[should_panic]
fn test_get_device_stream_format_by_unknown_device() {
assert!(get_device_stream_format(kAudioObjectUnknown, DeviceType::INPUT).is_err());
}
// get_device_stream_configuration
// ------------------------------------
#[test]
fn test_get_device_stream_configuration() {
if let Some(device) = test_get_default_device(Scope::Input) {
let buffers = get_device_stream_configuration(device, DeviceType::INPUT).unwrap();
println!("input stream config: {:?}", buffers);
} else {
println!("No input device.");
}
if let Some(device) = test_get_default_device(Scope::Output) {
let buffers = get_device_stream_configuration(device, DeviceType::OUTPUT).unwrap();
println!("output stream config: {:?}", buffers);
} else {
println!("No output device.");
}
}
#[test]
#[should_panic]
fn test_get_device_stream_configuration_by_unknown_device() {
assert!(get_device_stream_configuration(kAudioObjectUnknown, DeviceType::INPUT).is_err());
}
// get_stream_latency
// ------------------------------------
#[test]
@ -407,7 +359,7 @@ fn test_get_stream_latency() {
if let Some(device) = test_get_default_device(Scope::Input) {
let streams = get_device_streams(device, DeviceType::INPUT).unwrap();
for stream in streams {
let latency = get_stream_latency(stream, DeviceType::INPUT).unwrap();
let latency = get_stream_latency(stream).unwrap();
println!("latency of the input stream {} is {}", stream, latency);
}
} else {
@ -417,7 +369,7 @@ fn test_get_stream_latency() {
if let Some(device) = test_get_default_device(Scope::Output) {
let streams = get_device_streams(device, DeviceType::OUTPUT).unwrap();
for stream in streams {
let latency = get_stream_latency(stream, DeviceType::OUTPUT).unwrap();
let latency = get_stream_latency(stream).unwrap();
println!("latency of the output stream {} is {}", stream, latency);
}
} else {
@ -428,5 +380,94 @@ fn test_get_stream_latency() {
#[test]
#[should_panic]
fn test_get_stream_latency_by_unknown_device() {
assert!(get_stream_latency(kAudioObjectUnknown, DeviceType::INPUT).is_err());
assert!(get_stream_latency(kAudioObjectUnknown).is_err());
}
// get_stream_virtual_format
// ------------------------------------
#[test]
fn test_get_stream_virtual_format() {
if let Some(device) = test_get_default_device(Scope::Input) {
let streams = get_device_streams(device, DeviceType::INPUT).unwrap();
let formats = streams
.iter()
.map(|s| get_stream_virtual_format(*s))
.collect::<Vec<std::result::Result<AudioStreamBasicDescription, OSStatus>>>();
println!("input stream formats: {:?}", formats);
assert!(!formats.is_empty());
} else {
println!("No input device.");
}
if let Some(device) = test_get_default_device(Scope::Output) {
let streams = get_device_streams(device, DeviceType::OUTPUT).unwrap();
let formats = streams
.iter()
.map(|s| get_stream_virtual_format(*s))
.collect::<Vec<std::result::Result<AudioStreamBasicDescription, OSStatus>>>();
println!("output stream formats: {:?}", formats);
assert!(!formats.is_empty());
} else {
println!("No output device.");
}
}
#[test]
#[should_panic]
fn test_get_stream_virtual_format_by_unknown_stream() {
assert!(get_stream_virtual_format(kAudioObjectUnknown).is_err());
}
// get_stream_terminal_type
// ------------------------------------
#[test]
fn test_get_stream_terminal_type() {
fn terminal_type_to_device_type(terminal_type: u32) -> Option<DeviceType> {
#[allow(non_upper_case_globals)]
match terminal_type {
kAudioStreamTerminalTypeMicrophone
| kAudioStreamTerminalTypeHeadsetMicrophone
| kAudioStreamTerminalTypeReceiverMicrophone => Some(DeviceType::INPUT),
kAudioStreamTerminalTypeSpeaker
| kAudioStreamTerminalTypeHeadphones
| kAudioStreamTerminalTypeLFESpeaker
| kAudioStreamTerminalTypeReceiverSpeaker => Some(DeviceType::OUTPUT),
t if t > INPUT_UNDEFINED && t < OUTPUT_UNDEFINED => Some(DeviceType::INPUT),
t if t > OUTPUT_UNDEFINED && t < BIDIRECTIONAL_UNDEFINED => Some(DeviceType::OUTPUT),
t => {
println!("UNKNOWN TerminalType {:#06x}", t);
None
}
}
}
if let Some(device) = test_get_default_device(Scope::Input) {
let streams = get_device_streams(device, DeviceType::INPUT).unwrap();
for stream in streams {
assert_eq!(
terminal_type_to_device_type(get_stream_terminal_type(stream).unwrap()),
Some(DeviceType::INPUT)
);
}
} else {
println!("No input device.");
}
if let Some(device) = test_get_default_device(Scope::Output) {
let streams = get_device_streams(device, DeviceType::OUTPUT).unwrap();
for stream in streams {
assert_eq!(
terminal_type_to_device_type(get_stream_terminal_type(stream).unwrap()),
Some(DeviceType::OUTPUT)
);
}
} else {
println!("No output device.");
}
}
#[test]
#[should_panic]
fn test_get_stream_terminal_type_by_unknown_stream() {
assert!(get_stream_terminal_type(kAudioObjectUnknown).is_err());
}

Просмотреть файл

@ -1,5 +1,9 @@
extern crate itertools;
use self::itertools::iproduct;
use super::utils::{
test_get_default_device, test_ops_context_operation, test_ops_stream_operation, Scope,
noop_data_callback, test_get_default_device, test_ops_context_operation,
test_ops_stream_operation, Scope,
};
use super::*;
@ -449,6 +453,192 @@ fn test_ops_context_register_device_collection_changed_manual() {
);
}
#[test]
fn test_ops_context_stream_init_no_stream_params() {
let name = "context: stream_init with no stream params";
test_ops_context_operation(name, |context_ptr| {
let mut stream: *mut ffi::cubeb_stream = ptr::null_mut();
let stream_name = CString::new(name).expect("Failed to create stream name");
assert_eq!(
unsafe {
OPS.stream_init.unwrap()(
context_ptr,
&mut stream,
stream_name.as_ptr(),
ptr::null_mut(), // Use default input device.
ptr::null_mut(), // No input parameters.
ptr::null_mut(), // Use default output device.
ptr::null_mut(), // No output parameters.
4096, // TODO: Get latency by get_min_latency instead ?
Some(noop_data_callback),
None, // No state callback.
ptr::null_mut(), // No user data pointer.
)
},
ffi::CUBEB_ERROR_INVALID_PARAMETER
);
assert!(stream.is_null());
});
}
#[test]
fn test_ops_context_stream_init_no_input_stream_params() {
let name = "context: stream_init with no input stream params";
let input_device = test_get_default_device(Scope::Input);
if input_device.is_none() {
println!("No input device to perform input tests for \"{}\".", name);
return;
}
test_ops_context_operation(name, |context_ptr| {
let mut stream: *mut ffi::cubeb_stream = ptr::null_mut();
let stream_name = CString::new(name).expect("Failed to create stream name");
assert_eq!(
unsafe {
OPS.stream_init.unwrap()(
context_ptr,
&mut stream,
stream_name.as_ptr(),
input_device.unwrap() as ffi::cubeb_devid,
ptr::null_mut(), // No input parameters.
ptr::null_mut(), // Use default output device.
ptr::null_mut(), // No output parameters.
4096, // TODO: Get latency by get_min_latency instead ?
Some(noop_data_callback),
None, // No state callback.
ptr::null_mut(), // No user data pointer.
)
},
ffi::CUBEB_ERROR_INVALID_PARAMETER
);
assert!(stream.is_null());
});
}
#[test]
fn test_ops_context_stream_init_no_output_stream_params() {
let name = "context: stream_init with no output stream params";
let output_device = test_get_default_device(Scope::Output);
if output_device.is_none() {
println!("No output device to perform output tests for \"{}\".", name);
return;
}
test_ops_context_operation(name, |context_ptr| {
let mut stream: *mut ffi::cubeb_stream = ptr::null_mut();
let stream_name = CString::new(name).expect("Failed to create stream name");
assert_eq!(
unsafe {
OPS.stream_init.unwrap()(
context_ptr,
&mut stream,
stream_name.as_ptr(),
ptr::null_mut(), // Use default input device.
ptr::null_mut(), // No input parameters.
output_device.unwrap() as ffi::cubeb_devid,
ptr::null_mut(), // No output parameters.
4096, // TODO: Get latency by get_min_latency instead ?
Some(noop_data_callback),
None, // No state callback.
ptr::null_mut(), // No user data pointer.
)
},
ffi::CUBEB_ERROR_INVALID_PARAMETER
);
assert!(stream.is_null());
});
}
#[test]
fn test_ops_context_stream_init_no_data_callback() {
let name = "context: stream_init with no data callback";
test_ops_context_operation(name, |context_ptr| {
let mut stream: *mut ffi::cubeb_stream = ptr::null_mut();
let stream_name = CString::new(name).expect("Failed to create stream name");
let mut output_params = ffi::cubeb_stream_params::default();
output_params.format = ffi::CUBEB_SAMPLE_FLOAT32NE;
output_params.rate = 44100;
output_params.channels = 2;
output_params.layout = ffi::CUBEB_LAYOUT_UNDEFINED;
output_params.prefs = ffi::CUBEB_STREAM_PREF_NONE;
assert_eq!(
unsafe {
OPS.stream_init.unwrap()(
context_ptr,
&mut stream,
stream_name.as_ptr(),
ptr::null_mut(), // Use default input device.
ptr::null_mut(), // No input parameters.
ptr::null_mut(), // Use default output device.
&mut output_params,
4096, // TODO: Get latency by get_min_latency instead ?
None, // No data callback.
None, // No state callback.
ptr::null_mut(), // No user data pointer.
)
},
ffi::CUBEB_ERROR_INVALID_PARAMETER
);
assert!(stream.is_null());
});
}
#[test]
fn test_ops_context_stream_init_channel_rate_combinations() {
let name = "context: stream_init with various channels and rates";
test_ops_context_operation(name, |context_ptr| {
let mut stream: *mut ffi::cubeb_stream = ptr::null_mut();
let stream_name = CString::new(name).expect("Failed to create stream name");
const MAX_NUM_CHANNELS: u32 = 32;
let channel_values: Vec<u32> = vec![1, 2, 3, 4, 6];
let freq_values: Vec<u32> = vec![16000, 24000, 44100, 48000];
let is_float_values: Vec<bool> = vec![false, true];
for (channels, freq, is_float) in iproduct!(channel_values, freq_values, is_float_values) {
assert!(channels < MAX_NUM_CHANNELS);
println!("--------------------------");
println!(
"Testing {} channel(s), {} Hz, {}\n",
channels,
freq,
if is_float { "float" } else { "short" }
);
let mut output_params = ffi::cubeb_stream_params::default();
output_params.format = if is_float {
ffi::CUBEB_SAMPLE_FLOAT32NE
} else {
ffi::CUBEB_SAMPLE_S16NE
};
output_params.rate = freq;
output_params.channels = channels;
output_params.layout = ffi::CUBEB_LAYOUT_UNDEFINED;
output_params.prefs = ffi::CUBEB_STREAM_PREF_NONE;
assert_eq!(
unsafe {
OPS.stream_init.unwrap()(
context_ptr,
&mut stream,
stream_name.as_ptr(),
ptr::null_mut(), // Use default input device.
ptr::null_mut(), // No input parameters.
ptr::null_mut(), // Use default output device.
&mut output_params,
4096, // TODO: Get latency by get_min_latency instead ?
Some(noop_data_callback), // No data callback.
None, // No state callback.
ptr::null_mut(), // No user data pointer.
)
},
ffi::CUBEB_OK
);
assert!(!stream.is_null());
}
});
}
// Stream Operations
// ------------------------------------------------------------------------------------------------
fn test_default_output_stream_operation<F>(name: &'static str, operation: F)
@ -470,8 +660,8 @@ where
ptr::null_mut(), // No input parameters.
ptr::null_mut(), // Use default output device.
&mut output_params,
4096, // TODO: Get latency by get_min_latency instead ?
None, // No data callback.
4096, // TODO: Get latency by get_min_latency instead ?
Some(noop_data_callback),
None, // No state callback.
ptr::null_mut(), // No user data pointer.
operation,
@ -504,8 +694,8 @@ where
&mut input_params,
ptr::null_mut(), // Use default output device.
&mut output_params,
4096, // TODO: Get latency by get_min_latency instead ?
None, // No data callback.
4096, // TODO: Get latency by get_min_latency instead ?
Some(noop_data_callback),
None, // No state callback.
ptr::null_mut(), // No user data pointer.
operation,

Просмотреть файл

@ -1,6 +1,6 @@
use super::utils::{
test_audiounit_get_buffer_frame_size, test_get_default_audiounit, test_get_default_device,
test_ops_context_operation, PropertyScope, Scope,
noop_data_callback, test_audiounit_get_buffer_frame_size, test_get_default_audiounit,
test_get_default_device, test_ops_context_operation, PropertyScope, Scope,
};
use super::*;
use std::thread;
@ -232,7 +232,7 @@ fn create_streams_by_ops_in_parallel_with_different_latency<F>(
ptr::null_mut()
},
latency_frames,
None, // No data callback.
Some(noop_data_callback),
None, // No state callback.
ptr::null_mut(), // No user data pointer.
)
@ -468,7 +468,7 @@ fn create_streams_in_parallel_with_different_latency<F>(
None
},
latency_frames,
None, // No data callback.
Some(noop_data_callback),
None, // No state callback.
ptr::null_mut(), // No user data pointer.
)

Просмотреть файл

@ -2,6 +2,29 @@ use super::*;
// Common Utils
// ------------------------------------------------------------------------------------------------
pub extern "C" fn noop_data_callback(
stream: *mut ffi::cubeb_stream,
_user_ptr: *mut c_void,
_input_buffer: *const c_void,
output_buffer: *mut c_void,
nframes: i64,
) -> i64 {
assert!(!stream.is_null());
// Feed silence data to output buffer
if !output_buffer.is_null() {
let stm = unsafe { &mut *(stream as *mut AudioUnitStream) };
let channels = stm.core_stream_data.output_stream_params.channels();
let samples = nframes as usize * channels as usize;
let sample_size = cubeb_sample_size(stm.core_stream_data.output_stream_params.format());
unsafe {
ptr::write_bytes(output_buffer, 0, samples * sample_size);
}
}
nframes
}
#[derive(Clone, Debug, PartialEq)]
pub enum Scope {
Input,
@ -189,11 +212,7 @@ fn test_enable_audiounit_in_scope(
}
pub fn test_get_source_name(device: AudioObjectID, scope: Scope) -> Option<String> {
if let Some(source) = test_get_source_data(device, scope) {
Some(u32_to_string(source))
} else {
None
}
test_get_source_data(device, scope).map(u32_to_string)
}
pub fn test_get_source_data(device: AudioObjectID, scope: Scope) -> Option<u32> {
@ -238,8 +257,8 @@ fn u32_to_string(data: u32) -> String {
}
pub enum DeviceFilter {
ExcludeCubebAggregate,
IncludeCubebAggregate,
ExcludeCubebAggregateAndVPIO,
IncludeAll,
}
pub fn test_get_all_devices(filter: DeviceFilter) -> Vec<AudioObjectID> {
let mut devices = Vec::new();
@ -284,11 +303,12 @@ pub fn test_get_all_devices(filter: DeviceFilter) -> Vec<AudioObjectID> {
}
match filter {
DeviceFilter::ExcludeCubebAggregate => {
DeviceFilter::ExcludeCubebAggregateAndVPIO => {
devices.retain(|&device| {
if let Ok(uid) = get_device_global_uid(device) {
let uid = uid.into_string();
!uid.contains(PRIVATE_AGGREGATE_DEVICE_NAME)
&& !uid.contains(VOICEPROCESSING_AGGREGATE_DEVICE_NAME)
} else {
true
}
@ -301,7 +321,7 @@ pub fn test_get_all_devices(filter: DeviceFilter) -> Vec<AudioObjectID> {
}
pub fn test_get_devices_in_scope(scope: Scope) -> Vec<AudioObjectID> {
let mut devices = test_get_all_devices(DeviceFilter::ExcludeCubebAggregate);
let mut devices = test_get_all_devices(DeviceFilter::ExcludeCubebAggregateAndVPIO);
devices.retain(|device| test_device_in_scope(*device, scope.clone()));
devices
}
@ -323,7 +343,7 @@ pub fn get_devices_info_in_scope(scope: Scope) -> Vec<TestDeviceInfo> {
infos.push(TestDeviceInfo::new(device, scope.clone()));
print_info(infos.last().unwrap());
}
println!("");
println!();
infos
}
@ -605,7 +625,10 @@ pub fn test_set_default_device(
&device as *const AudioObjectID as *const c_void,
)
};
if status == NO_ERR {
let new_default = test_get_default_device(scope.clone()).unwrap();
if new_default == default {
Err(-1)
} else if status == NO_ERR {
Ok(default)
} else {
Err(status)
@ -628,8 +651,8 @@ impl TestDeviceSwitcher {
.position(|device| *device == current)
.unwrap();
Self {
scope: scope,
devices: devices,
scope,
devices,
current_device_index: index,
}
}
@ -642,9 +665,19 @@ impl TestDeviceSwitcher {
"Switch device for {:?}: {} -> {}",
self.scope, current, next
);
let prev = self.set_device(next).unwrap();
assert_eq!(prev, current);
self.current_device_index = next_index;
match self.set_device(next) {
Ok(prev) => {
assert_eq!(prev, current);
self.current_device_index = next_index;
}
_ => {
self.devices.remove(next_index);
if next_index < self.current_device_index {
self.current_device_index -= 1;
}
self.next();
}
}
}
fn set_device(&self, device: AudioObjectID) -> std::result::Result<AudioObjectID, OSStatus> {
@ -888,8 +921,9 @@ impl TestDevicePlugger {
);
CFRelease(device_uid as *const c_void);
// This device is private to the process creating it.
let private_value: i32 = 1;
// Make this device NOT private to the process creating it.
// On MacOS 14 devicechange events are not triggered when it is private.
let private_value: i32 = 0;
let device_private_key = CFNumberCreate(
kCFAllocatorDefault,
i64::from(kCFNumberIntType),
@ -1003,9 +1037,7 @@ impl TestDevicePlugger {
// AggregateDevice::get_sub_devices and audiounit_set_aggregate_sub_device_list.
fn get_sub_devices(scope: Scope) -> Option<CFArrayRef> {
let device = test_get_default_device(scope);
if device.is_none() {
return None;
}
device?;
let device = device.unwrap();
let uid = get_device_global_uid(device);
if uid.is_err() {
@ -1208,9 +1240,9 @@ pub fn test_get_stream_with_default_data_callback_by_type<F>(
bitflags! {
pub struct StreamType: u8 {
const INPUT = 0b01;
const OUTPUT = 0b10;
const DUPLEX = Self::INPUT.bits | Self::OUTPUT.bits;
const INPUT = 0x01;
const OUTPUT = 0x02;
const DUPLEX = 0x03;
}
}
@ -1252,32 +1284,9 @@ fn test_ops_stream_operation_with_default_data_callback<F>(
output_device,
output_stream_params,
4096, // TODO: Get latency by get_min_latency instead ?
Some(data_callback),
Some(noop_data_callback),
Some(state_callback),
data,
operation,
);
extern "C" fn data_callback(
stream: *mut ffi::cubeb_stream,
_user_ptr: *mut c_void,
_input_buffer: *const c_void,
output_buffer: *mut c_void,
nframes: i64,
) -> i64 {
assert!(!stream.is_null());
// Feed silence data to output buffer
if !output_buffer.is_null() {
let stm = unsafe { &mut *(stream as *mut AudioUnitStream) };
let channels = stm.core_stream_data.output_stream_params.channels();
let samples = nframes as usize * channels as usize;
let sample_size = cubeb_sample_size(stm.core_stream_data.output_stream_params.format());
unsafe {
ptr::write_bytes(output_buffer, 0, samples * sample_size);
}
}
nframes
}
}

Просмотреть файл

@ -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 = "93b5c01a131f65c83c11aeb317f4583405c5eb79", optional = true }
cubeb-coreaudio = { git = "https://github.com/mozilla/cubeb-coreaudio-rs", rev = "964e14628f285ad44522bdeeb566c1864ecd2fd8", optional = true }
cubeb-pulse = { git = "https://github.com/mozilla/cubeb-pulse-rs", rev="cf48897be5cbe147d051ebbbe1eaf5fd8fb6bbc9", optional = true, features=["pulse-dlopen"] }
cubeb-sys = { version = "0.10.3", optional = true, features=["gecko-in-tree"] }
audioipc2-client = { git = "https://github.com/mozilla/audioipc", rev = "6be424d75f1367e70f2f5ddcacd6d0237e81a6a9", optional = true }