summaryrefslogtreecommitdiffstats
path: root/third_party/rust/cubeb-coreaudio/src
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/cubeb-coreaudio/src')
-rw-r--r--third_party/rust/cubeb-coreaudio/src/backend/mixer.rs53
-rw-r--r--third_party/rust/cubeb-coreaudio/src/backend/mod.rs172
-rw-r--r--third_party/rust/cubeb-coreaudio/src/backend/tests/api.rs3
3 files changed, 207 insertions, 21 deletions
diff --git a/third_party/rust/cubeb-coreaudio/src/backend/mixer.rs b/third_party/rust/cubeb-coreaudio/src/backend/mixer.rs
index a4f63926b1..8b80738736 100644
--- a/third_party/rust/cubeb-coreaudio/src/backend/mixer.rs
+++ b/third_party/rust/cubeb-coreaudio/src/backend/mixer.rs
@@ -5,7 +5,7 @@ use std::os::raw::{c_int, c_void};
extern crate audio_mixer;
pub use self::audio_mixer::Channel;
-const CHANNEL_OERDER: [audio_mixer::Channel; audio_mixer::Channel::count()] = [
+const CHANNEL_ORDER: [audio_mixer::Channel; audio_mixer::Channel::count()] = [
audio_mixer::Channel::FrontLeft,
audio_mixer::Channel::FrontRight,
audio_mixer::Channel::FrontCenter,
@@ -25,6 +25,7 @@ const CHANNEL_OERDER: [audio_mixer::Channel; audio_mixer::Channel::count()] = [
audio_mixer::Channel::TopBackCenter,
audio_mixer::Channel::TopBackRight,
audio_mixer::Channel::Silence,
+ audio_mixer::Channel::Discrete,
];
pub fn get_channel_order(channel_layout: ChannelLayout) -> Vec<audio_mixer::Channel> {
@@ -33,7 +34,7 @@ pub fn get_channel_order(channel_layout: ChannelLayout) -> Vec<audio_mixer::Chan
let mut channel_index: usize = 0;
while map != 0 {
if map & 1 == 1 {
- order.push(CHANNEL_OERDER[channel_index]);
+ order.push(CHANNEL_ORDER[channel_index]);
}
map >>= 1;
channel_index += 1;
@@ -44,14 +45,14 @@ pub fn get_channel_order(channel_layout: ChannelLayout) -> Vec<audio_mixer::Chan
fn get_default_channel_order(channel_count: usize) -> Vec<audio_mixer::Channel> {
assert_ne!(channel_count, 0);
let mut channels = Vec::with_capacity(channel_count);
- for channel in CHANNEL_OERDER.iter().take(channel_count) {
+ for channel in CHANNEL_ORDER.iter().take(channel_count) {
channels.push(*channel);
}
- if channel_count > CHANNEL_OERDER.len() {
+ if channel_count > CHANNEL_ORDER.len() {
channels.extend(vec![
audio_mixer::Channel::Silence;
- channel_count - CHANNEL_OERDER.len()
+ channel_count - CHANNEL_ORDER.len()
]);
}
@@ -214,7 +215,7 @@ impl Mixer {
if output_channels.is_empty()
|| out_channel_count != output_channels.len()
|| all_silence == output_channels
- || Self::non_silent_duplicate_channel_present(&output_channels)
+ || Self::duplicate_channel_present(&output_channels)
{
cubeb_log!("Use invalid layout. Apply default layout instead");
output_channels = get_default_channel_order(out_channel_count);
@@ -261,10 +262,10 @@ impl Mixer {
)
}
- fn non_silent_duplicate_channel_present(channels: &[audio_mixer::Channel]) -> bool {
+ fn duplicate_channel_present(channels: &[audio_mixer::Channel]) -> bool {
let mut bitmap: u32 = 0;
for channel in channels {
- if channel != &Channel::Silence {
+ if channel != &Channel::Silence && channel != &Channel::Discrete {
if (bitmap & channel.bitmask()) != 0 {
return true;
}
@@ -456,14 +457,14 @@ fn test_get_channel_order() {
#[test]
fn test_get_default_channel_order() {
- for len in 1..CHANNEL_OERDER.len() + 10 {
+ for len in 1..CHANNEL_ORDER.len() + 10 {
let channels = get_default_channel_order(len);
- if len <= CHANNEL_OERDER.len() {
- assert_eq!(channels, &CHANNEL_OERDER[..len]);
+ if len <= CHANNEL_ORDER.len() {
+ assert_eq!(channels, &CHANNEL_ORDER[..len]);
} else {
- let silences = vec![audio_mixer::Channel::Silence; len - CHANNEL_OERDER.len()];
- assert_eq!(channels[..CHANNEL_OERDER.len()], CHANNEL_OERDER);
- assert_eq!(&channels[CHANNEL_OERDER.len()..], silences.as_slice());
+ let silences = vec![audio_mixer::Channel::Silence; len - CHANNEL_ORDER.len()];
+ assert_eq!(channels[..CHANNEL_ORDER.len()], CHANNEL_ORDER);
+ assert_eq!(&channels[CHANNEL_ORDER.len()..], silences.as_slice());
}
}
}
@@ -478,7 +479,7 @@ fn test_non_silent_duplicate_channels() {
Channel::Silence,
Channel::FrontRight,
];
- assert!(Mixer::non_silent_duplicate_channel_present(&duplicate));
+ assert!(Mixer::duplicate_channel_present(&duplicate));
let non_duplicate = [
Channel::FrontLeft,
@@ -488,5 +489,25 @@ fn test_non_silent_duplicate_channels() {
Channel::Silence,
Channel::Silence,
];
- assert!(!Mixer::non_silent_duplicate_channel_present(&non_duplicate));
+ assert!(!Mixer::duplicate_channel_present(&non_duplicate));
+
+ let duplicate = [
+ Channel::FrontLeft,
+ Channel::Discrete,
+ Channel::FrontRight,
+ Channel::FrontCenter,
+ Channel::Discrete,
+ Channel::FrontRight,
+ ];
+ assert!(Mixer::duplicate_channel_present(&duplicate));
+
+ let non_duplicate = [
+ Channel::FrontLeft,
+ Channel::Discrete,
+ Channel::FrontRight,
+ Channel::FrontCenter,
+ Channel::Discrete,
+ Channel::Discrete,
+ ];
+ assert!(!Mixer::duplicate_channel_present(&non_duplicate));
}
diff --git a/third_party/rust/cubeb-coreaudio/src/backend/mod.rs b/third_party/rust/cubeb-coreaudio/src/backend/mod.rs
index e6be028a2e..855c119b63 100644
--- a/third_party/rust/cubeb-coreaudio/src/backend/mod.rs
+++ b/third_party/rust/cubeb-coreaudio/src/backend/mod.rs
@@ -33,6 +33,8 @@ use self::mixer::*;
use self::resampler::*;
use self::utils::*;
use backend::ringbuf::RingBuffer;
+#[cfg(feature = "audio_dump")]
+use cubeb_backend::ffi::cubeb_audio_dump_stream_t;
use cubeb_backend::{
ffi, ChannelLayout, Context, ContextOps, DeviceCollectionRef, DeviceId, DeviceRef, DeviceType,
Error, InputProcessingParams, Ops, Result, SampleFormat, State, Stream, StreamOps,
@@ -114,6 +116,16 @@ lazy_static! {
};
}
+#[cfg(feature = "audio_dump")]
+fn dump_audio(stream: cubeb_audio_dump_stream_t, audio_samples: *mut c_void, count: u32) {
+ unsafe {
+ let rv = ffi::cubeb_audio_dump_write(stream, audio_samples, count);
+ if rv != 0 {
+ cubeb_alog!("Error dumping audio data");
+ }
+ }
+}
+
fn make_sized_audio_channel_layout(sz: usize) -> AutoRelease<AudioChannelLayout> {
assert!(sz >= mem::size_of::<AudioChannelLayout>());
assert_eq!(
@@ -194,7 +206,12 @@ impl From<CAChannelLabel> for mixer::Channel {
sys::kAudioChannelLabel_TopBackLeft => mixer::Channel::TopBackLeft,
sys::kAudioChannelLabel_TopBackCenter => mixer::Channel::TopBackCenter,
sys::kAudioChannelLabel_TopBackRight => mixer::Channel::TopBackRight,
- _ => mixer::Channel::Silence,
+ sys::kAudioChannelLabel_Unknown => mixer::Channel::Discrete,
+ sys::kAudioChannelLabel_Unused => mixer::Channel::Silence,
+ v => {
+ eprintln!("Warning: channel label value {} isn't handled", v);
+ mixer::Channel::Silence
+ }
}
}
}
@@ -551,6 +568,16 @@ extern "C" fn audiounit_input_callback(
ErrorHandle::Reinit
} else {
assert_eq!(status, NO_ERR);
+
+ #[cfg(feature = "audio_dump")]
+ {
+ dump_audio(
+ stm.core_stream_data.audio_dump_input,
+ input_buffer_list.mBuffers[0].mData,
+ input_frames * stm.core_stream_data.input_dev_desc.mChannelsPerFrame,
+ );
+ }
+
input_buffer_manager
.push_data(input_buffer_list.mBuffers[0].mData, input_frames as usize);
ErrorHandle::Return(status)
@@ -708,6 +735,14 @@ extern "C" fn audiounit_output_callback(
if stm.stopped.load(Ordering::SeqCst) {
cubeb_alog!("({:p}) output stopped.", stm as *const AudioUnitStream);
audiounit_make_silent(&buffers[0]);
+ #[cfg(feature = "audio_dump")]
+ {
+ dump_audio(
+ stm.core_stream_data.audio_dump_output,
+ buffers[0].mData,
+ output_frames * stm.core_stream_data.output_dev_desc.mChannelsPerFrame,
+ );
+ }
return NO_ERR;
}
@@ -718,12 +753,20 @@ extern "C" fn audiounit_output_callback(
cubeb_alog!("({:p}) output drained.", stm as *const AudioUnitStream);
stm.notify_state_changed(State::Drained);
let queue = stm.queue.clone();
+ audiounit_make_silent(&buffers[0]);
+ #[cfg(feature = "audio_dump")]
+ {
+ dump_audio(
+ stm.core_stream_data.audio_dump_output,
+ buffers[0].mData,
+ output_frames * stm.core_stream_data.output_dev_desc.mChannelsPerFrame,
+ );
+ }
// Use a new thread, through the queue, to avoid deadlock when calling
// AudioOutputUnitStop method from inside render callback
queue.run_async(move || {
stm.core_stream_data.stop_audiounits();
});
- audiounit_make_silent(&buffers[0]);
return NO_ERR;
}
@@ -846,12 +889,21 @@ extern "C" fn audiounit_output_callback(
stm.stopped.store(true, Ordering::SeqCst);
stm.notify_state_changed(State::Error);
let queue = stm.queue.clone();
+ audiounit_make_silent(&buffers[0]);
+
+ #[cfg(feature = "audio_dump")]
+ {
+ dump_audio(
+ stm.core_stream_data.audio_dump_output,
+ buffers[0].mData,
+ output_frames * stm.core_stream_data.output_dev_desc.mChannelsPerFrame,
+ );
+ }
// Use a new thread, through the queue, to avoid deadlock when calling
// AudioOutputUnitStop method from inside render callback
queue.run_async(move || {
stm.core_stream_data.stop_audiounits();
});
- audiounit_make_silent(&buffers[0]);
return NO_ERR;
}
@@ -898,6 +950,15 @@ extern "C" fn audiounit_output_callback(
buffers[0].mDataByteSize as usize,
);
}
+
+ #[cfg(feature = "audio_dump")]
+ {
+ dump_audio(
+ stm.core_stream_data.audio_dump_output,
+ buffers[0].mData,
+ output_frames * stm.core_stream_data.output_dev_desc.mChannelsPerFrame,
+ );
+ }
NO_ERR
}
@@ -3010,6 +3071,14 @@ struct CoreStreamData<'ctx> {
output_alive_listener: Option<device_property_listener>,
output_source_listener: Option<device_property_listener>,
input_logging: Option<InputCallbackLogger>,
+ #[cfg(feature = "audio_dump")]
+ audio_dump_session: ffi::cubeb_audio_dump_session_t,
+ #[cfg(feature = "audio_dump")]
+ audio_dump_session_running: bool,
+ #[cfg(feature = "audio_dump")]
+ audio_dump_input: ffi::cubeb_audio_dump_stream_t,
+ #[cfg(feature = "audio_dump")]
+ audio_dump_output: ffi::cubeb_audio_dump_stream_t,
}
impl<'ctx> Default for CoreStreamData<'ctx> {
@@ -3050,6 +3119,14 @@ impl<'ctx> Default for CoreStreamData<'ctx> {
output_alive_listener: None,
output_source_listener: None,
input_logging: None,
+ #[cfg(feature = "audio_dump")]
+ audio_dump_session: ptr::null_mut(),
+ #[cfg(feature = "audio_dump")]
+ audio_dump_session_running: false,
+ #[cfg(feature = "audio_dump")]
+ audio_dump_input: ptr::null_mut(),
+ #[cfg(feature = "audio_dump")]
+ audio_dump_output: ptr::null_mut(),
}
}
}
@@ -3097,6 +3174,14 @@ impl<'ctx> CoreStreamData<'ctx> {
output_alive_listener: None,
output_source_listener: None,
input_logging: None,
+ #[cfg(feature = "audio_dump")]
+ audio_dump_session: ptr::null_mut(),
+ #[cfg(feature = "audio_dump")]
+ audio_dump_session_running: false,
+ #[cfg(feature = "audio_dump")]
+ audio_dump_input: ptr::null_mut(),
+ #[cfg(feature = "audio_dump")]
+ audio_dump_output: ptr::null_mut(),
}
}
@@ -3454,6 +3539,11 @@ impl<'ctx> CoreStreamData<'ctx> {
assert!(!self.stm_ptr.is_null());
let stream = unsafe { &(*self.stm_ptr) };
+ #[cfg(feature = "audio_dump")]
+ unsafe {
+ ffi::cubeb_audio_dump_init(&mut self.audio_dump_session);
+ }
+
// Configure I/O stream
if self.has_input() {
assert!(!self.input_unit.is_null());
@@ -3543,6 +3633,26 @@ impl<'ctx> CoreStreamData<'ctx> {
e
})?;
+ #[cfg(feature = "audio_dump")]
+ {
+ let name = format!("input-{:p}.wav", self.stm_ptr);
+ let cname = CString::new(name).expect("OK");
+ let rv = unsafe {
+ ffi::cubeb_audio_dump_stream_init(
+ self.audio_dump_session,
+ &mut self.audio_dump_input,
+ *params.as_ptr(),
+ cname.as_ptr(),
+ )
+ };
+ if rv == 0 {
+ assert_ne!(self.audio_dump_input, ptr::null_mut(),);
+ cubeb_log!("Successfully inited audio dump for input");
+ } else {
+ cubeb_log!("Failed to init audio dump for input");
+ }
+ }
+
assert_eq!(self.input_dev_desc.mSampleRate, input_hw_desc.mSampleRate);
// Use latency to set buffer size
@@ -3739,6 +3849,26 @@ impl<'ctx> CoreStreamData<'ctx> {
e
})?;
+ #[cfg(feature = "audio_dump")]
+ {
+ let name = format!("output-{:p}.wav", self.stm_ptr);
+ let cname = CString::new(name).expect("OK");
+ let rv = unsafe {
+ ffi::cubeb_audio_dump_stream_init(
+ self.audio_dump_session,
+ &mut self.audio_dump_output,
+ *params.as_ptr(),
+ cname.as_ptr(),
+ )
+ };
+ if rv == 0 {
+ assert_ne!(self.audio_dump_output, ptr::null_mut(),);
+ cubeb_log!("Successfully inited audio dump for output");
+ } else {
+ cubeb_log!("Failed to init audio dump for output");
+ }
+ }
+
let device_layout = self
.get_output_channel_layout()
.map_err(|e| {
@@ -3908,6 +4038,12 @@ impl<'ctx> CoreStreamData<'ctx> {
self.input_logging = Some(InputCallbackLogger::new());
}
+ #[cfg(feature = "audio_dump")]
+ {
+ unsafe { ffi::cubeb_audio_dump_start(self.audio_dump_session) };
+ self.audio_dump_session_running = true;
+ }
+
if !self.input_unit.is_null() {
let r = audio_unit_initialize(self.input_unit);
if r != NO_ERR {
@@ -4081,6 +4217,36 @@ impl<'ctx> CoreStreamData<'ctx> {
// Return the VPIO unit if present.
self.voiceprocessing_unit_handle = None;
+ #[cfg(feature = "audio_dump")]
+ {
+ if !self.audio_dump_session.is_null() {
+ unsafe {
+ ffi::cubeb_audio_dump_stop(self.audio_dump_session);
+ if !self.audio_dump_input.is_null() {
+ let rv = ffi::cubeb_audio_dump_stream_shutdown(
+ self.audio_dump_session,
+ self.audio_dump_input,
+ );
+ if rv != 0 {
+ cubeb_log!("Failed to shutdown audio dump for input");
+ }
+ }
+ if !self.audio_dump_output.is_null() {
+ let rv = ffi::cubeb_audio_dump_stream_shutdown(
+ self.audio_dump_session,
+ self.audio_dump_output,
+ );
+ if rv != 0 {
+ cubeb_log!("Failed to shutdown audio dump for output");
+ }
+ }
+ ffi::cubeb_audio_dump_shutdown(self.audio_dump_session);
+ self.audio_dump_session = ptr::null_mut();
+ self.audio_dump_session_running = false;
+ }
+ }
+ }
+
self.resampler.destroy();
self.mixer = None;
self.aggregate_device = None;
diff --git a/third_party/rust/cubeb-coreaudio/src/backend/tests/api.rs b/third_party/rust/cubeb-coreaudio/src/backend/tests/api.rs
index 5ce2374a3e..ea08a5ef45 100644
--- a/third_party/rust/cubeb-coreaudio/src/backend/tests/api.rs
+++ b/third_party/rust/cubeb-coreaudio/src/backend/tests/api.rs
@@ -376,7 +376,6 @@ fn test_get_default_device_id_with_inout_type() {
#[test]
fn test_convert_channel_layout() {
let pairs = [
- (vec![kAudioObjectUnknown], vec![mixer::Channel::Silence]),
(
vec![kAudioChannelLabel_Mono],
vec![mixer::Channel::FrontCenter],
@@ -398,7 +397,7 @@ fn test_convert_channel_layout() {
vec![
mixer::Channel::FrontLeft,
mixer::Channel::FrontRight,
- mixer::Channel::Silence,
+ mixer::Channel::Discrete,
],
),
(