diff options
Diffstat (limited to 'third_party/rust/cubeb-coreaudio/src/backend')
-rw-r--r-- | third_party/rust/cubeb-coreaudio/src/backend/mixer.rs | 53 | ||||
-rw-r--r-- | third_party/rust/cubeb-coreaudio/src/backend/mod.rs | 172 | ||||
-rw-r--r-- | third_party/rust/cubeb-coreaudio/src/backend/tests/api.rs | 3 |
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, ], ), ( |