Handle channels positionning
This commit is contained in:
parent
0960f3c37d
commit
48282a068d
27
src/lib.rs
27
src/lib.rs
|
@ -107,14 +107,37 @@ impl Endpoint {
|
|||
/// Number of channels.
|
||||
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)]
|
||||
pub struct SamplesRate(pub u32);
|
||||
|
||||
/// Describes a format.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Format {
|
||||
pub channels: ChannelsCount,
|
||||
pub channels: Vec<ChannelPosition>,
|
||||
pub samples_rate: SamplesRate,
|
||||
pub data_type: SampleFormat,
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ use std::mem;
|
|||
|
||||
use Format;
|
||||
use FormatsEnumerationError;
|
||||
use ChannelPosition;
|
||||
use SamplesRate;
|
||||
use SampleFormat;
|
||||
|
||||
|
@ -18,6 +19,26 @@ pub use self::voice::{Voice, Buffer};
|
|||
|
||||
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 enumerate;
|
||||
mod voice;
|
||||
|
@ -119,21 +140,57 @@ impl Endpoint {
|
|||
};
|
||||
|
||||
let format = {
|
||||
let data_type = match (*format_ptr).wFormatTag {
|
||||
winapi::WAVE_FORMAT_PCM => SampleFormat::I16,
|
||||
let (channels, data_type) = match (*format_ptr).wFormatTag {
|
||||
winapi::WAVE_FORMAT_PCM => {
|
||||
(
|
||||
vec![ChannelPosition::FrontLeft, ChannelPosition::FrontRight],
|
||||
SampleFormat::I16
|
||||
)
|
||||
},
|
||||
winapi::WAVE_FORMAT_EXTENSIBLE => {
|
||||
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_PCM => SampleFormat::I16,
|
||||
g => panic!("Unknown SubFormat GUID returned by GetMixFormat: {:?}", g)
|
||||
}
|
||||
};
|
||||
|
||||
(channels, format)
|
||||
},
|
||||
|
||||
f => panic!("Unknown data format returned by GetMixFormat: {:?}", f)
|
||||
};
|
||||
|
||||
Format {
|
||||
channels: (*format_ptr).nChannels,
|
||||
channels: channels,
|
||||
samples_rate: SamplesRate((*format_ptr).nSamplesPerSec),
|
||||
data_type: data_type,
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ use std::ptr;
|
|||
use std::marker::PhantomData;
|
||||
|
||||
use CreationError;
|
||||
use ChannelPosition;
|
||||
use Format;
|
||||
use SampleFormat;
|
||||
|
||||
|
@ -52,12 +53,12 @@ impl Voice {
|
|||
SampleFormat::F32 => winapi::WAVE_FORMAT_EXTENSIBLE,
|
||||
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,
|
||||
nAvgBytesPerSec: format.channels as winapi::DWORD *
|
||||
nAvgBytesPerSec: format.channels.len() as winapi::DWORD *
|
||||
format.samples_rate.0 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,
|
||||
wBitsPerSample: 8 * format.data_type.get_sample_size() as winapi::WORD,
|
||||
cbSize: match format.data_type {
|
||||
|
@ -68,7 +69,40 @@ impl Voice {
|
|||
},
|
||||
},
|
||||
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 {
|
||||
SampleFormat::I16 => winapi::KSDATAFORMAT_SUBTYPE_PCM,
|
||||
SampleFormat::F32 => winapi::KSDATAFORMAT_SUBTYPE_IEEE_FLOAT,
|
||||
|
|
Loading…
Reference in New Issue