Bug 1638801 - mach vendor rust r=cubeb-reviewers,achronop

Differential Revision: https://phabricator.services.mozilla.com/D75776
This commit is contained in:
Paul Adenot 2020-05-28 09:54:57 +00:00
Родитель 6294bd3454
Коммит 2c64853b8e
5 изменённых файлов: 83 добавлений и 145 удалений

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

@ -80,7 +80,7 @@ rev = "5e870faf6f95d79d11efc813e56370ad124bbed5"
[source."https://github.com/ChunMinChang/cubeb-coreaudio-rs"]
git = "https://github.com/ChunMinChang/cubeb-coreaudio-rs"
replace-with = "vendored-sources"
rev = "c5aacdc75618025e72f62f727a7a0d91606e6276"
rev = "23cce37c8565708023c869913c0f24c2fda860d8"
[source.crates-io]
replace-with = "vendored-sources"

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

@ -736,7 +736,7 @@ dependencies = [
[[package]]
name = "coreaudio-sys-utils"
version = "0.1.0"
source = "git+https://github.com/ChunMinChang/cubeb-coreaudio-rs?rev=c5aacdc75618025e72f62f727a7a0d91606e6276#c5aacdc75618025e72f62f727a7a0d91606e6276"
source = "git+https://github.com/ChunMinChang/cubeb-coreaudio-rs?rev=23cce37c8565708023c869913c0f24c2fda860d8#23cce37c8565708023c869913c0f24c2fda860d8"
dependencies = [
"core-foundation-sys",
"coreaudio-sys",
@ -974,7 +974,7 @@ dependencies = [
[[package]]
name = "cubeb-coreaudio"
version = "0.1.0"
source = "git+https://github.com/ChunMinChang/cubeb-coreaudio-rs?rev=c5aacdc75618025e72f62f727a7a0d91606e6276#c5aacdc75618025e72f62f727a7a0d91606e6276"
source = "git+https://github.com/ChunMinChang/cubeb-coreaudio-rs?rev=23cce37c8565708023c869913c0f24c2fda860d8#23cce37c8565708023c869913c0f24c2fda860d8"
dependencies = [
"atomic",
"audio-mixer",

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

@ -1 +1 @@
{"files":{".editorconfig":"4e53b182bcc78b83d7e1b5c03efa14d22d4955c4ed2514d1ba4e99c1eb1a50ba",".githooks/pre-push":"8b8b26544cd56f54c0c33812551f786bb25cb08c86dbfeb6bf3daad881c826a1",".travis.yml":"dc07bac53f70f16c9bdf52264bdc58500ae6018c1b4c567bc7642f6b4ca3cc35","Cargo.toml":"93449267612163fe621c75c6195fcf5f961c2bddd975468d67fc2121d538f1c7","LICENSE":"6e6f56aff5bbf3cbc60747e152fb1a719bd0716aaf6d711c554f57d92e96297c","README.md":"ab0f168080dfdfc1512484aeb4a41e1625f6b4147e534899fab56b2cb6d9f32a","install_git_hook.sh":"d38c8e51e636f6b90b489621ac34ccd1d1b1f40dccce3d178ed1da1c5068f16d","install_rustfmt_clippy.sh":"4ae90d8dcb9757cb3ae4ae142ef80e5377c0dde61c63f4a3c32418646e80ca7b","run_device_tests.sh":"4b7d65eb638c1a278ffc8ecb6d30d47b3b8405392e976cae38c6f744e2bed532","run_sanitizers.sh":"2f0934ba01cbcd74485f19d50147f6b604cf9730bbd3a3d3f3d958e40d0f799f","run_tests.sh":"3dd76659f6dceeb0490dd92b355e113301ba0d0a8f034993a56f40e09edd25b2","src/backend/aggregate_device.rs":"ae21129aa6b3c7bd3376751b6a94d1ebe6c9f7afcd1db3107fb4d703d04da6b3","src/backend/auto_release.rs":"050fdcee74cf46b9a8a85a877e166d72a853d33220f59cf734cbb6ea09daa441","src/backend/buffer_manager.rs":"9c10a261792e32e75833b5f976b18547c338ca6beb2330eeab1ad203cc8c32bf","src/backend/device_property.rs":"d43642ea6e5f40e29c2a59ec7d81b42c154134685e417585045785359aa31686","src/backend/mixer.rs":"14e2156a8c1aeabcd4adb3336c3c9401b9c8526ec82a8c78942af7a79648f0f8","src/backend/mod.rs":"4c2967b7f581cebce875ea342658d32650695ebd57a026bd36e92ef3807866ae","src/backend/resampler.rs":"fd1281d28a4db1659d2f75e43b8457651745e1b6eb5a53a77f04d752135f6dc7","src/backend/tests/aggregate_device.rs":"107f5c637844cd5ae43d2b42cec4ef3369bb702751586078c0a9d50f039161cd","src/backend/tests/api.rs":"9ce44a867519d7b7a2b43c7f833327c35be38af7ba6fcc3d277ed1d7d8e7c8c2","src/backend/tests/backlog.rs":"3b189a7e036543c467cc242af0ed3332721179ee2b1c8847a6db563546f1ac52","src/backend/tests/device_change.rs":"8261f561f69dabd374ac47d69aa484812b65070a9e9581dfb2605e8404eaad6d","src/backend/tests/device_property.rs":"373f76d3bee83b263db3f02be3b94b408bdf852d84e4b5153273fda34b11a374","src/backend/tests/interfaces.rs":"14943e84a79976a7ef52882edeb9330350705d5190db6647f98b4ffa851a8396","src/backend/tests/manual.rs":"dc707836dab31f83d4b325afbc4dc4c8104ac8036e87f59ade3309ee83fe2d3f","src/backend/tests/mod.rs":"8dba770023d7f9c4228f0e11915347f0e07da5fd818e3ee4478c4b197af9aa2a","src/backend/tests/parallel.rs":"f9e1883660d6146b6e5075806561f5f689810e25c5e7764dfd28c9b939821a49","src/backend/tests/tone.rs":"16150438317ce501986734167b5fb97bfec567228acbcd8f3b4c4484c22f29e0","src/backend/tests/utils.rs":"1bb99ef71d3c18545bca49767e7b6bfffbe11896246994f41be7ed372772fd48","src/backend/utils.rs":"5ce1b753af0ffb654b6b2038d649aea88eebd27390a607a6d5988a9e40a4a717","src/capi.rs":"21b66b70545bf04ec719928004d1d9adb45b24ced51288f5b2993d79aaf78f5f","src/lib.rs":"5e586d45cd6b3722f0a6736d9252593299269817a153eef1930a5fb9bfbb56f5","todo.md":"7323051fa7f0c51eb2eb0d495dcd951502e4cc8ce0088e6e7b3b3a95180f43d4"},"package":null}
{"files":{".editorconfig":"4e53b182bcc78b83d7e1b5c03efa14d22d4955c4ed2514d1ba4e99c1eb1a50ba",".githooks/pre-push":"8b8b26544cd56f54c0c33812551f786bb25cb08c86dbfeb6bf3daad881c826a1",".travis.yml":"dc07bac53f70f16c9bdf52264bdc58500ae6018c1b4c567bc7642f6b4ca3cc35","Cargo.toml":"93449267612163fe621c75c6195fcf5f961c2bddd975468d67fc2121d538f1c7","LICENSE":"6e6f56aff5bbf3cbc60747e152fb1a719bd0716aaf6d711c554f57d92e96297c","README.md":"ab0f168080dfdfc1512484aeb4a41e1625f6b4147e534899fab56b2cb6d9f32a","install_git_hook.sh":"d38c8e51e636f6b90b489621ac34ccd1d1b1f40dccce3d178ed1da1c5068f16d","install_rustfmt_clippy.sh":"4ae90d8dcb9757cb3ae4ae142ef80e5377c0dde61c63f4a3c32418646e80ca7b","run_device_tests.sh":"4b7d65eb638c1a278ffc8ecb6d30d47b3b8405392e976cae38c6f744e2bed532","run_sanitizers.sh":"2f0934ba01cbcd74485f19d50147f6b604cf9730bbd3a3d3f3d958e40d0f799f","run_tests.sh":"3dd76659f6dceeb0490dd92b355e113301ba0d0a8f034993a56f40e09edd25b2","src/backend/aggregate_device.rs":"ae21129aa6b3c7bd3376751b6a94d1ebe6c9f7afcd1db3107fb4d703d04da6b3","src/backend/auto_release.rs":"050fdcee74cf46b9a8a85a877e166d72a853d33220f59cf734cbb6ea09daa441","src/backend/buffer_manager.rs":"9c10a261792e32e75833b5f976b18547c338ca6beb2330eeab1ad203cc8c32bf","src/backend/device_property.rs":"d43642ea6e5f40e29c2a59ec7d81b42c154134685e417585045785359aa31686","src/backend/mixer.rs":"14e2156a8c1aeabcd4adb3336c3c9401b9c8526ec82a8c78942af7a79648f0f8","src/backend/mod.rs":"5942040678e90c8cbcb46836b0c618facebe52c3d57218a73ef50ca589752913","src/backend/resampler.rs":"fd1281d28a4db1659d2f75e43b8457651745e1b6eb5a53a77f04d752135f6dc7","src/backend/tests/aggregate_device.rs":"107f5c637844cd5ae43d2b42cec4ef3369bb702751586078c0a9d50f039161cd","src/backend/tests/api.rs":"9ce44a867519d7b7a2b43c7f833327c35be38af7ba6fcc3d277ed1d7d8e7c8c2","src/backend/tests/backlog.rs":"3b189a7e036543c467cc242af0ed3332721179ee2b1c8847a6db563546f1ac52","src/backend/tests/device_change.rs":"8261f561f69dabd374ac47d69aa484812b65070a9e9581dfb2605e8404eaad6d","src/backend/tests/device_property.rs":"373f76d3bee83b263db3f02be3b94b408bdf852d84e4b5153273fda34b11a374","src/backend/tests/interfaces.rs":"14943e84a79976a7ef52882edeb9330350705d5190db6647f98b4ffa851a8396","src/backend/tests/manual.rs":"87210af9527feece99ad2b7b85651fbc8f02ec306ba8082da0c0705070e882af","src/backend/tests/mod.rs":"8dba770023d7f9c4228f0e11915347f0e07da5fd818e3ee4478c4b197af9aa2a","src/backend/tests/parallel.rs":"f9e1883660d6146b6e5075806561f5f689810e25c5e7764dfd28c9b939821a49","src/backend/tests/tone.rs":"16150438317ce501986734167b5fb97bfec567228acbcd8f3b4c4484c22f29e0","src/backend/tests/utils.rs":"1bb99ef71d3c18545bca49767e7b6bfffbe11896246994f41be7ed372772fd48","src/backend/utils.rs":"5ce1b753af0ffb654b6b2038d649aea88eebd27390a607a6d5988a9e40a4a717","src/capi.rs":"21b66b70545bf04ec719928004d1d9adb45b24ced51288f5b2993d79aaf78f5f","src/lib.rs":"5e586d45cd6b3722f0a6736d9252593299269817a153eef1930a5fb9bfbb56f5","todo.md":"7323051fa7f0c51eb2eb0d495dcd951502e4cc8ce0088e6e7b3b3a95180f43d4"},"package":null}

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

@ -344,9 +344,11 @@ extern "C" fn audiounit_input_callback(
assert!(!user_ptr.is_null());
let stm = unsafe { &mut *(user_ptr as *mut AudioUnitStream) };
let input_latency_frames = compute_input_latency(&stm, unsafe { (*tstamp).mHostTime });
stm.total_input_latency_frames
.store(input_latency_frames, Ordering::SeqCst);
if unsafe { *flags | kAudioTimeStampHostTimeValid } != 0 {
let input_latency_frames = compute_input_latency(&stm, unsafe { (*tstamp).mHostTime });
stm.total_input_latency_frames
.store(input_latency_frames, Ordering::SeqCst);
}
if stm.shutdown.load(Ordering::SeqCst) {
cubeb_log!("({:p}) input shutdown", stm as *const AudioUnitStream);
@ -492,42 +494,46 @@ fn host_time_to_ns(host_time: u64) -> u64 {
}
fn compute_output_latency(stm: &AudioUnitStream, host_time: u64) -> u32 {
const NS2S: u64 = 1_000_000_000;
let now = host_time_to_ns(unsafe { mach_absolute_time() });
let audio_output_time = host_time_to_ns(host_time);
let output_latency_ns = if audio_output_time < now {
let output_hw_rate = stm.core_stream_data.output_hw_rate as u64;
let fixed_latency_ns =
(stm.current_output_latency_frames.load(Ordering::SeqCst) as u64 * NS2S) / output_hw_rate;
let total_output_latency_ns = if audio_output_time < now {
0
} else {
audio_output_time - now
// The total output latency is the timestamp difference + the stream latency + the hardware
// latency.
(audio_output_time - now) + fixed_latency_ns
};
const NS2S: u64 = 1_000_000_000;
// The total output latency is the timestamp difference + the stream latency +
// the hardware latency.
let out_hw_rate = stm.core_stream_data.output_hw_rate as u64;
(output_latency_ns * out_hw_rate / NS2S
+ stm.current_output_latency_frames.load(Ordering::SeqCst) as u64) as u32
((total_output_latency_ns * output_hw_rate) / NS2S) as u32
}
fn compute_input_latency(stm: &AudioUnitStream, host_time: u64) -> u32 {
const NS2S: u64 = 1_000_000_000;
let now = host_time_to_ns(unsafe { mach_absolute_time() });
let audio_input_time = host_time_to_ns(host_time);
let input_latency_ns = if audio_input_time > now {
let input_hw_rate = stm.core_stream_data.input_hw_rate as u64;
let fixed_latency_ns =
(stm.current_input_latency_frames.load(Ordering::SeqCst) as u64 * NS2S) / input_hw_rate;
let total_input_latency_ns = if audio_input_time > now {
0
} else {
now - audio_input_time
// The total input latency is the timestamp difference + the stream latency +
// the hardware latency.
(now - audio_input_time) + fixed_latency_ns
};
const NS2S: u64 = 1_000_000_000;
// The total input latency is the timestamp difference + the stream latency +
// the hardware latency.
let input_hw_rate = stm.core_stream_data.input_hw_rate as u64;
(input_latency_ns * input_hw_rate / NS2S
+ stm.current_input_latency_frames.load(Ordering::SeqCst) as u64) as u32
((total_input_latency_ns * input_hw_rate) / NS2S) as u32
}
extern "C" fn audiounit_output_callback(
user_ptr: *mut c_void,
_: *mut AudioUnitRenderActionFlags,
flags: *mut AudioUnitRenderActionFlags,
tstamp: *const AudioTimeStamp,
bus: u32,
output_frames: u32,
@ -547,10 +553,11 @@ extern "C" fn audiounit_output_callback(
slice::from_raw_parts_mut(ptr, len)
};
let output_latency_frames = compute_output_latency(&stm, unsafe { (*tstamp).mHostTime });
stm.total_output_latency_frames
.store(output_latency_frames, Ordering::SeqCst);
if unsafe { *flags | kAudioTimeStampHostTimeValid } != 0 {
let output_latency_frames = compute_output_latency(&stm, unsafe { (*tstamp).mHostTime });
stm.total_output_latency_frames
.store(output_latency_frames, Ordering::SeqCst);
}
cubeb_logv!(
"({:p}) output: buffers {}, size {}, channels {}, frames {}.",
@ -624,7 +631,7 @@ extern "C" fn audiounit_output_callback(
cubeb_log!("Dropping {} frames in input buffer.", popped_samples);
}
if input_frames_needed > buffered_input_frames
let input_frames = if input_frames_needed > buffered_input_frames
&& (stm.switching_device.load(Ordering::SeqCst)
|| stm.frames_read.load(Ordering::SeqCst) == 0)
{
@ -643,12 +650,15 @@ extern "C" fn audiounit_output_callback(
},
silent_frames_to_push
);
}
input_frames_needed
} else {
buffered_input_frames
};
let input_samples_needed = buffered_input_frames * input_channels;
let input_samples_needed = input_frames * input_channels;
(
input_buffer_manager.get_linear_data(input_samples_needed),
buffered_input_frames as i64,
input_frames as i64,
)
} else {
(ptr::null_mut::<c_void>(), 0)
@ -2235,7 +2245,7 @@ impl ContextOps for AudioUnitContext {
let cubeb_stream = unsafe { Stream::from_ptr(Box::into_raw(boxed_stream) as *mut _) };
cubeb_log!(
"({:p}) Cubeb stream init successful.",
&cubeb_stream as *const Stream
cubeb_stream.as_ref()
);
Ok(cubeb_stream)
}
@ -3461,12 +3471,15 @@ impl<'ctx> StreamOps for AudioUnitStream<'ctx> {
let current_output_latency_frames =
u64::from(self.current_output_latency_frames.load(Ordering::SeqCst));
let frames_played = self.frames_played.load(Ordering::SeqCst);
let position = if current_output_latency_frames > frames_played {
0
} else {
frames_played - current_output_latency_frames
};
Ok(position)
if current_output_latency_frames != 0 {
let position = if current_output_latency_frames > frames_played {
0
} else {
frames_played - current_output_latency_frames
};
return Ok(position);
}
Err(Error::error())
}
#[cfg(target_os = "ios")]
fn latency(&mut self) -> Result<u32> {
@ -3485,10 +3498,14 @@ impl<'ctx> StreamOps for AudioUnitStream<'ctx> {
let user_rate = self.core_stream_data.input_stream_params.rate();
let hw_rate = self.core_stream_data.input_hw_rate as u32;
let frames = self.total_input_latency_frames.load(Ordering::SeqCst);
if hw_rate == user_rate {
Ok(frames)
if frames != 0 {
if hw_rate == user_rate {
Ok(frames)
} else {
Ok(frames * (user_rate / hw_rate))
}
} else {
Ok(frames * (user_rate / hw_rate))
Err(Error::error())
}
}
fn set_volume(&mut self, volume: f32) -> Result<()> {

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

@ -1,6 +1,6 @@
use super::utils::{
test_get_default_device, test_get_default_raw_stream, test_get_devices_in_scope,
test_ops_context_operation, test_ops_stream_operation, Scope, StreamType, TestDeviceSwitcher,
test_get_devices_in_scope, test_ops_context_operation, test_ops_stream_operation, Scope,
StreamType, TestDeviceSwitcher,
};
use super::*;
use std::io;
@ -112,106 +112,6 @@ fn test_switch_output_device() {
}
}
#[ignore]
#[test]
fn test_add_then_remove_listeners() {
extern "C" fn callback(
id: AudioObjectID,
number_of_addresses: u32,
addresses: *const AudioObjectPropertyAddress,
data: *mut c_void,
) -> OSStatus {
println!("device: {}, data @ {:p}", id, data);
let addrs = unsafe { std::slice::from_raw_parts(addresses, number_of_addresses as usize) };
for (i, addr) in addrs.iter().enumerate() {
let property_selector = PropertySelector::new(addr.mSelector);
println!(
"address {}\n\tselector {}({})\n\tscope {}\n\telement {}",
i, addr.mSelector, property_selector, addr.mScope, addr.mElement
);
}
NO_ERR
}
test_get_default_raw_stream(|stream| {
let mut listeners = Vec::new();
let default_output_listener = device_property_listener::new(
kAudioObjectSystemObject,
get_property_address(
Property::HardwareDefaultOutputDevice,
DeviceType::INPUT | DeviceType::OUTPUT,
),
callback,
);
listeners.push(default_output_listener);
let default_input_listener = device_property_listener::new(
kAudioObjectSystemObject,
get_property_address(
Property::HardwareDefaultInputDevice,
DeviceType::INPUT | DeviceType::OUTPUT,
),
callback,
);
listeners.push(default_input_listener);
if let Some(device) = test_get_default_device(Scope::Output) {
let output_source_listener = device_property_listener::new(
device,
get_property_address(Property::DeviceSource, DeviceType::OUTPUT),
callback,
);
listeners.push(output_source_listener);
}
if let Some(device) = test_get_default_device(Scope::Input) {
let input_source_listener = device_property_listener::new(
device,
get_property_address(Property::DeviceSource, DeviceType::INPUT),
callback,
);
listeners.push(input_source_listener);
let input_alive_listener = device_property_listener::new(
device,
get_property_address(
Property::DeviceIsAlive,
DeviceType::INPUT | DeviceType::OUTPUT,
),
callback,
);
listeners.push(input_alive_listener);
}
if listeners.is_empty() {
println!("No listeners to test.");
return;
}
add_listeners(stream, &listeners);
println!("Unplug/Plug device or switch input/output device to see the event log.\nEnter anything to finish.");
let mut input = String::new();
let _ = std::io::stdin().read_line(&mut input);
remove_listeners(stream, &listeners);
});
fn add_listeners(stream: &AudioUnitStream, listeners: &Vec<device_property_listener>) {
for listener in listeners {
assert_eq!(stream.add_device_listener(listener), NO_ERR);
}
}
fn remove_listeners(stream: &AudioUnitStream, listeners: &Vec<device_property_listener>) {
for listener in listeners {
assert_eq!(stream.remove_device_listener(listener), NO_ERR);
}
}
}
#[ignore]
#[test]
fn test_device_collection_change() {
@ -264,7 +164,8 @@ fn test_stream_tester() {
\t'c': create a stream\n\
\t'd': destroy a stream\n\
\t's': start the created stream\n\
\t't': stop the created stream"
\t't': stop the created stream\n\
\t'r': register a device changed callback"
);
let mut command = String::new();
@ -281,6 +182,7 @@ fn test_stream_tester() {
"d" => destroy_stream(&mut stream_ptr),
"s" => start_stream(stream_ptr),
"t" => stop_stream(stream_ptr),
"r" => register_device_change_callback(stream_ptr),
x => println!("Unknown command: {}", x),
}
}
@ -310,6 +212,25 @@ fn test_stream_tester() {
println!("Stream {:p} stopped.", stream_ptr);
}
fn register_device_change_callback(stream_ptr: *mut ffi::cubeb_stream) {
extern "C" fn callback(user_ptr: *mut c_void) {
println!("user pointer @ {:p}", user_ptr);
assert!(user_ptr.is_null());
}
if stream_ptr.is_null() {
println!("No stream for registering the callback.");
return;
}
assert_eq!(
unsafe {
OPS.stream_register_device_changed_callback.unwrap()(stream_ptr, Some(callback))
},
ffi::CUBEB_OK
);
println!("Stream {:p} now has a device change callback.", stream_ptr);
}
fn destroy_stream(stream_ptr: &mut *mut ffi::cubeb_stream) {
if stream_ptr.is_null() {
println!("No need to destroy stream.");