Handle channels positionning

This commit is contained in:
Pierre Krieger 2015-09-10 11:44:19 +02:00
parent 0960f3c37d
commit 48282a068d
3 changed files with 125 additions and 11 deletions

View File

@ -107,14 +107,37 @@ impl Endpoint {
/// Number of channels. /// Number of channels.
pub type ChannelsCount = u16; pub type ChannelsCount = u16;
/// Possible position of a channel.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum ChannelPosition {
FrontLeft,
FrontRight,
FrontCenter,
LowFrequency,
BackLeft,
BackRight,
FrontLeftOfCenter,
FrontRightOfCenter,
BackCenter,
SideLeft,
SideRight,
TopCenter,
TopFrontLeft,
TopFrontCenter,
TopFrontRight,
TopBackLeft,
TopBackCenter,
TopBackRight,
}
/// ///
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct SamplesRate(pub u32); pub struct SamplesRate(pub u32);
/// Describes a format. /// Describes a format.
#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct Format { pub struct Format {
pub channels: ChannelsCount, pub channels: Vec<ChannelPosition>,
pub samples_rate: SamplesRate, pub samples_rate: SamplesRate,
pub data_type: SampleFormat, pub data_type: SampleFormat,
} }

View File

@ -9,6 +9,7 @@ use std::mem;
use Format; use Format;
use FormatsEnumerationError; use FormatsEnumerationError;
use ChannelPosition;
use SamplesRate; use SamplesRate;
use SampleFormat; use SampleFormat;
@ -18,6 +19,26 @@ pub use self::voice::{Voice, Buffer};
pub type SupportedFormatsIterator = OptionIntoIter<Format>; pub type SupportedFormatsIterator = OptionIntoIter<Format>;
// TODO: these constants should be moved to winapi
const SPEAKER_FRONT_LEFT: winapi::DWORD = 0x1;
const SPEAKER_FRONT_RIGHT: winapi::DWORD = 0x2;
const SPEAKER_FRONT_CENTER: winapi::DWORD = 0x4;
const SPEAKER_LOW_FREQUENCY: winapi::DWORD = 0x8;
const SPEAKER_BACK_LEFT: winapi::DWORD = 0x10;
const SPEAKER_BACK_RIGHT: winapi::DWORD = 0x20;
const SPEAKER_FRONT_LEFT_OF_CENTER: winapi::DWORD = 0x40;
const SPEAKER_FRONT_RIGHT_OF_CENTER: winapi::DWORD = 0x80;
const SPEAKER_BACK_CENTER: winapi::DWORD = 0x100;
const SPEAKER_SIDE_LEFT: winapi::DWORD = 0x200;
const SPEAKER_SIDE_RIGHT: winapi::DWORD = 0x400;
const SPEAKER_TOP_CENTER: winapi::DWORD = 0x800;
const SPEAKER_TOP_FRONT_LEFT: winapi::DWORD = 0x1000;
const SPEAKER_TOP_FRONT_CENTER: winapi::DWORD = 0x2000;
const SPEAKER_TOP_FRONT_RIGHT: winapi::DWORD = 0x4000;
const SPEAKER_TOP_BACK_LEFT: winapi::DWORD = 0x8000;
const SPEAKER_TOP_BACK_CENTER: winapi::DWORD = 0x10000;
const SPEAKER_TOP_BACK_RIGHT: winapi::DWORD = 0x20000;
mod com; mod com;
mod enumerate; mod enumerate;
mod voice; mod voice;
@ -119,21 +140,57 @@ impl Endpoint {
}; };
let format = { let format = {
let data_type = match (*format_ptr).wFormatTag { let (channels, data_type) = match (*format_ptr).wFormatTag {
winapi::WAVE_FORMAT_PCM => SampleFormat::I16, winapi::WAVE_FORMAT_PCM => {
(
vec![ChannelPosition::FrontLeft, ChannelPosition::FrontRight],
SampleFormat::I16
)
},
winapi::WAVE_FORMAT_EXTENSIBLE => { winapi::WAVE_FORMAT_EXTENSIBLE => {
let format_ptr = format_ptr as *const winapi::WAVEFORMATEXTENSIBLE; let format_ptr = format_ptr as *const winapi::WAVEFORMATEXTENSIBLE;
match (*format_ptr).SubFormat {
let channels = {
let mut channels = Vec::new();
let mask = (*format_ptr).dwChannelMask;
if (mask & SPEAKER_FRONT_LEFT) != 0 { channels.push(ChannelPosition::FrontLeft); }
if (mask & SPEAKER_FRONT_RIGHT) != 0 { channels.push(ChannelPosition::FrontRight); }
if (mask & SPEAKER_FRONT_CENTER) != 0 { channels.push(ChannelPosition::FrontCenter); }
if (mask & SPEAKER_LOW_FREQUENCY) != 0 { channels.push(ChannelPosition::LowFrequency); }
if (mask & SPEAKER_BACK_LEFT) != 0 { channels.push(ChannelPosition::BackLeft); }
if (mask & SPEAKER_BACK_RIGHT) != 0 { channels.push(ChannelPosition::BackRight); }
if (mask & SPEAKER_FRONT_LEFT_OF_CENTER) != 0 { channels.push(ChannelPosition::FrontLeftOfCenter); }
if (mask & SPEAKER_FRONT_RIGHT_OF_CENTER) != 0 { channels.push(ChannelPosition::FrontRightOfCenter); }
if (mask & SPEAKER_BACK_CENTER) != 0 { channels.push(ChannelPosition::BackCenter); }
if (mask & SPEAKER_SIDE_LEFT) != 0 { channels.push(ChannelPosition::SideLeft); }
if (mask & SPEAKER_SIDE_RIGHT) != 0 { channels.push(ChannelPosition::SideRight); }
if (mask & SPEAKER_TOP_CENTER) != 0 { channels.push(ChannelPosition::TopCenter); }
if (mask & SPEAKER_TOP_FRONT_LEFT) != 0 { channels.push(ChannelPosition::TopFrontLeft); }
if (mask & SPEAKER_TOP_FRONT_CENTER) != 0 { channels.push(ChannelPosition::TopFrontCenter); }
if (mask & SPEAKER_TOP_FRONT_RIGHT) != 0 { channels.push(ChannelPosition::TopFrontRight); }
if (mask & SPEAKER_TOP_BACK_LEFT) != 0 { channels.push(ChannelPosition::TopBackLeft); }
if (mask & SPEAKER_TOP_BACK_CENTER) != 0 { channels.push(ChannelPosition::TopBackCenter); }
if (mask & SPEAKER_TOP_BACK_RIGHT) != 0 { channels.push(ChannelPosition::TopBackRight); }
assert_eq!((*format_ptr).Format.nChannels as usize, channels.len());
channels
};
let format = match (*format_ptr).SubFormat {
winapi::KSDATAFORMAT_SUBTYPE_IEEE_FLOAT => SampleFormat::F32, winapi::KSDATAFORMAT_SUBTYPE_IEEE_FLOAT => SampleFormat::F32,
winapi::KSDATAFORMAT_SUBTYPE_PCM => SampleFormat::I16, winapi::KSDATAFORMAT_SUBTYPE_PCM => SampleFormat::I16,
g => panic!("Unknown SubFormat GUID returned by GetMixFormat: {:?}", g) g => panic!("Unknown SubFormat GUID returned by GetMixFormat: {:?}", g)
} };
(channels, format)
}, },
f => panic!("Unknown data format returned by GetMixFormat: {:?}", f) f => panic!("Unknown data format returned by GetMixFormat: {:?}", f)
}; };
Format { Format {
channels: (*format_ptr).nChannels, channels: channels,
samples_rate: SamplesRate((*format_ptr).nSamplesPerSec), samples_rate: SamplesRate((*format_ptr).nSamplesPerSec),
data_type: data_type, data_type: data_type,
} }

View File

@ -11,6 +11,7 @@ use std::ptr;
use std::marker::PhantomData; use std::marker::PhantomData;
use CreationError; use CreationError;
use ChannelPosition;
use Format; use Format;
use SampleFormat; use SampleFormat;
@ -52,12 +53,12 @@ impl Voice {
SampleFormat::F32 => winapi::WAVE_FORMAT_EXTENSIBLE, SampleFormat::F32 => winapi::WAVE_FORMAT_EXTENSIBLE,
SampleFormat::U16 => return Err(CreationError::FormatNotSupported), SampleFormat::U16 => return Err(CreationError::FormatNotSupported),
}, },
nChannels: format.channels as winapi::WORD, nChannels: format.channels.len() as winapi::WORD,
nSamplesPerSec: format.samples_rate.0 as winapi::DWORD, nSamplesPerSec: format.samples_rate.0 as winapi::DWORD,
nAvgBytesPerSec: format.channels as winapi::DWORD * nAvgBytesPerSec: format.channels.len() as winapi::DWORD *
format.samples_rate.0 as winapi::DWORD * format.samples_rate.0 as winapi::DWORD *
format.data_type.get_sample_size() as winapi::DWORD, format.data_type.get_sample_size() as winapi::DWORD,
nBlockAlign: format.channels as winapi::WORD * nBlockAlign: format.channels.len() as winapi::WORD *
format.data_type.get_sample_size() as winapi::WORD, format.data_type.get_sample_size() as winapi::WORD,
wBitsPerSample: 8 * format.data_type.get_sample_size() as winapi::WORD, wBitsPerSample: 8 * format.data_type.get_sample_size() as winapi::WORD,
cbSize: match format.data_type { cbSize: match format.data_type {
@ -68,7 +69,40 @@ impl Voice {
}, },
}, },
Samples: 8 * format.data_type.get_sample_size() as winapi::WORD, Samples: 8 * format.data_type.get_sample_size() as winapi::WORD,
dwChannelMask: 3, // LEFT | RIGHT dwChannelMask: {
let mut mask = 0;
for &channel in format.channels.iter() {
let raw_value = match channel {
ChannelPosition::FrontLeft => super::SPEAKER_FRONT_LEFT,
ChannelPosition::FrontRight => super::SPEAKER_FRONT_RIGHT,
ChannelPosition::FrontCenter => super::SPEAKER_FRONT_CENTER,
ChannelPosition::LowFrequency => super::SPEAKER_LOW_FREQUENCY,
ChannelPosition::BackLeft => super::SPEAKER_BACK_LEFT,
ChannelPosition::BackRight => super::SPEAKER_BACK_RIGHT,
ChannelPosition::FrontLeftOfCenter => super::SPEAKER_FRONT_LEFT_OF_CENTER,
ChannelPosition::FrontRightOfCenter => super::SPEAKER_FRONT_RIGHT_OF_CENTER,
ChannelPosition::BackCenter => super::SPEAKER_BACK_CENTER,
ChannelPosition::SideLeft => super::SPEAKER_SIDE_LEFT,
ChannelPosition::SideRight => super::SPEAKER_SIDE_RIGHT,
ChannelPosition::TopCenter => super::SPEAKER_TOP_CENTER,
ChannelPosition::TopFrontLeft => super::SPEAKER_TOP_FRONT_LEFT,
ChannelPosition::TopFrontCenter => super::SPEAKER_TOP_FRONT_CENTER,
ChannelPosition::TopFrontRight => super::SPEAKER_TOP_FRONT_RIGHT,
ChannelPosition::TopBackLeft => super::SPEAKER_TOP_BACK_LEFT,
ChannelPosition::TopBackCenter => super::SPEAKER_TOP_BACK_CENTER,
ChannelPosition::TopBackRight => super::SPEAKER_TOP_BACK_RIGHT,
};
// channels must be in the right order
if raw_value <= mask {
return Err(CreationError::FormatNotSupported);
}
mask = mask | raw_value;
}
mask
},
SubFormat: match format.data_type { SubFormat: match format.data_type {
SampleFormat::I16 => winapi::KSDATAFORMAT_SUBTYPE_PCM, SampleFormat::I16 => winapi::KSDATAFORMAT_SUBTYPE_PCM,
SampleFormat::F32 => winapi::KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, SampleFormat::F32 => winapi::KSDATAFORMAT_SUBTYPE_IEEE_FLOAT,