From e0da586f77e8246898425d3c4f33bb37c92a1179 Mon Sep 17 00:00:00 2001 From: mitchmindtree Date: Tue, 28 Jan 2020 00:26:15 +0100 Subject: [PATCH] Update wasapi backend for stream format renaming --- src/host/wasapi/device.rs | 112 ++++++++++++++++++++------------------ src/host/wasapi/mod.rs | 4 +- 2 files changed, 61 insertions(+), 55 deletions(-) diff --git a/src/host/wasapi/device.rs b/src/host/wasapi/device.rs index 69c82f2..65d6263 100644 --- a/src/host/wasapi/device.rs +++ b/src/host/wasapi/device.rs @@ -1,6 +1,7 @@ use crate::{ - BackendSpecificError, Data, DefaultFormatError, DeviceNameError, DevicesError, Format, - SampleFormat, SampleRate, SupportedFormat, SupportedFormatsError, COMMON_SAMPLE_RATES, + BackendSpecificError, Data, DefaultStreamConfigError, DeviceNameError, DevicesError, + SampleFormat, SampleRate, SupportedStreamConfig, SupportedStreamConfigRange, + SupportedStreamConfigsError, COMMON_SAMPLE_RATES, }; use std; use std::ffi::OsString; @@ -49,8 +50,8 @@ use super::{ }; use crate::{traits::DeviceTrait, BuildStreamError, StreamError}; -pub type SupportedInputFormats = std::vec::IntoIter; -pub type SupportedOutputFormats = std::vec::IntoIter; +pub type SupportedInputConfigs = std::vec::IntoIter; +pub type SupportedOutputConfigs = std::vec::IntoIter; /// Wrapper because of that stupid decision to remove `Send` and `Sync` from raw pointers. #[derive(Copy, Clone)] @@ -67,37 +68,37 @@ pub struct Device { } impl DeviceTrait for Device { - type SupportedInputFormats = SupportedInputFormats; - type SupportedOutputFormats = SupportedOutputFormats; + type SupportedInputConfigs = SupportedInputConfigs; + type SupportedOutputConfigs = SupportedOutputConfigs; type Stream = Stream; fn name(&self) -> Result { Device::name(self) } - fn supported_input_formats( + fn supported_input_configs( &self, - ) -> Result { - Device::supported_input_formats(self) + ) -> Result { + Device::supported_input_configs(self) } - fn supported_output_formats( + fn supported_output_configs( &self, - ) -> Result { - Device::supported_output_formats(self) + ) -> Result { + Device::supported_output_configs(self) } - fn default_input_format(&self) -> Result { - Device::default_input_format(self) + fn default_input_config(&self) -> Result { + Device::default_input_config(self) } - fn default_output_format(&self) -> Result { - Device::default_output_format(self) + fn default_output_config(&self) -> Result { + Device::default_output_config(self) } fn build_input_stream_raw( &self, - format: &Format, + config: &SupportedStreamConfig, data_callback: D, error_callback: E, ) -> Result @@ -105,7 +106,7 @@ impl DeviceTrait for Device { D: FnMut(&Data) + 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( stream_inner, data_callback, @@ -115,7 +116,7 @@ impl DeviceTrait for Device { fn build_output_stream_raw( &self, - format: &Format, + config: &SupportedStreamConfig, data_callback: D, error_callback: E, ) -> Result @@ -123,7 +124,7 @@ impl DeviceTrait for Device { D: FnMut(&mut Data) + 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( stream_inner, data_callback, @@ -214,7 +215,7 @@ unsafe fn data_flow_from_immendpoint(endpoint: *const IMMEndpoint) -> EDataFlow pub unsafe fn is_format_supported( client: *const IAudioClient, waveformatex_ptr: *const mmreg::WAVEFORMATEX, -) -> Result { +) -> Result { /* // `IsFormatSupported` checks whether the format is supported and fills // 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. match (result, check_result(result)) { (_, Err(ref e)) if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) => { - Err(SupportedFormatsError::DeviceNotAvailable) + Err(SupportedStreamConfigsError::DeviceNotAvailable) } (_, Err(_)) => Ok(false), (winerror::S_FALSE, _) => Ok(false), @@ -291,11 +292,11 @@ pub unsafe fn is_format_supported( // Get a cpal Format from a WAVEFORMATEX. unsafe fn format_from_waveformatex_ptr( waveformatex_ptr: *const mmreg::WAVEFORMATEX, -) -> Option { +) -> Option { fn cmp_guid(a: &GUID, b: &GUID) -> bool { 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).wFormatTag, ) { @@ -315,10 +316,10 @@ unsafe fn format_from_waveformatex_ptr( // Unknown data format returned by GetMixFormat. _ => return None, }; - let format = Format { + let format = SupportedStreamConfig { channels: (*waveformatex_ptr).nChannels as _, sample_rate: SampleRate((*waveformatex_ptr).nSamplesPerSec), - data_type, + sample_format, }; Some(format) } @@ -433,7 +434,7 @@ impl Device { // 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 // number supported. - fn supported_formats(&self) -> Result { + fn supported_formats(&self) -> Result { // initializing COM because we call `CoTaskMemFree` to release the format. com::com_initialized(); @@ -441,7 +442,7 @@ impl Device { let lock = match self.ensure_future_audio_client() { Ok(lock) => lock, Err(ref e) if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) => { - return Err(SupportedFormatsError::DeviceNotAvailable) + return Err(SupportedStreamConfigsError::DeviceNotAvailable) } Err(e) => { let description = format!("{}", e); @@ -457,7 +458,7 @@ impl Device { match check_result((*client).GetMixFormat(&mut default_waveformatex_ptr.0)) { Ok(()) => (), Err(ref e) if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) => { - return Err(SupportedFormatsError::DeviceNotAvailable); + return Err(SupportedStreamConfigsError::DeviceNotAvailable); } Err(e) => { let description = format!("{}", e); @@ -514,7 +515,8 @@ impl Device { Some(fmt) => fmt, None => { 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 }; return Err(err.into()); } @@ -522,13 +524,15 @@ impl Device { let mut supported_formats = Vec::with_capacity(supported_sample_rates.len()); for rate in supported_sample_rates { 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()) } } - pub fn supported_input_formats(&self) -> Result { + pub fn supported_input_configs( + &self, + ) -> Result { if self.data_flow() == eCapture { self.supported_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, - ) -> Result { + ) -> Result { if self.data_flow() == eRender { self.supported_formats() // If it's an input device, assume no output formats. @@ -552,14 +556,14 @@ impl Device { // processor to mix them together. // // One format is guaranteed to be supported, the one returned by `GetMixFormat`. - fn default_format(&self) -> Result { + fn default_format(&self) -> Result { // initializing COM because we call `CoTaskMemFree` com::com_initialized(); let lock = match self.ensure_future_audio_client() { Ok(lock) => lock, Err(ref e) if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) => { - return Err(DefaultFormatError::DeviceNotAvailable) + return Err(DefaultStreamConfigError::DeviceNotAvailable) } Err(e) => { let description = format!("{}", e); @@ -573,7 +577,7 @@ impl Device { let mut format_ptr = WaveFormatExPtr(ptr::null_mut()); match check_result((*client).GetMixFormat(&mut format_ptr.0)) { Err(ref e) if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) => { - return Err(DefaultFormatError::DeviceNotAvailable); + return Err(DefaultStreamConfigError::DeviceNotAvailable); } Err(e) => { let description = format!("{}", e); @@ -584,7 +588,7 @@ impl Device { }; format_from_waveformatex_ptr(format_ptr.0) - .ok_or(DefaultFormatError::StreamTypeNotSupported) + .ok_or(DefaultStreamConfigError::StreamTypeNotSupported) } } @@ -593,26 +597,26 @@ impl Device { endpoint.data_flow() } - pub fn default_input_format(&self) -> Result { + pub fn default_input_config(&self) -> Result { if self.data_flow() == eCapture { self.default_format() } else { - Err(DefaultFormatError::StreamTypeNotSupported) + Err(DefaultStreamConfigError::StreamTypeNotSupported) } } - pub fn default_output_format(&self) -> Result { + pub fn default_output_config(&self) -> Result { let data_flow = self.data_flow(); if data_flow == eRender { self.default_format() } else { - Err(DefaultFormatError::StreamTypeNotSupported) + Err(DefaultStreamConfigError::StreamTypeNotSupported) } } pub(crate) fn build_input_stream_raw_inner( &self, - format: &Format, + format: &SupportedStreamConfig, ) -> Result { unsafe { // Making sure that COM is initialized. @@ -749,14 +753,14 @@ impl Device { playing: false, max_frames_in_buffer, bytes_per_frame: waveformatex.nBlockAlign, - sample_format: format.data_type, + sample_format: format.sample_format, }) } } pub(crate) fn build_output_stream_raw_inner( &self, - format: &Format, + format: &SupportedStreamConfig, ) -> Result { unsafe { // Making sure that COM is initialized. @@ -893,7 +897,7 @@ impl Device { playing: false, max_frames_in_buffer, 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 { // Turns a `Format` into a `WAVEFORMATEXTENSIBLE`. // // Returns `None` if the WAVEFORMATEXTENSIBLE does not support the given format. -fn format_to_waveformatextensible(format: &Format) -> Option { - let format_tag = match format.data_type { +fn format_to_waveformatextensible( + config: &SupportedStreamConfig, +) -> Option { + let format_tag = match config.sample_format { SampleFormat::I16 => mmreg::WAVE_FORMAT_PCM, SampleFormat::F32 => mmreg::WAVE_FORMAT_EXTENSIBLE, SampleFormat::U16 => return None, }; - let channels = format.channels as WORD; - let sample_rate = format.sample_rate.0 as DWORD; - let sample_bytes = format.data_type.sample_size() as WORD; + let channels = config.channels as WORD; + let sample_rate = config.sample_rate.0 as DWORD; + 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 block_align = channels * 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::F32 => { let extensible_size = mem::size_of::(); @@ -1177,7 +1183,7 @@ fn format_to_waveformatextensible(format: &Format) -> Option ksmedia::KSDATAFORMAT_SUBTYPE_PCM, SampleFormat::F32 => ksmedia::KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, SampleFormat::U16 => return None, diff --git a/src/host/wasapi/mod.rs b/src/host/wasapi/mod.rs index 7fb6038..abf00a2 100644 --- a/src/host/wasapi/mod.rs +++ b/src/host/wasapi/mod.rs @@ -1,8 +1,8 @@ extern crate winapi; pub use self::device::{ - default_input_device, default_output_device, Device, Devices, SupportedInputFormats, - SupportedOutputFormats, + default_input_device, default_output_device, Device, Devices, SupportedInputConfigs, + SupportedOutputConfigs, }; pub use self::stream::Stream; use self::winapi::um::winnt::HRESULT;