зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1890186: Update cubeb-coreaudio-rs to 1796ace5bd. r=cubeb-reviewers,padenot
Differential Revision: https://phabricator.services.mozilla.com/D212311
This commit is contained in:
Родитель
e18f2fd79f
Коммит
a303b96371
|
@ -70,9 +70,9 @@ git = "https://github.com/mozilla/audioipc"
|
|||
rev = "3495905752a4263827f5d43737f9ca3ed0243ce0"
|
||||
replace-with = "vendored-sources"
|
||||
|
||||
[source."git+https://github.com/mozilla/cubeb-coreaudio-rs?rev=4cc24c7dc74a4801455ba0bbe20ea67a49f28514"]
|
||||
[source."git+https://github.com/mozilla/cubeb-coreaudio-rs?rev=1796ace5bdd08ec8baa56bbf7170a08d760c984b"]
|
||||
git = "https://github.com/mozilla/cubeb-coreaudio-rs"
|
||||
rev = "4cc24c7dc74a4801455ba0bbe20ea67a49f28514"
|
||||
rev = "1796ace5bdd08ec8baa56bbf7170a08d760c984b"
|
||||
replace-with = "vendored-sources"
|
||||
|
||||
[source."git+https://github.com/mozilla/cubeb-pulse-rs?rev=8678dcab1c287de79c4c184ccc2e065bc62b70e2"]
|
||||
|
|
|
@ -921,7 +921,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "coreaudio-sys-utils"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/mozilla/cubeb-coreaudio-rs?rev=4cc24c7dc74a4801455ba0bbe20ea67a49f28514#4cc24c7dc74a4801455ba0bbe20ea67a49f28514"
|
||||
source = "git+https://github.com/mozilla/cubeb-coreaudio-rs?rev=1796ace5bdd08ec8baa56bbf7170a08d760c984b#1796ace5bdd08ec8baa56bbf7170a08d760c984b"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"coreaudio-sys",
|
||||
|
@ -1169,7 +1169,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "cubeb-coreaudio"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/mozilla/cubeb-coreaudio-rs?rev=4cc24c7dc74a4801455ba0bbe20ea67a49f28514#4cc24c7dc74a4801455ba0bbe20ea67a49f28514"
|
||||
source = "git+https://github.com/mozilla/cubeb-coreaudio-rs?rev=1796ace5bdd08ec8baa56bbf7170a08d760c984b#1796ace5bdd08ec8baa56bbf7170a08d760c984b"
|
||||
dependencies = [
|
||||
"atomic",
|
||||
"audio-mixer",
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"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":"90c2542fa3ff8a35fed894fae3a1aa0157117b7f0e28df14b8e6f7b1f1f43797","run_sanitizers.sh":"84e93a0da137803018f37403511e8c92760be730426bf6cea34419d93d1a7ff8","run_tests.sh":"bae82f66dd47a060b6fdcc238520084aec1079d5b1b1d66d103baa1ffaa8773d","src/backend/aggregate_device.rs":"6e94c36c09081a728b1ab748b460fe8f538cf5f50bc62fd47171a393fe2d609a","src/backend/auto_release.rs":"050fdcee74cf46b9a8a85a877e166d72a853d33220f59cf734cbb6ea09daa441","src/backend/buffer_manager.rs":"e9bcf964347daa8952f98caa2746e34a31ea8908375204896593f56e4b6147ca","src/backend/device_property.rs":"0714b90c3187b0b1709f5e4b7757e1b434659276e00db48a3f3270fbfd429640","src/backend/mixer.rs":"c4d09291598cbffb2217b551770ec590f34b6dd6b461dd99b019d5bb70f0eef3","src/backend/mod.rs":"48380d5a273fc3ff8b597e5974fc00361c66b512b1d95b6c15a6cea332a11a57","src/backend/resampler.rs":"48bf8f56ae8d60dbabca6417b768000619abee8731ac3902164b45651ac08a4d","src/backend/tests/aggregate_device.rs":"48e291b355a7c0c643fc58e9d238ed00234b4f1ac0f4c26737cc74862d4f2ac8","src/backend/tests/api.rs":"ef3babcd3410394b8d5bcdaf0ea526486b14d8e42f33211997aafe179430bf4a","src/backend/tests/backlog.rs":"3b189a7e036543c467cc242af0ed3332721179ee2b1c8847a6db563546f1ac52","src/backend/tests/device_change.rs":"babf50326fb38db24fe80f24f546e1b6ad04319ae8835bb372d893fc9b3038a2","src/backend/tests/device_property.rs":"73c25f579a995e8a59c9b7d391813afb75f739b5e2f825480cba04499a1d46e8","src/backend/tests/interfaces.rs":"cd58614435574444d8a1f039dc201cf371cccacd58efbae8ed8fbff919550d0a","src/backend/tests/manual.rs":"f72625c05110534775c4608ccc45472ea108286657ffc1f029844a13d0b883bf","src/backend/tests/mod.rs":"8dba770023d7f9c4228f0e11915347f0e07da5fd818e3ee4478c4b197af9aa2a","src/backend/tests/parallel.rs":"a7ebd579339c40ca64c0757cc9da6baec641e670f226e1b2ec5049894700bd7a","src/backend/tests/tone.rs":"b028c67777b6453a26190b6a49785dfe28556adcbe179cb10862ce0d47ee8509","src/backend/tests/utils.rs":"21c8e7f6f18da0f8d33733ad0fc981041b43586db6a637c3f7aec7e7b3936aed","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":"1403232694fabeae004179be8399d1fe2a1b100d60cd90db37d8860eddbaf2ae","run_sanitizers.sh":"84e93a0da137803018f37403511e8c92760be730426bf6cea34419d93d1a7ff8","run_tests.sh":"bae82f66dd47a060b6fdcc238520084aec1079d5b1b1d66d103baa1ffaa8773d","src/backend/aggregate_device.rs":"a910b9d596b1971cb4fee34f5030809ade584f41eb5cbad73a09abe7352ebd15","src/backend/auto_release.rs":"050fdcee74cf46b9a8a85a877e166d72a853d33220f59cf734cbb6ea09daa441","src/backend/buffer_manager.rs":"e9bcf964347daa8952f98caa2746e34a31ea8908375204896593f56e4b6147ca","src/backend/device_property.rs":"4719226a5fb3b5697d4624ccf1b15f0d522ddbc3f64a98fba47d9c55c5aeee36","src/backend/mixer.rs":"c4d09291598cbffb2217b551770ec590f34b6dd6b461dd99b019d5bb70f0eef3","src/backend/mod.rs":"c13d293223402bdb53451e6587a3de8a22be36d6e944baba88bda3977d2cebd9","src/backend/resampler.rs":"48bf8f56ae8d60dbabca6417b768000619abee8731ac3902164b45651ac08a4d","src/backend/tests/aggregate_device.rs":"afbdf1da1fcaddcad2986bd3146bf93ca75c24b3362f5f23a09517a926290ca2","src/backend/tests/api.rs":"3b0936810b3afa84cb80428c471e1097701fd790460d00c0a5715fd8026d0a4d","src/backend/tests/backlog.rs":"3b189a7e036543c467cc242af0ed3332721179ee2b1c8847a6db563546f1ac52","src/backend/tests/device_change.rs":"babf50326fb38db24fe80f24f546e1b6ad04319ae8835bb372d893fc9b3038a2","src/backend/tests/device_property.rs":"4ef3ab625809fe95e944c19cc5dc1cc79f473520a4314d123b1f80c6b7e11411","src/backend/tests/interfaces.rs":"cd58614435574444d8a1f039dc201cf371cccacd58efbae8ed8fbff919550d0a","src/backend/tests/manual.rs":"f72625c05110534775c4608ccc45472ea108286657ffc1f029844a13d0b883bf","src/backend/tests/mod.rs":"8dba770023d7f9c4228f0e11915347f0e07da5fd818e3ee4478c4b197af9aa2a","src/backend/tests/parallel.rs":"a7ebd579339c40ca64c0757cc9da6baec641e670f226e1b2ec5049894700bd7a","src/backend/tests/tone.rs":"b028c67777b6453a26190b6a49785dfe28556adcbe179cb10862ce0d47ee8509","src/backend/tests/utils.rs":"3e435569798b883db8342137098832b88837a387008852005363f74e5e6ff18e","src/backend/utils.rs":"6c3ffbcd602e6cc9f56deb9ecb07b2eef2e6f074ef924178e466f380aae5c595","src/capi.rs":"21b66b70545bf04ec719928004d1d9adb45b24ced51288f5b2993d79aaf78f5f","src/lib.rs":"5e586d45cd6b3722f0a6736d9252593299269817a153eef1930a5fb9bfbb56f5","todo.md":"efc1f012eb9a331a040cad4ac03aa79307f25885f71b6fb38f3ad7af8d7d515c"},"package":null}
|
|
@ -8,10 +8,15 @@ if [[ -z "${RUST_BACKTRACE}" ]]; then
|
|||
fi
|
||||
echo "RUST_BACKTRACE is set to ${RUST_BACKTRACE}\n"
|
||||
|
||||
cargo test test_aggregate -- --ignored --nocapture
|
||||
|
||||
cargo test test_switch_device -- --ignored --nocapture
|
||||
|
||||
cargo test test_plug_and_unplug_device -- --ignored --nocapture
|
||||
|
||||
cargo test test_get_channel_count_of_input_devices_with_vpio -- --ignored --nocapture
|
||||
cargo test test_get_channel_count_of_input_devices_with_aggregate_device_and_vpio -- --ignored --nocapture
|
||||
|
||||
cargo test test_register_device_changed_callback_to_check_default_device_changed_input -- --ignored --nocapture
|
||||
cargo test test_register_device_changed_callback_to_check_default_device_changed_output -- --ignored --nocapture
|
||||
cargo test test_register_device_changed_callback_to_check_default_device_changed_duplex -- --ignored --nocapture
|
||||
|
|
|
@ -185,9 +185,7 @@ impl AggregateDevice {
|
|||
let (lock, cvar) = &*condvar_pair;
|
||||
let guard = lock.lock().unwrap();
|
||||
let (_guard, timeout_res) = cvar
|
||||
.wait_timeout_while(guard, waiting_time, |()| {
|
||||
!audiounit_get_devices().contains(&device)
|
||||
})
|
||||
.wait_timeout_while(guard, waiting_time, |()| !get_devices().contains(&device))
|
||||
.unwrap();
|
||||
if timeout_res.timed_out() {
|
||||
cubeb_log!(
|
||||
|
@ -396,8 +394,8 @@ impl AggregateDevice {
|
|||
assert_ne!(input_id, output_id);
|
||||
debug_assert_running_serially();
|
||||
|
||||
let output_sub_devices = Self::get_sub_devices(output_id)?;
|
||||
let input_sub_devices = Self::get_sub_devices(input_id)?;
|
||||
let output_sub_devices = Self::get_sub_devices_or_self(output_id)?;
|
||||
let input_sub_devices = Self::get_sub_devices_or_self(input_id)?;
|
||||
|
||||
unsafe {
|
||||
let sub_devices = CFArrayCreateMutable(ptr::null(), 0, &kCFTypeArrayCallBacks);
|
||||
|
@ -445,16 +443,10 @@ impl AggregateDevice {
|
|||
let mut size: usize = 0;
|
||||
let status = audio_object_get_property_data_size(device_id, &address, &mut size);
|
||||
|
||||
if status == kAudioHardwareUnknownPropertyError as OSStatus {
|
||||
// Return a vector containing the device itself if the device has no sub devices.
|
||||
sub_devices.push(device_id);
|
||||
return Ok(sub_devices);
|
||||
} else if status != NO_ERR {
|
||||
if status != NO_ERR {
|
||||
return Err(Error::from(status));
|
||||
}
|
||||
|
||||
assert_ne!(size, 0);
|
||||
|
||||
let count = size / mem::size_of::<AudioObjectID>();
|
||||
sub_devices = allocate_array(count);
|
||||
let status = audio_object_get_property_data(
|
||||
|
@ -471,6 +463,17 @@ impl AggregateDevice {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_sub_devices_or_self(
|
||||
device_id: AudioDeviceID,
|
||||
) -> std::result::Result<Vec<AudioObjectID>, Error> {
|
||||
AggregateDevice::get_sub_devices(device_id).or_else(|e| match e {
|
||||
Error::OS(status) if status == kAudioHardwareUnknownPropertyError as OSStatus => {
|
||||
Ok(vec![device_id])
|
||||
}
|
||||
_ => Err(e),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_master_device_uid(device_id: AudioDeviceID) -> std::result::Result<String, Error> {
|
||||
debug_assert_running_serially();
|
||||
let address = AudioObjectPropertyAddress {
|
||||
|
@ -515,7 +518,7 @@ impl AggregateDevice {
|
|||
};
|
||||
|
||||
// The master device will be the 1st sub device of the primary device.
|
||||
let output_sub_devices = Self::get_sub_devices(primary_id)?;
|
||||
let output_sub_devices = Self::get_sub_devices_or_self(primary_id)?;
|
||||
assert!(!output_sub_devices.is_empty());
|
||||
let master_sub_device_uid = get_device_global_uid(output_sub_devices[0]).unwrap();
|
||||
let master_sub_device = master_sub_device_uid.get_raw();
|
||||
|
|
|
@ -18,6 +18,32 @@ pub fn get_device_uid(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_devices() -> Vec<AudioObjectID> {
|
||||
debug_assert_running_serially();
|
||||
let mut size: usize = 0;
|
||||
let address = get_property_address(
|
||||
Property::HardwareDevices,
|
||||
DeviceType::INPUT | DeviceType::OUTPUT,
|
||||
);
|
||||
let mut ret =
|
||||
audio_object_get_property_data_size(kAudioObjectSystemObject, &address, &mut size);
|
||||
if ret != NO_ERR {
|
||||
return Vec::new();
|
||||
}
|
||||
// Total number of input and output devices.
|
||||
let mut devices: Vec<AudioObjectID> = allocate_array_by_size(size);
|
||||
ret = audio_object_get_property_data(
|
||||
kAudioObjectSystemObject,
|
||||
&address,
|
||||
&mut size,
|
||||
devices.as_mut_ptr(),
|
||||
);
|
||||
if ret != NO_ERR {
|
||||
return Vec::new();
|
||||
}
|
||||
devices
|
||||
}
|
||||
|
||||
pub fn get_device_model_uid(
|
||||
id: AudioDeviceID,
|
||||
devtype: DeviceType,
|
||||
|
@ -169,10 +195,15 @@ pub fn get_device_latency(
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DeviceStream {
|
||||
pub device: AudioDeviceID,
|
||||
pub stream: AudioStreamID,
|
||||
}
|
||||
pub fn get_device_streams(
|
||||
id: AudioDeviceID,
|
||||
devtype: DeviceType,
|
||||
) -> std::result::Result<Vec<AudioStreamID>, OSStatus> {
|
||||
) -> std::result::Result<Vec<DeviceStream>, OSStatus> {
|
||||
assert_ne!(id, kAudioObjectUnknown);
|
||||
debug_assert_running_serially();
|
||||
|
||||
|
@ -184,13 +215,77 @@ pub fn get_device_streams(
|
|||
return Err(err);
|
||||
}
|
||||
|
||||
let mut streams: Vec<AudioObjectID> = allocate_array_by_size(size);
|
||||
let mut streams = vec![AudioObjectID::default(); size / mem::size_of::<AudioObjectID>()];
|
||||
let err = audio_object_get_property_data(id, &address, &mut size, streams.as_mut_ptr());
|
||||
if err == NO_ERR {
|
||||
Ok(streams)
|
||||
} else {
|
||||
Err(err)
|
||||
if err != NO_ERR {
|
||||
return Err(err);
|
||||
}
|
||||
|
||||
let mut device_streams = streams
|
||||
.into_iter()
|
||||
.map(|stream| DeviceStream { device: id, stream })
|
||||
.collect::<Vec<_>>();
|
||||
if devtype.contains(DeviceType::INPUT) {
|
||||
// With VPIO, output devices will/may get a Tap that appears as an input stream on the
|
||||
// output device id. It is unclear what kind of Tap this is as it cannot be enumerated
|
||||
// as a Tap through the public APIs. There is no property on the stream itself that
|
||||
// can consistently identify it as originating from another device's output either.
|
||||
// TerminalType gets close but is often kAudioStreamTerminalTypeUnknown, and there are
|
||||
// cases reported where real input streams have that TerminalType, too.
|
||||
// See Firefox bug 1890186.
|
||||
// We rely on AudioObjectID order instead. AudioDeviceID and AudioStreamID (and more)
|
||||
// are all AudioObjectIDs underneath, and they're all distinct. The Tap streams
|
||||
// mentioned above are created when VPIO is created, and their AudioObjectIDs are higher
|
||||
// than the VPIO device's AudioObjectID, but lower than the next *real* device's
|
||||
// AudioObjectID.
|
||||
// Simplified, a device's native streams have AudioObjectIDs higher than their device's
|
||||
// AudioObjectID but lower than the next device's AudioObjectID.
|
||||
// We use this to filter streams, and hope that it holds across macOS versions.
|
||||
// Note that for aggregate devices this does not hold, as their stream IDs seem to be
|
||||
// repurposed by VPIO. We sum up the result of the above algorithm for each of their sub
|
||||
// devices instead, as that seems to hold.
|
||||
let mut devices = get_devices();
|
||||
let sub_devices = AggregateDevice::get_sub_devices(id);
|
||||
if let Ok(sub_device_ids) = sub_devices {
|
||||
cubeb_log!(
|
||||
"Getting input device streams for aggregate device {}. Summing over sub devices {:?}.",
|
||||
id,
|
||||
sub_device_ids
|
||||
);
|
||||
return Ok(sub_device_ids
|
||||
.into_iter()
|
||||
.filter_map(|sub_id| get_device_streams(sub_id, devtype).ok())
|
||||
.flatten()
|
||||
.collect());
|
||||
}
|
||||
debug_assert!(devices.contains(&id));
|
||||
devices.sort();
|
||||
let next_id = devices.into_iter().skip_while(|&i| i != id).nth(1);
|
||||
cubeb_log!(
|
||||
"Filtering input streams {:?} for device {}. Next device is {:?}.",
|
||||
device_streams
|
||||
.iter()
|
||||
.map(|ds| ds.stream)
|
||||
.collect::<Vec<_>>(),
|
||||
id,
|
||||
next_id
|
||||
);
|
||||
if let Some(next_id) = next_id {
|
||||
device_streams.retain(|ds| ds.stream > id && ds.stream < next_id);
|
||||
} else {
|
||||
device_streams.retain(|ds| ds.stream > id);
|
||||
}
|
||||
cubeb_log!(
|
||||
"Input stream filtering for device {} retained {:?}.",
|
||||
id,
|
||||
device_streams
|
||||
.iter()
|
||||
.map(|ds| ds.stream)
|
||||
.collect::<Vec<_>>()
|
||||
);
|
||||
}
|
||||
|
||||
Ok(device_streams)
|
||||
}
|
||||
|
||||
pub fn get_device_sample_rate(
|
||||
|
@ -253,24 +348,6 @@ pub fn get_stream_latency(id: AudioStreamID) -> std::result::Result<u32, OSStatu
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_stream_terminal_type(id: AudioStreamID) -> std::result::Result<u32, OSStatus> {
|
||||
assert_ne!(id, kAudioObjectUnknown);
|
||||
debug_assert_running_serially();
|
||||
|
||||
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> {
|
||||
|
|
|
@ -1620,77 +1620,17 @@ fn get_channel_count(
|
|||
assert_ne!(devid, kAudioObjectUnknown);
|
||||
debug_assert_running_serially();
|
||||
|
||||
let mut streams = get_device_streams(devid, devtype)?;
|
||||
let model_uid =
|
||||
get_device_model_uid(devid, devtype).map_or_else(|_| String::new(), |s| s.into_string());
|
||||
|
||||
if devtype == DeviceType::INPUT {
|
||||
// With VPIO, output devices will/may get a Tap that appears as input channels on the
|
||||
// output device id. One could check for whether the output device has a tap enabled,
|
||||
// but it is impossible to distinguish an output-only device from an input+output
|
||||
// device. There have also been corner cases observed, where the device does NOT have
|
||||
// a Tap enabled, but it still has the extra input channels from the Tap.
|
||||
// We can check the terminal type of the input stream instead, the VPIO type is
|
||||
// INPUT_UNDEFINED or an output type, we explicitly ignore those and keep all other cases.
|
||||
streams.retain(|stream| {
|
||||
let terminal_type = get_stream_terminal_type(*stream);
|
||||
if terminal_type.is_err() {
|
||||
return true;
|
||||
}
|
||||
|
||||
#[allow(non_upper_case_globals)]
|
||||
match terminal_type.unwrap() {
|
||||
kAudioStreamTerminalTypeMicrophone
|
||||
| kAudioStreamTerminalTypeHeadsetMicrophone
|
||||
| kAudioStreamTerminalTypeReceiverMicrophone => true,
|
||||
kAudioStreamTerminalTypeUnknown => {
|
||||
cubeb_log!("Unknown TerminalType for input stream. Ignoring its channels.");
|
||||
false
|
||||
}
|
||||
t if [
|
||||
kAudioStreamTerminalTypeSpeaker,
|
||||
kAudioStreamTerminalTypeHeadphones,
|
||||
kAudioStreamTerminalTypeLFESpeaker,
|
||||
kAudioStreamTerminalTypeReceiverSpeaker,
|
||||
]
|
||||
.contains(&t) =>
|
||||
let devstreams = get_device_streams(devid, devtype)?;
|
||||
let mut count: u32 = 0;
|
||||
for ds in devstreams {
|
||||
if devtype == DeviceType::INPUT
|
||||
&& CoreStreamData::should_force_vpio_for_input_device(ds.device)
|
||||
{
|
||||
cubeb_log!(
|
||||
"Output TerminalType {:#06X} for input stream. Ignoring its channels.",
|
||||
t
|
||||
);
|
||||
false
|
||||
}
|
||||
INPUT_UNDEFINED => {
|
||||
cubeb_log!(
|
||||
"INPUT_UNDEFINED TerminalType for input stream. Ignoring its channels."
|
||||
);
|
||||
false
|
||||
}
|
||||
// The input tap stream on the Studio Display Speakers has a terminal type that
|
||||
// is not clearly output-specific. We special-case it here.
|
||||
EXTERNAL_DIGITAL_AUDIO_INTERFACE
|
||||
if model_uid.contains(APPLE_STUDIO_DISPLAY_USB_ID) =>
|
||||
{
|
||||
false
|
||||
}
|
||||
// Note INPUT_UNDEFINED is 0x200 and INPUT_MICROPHONE is 0x201
|
||||
t if (INPUT_MICROPHONE..OUTPUT_UNDEFINED).contains(&t) => true,
|
||||
t if (OUTPUT_UNDEFINED..BIDIRECTIONAL_UNDEFINED).contains(&t) => false,
|
||||
t if (BIDIRECTIONAL_UNDEFINED..TELEPHONY_UNDEFINED).contains(&t) => true,
|
||||
t if (TELEPHONY_UNDEFINED..EXTERNAL_UNDEFINED).contains(&t) => true,
|
||||
t => {
|
||||
cubeb_log!("Unknown TerminalType {:#06X} for input stream.", t);
|
||||
true
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let mut count = 0;
|
||||
for stream in streams {
|
||||
if let Ok(format) = get_stream_virtual_format(stream) {
|
||||
count += format.mChannelsPerFrame;
|
||||
count += 1;
|
||||
} else {
|
||||
count += get_stream_virtual_format(ds.stream)
|
||||
.map(|f| f.mChannelsPerFrame)
|
||||
.unwrap_or(0);
|
||||
}
|
||||
}
|
||||
Ok(count)
|
||||
|
@ -1736,8 +1676,8 @@ fn get_fixed_latency(devid: AudioObjectID, devtype: DeviceType) -> u32 {
|
|||
}
|
||||
};
|
||||
|
||||
let stream_latency = get_device_streams(devid, devtype).and_then(|streams| {
|
||||
if streams.is_empty() {
|
||||
let stream_latency = get_device_streams(devid, devtype).and_then(|devstreams| {
|
||||
if devstreams.is_empty() {
|
||||
cubeb_log!(
|
||||
"No stream on device {} in {:?} scope!",
|
||||
devid,
|
||||
|
@ -1745,7 +1685,7 @@ fn get_fixed_latency(devid: AudioObjectID, devtype: DeviceType) -> u32 {
|
|||
);
|
||||
Ok(0) // default stream latency
|
||||
} else {
|
||||
get_stream_latency(streams[0])
|
||||
get_stream_latency(devstreams[0].stream)
|
||||
}
|
||||
}).map_err(|e| {
|
||||
cubeb_log!(
|
||||
|
@ -2031,37 +1971,11 @@ fn destroy_cubeb_device_info(device: &mut ffi::cubeb_device_info) {
|
|||
}
|
||||
}
|
||||
|
||||
fn audiounit_get_devices() -> Vec<AudioObjectID> {
|
||||
debug_assert_running_serially();
|
||||
let mut size: usize = 0;
|
||||
let address = get_property_address(
|
||||
Property::HardwareDevices,
|
||||
DeviceType::INPUT | DeviceType::OUTPUT,
|
||||
);
|
||||
let mut ret =
|
||||
audio_object_get_property_data_size(kAudioObjectSystemObject, &address, &mut size);
|
||||
if ret != NO_ERR {
|
||||
return Vec::new();
|
||||
}
|
||||
// Total number of input and output devices.
|
||||
let mut devices: Vec<AudioObjectID> = allocate_array_by_size(size);
|
||||
ret = audio_object_get_property_data(
|
||||
kAudioObjectSystemObject,
|
||||
&address,
|
||||
&mut size,
|
||||
devices.as_mut_ptr(),
|
||||
);
|
||||
if ret != NO_ERR {
|
||||
return Vec::new();
|
||||
}
|
||||
devices
|
||||
}
|
||||
|
||||
fn audiounit_get_devices_of_type(devtype: DeviceType) -> Vec<AudioObjectID> {
|
||||
assert!(devtype.intersects(DeviceType::INPUT | DeviceType::OUTPUT));
|
||||
debug_assert_running_serially();
|
||||
|
||||
let mut devices = audiounit_get_devices();
|
||||
let mut devices = get_devices();
|
||||
|
||||
// Remove the aggregate device from the list of devices (if any).
|
||||
devices.retain(|&device| {
|
||||
|
@ -3304,14 +3218,15 @@ impl<'ctx> CoreStreamData<'ctx> {
|
|||
}
|
||||
|
||||
#[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) {
|
||||
fn should_force_vpio_for_input_device(id: AudioDeviceID) -> bool {
|
||||
assert!(id != kAudioObjectUnknown);
|
||||
debug_assert_running_serially();
|
||||
match get_device_transport_type(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."
|
||||
"Input device {} is on the VPIO force list because it is built in, \
|
||||
and its volume is known to be very low without VPIO whenever VPIO \
|
||||
is hooked up to it elsewhere."
|
||||
);
|
||||
true
|
||||
}
|
||||
|
@ -3388,7 +3303,7 @@ impl<'ctx> CoreStreamData<'ctx> {
|
|||
.input_stream_params
|
||||
.prefs()
|
||||
.contains(StreamPrefs::VOICE)
|
||||
|| self.should_force_vpio_for_input_device(&self.input_device))
|
||||
|| CoreStreamData::should_force_vpio_for_input_device(self.input_device.id))
|
||||
&& !self.should_block_vpio_for_device_pair(&self.input_device, &self.output_device)
|
||||
&& macos_kernel_major_version() != Ok(MACOS_KERNEL_MAJOR_VERSION_MONTEREY);
|
||||
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
extern crate itertools;
|
||||
|
||||
use super::utils::{
|
||||
test_get_all_devices, test_get_all_onwed_devices, test_get_default_device,
|
||||
test_get_drift_compensations, test_get_master_device, DeviceFilter, Scope,
|
||||
};
|
||||
use super::*;
|
||||
use std::collections::HashSet;
|
||||
use std::iter::zip;
|
||||
use std::panic;
|
||||
|
||||
|
@ -46,25 +49,73 @@ fn test_aggregate_set_sub_devices_for_unknown_devices() {
|
|||
|
||||
// AggregateDevice::get_sub_devices
|
||||
// ------------------------------------
|
||||
// You can check this by creating an aggregate device in `Audio MIDI Setup`
|
||||
// application and print out the sub devices of them!
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_aggregate_get_sub_devices() {
|
||||
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
|
||||
// is not an empty aggregate device (Test will panic when calling get_sub_devices with
|
||||
// an empty aggregate device).
|
||||
println!(
|
||||
"get_sub_devices({}={})",
|
||||
device,
|
||||
run_serially_forward_panics(|| get_device_uid(device))
|
||||
fn diff(lhs: Vec<u32>, rhs: Vec<u32>) -> Vec<u32> {
|
||||
let left: HashSet<u32> = lhs.into_iter().collect();
|
||||
let right: HashSet<u32> = rhs.into_iter().collect();
|
||||
left.symmetric_difference(&right)
|
||||
.map(|&i| i.clone())
|
||||
.collect()
|
||||
}
|
||||
|
||||
// Run in a large block so other test cases cannot add or remove devices while this runs.
|
||||
let input_device = test_get_default_device(Scope::Input);
|
||||
let output_device = test_get_default_device(Scope::Output);
|
||||
if input_device.is_none() || output_device.is_none() || input_device == output_device {
|
||||
println!("No input and output device to create an aggregate device.");
|
||||
return;
|
||||
}
|
||||
let devices_base = test_get_all_devices(DeviceFilter::ExcludeVPIO);
|
||||
run_serially_forward_panics(|| {
|
||||
assert!(
|
||||
devices_base
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(AggregateDevice::get_sub_devices)
|
||||
.any(|r| r.is_err()),
|
||||
"There should be some device that is not an aggregate."
|
||||
)
|
||||
});
|
||||
|
||||
{
|
||||
// Test get_sub_devices on an empty aggregate device.
|
||||
let plugin_id = AggregateDevice::get_system_plugin_id().unwrap();
|
||||
let aggr = run_serially_forward_panics(|| AggregateDevice::create_blank_device(plugin_id))
|
||||
.unwrap();
|
||||
let new = diff(
|
||||
devices_base.clone(),
|
||||
test_get_all_devices(DeviceFilter::ExcludeVPIO),
|
||||
);
|
||||
let sub_devices =
|
||||
run_serially_forward_panics(|| AggregateDevice::get_sub_devices(device).unwrap());
|
||||
// TODO: If the device is a blank aggregate device, then the assertion fails!
|
||||
assert!(!sub_devices.is_empty());
|
||||
assert_eq!(new.len(), 1);
|
||||
let new_subs = run_serially_forward_panics(|| AggregateDevice::get_sub_devices(new[0]));
|
||||
assert!(new_subs.is_ok());
|
||||
assert_eq!(new_subs.unwrap().len(), 0);
|
||||
assert!(
|
||||
run_serially_forward_panics(|| AggregateDevice::destroy_device(plugin_id, aggr))
|
||||
.is_ok()
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
// Test get_sub_devices on an aggregate device with two sub devices.
|
||||
let aggr = run_serially_forward_panics(|| {
|
||||
let input_device = input_device.unwrap();
|
||||
let output_device = output_device.unwrap();
|
||||
|
||||
AggregateDevice::new(input_device, output_device)
|
||||
})
|
||||
.unwrap();
|
||||
let new = diff(
|
||||
devices_base.clone(),
|
||||
test_get_all_devices(DeviceFilter::ExcludeVPIO),
|
||||
);
|
||||
assert_eq!(new.len(), 1);
|
||||
let new_subs = run_serially_forward_panics(|| AggregateDevice::get_sub_devices(new[0]));
|
||||
assert!(new_subs.is_ok());
|
||||
assert_eq!(new_subs.unwrap().len(), 2);
|
||||
run_serially_forward_panics(|| drop(aggr));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,8 +123,7 @@ fn test_aggregate_get_sub_devices() {
|
|||
#[should_panic]
|
||||
fn test_aggregate_get_sub_devices_for_a_unknown_device() {
|
||||
run_serially_forward_panics(|| {
|
||||
let devices = AggregateDevice::get_sub_devices(kAudioObjectUnknown).unwrap();
|
||||
assert!(devices.is_empty());
|
||||
AggregateDevice::get_sub_devices(kAudioObjectUnknown);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -135,15 +185,11 @@ fn test_aggregate_create_blank_device() {
|
|||
// AggregateDevice::get_sub_devices
|
||||
// ------------------------------------
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_aggregate_get_sub_devices_for_blank_aggregate_devices() {
|
||||
run_serially_forward_panics(|| {
|
||||
// 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();
|
||||
// There is no sub device in a blank aggregate device!
|
||||
// AggregateDevice::get_sub_devices guarantees returning a non-empty devices vector, so
|
||||
// the following call will panic!
|
||||
let sub_devices = AggregateDevice::get_sub_devices(device).unwrap();
|
||||
assert!(sub_devices.is_empty());
|
||||
assert!(AggregateDevice::destroy_device(plugin, device).is_ok());
|
||||
|
@ -173,11 +219,11 @@ fn test_aggregate_set_sub_devices() {
|
|||
))
|
||||
.is_ok());
|
||||
|
||||
let sub_devices = run_serially(|| AggregateDevice::get_sub_devices(device)).unwrap();
|
||||
let sub_devices = run_serially(|| AggregateDevice::get_sub_devices_or_self(device)).unwrap();
|
||||
let input_sub_devices =
|
||||
run_serially(|| AggregateDevice::get_sub_devices(input_device)).unwrap();
|
||||
run_serially(|| AggregateDevice::get_sub_devices_or_self(input_device)).unwrap();
|
||||
let output_sub_devices =
|
||||
run_serially(|| AggregateDevice::get_sub_devices(output_device)).unwrap();
|
||||
run_serially(|| AggregateDevice::get_sub_devices_or_self(output_device)).unwrap();
|
||||
|
||||
// TODO: There may be overlapping devices between input_sub_devices and output_sub_devices,
|
||||
// but now AggregateDevice::set_sub_devices will add them directly.
|
||||
|
@ -280,7 +326,7 @@ fn test_aggregate_set_master_device() {
|
|||
assert!(run_serially(|| AggregateDevice::set_master_device(device, output_device)).is_ok());
|
||||
|
||||
let output_sub_devices =
|
||||
run_serially(|| AggregateDevice::get_sub_devices(output_device)).unwrap();
|
||||
run_serially(|| AggregateDevice::get_sub_devices_or_self(output_device)).unwrap();
|
||||
let first_output_sub_device_uid = run_serially(|| get_device_uid(output_sub_devices[0]));
|
||||
|
||||
// Check that the first sub device of the output device is set as master device.
|
||||
|
@ -391,10 +437,12 @@ fn test_aggregate_activate_clock_drift_compensation_for_an_aggregate_device_with
|
|||
// The master device is by default the first sub device in the list.
|
||||
// This happens to be the first sub device of the input device, see implementation of
|
||||
// AggregateDevice::set_sub_devices.
|
||||
let first_input_sub_device_uid =
|
||||
run_serially(|| get_device_uid(AggregateDevice::get_sub_devices(input_device).unwrap()[0]));
|
||||
let first_sub_device_uid =
|
||||
run_serially(|| get_device_uid(AggregateDevice::get_sub_devices(device).unwrap()[0]));
|
||||
let first_input_sub_device_uid = run_serially(|| {
|
||||
get_device_uid(AggregateDevice::get_sub_devices_or_self(input_device).unwrap()[0])
|
||||
});
|
||||
let first_sub_device_uid = run_serially(|| {
|
||||
get_device_uid(AggregateDevice::get_sub_devices_or_self(device).unwrap()[0])
|
||||
});
|
||||
assert_eq!(first_input_sub_device_uid, first_sub_device_uid);
|
||||
let master_device_uid = run_serially(|| test_get_master_device(device));
|
||||
assert_eq!(first_sub_device_uid, master_device_uid);
|
||||
|
@ -422,7 +470,7 @@ fn test_aggregate_activate_clock_drift_compensation_for_a_blank_aggregate_device
|
|||
let plugin = AggregateDevice::get_system_plugin_id().unwrap();
|
||||
let device = AggregateDevice::create_blank_device_sync(plugin).unwrap();
|
||||
|
||||
let sub_devices = AggregateDevice::get_sub_devices(device).unwrap();
|
||||
let sub_devices = AggregateDevice::get_sub_devices_or_self(device).unwrap();
|
||||
assert!(sub_devices.is_empty());
|
||||
let onwed_devices = test_get_all_onwed_devices(device);
|
||||
assert!(onwed_devices.is_empty());
|
||||
|
@ -475,7 +523,7 @@ fn test_aggregate_new() {
|
|||
let aggr = AggregateDevice::new(input_device, output_device).unwrap();
|
||||
|
||||
// Check main device
|
||||
let output_sub_devices = AggregateDevice::get_sub_devices(output_device).unwrap();
|
||||
let output_sub_devices = AggregateDevice::get_sub_devices_or_self(output_device).unwrap();
|
||||
let first_output_sub_device_uid = get_device_uid(output_sub_devices[0]);
|
||||
let master_device_uid = test_get_master_device(aggr.get_device_id());
|
||||
assert_eq!(first_output_sub_device_uid, master_device_uid);
|
||||
|
|
|
@ -1134,6 +1134,98 @@ fn test_get_channel_count_of_unknwon_type() {
|
|||
}
|
||||
}
|
||||
|
||||
fn is_vpio(id: AudioObjectID) -> bool {
|
||||
debug_assert_running_serially();
|
||||
get_device_global_uid(id)
|
||||
.map(|uid| uid.into_string())
|
||||
.map(|uid| uid.contains(VOICEPROCESSING_AGGREGATE_DEVICE_NAME))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
fn get_nonvpio_input_channel_counts() -> Vec<u32> {
|
||||
debug_assert_running_serially();
|
||||
get_devices()
|
||||
.into_iter()
|
||||
.filter(|&id| !is_vpio(id))
|
||||
.filter_map(|id| get_channel_count(id, DeviceType::INPUT).ok())
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_get_channel_count_of_input_devices_with_vpio() {
|
||||
let non_vpio_channel_counts =
|
||||
run_serially_forward_panics(|| get_nonvpio_input_channel_counts());
|
||||
|
||||
let queue = Queue::new_with_target(
|
||||
"test_get_channel_count_of_input_devices_with_vpio",
|
||||
get_serial_queue_singleton(),
|
||||
);
|
||||
let mut shared = SharedVoiceProcessingUnitManager::new(queue.clone());
|
||||
let _vpio = queue.run_sync(|| shared.take_or_create()).unwrap().unwrap();
|
||||
|
||||
let vpio_channel_counts = run_serially_forward_panics(|| get_nonvpio_input_channel_counts());
|
||||
assert_eq!(non_vpio_channel_counts, vpio_channel_counts);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_get_channel_count_of_input_devices_with_aggregate_device_and_vpio() {
|
||||
let input_device = test_get_default_device(Scope::Input);
|
||||
let output_device = test_get_default_device(Scope::Output);
|
||||
if input_device.is_none() || output_device.is_none() || input_device == output_device {
|
||||
println!("No input or output device to create an aggregate device.");
|
||||
return;
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct State {
|
||||
aggr: Option<AggregateDevice>,
|
||||
vpio_mgr: Option<SharedVoiceProcessingUnitManager>,
|
||||
vpio: Option<OwningHandle<VoiceProcessingUnit>>,
|
||||
}
|
||||
impl Drop for State {
|
||||
fn drop(&mut self) {
|
||||
let mut aggr = self.aggr.take();
|
||||
let mut vpio = self.vpio.take();
|
||||
run_serially_forward_panics(move || {
|
||||
aggr.take();
|
||||
vpio.take();
|
||||
});
|
||||
}
|
||||
}
|
||||
let state = Arc::new(Mutex::new(State::default()));
|
||||
|
||||
// Set up an AggregateDevice with input and output.
|
||||
let initial_channel_counts = run_serially_forward_panics(|| get_nonvpio_input_channel_counts());
|
||||
let s1 = state.clone();
|
||||
let aggr_channel_counts = run_serially_forward_panics(|| {
|
||||
let mut state = s1.lock().unwrap();
|
||||
state.aggr =
|
||||
Some(AggregateDevice::new(input_device.unwrap(), output_device.unwrap()).unwrap());
|
||||
|
||||
get_nonvpio_input_channel_counts()
|
||||
});
|
||||
assert_eq!(initial_channel_counts.len() + 1, aggr_channel_counts.len());
|
||||
|
||||
let queue = Queue::new_with_target(
|
||||
"test_get_channel_count_of_input_devices_with_aggregate_device_and_vpio",
|
||||
get_serial_queue_singleton(),
|
||||
);
|
||||
{
|
||||
let mut s = state.lock().unwrap();
|
||||
s.vpio_mgr = Some(SharedVoiceProcessingUnitManager::new(queue.clone()));
|
||||
}
|
||||
let s2 = state.clone();
|
||||
let aggr_vpio_channel_counts = run_serially_forward_panics(|| {
|
||||
let mut state = s2.lock().unwrap();
|
||||
state.vpio = state.vpio_mgr.as_mut().map(|m| m.take_or_create().unwrap());
|
||||
|
||||
get_nonvpio_input_channel_counts()
|
||||
});
|
||||
assert_eq!(aggr_channel_counts, aggr_vpio_channel_counts);
|
||||
}
|
||||
|
||||
// get_range_of_sample_rates
|
||||
// ------------------------------------
|
||||
#[test]
|
||||
|
|
|
@ -413,20 +413,20 @@ fn test_get_ranges_of_device_sample_rate_by_unknown_device() {
|
|||
#[test]
|
||||
fn test_get_stream_latency() {
|
||||
if let Some(device) = test_get_default_device(Scope::Input) {
|
||||
let streams = run_serially(|| get_device_streams(device, DeviceType::INPUT)).unwrap();
|
||||
for stream in streams {
|
||||
let latency = run_serially(|| get_stream_latency(stream)).unwrap();
|
||||
println!("latency of the input stream {} is {}", stream, latency);
|
||||
let devstreams = run_serially(|| get_device_streams(device, DeviceType::INPUT)).unwrap();
|
||||
for ds in devstreams {
|
||||
let latency = run_serially(|| get_stream_latency(ds.stream)).unwrap();
|
||||
println!("latency of the input stream {} is {}", ds.stream, latency);
|
||||
}
|
||||
} else {
|
||||
println!("No input device.");
|
||||
}
|
||||
|
||||
if let Some(device) = test_get_default_device(Scope::Output) {
|
||||
let streams = run_serially(|| get_device_streams(device, DeviceType::OUTPUT)).unwrap();
|
||||
for stream in streams {
|
||||
let latency = run_serially(|| get_stream_latency(stream)).unwrap();
|
||||
println!("latency of the output stream {} is {}", stream, latency);
|
||||
let devstreams = run_serially(|| get_device_streams(device, DeviceType::OUTPUT)).unwrap();
|
||||
for ds in devstreams {
|
||||
let latency = run_serially(|| get_stream_latency(ds.stream)).unwrap();
|
||||
println!("latency of the output stream {} is {}", ds.stream, latency);
|
||||
}
|
||||
} else {
|
||||
println!("No output device.");
|
||||
|
@ -444,10 +444,10 @@ fn test_get_stream_latency_by_unknown_device() {
|
|||
#[test]
|
||||
fn test_get_stream_virtual_format() {
|
||||
if let Some(device) = test_get_default_device(Scope::Input) {
|
||||
let streams = run_serially(|| get_device_streams(device, DeviceType::INPUT)).unwrap();
|
||||
let formats = streams
|
||||
let devstreams = run_serially(|| get_device_streams(device, DeviceType::INPUT)).unwrap();
|
||||
let formats = devstreams
|
||||
.iter()
|
||||
.map(|s| run_serially(|| get_stream_virtual_format(*s)))
|
||||
.map(|ds| run_serially(|| get_stream_virtual_format(ds.stream)))
|
||||
.collect::<Vec<std::result::Result<AudioStreamBasicDescription, OSStatus>>>();
|
||||
println!("input stream formats: {:?}", formats);
|
||||
assert!(!formats.is_empty());
|
||||
|
@ -456,10 +456,10 @@ fn test_get_stream_virtual_format() {
|
|||
}
|
||||
|
||||
if let Some(device) = test_get_default_device(Scope::Output) {
|
||||
let streams = run_serially(|| get_device_streams(device, DeviceType::OUTPUT)).unwrap();
|
||||
let formats = streams
|
||||
let devstreams = run_serially(|| get_device_streams(device, DeviceType::OUTPUT)).unwrap();
|
||||
let formats = devstreams
|
||||
.iter()
|
||||
.map(|s| run_serially(|| get_stream_virtual_format(*s)))
|
||||
.map(|ds| run_serially(|| get_stream_virtual_format(ds.stream)))
|
||||
.collect::<Vec<std::result::Result<AudioStreamBasicDescription, OSStatus>>>();
|
||||
println!("output stream formats: {:?}", formats);
|
||||
assert!(!formats.is_empty());
|
||||
|
@ -476,52 +476,22 @@ fn test_get_stream_virtual_format_by_unknown_stream() {
|
|||
);
|
||||
}
|
||||
|
||||
// get_stream_terminal_type
|
||||
// get_devices
|
||||
// ------------------------------------
|
||||
|
||||
#[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
|
||||
}
|
||||
}
|
||||
}
|
||||
fn test_get_devices() {
|
||||
if let Some(device) = test_get_default_device(Scope::Input) {
|
||||
let streams = run_serially(|| get_device_streams(device, DeviceType::INPUT)).unwrap();
|
||||
assert!(streams.iter().any(|&s| {
|
||||
terminal_type_to_device_type(run_serially(|| get_stream_terminal_type(s)).unwrap())
|
||||
== Some(DeviceType::INPUT)
|
||||
}));
|
||||
let devices = run_serially(|| get_devices());
|
||||
assert!(devices.contains(&device));
|
||||
} else {
|
||||
println!("No input device.");
|
||||
}
|
||||
|
||||
if let Some(device) = test_get_default_device(Scope::Output) {
|
||||
let streams = run_serially(|| get_device_streams(device, DeviceType::OUTPUT)).unwrap();
|
||||
assert!(streams.iter().any(|&s| {
|
||||
terminal_type_to_device_type(run_serially(|| get_stream_terminal_type(s)).unwrap())
|
||||
== Some(DeviceType::OUTPUT)
|
||||
}));
|
||||
let devices = run_serially(|| get_devices());
|
||||
assert!(devices.contains(&device));
|
||||
} 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());
|
||||
}
|
||||
|
|
|
@ -293,6 +293,7 @@ fn test_enable_audiounit_in_scope(
|
|||
|
||||
pub enum DeviceFilter {
|
||||
ExcludeCubebAggregateAndVPIO,
|
||||
ExcludeVPIO,
|
||||
IncludeAll,
|
||||
}
|
||||
pub fn test_get_all_devices(filter: DeviceFilter) -> Vec<AudioObjectID> {
|
||||
|
@ -354,6 +355,16 @@ pub fn test_get_all_devices(filter: DeviceFilter) -> Vec<AudioObjectID> {
|
|||
}
|
||||
});
|
||||
}
|
||||
DeviceFilter::ExcludeVPIO => {
|
||||
devices.retain(|&device| {
|
||||
if let Ok(uid) = get_device_global_uid(device) {
|
||||
let uid = uid.into_string();
|
||||
!uid.contains(VOICEPROCESSING_AGGREGATE_DEVICE_NAME)
|
||||
} else {
|
||||
true
|
||||
}
|
||||
});
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 = "4cc24c7dc74a4801455ba0bbe20ea67a49f28514", optional = true }
|
||||
cubeb-coreaudio = { git = "https://github.com/mozilla/cubeb-coreaudio-rs", rev = "1796ace5bdd08ec8baa56bbf7170a08d760c984b", optional = true }
|
||||
cubeb-pulse = { git = "https://github.com/mozilla/cubeb-pulse-rs", rev="8678dcab1c287de79c4c184ccc2e065bc62b70e2", optional = true, features=["pulse-dlopen"] }
|
||||
cubeb-sys = { version = "0.13", optional = true, features=["gecko-in-tree"] }
|
||||
audioipc2-client = { git = "https://github.com/mozilla/audioipc", rev = "3495905752a4263827f5d43737f9ca3ed0243ce0", optional = true }
|
||||
|
|
Загрузка…
Ссылка в новой задаче