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:
Chun-Min Chang 2019-08-02 18:29:37 +00:00
Родитель f29bfc124d
Коммит 817f6f88f6
6 изменённых файлов: 118 добавлений и 63 удалений

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

@ -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;