зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1530715 - P29: Move mixer to a struct within a mutex. r=padenot
The mixer of the stream will be created, reinitialized, used or destroyed on different threads, so its operations should be in the critical sections. We do create critical sections by our custom mutex. However, this custom mutex will be gradually replaced by the standard Rust mutex in the following patches. To replace the custom mutex, we put the mixer to the struct wrapped by a Rust mutex and do all the mixer operations in the critical section created by this struct. At the end when the custom mutex is removed, those operations are still in critical sections. Calling notify_state_changed needs to borrow AudioUnitStream as a mutuable. To avoid the borrowing-twice issue, the notify_state_changed calling is moved out the scope of the critical section created in the output data callback. Differential Revision: https://phabricator.services.mozilla.com/D34062 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
c7c35b3626
Коммит
c47370ecc1
|
@ -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 cubeb-coreaudio-rs git repository is: https://github.com/ChunMinChang/cubeb-coreaudio-rs
|
||||||
|
|
||||||
The git commit ID used was 5c9b94910dabb1f64b1c6e6d5907304d08c53d44 (2019-06-25 11:32:22 -0700)
|
The git commit ID used was b37d939bb7d2530047d624a5769ce2cfaa6d0dd5 (2019-06-25 11:32:22 -0700)
|
||||||
|
|
|
@ -453,12 +453,13 @@ extern "C" fn audiounit_output_callback(
|
||||||
) -> OSStatus {
|
) -> OSStatus {
|
||||||
assert_eq!(bus, AU_OUT_BUS);
|
assert_eq!(bus, AU_OUT_BUS);
|
||||||
assert!(!out_buffer_list.is_null());
|
assert!(!out_buffer_list.is_null());
|
||||||
let out_buffer_list_ref = unsafe { &mut (*out_buffer_list) };
|
|
||||||
|
|
||||||
assert_eq!(out_buffer_list_ref.mNumberBuffers, 1);
|
|
||||||
|
|
||||||
|
assert!(!user_ptr.is_null());
|
||||||
let stm = unsafe { &mut *(user_ptr as *mut AudioUnitStream) };
|
let stm = unsafe { &mut *(user_ptr as *mut AudioUnitStream) };
|
||||||
let buffers = unsafe {
|
|
||||||
|
let out_buffer_list_ref = unsafe { &mut (*out_buffer_list) };
|
||||||
|
assert_eq!(out_buffer_list_ref.mNumberBuffers, 1);
|
||||||
|
let mut buffers = unsafe {
|
||||||
let ptr = out_buffer_list_ref.mBuffers.as_mut_ptr();
|
let ptr = out_buffer_list_ref.mBuffers.as_mut_ptr();
|
||||||
let len = out_buffer_list_ref.mNumberBuffers as usize;
|
let len = out_buffer_list_ref.mNumberBuffers as usize;
|
||||||
slice::from_raw_parts_mut(ptr, len)
|
slice::from_raw_parts_mut(ptr, len)
|
||||||
|
@ -479,10 +480,6 @@ extern "C" fn audiounit_output_callback(
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut input_frames: i64 = 0;
|
|
||||||
let mut output_buffer = ptr::null_mut::<c_void>();
|
|
||||||
let mut input_buffer = ptr::null_mut::<c_void>();
|
|
||||||
|
|
||||||
if stm.shutdown.load(Ordering::SeqCst) {
|
if stm.shutdown.load(Ordering::SeqCst) {
|
||||||
cubeb_log!("({:p}) output shutdown.", stm as *const AudioUnitStream);
|
cubeb_log!("({:p}) output shutdown.", stm as *const AudioUnitStream);
|
||||||
audiounit_make_silent(&mut buffers[0]);
|
audiounit_make_silent(&mut buffers[0]);
|
||||||
|
@ -499,8 +496,18 @@ extern "C" fn audiounit_output_callback(
|
||||||
return NO_ERR;
|
return NO_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let handler = |stm: &mut AudioUnitStream,
|
||||||
|
output_frames: u32,
|
||||||
|
buffers: &mut [AudioBuffer]|
|
||||||
|
-> (OSStatus, Option<State>) {
|
||||||
|
let mut input_frames: i64 = 0;
|
||||||
|
let mut output_buffer = ptr::null_mut::<c_void>();
|
||||||
|
let mut input_buffer = ptr::null_mut::<c_void>();
|
||||||
|
|
||||||
|
let mut stream_device = stm.stream_device.lock().unwrap();
|
||||||
|
|
||||||
// Get output buffer
|
// Get output buffer
|
||||||
output_buffer = match stm.mixer.as_mut() {
|
output_buffer = match stream_device.mixer.as_mut() {
|
||||||
None => buffers[0].mData,
|
None => buffers[0].mData,
|
||||||
Some(mixer) => {
|
Some(mixer) => {
|
||||||
// If remixing needs to occur, we can't directly work in our final
|
// If remixing needs to occur, we can't directly work in our final
|
||||||
|
@ -513,7 +520,7 @@ extern "C" fn audiounit_output_callback(
|
||||||
stm.frames_written
|
stm.frames_written
|
||||||
.fetch_add(i64::from(output_frames), Ordering::SeqCst);
|
.fetch_add(i64::from(output_frames), Ordering::SeqCst);
|
||||||
|
|
||||||
// If Full duplex get also input buffer
|
// Also get the input buffer if the stream is duplex
|
||||||
if !stm.input_unit.is_null() {
|
if !stm.input_unit.is_null() {
|
||||||
// If the output callback came first and this is a duplex stream, we need to
|
// If the output callback came first and this is a duplex stream, we need to
|
||||||
// fill in some additional silence in the resampler.
|
// fill in some additional silence in the resampler.
|
||||||
|
@ -552,9 +559,7 @@ extern "C" fn audiounit_output_callback(
|
||||||
|
|
||||||
// Call user callback through resampler.
|
// Call user callback through resampler.
|
||||||
assert!(!output_buffer.is_null());
|
assert!(!output_buffer.is_null());
|
||||||
let outframes = {
|
let outframes = stream_device.resampler.fill(
|
||||||
let mut stream_device = stm.stream_device.lock().unwrap();
|
|
||||||
stream_device.resampler.fill(
|
|
||||||
input_buffer,
|
input_buffer,
|
||||||
if input_buffer.is_null() {
|
if input_buffer.is_null() {
|
||||||
ptr::null_mut()
|
ptr::null_mut()
|
||||||
|
@ -563,8 +568,7 @@ extern "C" fn audiounit_output_callback(
|
||||||
},
|
},
|
||||||
output_buffer,
|
output_buffer,
|
||||||
i64::from(output_frames),
|
i64::from(output_frames),
|
||||||
)
|
);
|
||||||
};
|
|
||||||
if !input_buffer.is_null() {
|
if !input_buffer.is_null() {
|
||||||
// Pop from the buffer the frames used by the the resampler.
|
// Pop from the buffer the frames used by the the resampler.
|
||||||
stm.input_linear_buffer
|
stm.input_linear_buffer
|
||||||
|
@ -579,9 +583,8 @@ extern "C" fn audiounit_output_callback(
|
||||||
if !stm.input_unit.is_null() {
|
if !stm.input_unit.is_null() {
|
||||||
assert_eq!(audio_output_unit_stop(stm.input_unit), NO_ERR);
|
assert_eq!(audio_output_unit_stop(stm.input_unit), NO_ERR);
|
||||||
}
|
}
|
||||||
stm.notify_state_changed(State::Error);
|
|
||||||
audiounit_make_silent(&mut buffers[0]);
|
audiounit_make_silent(&mut buffers[0]);
|
||||||
return NO_ERR;
|
return (NO_ERR, Some(State::Error));
|
||||||
}
|
}
|
||||||
|
|
||||||
*stm.draining.get_mut() = outframes < i64::from(output_frames);
|
*stm.draining.get_mut() = outframes < i64::from(output_frames);
|
||||||
|
@ -616,7 +619,7 @@ extern "C" fn audiounit_output_callback(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mixing
|
// Mixing
|
||||||
if stm.mixer.is_none() {
|
if stream_device.mixer.is_none() {
|
||||||
// Pan stereo.
|
// Pan stereo.
|
||||||
if panning != 0.0 {
|
if panning != 0.0 {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -637,14 +640,21 @@ extern "C" fn audiounit_output_callback(
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
assert!(buffers[0].mDataByteSize >= stm.output_desc.mBytesPerFrame * output_frames);
|
assert!(buffers[0].mDataByteSize >= stm.output_desc.mBytesPerFrame * output_frames);
|
||||||
stm.mixer.as_mut().unwrap().mix(
|
stream_device.mixer.as_mut().unwrap().mix(
|
||||||
output_frames as usize,
|
output_frames as usize,
|
||||||
buffers[0].mData,
|
buffers[0].mData,
|
||||||
buffers[0].mDataByteSize as usize,
|
buffers[0].mDataByteSize as usize,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
NO_ERR
|
(NO_ERR, None)
|
||||||
|
};
|
||||||
|
|
||||||
|
let (status, notification) = handler(stm, output_frames, &mut buffers);
|
||||||
|
if let Some(state) = notification {
|
||||||
|
stm.notify_state_changed(state);
|
||||||
|
}
|
||||||
|
status
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" fn audiounit_property_listener_callback(
|
extern "C" fn audiounit_property_listener_callback(
|
||||||
|
@ -2392,6 +2402,7 @@ unsafe impl Sync for AudioUnitContext {}
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct StreamDevice {
|
struct StreamDevice {
|
||||||
aggregate_device: AggregateDevice,
|
aggregate_device: AggregateDevice,
|
||||||
|
mixer: Option<Mixer>,
|
||||||
resampler: Resampler,
|
resampler: Resampler,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2399,6 +2410,7 @@ impl Default for StreamDevice {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
aggregate_device: AggregateDevice::default(),
|
aggregate_device: AggregateDevice::default(),
|
||||||
|
mixer: None,
|
||||||
resampler: Resampler::default(),
|
resampler: Resampler::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2452,8 +2464,6 @@ struct AudioUnitStream<'ctx> {
|
||||||
panning: atomic::Atomic<f32>,
|
panning: atomic::Atomic<f32>,
|
||||||
// This is true if a device change callback is currently running.
|
// This is true if a device change callback is currently running.
|
||||||
switching_device: AtomicBool,
|
switching_device: AtomicBool,
|
||||||
// Mixer interface
|
|
||||||
mixer: Option<Mixer>,
|
|
||||||
// Listeners indicating what system events are monitored.
|
// Listeners indicating what system events are monitored.
|
||||||
default_input_listener: Option<device_property_listener>,
|
default_input_listener: Option<device_property_listener>,
|
||||||
default_output_listener: Option<device_property_listener>,
|
default_output_listener: Option<device_property_listener>,
|
||||||
|
@ -2513,7 +2523,6 @@ impl<'ctx> AudioUnitStream<'ctx> {
|
||||||
current_latency_frames: AtomicU32::new(0),
|
current_latency_frames: AtomicU32::new(0),
|
||||||
panning: atomic::Atomic::new(0.0_f32),
|
panning: atomic::Atomic::new(0.0_f32),
|
||||||
switching_device: AtomicBool::new(false),
|
switching_device: AtomicBool::new(false),
|
||||||
mixer: None,
|
|
||||||
default_input_listener: None,
|
default_input_listener: None,
|
||||||
default_output_listener: None,
|
default_output_listener: None,
|
||||||
input_alive_listener: None,
|
input_alive_listener: None,
|
||||||
|
@ -3165,18 +3174,14 @@ impl<'ctx> AudioUnitStream<'ctx> {
|
||||||
self,
|
self,
|
||||||
self.context.layout
|
self.context.layout
|
||||||
);
|
);
|
||||||
if self.context.channels != self.output_stream_params.channels()
|
|
||||||
|
{
|
||||||
|
let mut stream_device = self.stream_device.lock().unwrap();
|
||||||
|
stream_device.mixer = if self.context.channels != self.output_stream_params.channels()
|
||||||
|| self.context.layout.load(atomic::Ordering::SeqCst)
|
|| self.context.layout.load(atomic::Ordering::SeqCst)
|
||||||
!= self.output_stream_params.layout()
|
!= self.output_stream_params.layout()
|
||||||
{
|
{
|
||||||
cubeb_log!("Incompatible channel layouts detected, setting up remixer");
|
cubeb_log!("Incompatible channel layouts detected, setting up remixer");
|
||||||
self.mixer = Some(Mixer::new(
|
|
||||||
self.output_stream_params.format(),
|
|
||||||
self.output_stream_params.channels(),
|
|
||||||
self.output_stream_params.layout(),
|
|
||||||
self.context.channels,
|
|
||||||
self.context.layout.load(atomic::Ordering::SeqCst),
|
|
||||||
));
|
|
||||||
// We will be remixing the data before it reaches the output device.
|
// We will be remixing the data before it reaches the output device.
|
||||||
// We need to adjust the number of channels and other
|
// We need to adjust the number of channels and other
|
||||||
// AudioStreamDescription details.
|
// AudioStreamDescription details.
|
||||||
|
@ -3185,8 +3190,16 @@ impl<'ctx> AudioUnitStream<'ctx> {
|
||||||
(self.output_desc.mBitsPerChannel / 8) * self.output_desc.mChannelsPerFrame;
|
(self.output_desc.mBitsPerChannel / 8) * self.output_desc.mChannelsPerFrame;
|
||||||
self.output_desc.mBytesPerPacket =
|
self.output_desc.mBytesPerPacket =
|
||||||
self.output_desc.mBytesPerFrame * self.output_desc.mFramesPerPacket;
|
self.output_desc.mBytesPerFrame * self.output_desc.mFramesPerPacket;
|
||||||
|
Some(Mixer::new(
|
||||||
|
self.output_stream_params.format(),
|
||||||
|
self.output_stream_params.channels(),
|
||||||
|
self.output_stream_params.layout(),
|
||||||
|
self.context.channels,
|
||||||
|
self.context.layout.load(atomic::Ordering::SeqCst),
|
||||||
|
))
|
||||||
} else {
|
} else {
|
||||||
self.mixer = None;
|
None
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
r = audio_unit_set_property(
|
r = audio_unit_set_property(
|
||||||
|
@ -3448,11 +3461,10 @@ impl<'ctx> AudioUnitStream<'ctx> {
|
||||||
self.output_unit = ptr::null_mut();
|
self.output_unit = ptr::null_mut();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.mixer = None;
|
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut stream_device = self.stream_device.lock().unwrap();
|
let mut stream_device = self.stream_device.lock().unwrap();
|
||||||
stream_device.resampler.destroy();
|
stream_device.resampler.destroy();
|
||||||
|
stream_device.mixer = None;
|
||||||
stream_device.aggregate_device = AggregateDevice::default();
|
stream_device.aggregate_device = AggregateDevice::default();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче