Update wasapi backend for stream format renaming

This commit is contained in:
mitchmindtree 2020-01-28 00:26:15 +01:00
parent 669aada98a
commit e0da586f77
2 changed files with 61 additions and 55 deletions

View File

@ -1,6 +1,7 @@
use crate::{ use crate::{
BackendSpecificError, Data, DefaultFormatError, DeviceNameError, DevicesError, Format, BackendSpecificError, Data, DefaultStreamConfigError, DeviceNameError, DevicesError,
SampleFormat, SampleRate, SupportedFormat, SupportedFormatsError, COMMON_SAMPLE_RATES, SampleFormat, SampleRate, SupportedStreamConfig, SupportedStreamConfigRange,
SupportedStreamConfigsError, COMMON_SAMPLE_RATES,
}; };
use std; use std;
use std::ffi::OsString; use std::ffi::OsString;
@ -49,8 +50,8 @@ use super::{
}; };
use crate::{traits::DeviceTrait, BuildStreamError, StreamError}; use crate::{traits::DeviceTrait, BuildStreamError, StreamError};
pub type SupportedInputFormats = std::vec::IntoIter<SupportedFormat>; pub type SupportedInputConfigs = std::vec::IntoIter<SupportedStreamConfigRange>;
pub type SupportedOutputFormats = std::vec::IntoIter<SupportedFormat>; pub type SupportedOutputConfigs = std::vec::IntoIter<SupportedStreamConfigRange>;
/// Wrapper because of that stupid decision to remove `Send` and `Sync` from raw pointers. /// Wrapper because of that stupid decision to remove `Send` and `Sync` from raw pointers.
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
@ -67,37 +68,37 @@ pub struct Device {
} }
impl DeviceTrait for Device { impl DeviceTrait for Device {
type SupportedInputFormats = SupportedInputFormats; type SupportedInputConfigs = SupportedInputConfigs;
type SupportedOutputFormats = SupportedOutputFormats; type SupportedOutputConfigs = SupportedOutputConfigs;
type Stream = Stream; type Stream = Stream;
fn name(&self) -> Result<String, DeviceNameError> { fn name(&self) -> Result<String, DeviceNameError> {
Device::name(self) Device::name(self)
} }
fn supported_input_formats( fn supported_input_configs(
&self, &self,
) -> Result<Self::SupportedInputFormats, SupportedFormatsError> { ) -> Result<Self::SupportedInputConfigs, SupportedStreamConfigsError> {
Device::supported_input_formats(self) Device::supported_input_configs(self)
} }
fn supported_output_formats( fn supported_output_configs(
&self, &self,
) -> Result<Self::SupportedOutputFormats, SupportedFormatsError> { ) -> Result<Self::SupportedOutputConfigs, SupportedStreamConfigsError> {
Device::supported_output_formats(self) Device::supported_output_configs(self)
} }
fn default_input_format(&self) -> Result<Format, DefaultFormatError> { fn default_input_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError> {
Device::default_input_format(self) Device::default_input_config(self)
} }
fn default_output_format(&self) -> Result<Format, DefaultFormatError> { fn default_output_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError> {
Device::default_output_format(self) Device::default_output_config(self)
} }
fn build_input_stream_raw<D, E>( fn build_input_stream_raw<D, E>(
&self, &self,
format: &Format, config: &SupportedStreamConfig,
data_callback: D, data_callback: D,
error_callback: E, error_callback: E,
) -> Result<Self::Stream, BuildStreamError> ) -> Result<Self::Stream, BuildStreamError>
@ -105,7 +106,7 @@ impl DeviceTrait for Device {
D: FnMut(&Data) + Send + 'static, D: FnMut(&Data) + Send + 'static,
E: FnMut(StreamError) + Send + 'static, E: FnMut(StreamError) + Send + 'static,
{ {
let stream_inner = self.build_input_stream_raw_inner(format)?; let stream_inner = self.build_input_stream_raw_inner(config)?;
Ok(Stream::new_input( Ok(Stream::new_input(
stream_inner, stream_inner,
data_callback, data_callback,
@ -115,7 +116,7 @@ impl DeviceTrait for Device {
fn build_output_stream_raw<D, E>( fn build_output_stream_raw<D, E>(
&self, &self,
format: &Format, config: &SupportedStreamConfig,
data_callback: D, data_callback: D,
error_callback: E, error_callback: E,
) -> Result<Self::Stream, BuildStreamError> ) -> Result<Self::Stream, BuildStreamError>
@ -123,7 +124,7 @@ impl DeviceTrait for Device {
D: FnMut(&mut Data) + Send + 'static, D: FnMut(&mut Data) + Send + 'static,
E: FnMut(StreamError) + Send + 'static, E: FnMut(StreamError) + Send + 'static,
{ {
let stream_inner = self.build_output_stream_raw_inner(format)?; let stream_inner = self.build_output_stream_raw_inner(config)?;
Ok(Stream::new_output( Ok(Stream::new_output(
stream_inner, stream_inner,
data_callback, data_callback,
@ -214,7 +215,7 @@ unsafe fn data_flow_from_immendpoint(endpoint: *const IMMEndpoint) -> EDataFlow
pub unsafe fn is_format_supported( pub unsafe fn is_format_supported(
client: *const IAudioClient, client: *const IAudioClient,
waveformatex_ptr: *const mmreg::WAVEFORMATEX, waveformatex_ptr: *const mmreg::WAVEFORMATEX,
) -> Result<bool, SupportedFormatsError> { ) -> Result<bool, SupportedStreamConfigsError> {
/* /*
// `IsFormatSupported` checks whether the format is supported and fills // `IsFormatSupported` checks whether the format is supported and fills
// a `WAVEFORMATEX` // a `WAVEFORMATEX`
@ -258,7 +259,7 @@ pub unsafe fn is_format_supported(
// has been found, but not an exact match) so we also treat this as unsupported. // has been found, but not an exact match) so we also treat this as unsupported.
match (result, check_result(result)) { match (result, check_result(result)) {
(_, Err(ref e)) if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) => { (_, Err(ref e)) if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) => {
Err(SupportedFormatsError::DeviceNotAvailable) Err(SupportedStreamConfigsError::DeviceNotAvailable)
} }
(_, Err(_)) => Ok(false), (_, Err(_)) => Ok(false),
(winerror::S_FALSE, _) => Ok(false), (winerror::S_FALSE, _) => Ok(false),
@ -291,11 +292,11 @@ pub unsafe fn is_format_supported(
// Get a cpal Format from a WAVEFORMATEX. // Get a cpal Format from a WAVEFORMATEX.
unsafe fn format_from_waveformatex_ptr( unsafe fn format_from_waveformatex_ptr(
waveformatex_ptr: *const mmreg::WAVEFORMATEX, waveformatex_ptr: *const mmreg::WAVEFORMATEX,
) -> Option<Format> { ) -> Option<SupportedStreamConfig> {
fn cmp_guid(a: &GUID, b: &GUID) -> bool { fn cmp_guid(a: &GUID, b: &GUID) -> bool {
a.Data1 == b.Data1 && a.Data2 == b.Data2 && a.Data3 == b.Data3 && a.Data4 == b.Data4 a.Data1 == b.Data1 && a.Data2 == b.Data2 && a.Data3 == b.Data3 && a.Data4 == b.Data4
} }
let data_type = match ( let sample_format = match (
(*waveformatex_ptr).wBitsPerSample, (*waveformatex_ptr).wBitsPerSample,
(*waveformatex_ptr).wFormatTag, (*waveformatex_ptr).wFormatTag,
) { ) {
@ -315,10 +316,10 @@ unsafe fn format_from_waveformatex_ptr(
// Unknown data format returned by GetMixFormat. // Unknown data format returned by GetMixFormat.
_ => return None, _ => return None,
}; };
let format = Format { let format = SupportedStreamConfig {
channels: (*waveformatex_ptr).nChannels as _, channels: (*waveformatex_ptr).nChannels as _,
sample_rate: SampleRate((*waveformatex_ptr).nSamplesPerSec), sample_rate: SampleRate((*waveformatex_ptr).nSamplesPerSec),
data_type, sample_format,
}; };
Some(format) Some(format)
} }
@ -433,7 +434,7 @@ impl Device {
// number of channels seems to be supported. Any more or less returns an invalid // number of channels seems to be supported. Any more or less returns an invalid
// parameter error. Thus we just assume that the default number of channels is the only // parameter error. Thus we just assume that the default number of channels is the only
// number supported. // number supported.
fn supported_formats(&self) -> Result<SupportedInputFormats, SupportedFormatsError> { fn supported_formats(&self) -> Result<SupportedInputConfigs, SupportedStreamConfigsError> {
// initializing COM because we call `CoTaskMemFree` to release the format. // initializing COM because we call `CoTaskMemFree` to release the format.
com::com_initialized(); com::com_initialized();
@ -441,7 +442,7 @@ impl Device {
let lock = match self.ensure_future_audio_client() { let lock = match self.ensure_future_audio_client() {
Ok(lock) => lock, Ok(lock) => lock,
Err(ref e) if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) => { Err(ref e) if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) => {
return Err(SupportedFormatsError::DeviceNotAvailable) return Err(SupportedStreamConfigsError::DeviceNotAvailable)
} }
Err(e) => { Err(e) => {
let description = format!("{}", e); let description = format!("{}", e);
@ -457,7 +458,7 @@ impl Device {
match check_result((*client).GetMixFormat(&mut default_waveformatex_ptr.0)) { match check_result((*client).GetMixFormat(&mut default_waveformatex_ptr.0)) {
Ok(()) => (), Ok(()) => (),
Err(ref e) if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) => { Err(ref e) if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) => {
return Err(SupportedFormatsError::DeviceNotAvailable); return Err(SupportedStreamConfigsError::DeviceNotAvailable);
} }
Err(e) => { Err(e) => {
let description = format!("{}", e); let description = format!("{}", e);
@ -514,7 +515,8 @@ impl Device {
Some(fmt) => fmt, Some(fmt) => fmt,
None => { None => {
let description = let description =
"could not create a `cpal::Format` from a `WAVEFORMATEX`".to_string(); "could not create a `cpal::SupportedStreamConfig` from a `WAVEFORMATEX`"
.to_string();
let err = BackendSpecificError { description }; let err = BackendSpecificError { description };
return Err(err.into()); return Err(err.into());
} }
@ -522,13 +524,15 @@ impl Device {
let mut supported_formats = Vec::with_capacity(supported_sample_rates.len()); let mut supported_formats = Vec::with_capacity(supported_sample_rates.len());
for rate in supported_sample_rates { for rate in supported_sample_rates {
format.sample_rate = SampleRate(rate as _); format.sample_rate = SampleRate(rate as _);
supported_formats.push(SupportedFormat::from(format.clone())); supported_formats.push(SupportedStreamConfigRange::from(format.clone()));
} }
Ok(supported_formats.into_iter()) Ok(supported_formats.into_iter())
} }
} }
pub fn supported_input_formats(&self) -> Result<SupportedInputFormats, SupportedFormatsError> { pub fn supported_input_configs(
&self,
) -> Result<SupportedInputConfigs, SupportedStreamConfigsError> {
if self.data_flow() == eCapture { if self.data_flow() == eCapture {
self.supported_formats() self.supported_formats()
// If it's an output device, assume no input formats. // If it's an output device, assume no input formats.
@ -537,9 +541,9 @@ impl Device {
} }
} }
pub fn supported_output_formats( pub fn supported_output_configs(
&self, &self,
) -> Result<SupportedOutputFormats, SupportedFormatsError> { ) -> Result<SupportedOutputConfigs, SupportedStreamConfigsError> {
if self.data_flow() == eRender { if self.data_flow() == eRender {
self.supported_formats() self.supported_formats()
// If it's an input device, assume no output formats. // If it's an input device, assume no output formats.
@ -552,14 +556,14 @@ impl Device {
// processor to mix them together. // processor to mix them together.
// //
// One format is guaranteed to be supported, the one returned by `GetMixFormat`. // One format is guaranteed to be supported, the one returned by `GetMixFormat`.
fn default_format(&self) -> Result<Format, DefaultFormatError> { fn default_format(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError> {
// initializing COM because we call `CoTaskMemFree` // initializing COM because we call `CoTaskMemFree`
com::com_initialized(); com::com_initialized();
let lock = match self.ensure_future_audio_client() { let lock = match self.ensure_future_audio_client() {
Ok(lock) => lock, Ok(lock) => lock,
Err(ref e) if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) => { Err(ref e) if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) => {
return Err(DefaultFormatError::DeviceNotAvailable) return Err(DefaultStreamConfigError::DeviceNotAvailable)
} }
Err(e) => { Err(e) => {
let description = format!("{}", e); let description = format!("{}", e);
@ -573,7 +577,7 @@ impl Device {
let mut format_ptr = WaveFormatExPtr(ptr::null_mut()); let mut format_ptr = WaveFormatExPtr(ptr::null_mut());
match check_result((*client).GetMixFormat(&mut format_ptr.0)) { match check_result((*client).GetMixFormat(&mut format_ptr.0)) {
Err(ref e) if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) => { Err(ref e) if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) => {
return Err(DefaultFormatError::DeviceNotAvailable); return Err(DefaultStreamConfigError::DeviceNotAvailable);
} }
Err(e) => { Err(e) => {
let description = format!("{}", e); let description = format!("{}", e);
@ -584,7 +588,7 @@ impl Device {
}; };
format_from_waveformatex_ptr(format_ptr.0) format_from_waveformatex_ptr(format_ptr.0)
.ok_or(DefaultFormatError::StreamTypeNotSupported) .ok_or(DefaultStreamConfigError::StreamTypeNotSupported)
} }
} }
@ -593,26 +597,26 @@ impl Device {
endpoint.data_flow() endpoint.data_flow()
} }
pub fn default_input_format(&self) -> Result<Format, DefaultFormatError> { pub fn default_input_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError> {
if self.data_flow() == eCapture { if self.data_flow() == eCapture {
self.default_format() self.default_format()
} else { } else {
Err(DefaultFormatError::StreamTypeNotSupported) Err(DefaultStreamConfigError::StreamTypeNotSupported)
} }
} }
pub fn default_output_format(&self) -> Result<Format, DefaultFormatError> { pub fn default_output_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError> {
let data_flow = self.data_flow(); let data_flow = self.data_flow();
if data_flow == eRender { if data_flow == eRender {
self.default_format() self.default_format()
} else { } else {
Err(DefaultFormatError::StreamTypeNotSupported) Err(DefaultStreamConfigError::StreamTypeNotSupported)
} }
} }
pub(crate) fn build_input_stream_raw_inner( pub(crate) fn build_input_stream_raw_inner(
&self, &self,
format: &Format, format: &SupportedStreamConfig,
) -> Result<StreamInner, BuildStreamError> { ) -> Result<StreamInner, BuildStreamError> {
unsafe { unsafe {
// Making sure that COM is initialized. // Making sure that COM is initialized.
@ -749,14 +753,14 @@ impl Device {
playing: false, playing: false,
max_frames_in_buffer, max_frames_in_buffer,
bytes_per_frame: waveformatex.nBlockAlign, bytes_per_frame: waveformatex.nBlockAlign,
sample_format: format.data_type, sample_format: format.sample_format,
}) })
} }
} }
pub(crate) fn build_output_stream_raw_inner( pub(crate) fn build_output_stream_raw_inner(
&self, &self,
format: &Format, format: &SupportedStreamConfig,
) -> Result<StreamInner, BuildStreamError> { ) -> Result<StreamInner, BuildStreamError> {
unsafe { unsafe {
// Making sure that COM is initialized. // Making sure that COM is initialized.
@ -893,7 +897,7 @@ impl Device {
playing: false, playing: false,
max_frames_in_buffer, max_frames_in_buffer,
bytes_per_frame: waveformatex.nBlockAlign, bytes_per_frame: waveformatex.nBlockAlign,
sample_format: format.data_type, sample_format: format.sample_format,
}) })
} }
} }
@ -1141,19 +1145,21 @@ pub fn default_output_device() -> Option<Device> {
// Turns a `Format` into a `WAVEFORMATEXTENSIBLE`. // Turns a `Format` into a `WAVEFORMATEXTENSIBLE`.
// //
// Returns `None` if the WAVEFORMATEXTENSIBLE does not support the given format. // Returns `None` if the WAVEFORMATEXTENSIBLE does not support the given format.
fn format_to_waveformatextensible(format: &Format) -> Option<mmreg::WAVEFORMATEXTENSIBLE> { fn format_to_waveformatextensible(
let format_tag = match format.data_type { config: &SupportedStreamConfig,
) -> Option<mmreg::WAVEFORMATEXTENSIBLE> {
let format_tag = match config.sample_format {
SampleFormat::I16 => mmreg::WAVE_FORMAT_PCM, SampleFormat::I16 => mmreg::WAVE_FORMAT_PCM,
SampleFormat::F32 => mmreg::WAVE_FORMAT_EXTENSIBLE, SampleFormat::F32 => mmreg::WAVE_FORMAT_EXTENSIBLE,
SampleFormat::U16 => return None, SampleFormat::U16 => return None,
}; };
let channels = format.channels as WORD; let channels = config.channels as WORD;
let sample_rate = format.sample_rate.0 as DWORD; let sample_rate = config.sample_rate.0 as DWORD;
let sample_bytes = format.data_type.sample_size() as WORD; let sample_bytes = config.sample_format.sample_size() as WORD;
let avg_bytes_per_sec = u32::from(channels) * sample_rate * u32::from(sample_bytes); let avg_bytes_per_sec = u32::from(channels) * sample_rate * u32::from(sample_bytes);
let block_align = channels * sample_bytes; let block_align = channels * sample_bytes;
let bits_per_sample = 8 * sample_bytes; let bits_per_sample = 8 * sample_bytes;
let cb_size = match format.data_type { let cb_size = match config.sample_format {
SampleFormat::I16 => 0, SampleFormat::I16 => 0,
SampleFormat::F32 => { SampleFormat::F32 => {
let extensible_size = mem::size_of::<mmreg::WAVEFORMATEXTENSIBLE>(); let extensible_size = mem::size_of::<mmreg::WAVEFORMATEXTENSIBLE>();
@ -1177,7 +1183,7 @@ fn format_to_waveformatextensible(format: &Format) -> Option<mmreg::WAVEFORMATEX
const KSAUDIO_SPEAKER_DIRECTOUT: DWORD = 0; const KSAUDIO_SPEAKER_DIRECTOUT: DWORD = 0;
let channel_mask = KSAUDIO_SPEAKER_DIRECTOUT; let channel_mask = KSAUDIO_SPEAKER_DIRECTOUT;
let sub_format = match format.data_type { let sub_format = match config.sample_format {
SampleFormat::I16 => ksmedia::KSDATAFORMAT_SUBTYPE_PCM, SampleFormat::I16 => ksmedia::KSDATAFORMAT_SUBTYPE_PCM,
SampleFormat::F32 => ksmedia::KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, SampleFormat::F32 => ksmedia::KSDATAFORMAT_SUBTYPE_IEEE_FLOAT,
SampleFormat::U16 => return None, SampleFormat::U16 => return None,

View File

@ -1,8 +1,8 @@
extern crate winapi; extern crate winapi;
pub use self::device::{ pub use self::device::{
default_input_device, default_output_device, Device, Devices, SupportedInputFormats, default_input_device, default_output_device, Device, Devices, SupportedInputConfigs,
SupportedOutputFormats, SupportedOutputConfigs,
}; };
pub use self::stream::Stream; pub use self::stream::Stream;
use self::winapi::um::winnt::HRESULT; use self::winapi::um::winnt::HRESULT;