Make workaround_for_airpod become a member functions

This commit is contained in:
Chun-Min Chang 2019-04-23 14:14:50 -07:00
Родитель fde2106645
Коммит b5ab6f1dd5
1 изменённых файлов: 85 добавлений и 77 удалений

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

@ -1507,82 +1507,6 @@ fn audiounit_activate_clock_drift_compensation(aggregate_device_id: AudioDeviceI
Ok(())
}
// TODO: If this is only called when airpod is part of the aggregate device,
// should we add a check for this ?
fn audiounit_workaround_for_airpod(stm: &AudioUnitStream)
{
let mut input_device_info = ffi::cubeb_device_info::default();
// TODO: Check input_device.id ? Check if the call is successful ?
assert_ne!(stm.input_device.id, kAudioObjectUnknown);
audiounit_create_device_from_hwdev(&mut input_device_info, stm.input_device.id, DeviceType::INPUT);
let mut output_device_info = ffi::cubeb_device_info::default();
assert_ne!(stm.output_device.id, kAudioObjectUnknown);
audiounit_create_device_from_hwdev(&mut output_device_info, stm.output_device.id, DeviceType::OUTPUT);
// TODO: Check input_device_info.friendly_name and
// output_device_info.friendly_name ?
// NOTE: Retake the leaked friendly_name strings.
// It's better to extract the part of getting name of the data source
// into a function, so we don't need to call
// `audiounit_create_device_from_hwdev` to get this info.
let input_name_str = unsafe {
CString::from_raw(input_device_info.friendly_name as *mut c_char)
.into_string()
.expect("Fail to convert input name from CString into String")
};
input_device_info.friendly_name = ptr::null();
let output_name_str = unsafe {
CString::from_raw(output_device_info.friendly_name as *mut c_char)
.into_string()
.expect("Fail to convert output name from CString into String")
};
output_device_info.friendly_name = ptr::null();
if input_name_str.contains("AirPods") &&
output_name_str.contains("AirPods") {
let mut input_min_rate = 0;
let mut input_max_rate = 0;
let mut input_nominal_rate = 0;
audiounit_get_available_samplerate(stm.input_device.id, kAudioObjectPropertyScopeGlobal,
&mut input_min_rate, &mut input_max_rate, &mut input_nominal_rate);
cubeb_log!("({:p}) Input device {}, name: {}, min: {}, max: {}, nominal rate: {}", stm as *const AudioUnitStream, stm.input_device.id
, input_name_str, input_min_rate, input_max_rate, input_nominal_rate);
let mut output_min_rate = 0;
let mut output_max_rate = 0;
let mut output_nominal_rate = 0;
audiounit_get_available_samplerate(stm.output_device.id, kAudioObjectPropertyScopeGlobal,
&mut output_min_rate, &mut output_max_rate, &mut output_nominal_rate);
cubeb_log!("({:p}) Output device {}, name: {}, min: {}, max: {}, nominal rate: {}", stm as *const AudioUnitStream, stm.output_device.id
, output_name_str, output_min_rate, output_max_rate, output_nominal_rate);
let rate = f64::from(input_nominal_rate);
let addr = AudioObjectPropertyAddress {
mSelector: kAudioDevicePropertyNominalSampleRate,
mScope: kAudioObjectPropertyScopeGlobal,
mElement: kAudioObjectPropertyElementMaster
};
// TODO: Check the aggregate_device_id ?
let rv = audio_object_set_property_data(stm.aggregate_device_id,
&addr,
mem::size_of::<f64>(),
&rate);
if rv != NO_ERR {
cubeb_log!("Non fatal error, AudioObjectSetPropertyData/kAudioDevicePropertyNominalSampleRate, rv={}", rv);
}
}
// Retrieve the rest lost memory.
// No need to retrieve the memory of {input,output}_device_info.friendly_name
// since they are already retrieved/retaken above.
assert!(input_device_info.friendly_name.is_null());
audiounit_device_destroy(&mut input_device_info);
assert!(output_device_info.friendly_name.is_null());
audiounit_device_destroy(&mut output_device_info);
}
/*
* Aggregate Device is a virtual audio interface which utilizes inputs and outputs
* of one or more physical audio interfaces. It is possible to use the clock of
@ -1633,7 +1557,7 @@ fn audiounit_create_aggregate_device(stm: &mut AudioUnitStream) -> Result<()>
return Err(r);
}
audiounit_workaround_for_airpod(stm);
stm.workaround_for_airpod();
Ok(())
}
@ -3595,6 +3519,90 @@ impl<'ctx> AudioUnitStream<'ctx> {
audiounit_set_channel_layout(self.output_unit, io_side::OUTPUT, self.context.layout.load(atomic::Ordering::SeqCst));
}
fn workaround_for_airpod(&self) {
assert_ne!(self.input_device.id, self.output_device.id);
assert_ne!(self.aggregate_device_id, kAudioObjectUnknown);
let mut input_device_info = ffi::cubeb_device_info::default();
assert_ne!(self.input_device.id, kAudioObjectUnknown);
audiounit_create_device_from_hwdev(&mut input_device_info, self.input_device.id, DeviceType::INPUT);
let mut output_device_info = ffi::cubeb_device_info::default();
assert_ne!(self.output_device.id, kAudioObjectUnknown);
audiounit_create_device_from_hwdev(&mut output_device_info, self.output_device.id, DeviceType::OUTPUT);
// NOTE: Retake the leaked friendly_name strings.
// It's better to extract the part of getting name of the data source
// into a function, so we don't need to call
// `audiounit_create_device_from_hwdev` to get this info.
let input_name_str = unsafe {
CString::from_raw(input_device_info.friendly_name as *mut c_char)
.into_string()
.expect("Fail to convert input name from CString into String")
};
input_device_info.friendly_name = ptr::null();
let output_name_str = unsafe {
CString::from_raw(output_device_info.friendly_name as *mut c_char)
.into_string()
.expect("Fail to convert output name from CString into String")
};
output_device_info.friendly_name = ptr::null();
if input_name_str.contains("AirPods") && output_name_str.contains("AirPods") {
let mut input_min_rate = 0;
let mut input_max_rate = 0;
let mut input_nominal_rate = 0;
audiounit_get_available_samplerate(
self.input_device.id,
kAudioObjectPropertyScopeGlobal,
&mut input_min_rate,
&mut input_max_rate,
&mut input_nominal_rate
);
cubeb_log!("({:p}) Input device {}, name: {}, min: {}, max: {}, nominal rate: {}",
self as *const AudioUnitStream, self.input_device.id, input_name_str,
input_min_rate, input_max_rate, input_nominal_rate);
let mut output_min_rate = 0;
let mut output_max_rate = 0;
let mut output_nominal_rate = 0;
audiounit_get_available_samplerate(
self.output_device.id,
kAudioObjectPropertyScopeGlobal,
&mut output_min_rate,
&mut output_max_rate,
&mut output_nominal_rate
);
cubeb_log!("({:p}) Output device {}, name: {}, min: {}, max: {}, nominal rate: {}",
self as *const AudioUnitStream, self.output_device.id, output_name_str,
output_min_rate, output_max_rate, output_nominal_rate);
let rate = f64::from(input_nominal_rate);
let addr = AudioObjectPropertyAddress {
mSelector: kAudioDevicePropertyNominalSampleRate,
mScope: kAudioObjectPropertyScopeGlobal,
mElement: kAudioObjectPropertyElementMaster
};
let rv = audio_object_set_property_data(self.aggregate_device_id,
&addr,
mem::size_of::<f64>(),
&rate);
if rv != NO_ERR {
cubeb_log!("Non fatal error, AudioObjectSetPropertyData/kAudioDevicePropertyNominalSampleRate, rv={}", rv);
}
}
// Retrieve the rest lost memory.
// No need to retrieve the memory of {input,output}_device_info.friendly_name
// since they are already retrieved/retaken above.
assert!(input_device_info.friendly_name.is_null());
audiounit_device_destroy(&mut input_device_info);
assert!(output_device_info.friendly_name.is_null());
audiounit_device_destroy(&mut output_device_info);
}
fn init_input_linear_buffer(&mut self, capacity: u32) -> Result<()> {
// FIXIT: Make sure `input_desc` is initialized, or the type of the buffer is set to float!
// assert_ne!(self.input_desc.mFormatFlags, 0);