зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1570446 - P2: Update cubeb-coreaudio-rs to version ee0f981. r=padenot
Differential Revision: https://phabricator.services.mozilla.com/D39979 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
f29bfc124d
Коммит
817f6f88f6
|
@ -16,3 +16,5 @@ coreaudio-sys-utils = { path = "coreaudio-sys-utils" }
|
|||
# the minimal version of cubeb-backend is 0.5.1.
|
||||
cubeb-backend = "0.5.3"
|
||||
libc = "0.2"
|
||||
lazy_static = "1.2"
|
||||
mach = "0.3"
|
||||
|
|
|
@ -3,4 +3,4 @@ git repository using the update.sh script.
|
|||
|
||||
The cubeb-coreaudio-rs git repository is: https://github.com/ChunMinChang/cubeb-coreaudio-rs
|
||||
|
||||
The git commit ID used was c5b109e0c51bcd24fddd069bcf994aa0005a6497 (2019-06-25 11:37:14 -0700)
|
||||
The git commit ID used was ee0f9814230f4a236516444eff9406857ab6c70d (2019-08-01 10:57:48 -0700)
|
||||
|
|
|
@ -161,5 +161,7 @@ pub fn audio_unit_remove_property_listener_with_user_data<T>(
|
|||
data: *mut T,
|
||||
) -> OSStatus {
|
||||
assert!(!unit.is_null());
|
||||
unsafe { AudioUnitRemovePropertyListenerWithUserData(unit, id, Some(listener), data as *mut c_void) }
|
||||
unsafe {
|
||||
AudioUnitRemovePropertyListenerWithUserData(unit, id, Some(listener), data as *mut c_void)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -341,8 +341,8 @@ impl AggregateDevice {
|
|||
assert_ne!(output_id, kAudioObjectUnknown);
|
||||
assert_ne!(input_id, output_id);
|
||||
|
||||
let output_sub_devices = audiounit_get_sub_devices(output_id);
|
||||
let input_sub_devices = audiounit_get_sub_devices(input_id);
|
||||
let output_sub_devices = Self::get_sub_devices(output_id)?;
|
||||
let input_sub_devices = Self::get_sub_devices(input_id)?;
|
||||
|
||||
unsafe {
|
||||
let sub_devices = CFArrayCreateMutable(ptr::null(), 0, &kCFTypeArrayCallBacks);
|
||||
|
@ -379,6 +379,46 @@ impl AggregateDevice {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_sub_devices(
|
||||
device_id: AudioDeviceID,
|
||||
) -> std::result::Result<Vec<AudioObjectID>, OSStatus> {
|
||||
assert_ne!(device_id, kAudioObjectUnknown);
|
||||
|
||||
let mut sub_devices = Vec::new();
|
||||
let address = AudioObjectPropertyAddress {
|
||||
mSelector: kAudioAggregateDevicePropertyActiveSubDeviceList,
|
||||
mScope: kAudioObjectPropertyScopeGlobal,
|
||||
mElement: kAudioObjectPropertyElementMaster,
|
||||
};
|
||||
let mut size: usize = 0;
|
||||
let rv = audio_object_get_property_data_size(device_id, &address, &mut size);
|
||||
|
||||
if rv == 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 rv != NO_ERR {
|
||||
return Err(rv);
|
||||
}
|
||||
|
||||
assert_ne!(size, 0);
|
||||
|
||||
let count = size / mem::size_of::<AudioObjectID>();
|
||||
sub_devices = allocate_array(count);
|
||||
let rv = audio_object_get_property_data(
|
||||
device_id,
|
||||
&address,
|
||||
&mut size,
|
||||
sub_devices.as_mut_ptr(),
|
||||
);
|
||||
|
||||
if rv == NO_ERR {
|
||||
Ok(sub_devices)
|
||||
} else {
|
||||
Err(rv)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_master_device(device_id: AudioDeviceID) -> std::result::Result<(), OSStatus> {
|
||||
assert_ne!(device_id, kAudioObjectUnknown);
|
||||
let address = AudioObjectPropertyAddress {
|
||||
|
@ -390,7 +430,7 @@ impl AggregateDevice {
|
|||
// Master become the 1st output sub device
|
||||
let output_device_id = audiounit_get_default_device_id(DeviceType::OUTPUT);
|
||||
assert_ne!(output_device_id, kAudioObjectUnknown);
|
||||
let output_sub_devices = audiounit_get_sub_devices(output_device_id);
|
||||
let output_sub_devices = Self::get_sub_devices(output_device_id)?;
|
||||
assert!(!output_sub_devices.is_empty());
|
||||
let master_sub_device = get_device_name(output_sub_devices[0]);
|
||||
let size = mem::size_of::<CFStringRef>();
|
||||
|
|
|
@ -36,6 +36,7 @@ use cubeb_backend::{
|
|||
Error, Ops, Result, SampleFormat, State, Stream, StreamOps, StreamParams, StreamParamsRef,
|
||||
StreamPrefs,
|
||||
};
|
||||
use mach::mach_time::{mach_absolute_time, mach_timebase_info};
|
||||
use std::cmp;
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::fmt;
|
||||
|
@ -57,7 +58,7 @@ const PRIVATE_AGGREGATE_DEVICE_NAME: &str = "CubebAggregateDevice";
|
|||
|
||||
// Testing empirically, some headsets report a minimal latency that is very low,
|
||||
// but this does not work in practice. Lie and say the minimum is 256 frames.
|
||||
const SAFE_MIN_LATENCY_FRAMES: u32 = 256;
|
||||
const SAFE_MIN_LATENCY_FRAMES: u32 = 128;
|
||||
const SAFE_MAX_LATENCY_FRAMES: u32 = 512;
|
||||
|
||||
bitflags! {
|
||||
|
@ -71,6 +72,16 @@ bitflags! {
|
|||
}
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref HOST_TIME_TO_NS_RATIO: (u32, u32) = {
|
||||
let mut timebase_info = mach_timebase_info { numer: 0, denom: 0 };
|
||||
unsafe {
|
||||
mach_timebase_info(&mut timebase_info);
|
||||
}
|
||||
(timebase_info.numer, timebase_info.denom)
|
||||
};
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
enum io_side {
|
||||
|
@ -573,10 +584,30 @@ extern "C" fn audiounit_input_callback(
|
|||
status
|
||||
}
|
||||
|
||||
fn host_time_to_ns(host_time: u64) -> u64 {
|
||||
let mut rv: f64 = host_time as f64;
|
||||
rv *= HOST_TIME_TO_NS_RATIO.0 as f64;
|
||||
rv /= HOST_TIME_TO_NS_RATIO.1 as f64;
|
||||
return rv as u64;
|
||||
}
|
||||
|
||||
fn compute_output_latency(stm: &AudioUnitStream, host_time: u64) -> u32 {
|
||||
let now = host_time_to_ns(unsafe { mach_absolute_time() });
|
||||
let audio_output_time = host_time_to_ns(host_time);
|
||||
let output_latency_ns = (audio_output_time - now) as u64;
|
||||
|
||||
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_latency_frames.load(Ordering::SeqCst) as u64) as u32
|
||||
}
|
||||
|
||||
extern "C" fn audiounit_output_callback(
|
||||
user_ptr: *mut c_void,
|
||||
_: *mut AudioUnitRenderActionFlags,
|
||||
_tstamp: *const AudioTimeStamp,
|
||||
tstamp: *const AudioTimeStamp,
|
||||
bus: u32,
|
||||
output_frames: u32,
|
||||
out_buffer_list: *mut AudioBufferList,
|
||||
|
@ -595,6 +626,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);
|
||||
|
||||
cubeb_logv!(
|
||||
"({:p}) output: buffers {}, size {}, channels {}, frames {}.",
|
||||
stm as *const AudioUnitStream,
|
||||
|
@ -638,15 +674,6 @@ extern "C" fn audiounit_output_callback(
|
|||
// Also get the input buffer if the stream is duplex
|
||||
let (input_buffer, mut input_frames) = if !stm.core_stream_data.input_unit.is_null() {
|
||||
assert!(stm.core_stream_data.input_linear_buffer.is_some());
|
||||
let input_frames = stm
|
||||
.core_stream_data
|
||||
.input_linear_buffer
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.elements()
|
||||
/ stm.core_stream_data.input_desc.mChannelsPerFrame as usize;
|
||||
cubeb_logv!("Total input frames: {}", input_frames);
|
||||
|
||||
assert_ne!(stm.core_stream_data.input_desc.mChannelsPerFrame, 0);
|
||||
// If the output callback came first and this is a duplex stream, we need to
|
||||
// fill in some additional silence in the resampler.
|
||||
|
@ -683,6 +710,14 @@ extern "C" fn audiounit_output_callback(
|
|||
missing_frames
|
||||
);
|
||||
}
|
||||
let input_frames = stm
|
||||
.core_stream_data
|
||||
.input_linear_buffer
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.elements()
|
||||
/ stm.core_stream_data.input_desc.mChannelsPerFrame as usize;
|
||||
cubeb_logv!("Total input frames: {}", input_frames);
|
||||
(
|
||||
stm.core_stream_data
|
||||
.input_linear_buffer
|
||||
|
@ -1133,43 +1168,6 @@ fn audiounit_set_channel_layout(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn audiounit_get_sub_devices(device_id: AudioDeviceID) -> Vec<AudioObjectID> {
|
||||
assert_ne!(device_id, kAudioObjectUnknown);
|
||||
|
||||
let mut sub_devices = Vec::new();
|
||||
let property_address = AudioObjectPropertyAddress {
|
||||
mSelector: kAudioAggregateDevicePropertyActiveSubDeviceList,
|
||||
mScope: kAudioObjectPropertyScopeGlobal,
|
||||
mElement: kAudioObjectPropertyElementMaster,
|
||||
};
|
||||
let mut size: usize = 0;
|
||||
let rv = audio_object_get_property_data_size(device_id, &property_address, &mut size);
|
||||
|
||||
if rv != NO_ERR {
|
||||
sub_devices.push(device_id);
|
||||
return sub_devices;
|
||||
}
|
||||
|
||||
assert_ne!(size, 0);
|
||||
|
||||
let count = size / mem::size_of::<AudioObjectID>();
|
||||
sub_devices = allocate_array(count);
|
||||
let rv = audio_object_get_property_data(
|
||||
device_id,
|
||||
&property_address,
|
||||
&mut size,
|
||||
sub_devices.as_mut_ptr(),
|
||||
);
|
||||
|
||||
if rv != NO_ERR {
|
||||
sub_devices.clear();
|
||||
sub_devices.push(device_id);
|
||||
} else {
|
||||
cubeb_log!("Found {} sub-devices", count);
|
||||
}
|
||||
sub_devices
|
||||
}
|
||||
|
||||
fn get_device_name(id: AudioDeviceID) -> CFStringRef {
|
||||
let mut size = mem::size_of::<CFStringRef>();
|
||||
let mut uiname: CFStringRef = ptr::null();
|
||||
|
@ -2854,7 +2852,11 @@ impl<'ctx> CoreStreamData<'ctx> {
|
|||
|
||||
stream.frames_read.store(0, Ordering::SeqCst);
|
||||
|
||||
cubeb_log!("({:p}) Input audiounit init successfully.", self.stm_ptr);
|
||||
cubeb_log!(
|
||||
"({:p}) Input audiounit init with device {} successfully.",
|
||||
self.stm_ptr,
|
||||
in_dev_info.id
|
||||
);
|
||||
}
|
||||
|
||||
if self.has_output() {
|
||||
|
@ -3005,7 +3007,11 @@ impl<'ctx> CoreStreamData<'ctx> {
|
|||
|
||||
stream.frames_written.store(0, Ordering::SeqCst);
|
||||
|
||||
cubeb_log!("({:p}) Output audiounit init successfully.", self.stm_ptr);
|
||||
cubeb_log!(
|
||||
"({:p}) Output audiounit init with device {} successfully.",
|
||||
self.stm_ptr,
|
||||
out_dev_info.id
|
||||
);
|
||||
}
|
||||
|
||||
// We use a resampler because input AudioUnit operates
|
||||
|
@ -3341,6 +3347,7 @@ struct AudioUnitStream<'ctx> {
|
|||
// Latency requested by the user.
|
||||
latency_frames: u32,
|
||||
current_latency_frames: AtomicU32,
|
||||
total_output_latency_frames: AtomicU32,
|
||||
panning: atomic::Atomic<f32>,
|
||||
// This is true if a device change callback is currently running.
|
||||
switching_device: AtomicBool,
|
||||
|
@ -3371,6 +3378,7 @@ impl<'ctx> AudioUnitStream<'ctx> {
|
|||
destroy_pending: AtomicBool::new(false),
|
||||
latency_frames,
|
||||
current_latency_frames: AtomicU32::new(0),
|
||||
total_output_latency_frames: AtomicU32::new(0),
|
||||
panning: atomic::Atomic::new(0.0_f32),
|
||||
switching_device: AtomicBool::new(false),
|
||||
core_stream_data: CoreStreamData::default(),
|
||||
|
@ -3428,6 +3436,13 @@ impl<'ctx> AudioUnitStream<'ctx> {
|
|||
get_volume(self.core_stream_data.output_unit)
|
||||
};
|
||||
|
||||
let has_input = !self.core_stream_data.input_unit.is_null();
|
||||
let input_device = if has_input {
|
||||
self.core_stream_data.input_device.id
|
||||
} else {
|
||||
kAudioObjectUnknown
|
||||
};
|
||||
|
||||
self.core_stream_data.close();
|
||||
|
||||
// Reinit occurs in one of the following case:
|
||||
|
@ -3436,13 +3451,6 @@ impl<'ctx> AudioUnitStream<'ctx> {
|
|||
// - The bluetooth device changed from A2DP to/from HFP/HSP profile
|
||||
// We first attempt to re-use the same device id, should that fail we will
|
||||
// default to the (potentially new) default device.
|
||||
let has_input = !self.core_stream_data.input_unit.is_null();
|
||||
let input_device = if has_input {
|
||||
self.core_stream_data.input_device.id
|
||||
} else {
|
||||
kAudioObjectUnknown
|
||||
};
|
||||
|
||||
if has_input {
|
||||
self.core_stream_data.input_device = create_device_info(input_device, DeviceType::INPUT).map_err(|e| {
|
||||
cubeb_log!(
|
||||
|
@ -3637,7 +3645,7 @@ impl<'ctx> StreamOps for AudioUnitStream<'ctx> {
|
|||
}
|
||||
#[cfg(not(target_os = "ios"))]
|
||||
fn latency(&mut self) -> Result<u32> {
|
||||
Ok(self.current_latency_frames.load(Ordering::SeqCst))
|
||||
Ok(self.total_output_latency_frames.load(Ordering::SeqCst))
|
||||
}
|
||||
fn set_volume(&mut self, volume: f32) -> Result<()> {
|
||||
set_volume(self.core_stream_data.output_unit, volume)
|
||||
|
|
|
@ -8,6 +8,9 @@ extern crate atomic;
|
|||
extern crate bitflags;
|
||||
#[macro_use]
|
||||
extern crate cubeb_backend;
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
extern crate mach;
|
||||
|
||||
mod backend;
|
||||
mod capi;
|
||||
|
|
Загрузка…
Ссылка в новой задаче