Source code

Revision control

Copy as Markdown

Other Tools

use cubeb_backend::{ChannelLayout, SampleFormat};
use std::mem;
use std::os::raw::{c_int, c_void};
extern crate audio_mixer;
pub use self::audio_mixer::Channel;
const CHANNEL_ORDER: [audio_mixer::Channel; audio_mixer::Channel::count()] = [
audio_mixer::Channel::FrontLeft,
audio_mixer::Channel::FrontRight,
audio_mixer::Channel::FrontCenter,
audio_mixer::Channel::LowFrequency,
audio_mixer::Channel::BackLeft,
audio_mixer::Channel::BackRight,
audio_mixer::Channel::FrontLeftOfCenter,
audio_mixer::Channel::FrontRightOfCenter,
audio_mixer::Channel::BackCenter,
audio_mixer::Channel::SideLeft,
audio_mixer::Channel::SideRight,
audio_mixer::Channel::TopCenter,
audio_mixer::Channel::TopFrontLeft,
audio_mixer::Channel::TopFrontCenter,
audio_mixer::Channel::TopFrontRight,
audio_mixer::Channel::TopBackLeft,
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> {
let mut map = channel_layout.bits();
let mut order = Vec::new();
let mut channel_index: usize = 0;
while map != 0 {
if map & 1 == 1 {
order.push(CHANNEL_ORDER[channel_index]);
}
map >>= 1;
channel_index += 1;
}
order
}
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_ORDER.iter().take(channel_count) {
channels.push(*channel);
}
if channel_count > CHANNEL_ORDER.len() {
channels.extend(vec![
audio_mixer::Channel::Silence;
channel_count - CHANNEL_ORDER.len()
]);
}
channels
}
#[derive(Debug)]
enum MixerType {
IntegerMixer(audio_mixer::Mixer<i16>),
FloatMixer(audio_mixer::Mixer<f32>),
}
impl MixerType {
fn new(
format: SampleFormat,
input_channels: &[audio_mixer::Channel],
output_channels: &[audio_mixer::Channel],
) -> Self {
match format {
SampleFormat::S16LE | SampleFormat::S16BE | SampleFormat::S16NE => {
cubeb_log!("Create an integer type(i16) mixer");
Self::IntegerMixer(audio_mixer::Mixer::<i16>::new(
input_channels,
output_channels,
))
}
SampleFormat::Float32LE | SampleFormat::Float32BE | SampleFormat::Float32NE => {
cubeb_log!("Create an floating type(f32) mixer");
Self::FloatMixer(audio_mixer::Mixer::<f32>::new(
input_channels,
output_channels,
))
}
}
}
fn sample_size(&self) -> usize {
match self {
MixerType::IntegerMixer(_) => mem::size_of::<i16>(),
MixerType::FloatMixer(_) => mem::size_of::<f32>(),
}
}
fn input_channels(&self) -> &[Channel] {
match self {
MixerType::IntegerMixer(m) => m.input_channels(),
MixerType::FloatMixer(m) => m.input_channels(),
}
}
fn output_channels(&self) -> &[Channel] {
match self {
MixerType::IntegerMixer(m) => m.output_channels(),
MixerType::FloatMixer(m) => m.output_channels(),
}
}
fn mix(
&self,
input_buffer_ptr: *const (),
input_buffer_size: usize,
output_buffer_ptr: *mut (),
output_buffer_size: usize,
frames: usize,
) {
use std::slice;
// Check input buffer size.
let size_needed = frames * self.input_channels().len() * self.sample_size();
assert!(input_buffer_size >= size_needed);
// Check output buffer size.
let size_needed = frames * self.output_channels().len() * self.sample_size();
assert!(output_buffer_size >= size_needed);
match self {
MixerType::IntegerMixer(m) => {
let in_buf_ptr = input_buffer_ptr as *const i16;
let out_buf_ptr = output_buffer_ptr as *mut i16;
let input_buffer = unsafe {
slice::from_raw_parts(in_buf_ptr, frames * self.input_channels().len())
};
let output_buffer = unsafe {
slice::from_raw_parts_mut(out_buf_ptr, frames * self.output_channels().len())
};
let mut in_buf = input_buffer.chunks(self.input_channels().len());
let mut out_buf = output_buffer.chunks_mut(self.output_channels().len());
for _ in 0..frames {
m.mix(in_buf.next().unwrap(), out_buf.next().unwrap());
}
}
MixerType::FloatMixer(m) => {
let in_buf_ptr = input_buffer_ptr as *const f32;
let out_buf_ptr = output_buffer_ptr as *mut f32;
let input_buffer = unsafe {
slice::from_raw_parts(in_buf_ptr, frames * self.input_channels().len())
};
let output_buffer = unsafe {
slice::from_raw_parts_mut(out_buf_ptr, frames * self.output_channels().len())
};
let mut in_buf = input_buffer.chunks(self.input_channels().len());
let mut out_buf = output_buffer.chunks_mut(self.output_channels().len());
for _ in 0..frames {
m.mix(in_buf.next().unwrap(), out_buf.next().unwrap());
}
}
};
}
}
#[derive(Debug)]
pub struct Mixer {
mixer: MixerType,
// Only accessed from callback thread.
buffer: Vec<u8>,
}
impl Mixer {
pub fn new(
format: SampleFormat,
in_channel_count: usize,
input_layout: ChannelLayout,
out_channel_count: usize,
mut output_channels: Vec<audio_mixer::Channel>,
) -> Self {
assert!(in_channel_count > 0);
assert!(out_channel_count > 0);
cubeb_log!(
"Creating a mixer with input channel count: {}, input layout: {:?},\
out channel count: {}, output channels: {:?}",
in_channel_count,
input_layout,
out_channel_count,
output_channels
);
let input_channels = if in_channel_count as u32 != input_layout.bits().count_ones() {
cubeb_log!(
"Mismatch between input channels and layout. Applying default layout instead"
);
get_default_channel_order(in_channel_count)
} else {
get_channel_order(input_layout)
};
// When having one or two channel, force mono or stereo. Some devices (namely,
// Bose QC35, mark 1 and 2), expose a single channel mapped to the right for
// some reason. Some devices (e.g., builtin speaker on MacBook Pro 2018) map
// the channel layout to the undefined channels.
if out_channel_count == 1 {
output_channels = vec![audio_mixer::Channel::FrontCenter];
} else if out_channel_count == 2 {
output_channels = vec![
audio_mixer::Channel::FrontLeft,
audio_mixer::Channel::FrontRight,
];
}
let all_silence = vec![audio_mixer::Channel::Silence; out_channel_count];
if output_channels.is_empty()
|| out_channel_count != output_channels.len()
|| all_silence == 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);
}
Self {
mixer: MixerType::new(format, &input_channels, &output_channels),
buffer: Vec::new(),
}
}
pub fn update_buffer_size(&mut self, frames: usize) -> bool {
let size_needed = frames * self.mixer.input_channels().len() * self.mixer.sample_size();
let elements_needed = size_needed / mem::size_of::<u8>();
if self.buffer.len() < elements_needed {
self.buffer.resize(elements_needed, 0);
true
} else {
false
}
}
pub fn get_buffer_mut_ptr(&mut self) -> *mut u8 {
self.buffer.as_mut_ptr()
}
// `update_buffer_size` must be called before this.
pub fn mix(&self, frames: usize, dest_buffer: *mut c_void, dest_buffer_size: usize) -> c_int {
let (src_buffer_ptr, src_buffer_size) = self.get_buffer_info();
self.mixer.mix(
src_buffer_ptr as *const (),
src_buffer_size,
dest_buffer as *mut (),
dest_buffer_size,
frames,
);
0
}
fn get_buffer_info(&self) -> (*const u8, usize) {
(
self.buffer.as_ptr(),
self.buffer.len() * mem::size_of::<u8>(),
)
}
fn duplicate_channel_present(channels: &[audio_mixer::Channel]) -> bool {
let mut bitmap: u32 = 0;
for channel in channels {
if channel != &Channel::Silence && channel != &Channel::Discrete {
if (bitmap & channel.bitmask()) != 0 {
return true;
}
bitmap |= channel.bitmask();
}
}
false
}
}
// This test gives a clear channel order of the ChannelLayout passed from cubeb interface.
#[test]
fn test_get_channel_order() {
assert_eq!(
get_channel_order(ChannelLayout::MONO),
[Channel::FrontCenter]
);
assert_eq!(
get_channel_order(ChannelLayout::MONO_LFE),
[Channel::FrontCenter, Channel::LowFrequency]
);
assert_eq!(
get_channel_order(ChannelLayout::STEREO),
[Channel::FrontLeft, Channel::FrontRight]
);
assert_eq!(
get_channel_order(ChannelLayout::STEREO_LFE),
[
Channel::FrontLeft,
Channel::FrontRight,
Channel::LowFrequency
]
);
assert_eq!(
get_channel_order(ChannelLayout::_3F),
[
Channel::FrontLeft,
Channel::FrontRight,
Channel::FrontCenter
]
);
assert_eq!(
get_channel_order(ChannelLayout::_3F_LFE),
[
Channel::FrontLeft,
Channel::FrontRight,
Channel::FrontCenter,
Channel::LowFrequency
]
);
assert_eq!(
get_channel_order(ChannelLayout::_2F1),
[Channel::FrontLeft, Channel::FrontRight, Channel::BackCenter]
);
assert_eq!(
get_channel_order(ChannelLayout::_2F1_LFE),
[
Channel::FrontLeft,
Channel::FrontRight,
Channel::LowFrequency,
Channel::BackCenter
]
);
assert_eq!(
get_channel_order(ChannelLayout::_3F1),
[
Channel::FrontLeft,
Channel::FrontRight,
Channel::FrontCenter,
Channel::BackCenter
]
);
assert_eq!(
get_channel_order(ChannelLayout::_3F1_LFE),
[
Channel::FrontLeft,
Channel::FrontRight,
Channel::FrontCenter,
Channel::LowFrequency,
Channel::BackCenter
]
);
assert_eq!(
get_channel_order(ChannelLayout::_2F2),
[
Channel::FrontLeft,
Channel::FrontRight,
Channel::SideLeft,
Channel::SideRight
]
);
assert_eq!(
get_channel_order(ChannelLayout::_2F2_LFE),
[
Channel::FrontLeft,
Channel::FrontRight,
Channel::LowFrequency,
Channel::SideLeft,
Channel::SideRight
]
);
assert_eq!(
get_channel_order(ChannelLayout::QUAD),
[
Channel::FrontLeft,
Channel::FrontRight,
Channel::BackLeft,
Channel::BackRight
]
);
assert_eq!(
get_channel_order(ChannelLayout::QUAD_LFE),
[
Channel::FrontLeft,
Channel::FrontRight,
Channel::LowFrequency,
Channel::BackLeft,
Channel::BackRight
]
);
assert_eq!(
get_channel_order(ChannelLayout::_3F2),
[
Channel::FrontLeft,
Channel::FrontRight,
Channel::FrontCenter,
Channel::SideLeft,
Channel::SideRight
]
);
assert_eq!(
get_channel_order(ChannelLayout::_3F2_LFE),
[
Channel::FrontLeft,
Channel::FrontRight,
Channel::FrontCenter,
Channel::LowFrequency,
Channel::SideLeft,
Channel::SideRight
]
);
assert_eq!(
get_channel_order(ChannelLayout::_3F2_BACK),
[
Channel::FrontLeft,
Channel::FrontRight,
Channel::FrontCenter,
Channel::BackLeft,
Channel::BackRight
]
);
assert_eq!(
get_channel_order(ChannelLayout::_3F2_LFE_BACK),
[
Channel::FrontLeft,
Channel::FrontRight,
Channel::FrontCenter,
Channel::LowFrequency,
Channel::BackLeft,
Channel::BackRight
]
);
assert_eq!(
get_channel_order(ChannelLayout::_3F3R_LFE),
[
Channel::FrontLeft,
Channel::FrontRight,
Channel::FrontCenter,
Channel::LowFrequency,
Channel::BackCenter,
Channel::SideLeft,
Channel::SideRight
]
);
assert_eq!(
get_channel_order(ChannelLayout::_3F4_LFE),
[
Channel::FrontLeft,
Channel::FrontRight,
Channel::FrontCenter,
Channel::LowFrequency,
Channel::BackLeft,
Channel::BackRight,
Channel::SideLeft,
Channel::SideRight
]
);
}
#[test]
fn test_get_default_channel_order() {
for len in 1..CHANNEL_ORDER.len() + 10 {
let channels = get_default_channel_order(len);
if len <= CHANNEL_ORDER.len() {
assert_eq!(channels, &CHANNEL_ORDER[..len]);
} else {
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());
}
}
}
#[test]
fn test_non_silent_duplicate_channels() {
let duplicate = [
Channel::FrontLeft,
Channel::Silence,
Channel::FrontRight,
Channel::FrontCenter,
Channel::Silence,
Channel::FrontRight,
];
assert!(Mixer::duplicate_channel_present(&duplicate));
let non_duplicate = [
Channel::FrontLeft,
Channel::Silence,
Channel::FrontRight,
Channel::FrontCenter,
Channel::Silence,
Channel::Silence,
];
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));
}