`cargo fmt`

This commit is contained in:
Viktor Lazarev 2019-08-29 09:00:21 +02:00 committed by mitchmindtree
parent c62cb48e19
commit d4965d3673
4 changed files with 241 additions and 250 deletions

View File

@ -3,8 +3,8 @@
use super::check_result; use super::check_result;
use std::ptr; use std::ptr;
use super::winapi::um::objbase::{COINIT_MULTITHREADED};
use super::winapi::um::combaseapi::{CoInitializeEx, CoUninitialize}; use super::winapi::um::combaseapi::{CoInitializeEx, CoUninitialize};
use super::winapi::um::objbase::COINIT_MULTITHREADED;
thread_local!(static COM_INITIALIZED: ComInitialized = { thread_local!(static COM_INITIALIZED: ComInitialized = {
unsafe { unsafe {

View File

@ -14,65 +14,47 @@ use DefaultFormatError;
use DeviceNameError; use DeviceNameError;
use DevicesError; use DevicesError;
use Format; use Format;
use SupportedFormatsError;
use SampleFormat; use SampleFormat;
use SampleRate; use SampleRate;
use SupportedFormat; use SupportedFormat;
use SupportedFormatsError;
use COMMON_SAMPLE_RATES; use COMMON_SAMPLE_RATES;
use super::check_result; use super::check_result;
use super::check_result_backend_specific; use super::check_result_backend_specific;
use super::com; use super::com;
use super::winapi::Interface;
use super::winapi::ctypes::c_void; use super::winapi::ctypes::c_void;
use super::winapi::shared::devpkey; use super::winapi::shared::devpkey;
use super::winapi::shared::guiddef::GUID;
use super::winapi::shared::ksmedia; use super::winapi::shared::ksmedia;
use super::winapi::shared::guiddef::{ use super::winapi::shared::minwindef::{DWORD, WORD};
GUID,
};
use super::winapi::shared::winerror;
use super::winapi::shared::minwindef::{
DWORD,
WORD,
};
use super::winapi::shared::mmreg; use super::winapi::shared::mmreg;
use super::winapi::shared::winerror;
use super::winapi::shared::wtypes; use super::winapi::shared::wtypes;
use super::winapi::Interface;
// https://msdn.microsoft.com/en-us/library/cc230355.aspx // https://msdn.microsoft.com/en-us/library/cc230355.aspx
use super::winapi::um::winnt::LPWSTR;
use super::winapi::um::winnt::WCHAR;
use super::winapi::um::coml2api;
use super::winapi::um::audioclient::{ use super::winapi::um::audioclient::{
self, self, IAudioClient, IID_IAudioClient, AUDCLNT_E_DEVICE_INVALIDATED,
IAudioClient,
IID_IAudioClient,
AUDCLNT_E_DEVICE_INVALIDATED,
}; };
use super::winapi::um::audiosessiontypes::{ use super::winapi::um::audiosessiontypes::{
AUDCLNT_SHAREMODE_SHARED, AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
}; };
use super::winapi::um::combaseapi::{ use super::winapi::um::combaseapi::{
CoCreateInstance, CoCreateInstance, CoTaskMemFree, PropVariantClear, CLSCTX_ALL,
CoTaskMemFree,
CLSCTX_ALL,
PropVariantClear,
}; };
use super::winapi::um::coml2api;
use super::winapi::um::mmdeviceapi::{ use super::winapi::um::mmdeviceapi::{
eAll, eAll, eCapture, eConsole, eRender, CLSID_MMDeviceEnumerator, EDataFlow, IMMDevice,
eCapture, IMMDeviceCollection, IMMDeviceEnumerator, IMMEndpoint, DEVICE_STATE_ACTIVE,
eConsole,
eRender,
CLSID_MMDeviceEnumerator,
DEVICE_STATE_ACTIVE,
EDataFlow,
IMMDevice,
IMMDeviceCollection,
IMMDeviceEnumerator,
IMMEndpoint,
}; };
use super::winapi::um::winnt::LPWSTR;
use super::winapi::um::winnt::WCHAR;
use super::{
stream::{AudioClientFlow, Stream, StreamInner},
winapi::um::synchapi,
};
use crate::{traits::DeviceTrait, BuildStreamError, StreamData, StreamError}; use crate::{traits::DeviceTrait, BuildStreamError, StreamData, StreamError};
use super::{stream::{Stream, AudioClientFlow, StreamInner}, winapi::um::synchapi};
pub type SupportedInputFormats = std::vec::IntoIter<SupportedFormat>; pub type SupportedInputFormats = std::vec::IntoIter<SupportedFormat>;
pub type SupportedOutputFormats = std::vec::IntoIter<SupportedFormat>; pub type SupportedOutputFormats = std::vec::IntoIter<SupportedFormat>;
@ -80,10 +62,8 @@ pub type SupportedOutputFormats = std::vec::IntoIter<SupportedFormat>;
/// 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)]
struct IAudioClientWrapper(*mut IAudioClient); struct IAudioClientWrapper(*mut IAudioClient);
unsafe impl Send for IAudioClientWrapper { unsafe impl Send for IAudioClientWrapper {}
} unsafe impl Sync for IAudioClientWrapper {}
unsafe impl Sync for IAudioClientWrapper {
}
/// An opaque type that identifies an end point. /// An opaque type that identifies an end point.
pub struct Device { pub struct Device {
@ -102,11 +82,15 @@ impl DeviceTrait for Device {
Device::name(self) Device::name(self)
} }
fn supported_input_formats(&self) -> Result<Self::SupportedInputFormats, SupportedFormatsError> { fn supported_input_formats(
&self,
) -> Result<Self::SupportedInputFormats, SupportedFormatsError> {
Device::supported_input_formats(self) Device::supported_input_formats(self)
} }
fn supported_output_formats(&self) -> Result<Self::SupportedOutputFormats, SupportedFormatsError> { fn supported_output_formats(
&self,
) -> Result<Self::SupportedOutputFormats, SupportedFormatsError> {
Device::supported_output_formats(self) Device::supported_output_formats(self)
} }
@ -118,8 +102,16 @@ impl DeviceTrait for Device {
Device::default_output_format(self) Device::default_output_format(self)
} }
fn build_input_stream<D, E>(&self, format: &Format, data_callback: D, error_callback: E) -> Result<Self::Stream, BuildStreamError> fn build_input_stream<D, E>(
where D: FnMut(StreamData) + Send + 'static, E: FnMut(StreamError) + Send + 'static { &self,
format: &Format,
data_callback: D,
error_callback: E,
) -> Result<Self::Stream, BuildStreamError>
where
D: FnMut(StreamData) + Send + 'static,
E: FnMut(StreamError) + Send + 'static,
{
Ok(Stream::new( Ok(Stream::new(
Arc::new(self.build_input_stream_inner(format)?), Arc::new(self.build_input_stream_inner(format)?),
data_callback, data_callback,
@ -127,8 +119,16 @@ impl DeviceTrait for Device {
)) ))
} }
fn build_output_stream<D, E>(&self, format: &Format, data_callback: D, error_callback: E) -> Result<Self::Stream, BuildStreamError> fn build_output_stream<D, E>(
where D: FnMut(StreamData) + Send + 'static, E: FnMut(StreamError) + Send + 'static { &self,
format: &Format,
data_callback: D,
error_callback: E,
) -> Result<Self::Stream, BuildStreamError>
where
D: FnMut(StreamData) + Send + 'static,
E: FnMut(StreamError) + Send + 'static,
{
Ok(Stream::new( Ok(Stream::new(
Arc::new(self.build_output_stream_inner(format)?), Arc::new(self.build_output_stream_inner(format)?),
data_callback, data_callback,
@ -157,7 +157,6 @@ impl Drop for WaveFormatExPtr {
} }
} }
impl WaveFormat { impl WaveFormat {
// Given a pointer to some format, returns a valid copy of the format. // Given a pointer to some format, returns a valid copy of the format.
pub fn copy_from_waveformatex_ptr(ptr: *const mmreg::WAVEFORMATEX) -> Option<Self> { pub fn copy_from_waveformatex_ptr(ptr: *const mmreg::WAVEFORMATEX) -> Option<Self> {
@ -165,11 +164,11 @@ impl WaveFormat {
match (*ptr).wFormatTag { match (*ptr).wFormatTag {
mmreg::WAVE_FORMAT_PCM | mmreg::WAVE_FORMAT_IEEE_FLOAT => { mmreg::WAVE_FORMAT_PCM | mmreg::WAVE_FORMAT_IEEE_FLOAT => {
Some(WaveFormat::Ex(*ptr)) Some(WaveFormat::Ex(*ptr))
}, }
mmreg::WAVE_FORMAT_EXTENSIBLE => { mmreg::WAVE_FORMAT_EXTENSIBLE => {
let extensible_ptr = ptr as *const mmreg::WAVEFORMATEXTENSIBLE; let extensible_ptr = ptr as *const mmreg::WAVEFORMATEXTENSIBLE;
Some(WaveFormat::Extensible(*extensible_ptr)) Some(WaveFormat::Extensible(*extensible_ptr))
}, }
_ => None, _ => None,
} }
} }
@ -200,11 +199,12 @@ impl DerefMut for WaveFormat {
} }
} }
unsafe fn immendpoint_from_immdevice(device: *const IMMDevice) -> *mut IMMEndpoint { unsafe fn immendpoint_from_immdevice(device: *const IMMDevice) -> *mut IMMEndpoint {
let mut endpoint: *mut IMMEndpoint = mem::uninitialized(); let mut endpoint: *mut IMMEndpoint = mem::uninitialized();
check_result((*device).QueryInterface(&IMMEndpoint::uuidof(), &mut endpoint as *mut _ as *mut _)) check_result(
.expect("could not query IMMDevice interface for IMMEndpoint"); (*device).QueryInterface(&IMMEndpoint::uuidof(), &mut endpoint as *mut _ as *mut _),
)
.expect("could not query IMMDevice interface for IMMEndpoint");
endpoint endpoint
} }
@ -219,10 +219,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, SupportedFormatsError> {
{
/* /*
// `IsFormatSupported` checks whether the format is supported and fills // `IsFormatSupported` checks whether the format is supported and fills
// a `WAVEFORMATEX` // a `WAVEFORMATEX`
@ -255,7 +252,6 @@ pub unsafe fn is_format_supported(
}; };
*/ */
// Check if the given format is supported. // Check if the given format is supported.
let is_supported = |waveformatex_ptr, mut closest_waveformatex_ptr| { let is_supported = |waveformatex_ptr, mut closest_waveformatex_ptr| {
let result = (*client).IsFormatSupported( let result = (*client).IsFormatSupported(
@ -268,16 +264,10 @@ pub unsafe fn is_format_supported(
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(SupportedFormatsError::DeviceNotAvailable)
}, }
(_, Err(_)) => { (_, Err(_)) => Ok(false),
Ok(false) (winerror::S_FALSE, _) => Ok(false),
}, (_, Ok(())) => Ok(true),
(winerror::S_FALSE, _) => {
Ok(false)
},
(_, Ok(())) => {
Ok(true)
},
} }
}; };
@ -290,34 +280,30 @@ pub unsafe fn is_format_supported(
let mut closest_waveformatex = *waveformatex_ptr; let mut closest_waveformatex = *waveformatex_ptr;
let closest_waveformatex_ptr = &mut closest_waveformatex as *mut _; let closest_waveformatex_ptr = &mut closest_waveformatex as *mut _;
is_supported(waveformatex_ptr, closest_waveformatex_ptr) is_supported(waveformatex_ptr, closest_waveformatex_ptr)
}, }
mmreg::WAVE_FORMAT_EXTENSIBLE => { mmreg::WAVE_FORMAT_EXTENSIBLE => {
let waveformatextensible_ptr = let waveformatextensible_ptr = waveformatex_ptr as *const mmreg::WAVEFORMATEXTENSIBLE;
waveformatex_ptr as *const mmreg::WAVEFORMATEXTENSIBLE;
let mut closest_waveformatextensible = *waveformatextensible_ptr; let mut closest_waveformatextensible = *waveformatextensible_ptr;
let closest_waveformatextensible_ptr = let closest_waveformatextensible_ptr = &mut closest_waveformatextensible as *mut _;
&mut closest_waveformatextensible as *mut _;
let closest_waveformatex_ptr = let closest_waveformatex_ptr =
closest_waveformatextensible_ptr as *mut mmreg::WAVEFORMATEX; closest_waveformatextensible_ptr as *mut mmreg::WAVEFORMATEX;
is_supported(waveformatex_ptr, closest_waveformatex_ptr) is_supported(waveformatex_ptr, closest_waveformatex_ptr)
}, }
_ => Ok(false), _ => Ok(false),
} }
} }
// 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<Format> {
{
fn cmp_guid(a: &GUID, b: &GUID) -> bool { fn cmp_guid(a: &GUID, b: &GUID) -> bool {
a.Data1 == b.Data1 a.Data1 == b.Data1 && a.Data2 == b.Data2 && a.Data3 == b.Data3 && a.Data4 == b.Data4
&& a.Data2 == b.Data2
&& a.Data3 == b.Data3
&& a.Data4 == b.Data4
} }
let data_type = match ((*waveformatex_ptr).wBitsPerSample, (*waveformatex_ptr).wFormatTag) { let data_type = match (
(*waveformatex_ptr).wBitsPerSample,
(*waveformatex_ptr).wFormatTag,
) {
(16, mmreg::WAVE_FORMAT_PCM) => SampleFormat::I16, (16, mmreg::WAVE_FORMAT_PCM) => SampleFormat::I16,
(32, mmreg::WAVE_FORMAT_IEEE_FLOAT) => SampleFormat::F32, (32, mmreg::WAVE_FORMAT_IEEE_FLOAT) => SampleFormat::F32,
(n_bits, mmreg::WAVE_FORMAT_EXTENSIBLE) => { (n_bits, mmreg::WAVE_FORMAT_EXTENSIBLE) => {
@ -330,7 +316,7 @@ unsafe fn format_from_waveformatex_ptr(
} else { } else {
return None; return None;
} }
}, }
// Unknown data format returned by GetMixFormat. // Unknown data format returned by GetMixFormat.
_ => return None, _ => return None,
}; };
@ -342,10 +328,8 @@ unsafe fn format_from_waveformatex_ptr(
Some(format) Some(format)
} }
unsafe impl Send for Device { unsafe impl Send for Device {}
} unsafe impl Sync for Device {}
unsafe impl Sync for Device {
}
impl Device { impl Device {
pub fn name(&self) -> Result<String, DeviceNameError> { pub fn name(&self) -> Result<String, DeviceNameError> {
@ -356,12 +340,10 @@ impl Device {
// Get the endpoint's friendly-name property. // Get the endpoint's friendly-name property.
let mut property_value = mem::zeroed(); let mut property_value = mem::zeroed();
if let Err(err) = check_result( if let Err(err) = check_result((*property_store).GetValue(
(*property_store).GetValue( &devpkey::DEVPKEY_Device_FriendlyName as *const _ as *const _,
&devpkey::DEVPKEY_Device_FriendlyName as *const _ as *const _, &mut property_value,
&mut property_value )) {
)
) {
let description = format!("failed to retrieve name from property store: {}", err); let description = format!("failed to retrieve name from property store: {}", err);
let err = BackendSpecificError { description }; let err = BackendSpecificError { description };
return Err(err.into()); return Err(err.into());
@ -369,8 +351,10 @@ impl Device {
// Read the friendly-name from the union data field, expecting a *const u16. // Read the friendly-name from the union data field, expecting a *const u16.
if property_value.vt != wtypes::VT_LPWSTR as _ { if property_value.vt != wtypes::VT_LPWSTR as _ {
let description = let description = format!(
format!("property store produced invalid data: {:?}", property_value.vt); "property store produced invalid data: {:?}",
property_value.vt
);
let err = BackendSpecificError { description }; let err = BackendSpecificError { description };
return Err(err.into()); return Err(err.into());
} }
@ -407,8 +391,9 @@ impl Device {
} }
/// Ensures that `future_audio_client` contains a `Some` and returns a locked mutex to it. /// Ensures that `future_audio_client` contains a `Some` and returns a locked mutex to it.
fn ensure_future_audio_client(&self) fn ensure_future_audio_client(
-> Result<MutexGuard<Option<IAudioClientWrapper>>, IoError> { &self,
) -> Result<MutexGuard<Option<IAudioClientWrapper>>, IoError> {
let mut lock = self.future_audio_client.lock().unwrap(); let mut lock = self.future_audio_client.lock().unwrap();
if lock.is_some() { if lock.is_some() {
return Ok(lock); return Ok(lock);
@ -416,10 +401,12 @@ impl Device {
let audio_client: *mut IAudioClient = unsafe { let audio_client: *mut IAudioClient = unsafe {
let mut audio_client = mem::uninitialized(); let mut audio_client = mem::uninitialized();
let hresult = (*self.device).Activate(&IID_IAudioClient, let hresult = (*self.device).Activate(
CLSCTX_ALL, &IID_IAudioClient,
ptr::null_mut(), CLSCTX_ALL,
&mut audio_client); ptr::null_mut(),
&mut audio_client,
);
// can fail if the device has been disconnected since we enumerated it, or if // can fail if the device has been disconnected since we enumerated it, or if
// the device doesn't support playback for some reason // the device doesn't support playback for some reason
@ -466,7 +453,7 @@ impl Device {
let description = format!("{}", e); let description = format!("{}", e);
let err = BackendSpecificError { description }; let err = BackendSpecificError { description };
return Err(err.into()); return Err(err.into());
}, }
}; };
let client = lock.unwrap().0; let client = lock.unwrap().0;
@ -477,16 +464,19 @@ impl Device {
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(SupportedFormatsError::DeviceNotAvailable);
}, }
Err(e) => { Err(e) => {
let description = format!("{}", e); let description = format!("{}", e);
let err = BackendSpecificError { description }; let err = BackendSpecificError { description };
return Err(err.into()); return Err(err.into());
}, }
}; };
// If the default format can't succeed we have no hope of finding other formats. // If the default format can't succeed we have no hope of finding other formats.
assert_eq!(is_format_supported(client, default_waveformatex_ptr.0)?, true); assert_eq!(
is_format_supported(client, default_waveformatex_ptr.0)?,
true
);
// Copy the format to use as a test format (as to avoid mutating the original format). // Copy the format to use as a test format (as to avoid mutating the original format).
let mut test_format = { let mut test_format = {
@ -553,7 +543,9 @@ impl Device {
} }
} }
pub fn supported_output_formats(&self) -> Result<SupportedOutputFormats, SupportedFormatsError> { pub fn supported_output_formats(
&self,
) -> Result<SupportedOutputFormats, SupportedFormatsError> {
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.
@ -588,12 +580,12 @@ impl Device {
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(DefaultFormatError::DeviceNotAvailable);
}, }
Err(e) => { Err(e) => {
let description = format!("{}", e); let description = format!("{}", e);
let err = BackendSpecificError { description }; let err = BackendSpecificError { description };
return Err(err.into()); return Err(err.into());
}, }
Ok(()) => (), Ok(()) => (),
}; };
@ -623,12 +615,11 @@ impl Device {
Err(DefaultFormatError::StreamTypeNotSupported) Err(DefaultFormatError::StreamTypeNotSupported)
} }
} }
pub(crate) fn build_input_stream_inner( pub(crate) fn build_input_stream_inner(
&self, &self,
format: &Format, format: &Format,
) -> Result<StreamInner, BuildStreamError> ) -> Result<StreamInner, BuildStreamError> {
{
unsafe { unsafe {
// Making sure that COM is initialized. // Making sure that COM is initialized.
// It's not actually sure that this is required, but when in doubt do it. // It's not actually sure that this is required, but when in doubt do it.
@ -637,8 +628,9 @@ impl Device {
// Obtaining a `IAudioClient`. // Obtaining a `IAudioClient`.
let audio_client = match self.build_audioclient() { let audio_client = match self.build_audioclient() {
Ok(client) => client, Ok(client) => client,
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(BuildStreamError::DeviceNotAvailable), return Err(BuildStreamError::DeviceNotAvailable)
}
Err(e) => { Err(e) => {
let description = format!("{}", e); let description = format!("{}", e);
let err = BackendSpecificError { description }; let err = BackendSpecificError { description };
@ -669,17 +661,16 @@ impl Device {
ptr::null(), ptr::null(),
); );
match check_result(hresult) { match check_result(hresult) {
Err(ref e) Err(ref e) if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) => {
if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) => {
(*audio_client).Release(); (*audio_client).Release();
return Err(BuildStreamError::DeviceNotAvailable); return Err(BuildStreamError::DeviceNotAvailable);
}, }
Err(e) => { Err(e) => {
(*audio_client).Release(); (*audio_client).Release();
let description = format!("{}", e); let description = format!("{}", e);
let err = BackendSpecificError { description }; let err = BackendSpecificError { description };
return Err(err.into()); return Err(err.into());
}, }
Ok(()) => (), Ok(()) => (),
}; };
@ -692,17 +683,16 @@ impl Device {
let hresult = (*audio_client).GetBufferSize(&mut max_frames_in_buffer); let hresult = (*audio_client).GetBufferSize(&mut max_frames_in_buffer);
match check_result(hresult) { match check_result(hresult) {
Err(ref e) Err(ref e) if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) => {
if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) => {
(*audio_client).Release(); (*audio_client).Release();
return Err(BuildStreamError::DeviceNotAvailable); return Err(BuildStreamError::DeviceNotAvailable);
}, }
Err(e) => { Err(e) => {
(*audio_client).Release(); (*audio_client).Release();
let description = format!("{}", e); let description = format!("{}", e);
let err = BackendSpecificError { description }; let err = BackendSpecificError { description };
return Err(err.into()); return Err(err.into());
}, }
Ok(()) => (), Ok(()) => (),
}; };
@ -731,24 +721,24 @@ impl Device {
// Building a `IAudioCaptureClient` that will be used to read captured samples. // Building a `IAudioCaptureClient` that will be used to read captured samples.
let capture_client = { let capture_client = {
let mut capture_client: *mut audioclient::IAudioCaptureClient = mem::uninitialized(); let mut capture_client: *mut audioclient::IAudioCaptureClient =
mem::uninitialized();
let hresult = (*audio_client).GetService( let hresult = (*audio_client).GetService(
&audioclient::IID_IAudioCaptureClient, &audioclient::IID_IAudioCaptureClient,
&mut capture_client as *mut *mut audioclient::IAudioCaptureClient as *mut _, &mut capture_client as *mut *mut audioclient::IAudioCaptureClient as *mut _,
); );
match check_result(hresult) { match check_result(hresult) {
Err(ref e) Err(ref e) if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) => {
if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) => {
(*audio_client).Release(); (*audio_client).Release();
return Err(BuildStreamError::DeviceNotAvailable); return Err(BuildStreamError::DeviceNotAvailable);
}, }
Err(e) => { Err(e) => {
(*audio_client).Release(); (*audio_client).Release();
let description = format!("failed to build capture client: {}", e); let description = format!("failed to build capture client: {}", e);
let err = BackendSpecificError { description }; let err = BackendSpecificError { description };
return Err(err.into()); return Err(err.into());
}, }
Ok(()) => (), Ok(()) => (),
}; };
@ -757,11 +747,9 @@ impl Device {
// Once we built the `StreamInner`, we add a command that will be picked up by the // Once we built the `StreamInner`, we add a command that will be picked up by the
// `run()` method and added to the `RunContext`. // `run()` method and added to the `RunContext`.
let client_flow = AudioClientFlow::Capture { let client_flow = AudioClientFlow::Capture { capture_client };
capture_client,
};
Ok( StreamInner { Ok(StreamInner {
audio_client, audio_client,
client_flow, client_flow,
event, event,
@ -776,8 +764,7 @@ impl Device {
pub(crate) fn build_output_stream_inner( pub(crate) fn build_output_stream_inner(
&self, &self,
format: &Format, format: &Format,
) -> Result<StreamInner, BuildStreamError> ) -> Result<StreamInner, BuildStreamError> {
{
unsafe { unsafe {
// Making sure that COM is initialized. // Making sure that COM is initialized.
// It's not actually sure that this is required, but when in doubt do it. // It's not actually sure that this is required, but when in doubt do it.
@ -786,8 +773,9 @@ impl Device {
// Obtaining a `IAudioClient`. // Obtaining a `IAudioClient`.
let audio_client = match self.build_audioclient() { let audio_client = match self.build_audioclient() {
Ok(client) => client, Ok(client) => client,
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(BuildStreamError::DeviceNotAvailable), return Err(BuildStreamError::DeviceNotAvailable)
}
Err(e) => { Err(e) => {
let description = format!("{}", e); let description = format!("{}", e);
let err = BackendSpecificError { description }; let err = BackendSpecificError { description };
@ -809,24 +797,25 @@ impl Device {
} }
// finally initializing the audio client // finally initializing the audio client
let hresult = (*audio_client).Initialize(share_mode, let hresult = (*audio_client).Initialize(
AUDCLNT_STREAMFLAGS_EVENTCALLBACK, share_mode,
0, AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
0, 0,
&format_attempt.Format, 0,
ptr::null()); &format_attempt.Format,
ptr::null(),
);
match check_result(hresult) { match check_result(hresult) {
Err(ref e) Err(ref e) if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) => {
if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) => {
(*audio_client).Release(); (*audio_client).Release();
return Err(BuildStreamError::DeviceNotAvailable); return Err(BuildStreamError::DeviceNotAvailable);
}, }
Err(e) => { Err(e) => {
(*audio_client).Release(); (*audio_client).Release();
let description = format!("{}", e); let description = format!("{}", e);
let err = BackendSpecificError { description }; let err = BackendSpecificError { description };
return Err(err.into()); return Err(err.into());
}, }
Ok(()) => (), Ok(()) => (),
}; };
@ -849,7 +838,7 @@ impl Device {
let description = format!("failed to call SetEventHandle: {}", e); let description = format!("failed to call SetEventHandle: {}", e);
let err = BackendSpecificError { description }; let err = BackendSpecificError { description };
return Err(err.into()); return Err(err.into());
}, }
Ok(_) => (), Ok(_) => (),
}; };
@ -862,17 +851,16 @@ impl Device {
let hresult = (*audio_client).GetBufferSize(&mut max_frames_in_buffer); let hresult = (*audio_client).GetBufferSize(&mut max_frames_in_buffer);
match check_result(hresult) { match check_result(hresult) {
Err(ref e) Err(ref e) if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) => {
if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) => {
(*audio_client).Release(); (*audio_client).Release();
return Err(BuildStreamError::DeviceNotAvailable); return Err(BuildStreamError::DeviceNotAvailable);
}, }
Err(e) => { Err(e) => {
(*audio_client).Release(); (*audio_client).Release();
let description = format!("failed to obtain buffer size: {}", e); let description = format!("failed to obtain buffer size: {}", e);
let err = BackendSpecificError { description }; let err = BackendSpecificError { description };
return Err(err.into()); return Err(err.into());
}, }
Ok(()) => (), Ok(()) => (),
}; };
@ -882,23 +870,22 @@ impl Device {
// Building a `IAudioRenderClient` that will be used to fill the samples buffer. // Building a `IAudioRenderClient` that will be used to fill the samples buffer.
let render_client = { let render_client = {
let mut render_client: *mut audioclient::IAudioRenderClient = mem::uninitialized(); let mut render_client: *mut audioclient::IAudioRenderClient = mem::uninitialized();
let hresult = (*audio_client).GetService(&audioclient::IID_IAudioRenderClient, let hresult = (*audio_client).GetService(
&mut render_client as &audioclient::IID_IAudioRenderClient,
*mut *mut audioclient::IAudioRenderClient as &mut render_client as *mut *mut audioclient::IAudioRenderClient as *mut _,
*mut _); );
match check_result(hresult) { match check_result(hresult) {
Err(ref e) Err(ref e) if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) => {
if e.raw_os_error() == Some(AUDCLNT_E_DEVICE_INVALIDATED) => {
(*audio_client).Release(); (*audio_client).Release();
return Err(BuildStreamError::DeviceNotAvailable); return Err(BuildStreamError::DeviceNotAvailable);
}, }
Err(e) => { Err(e) => {
(*audio_client).Release(); (*audio_client).Release();
let description = format!("failed to build render client: {}", e); let description = format!("failed to build render client: {}", e);
let err = BackendSpecificError { description }; let err = BackendSpecificError { description };
return Err(err.into()); return Err(err.into());
}, }
Ok(()) => (), Ok(()) => (),
}; };
@ -907,9 +894,7 @@ impl Device {
// Once we built the `StreamInner`, we add a command that will be picked up by the // Once we built the `StreamInner`, we add a command that will be picked up by the
// `run()` method and added to the `RunContext`. // `run()` method and added to the `RunContext`.
let client_flow = AudioClientFlow::Render { let client_flow = AudioClientFlow::Render { render_client };
render_client,
};
Ok(StreamInner { Ok(StreamInner {
audio_client, audio_client,
@ -935,38 +920,45 @@ impl PartialEq for Device {
// In this code section we're trying to use the GetId method for the device comparison, cf. // In this code section we're trying to use the GetId method for the device comparison, cf.
// https://docs.microsoft.com/en-us/windows/desktop/api/mmdeviceapi/nf-mmdeviceapi-immdevice-getid // https://docs.microsoft.com/en-us/windows/desktop/api/mmdeviceapi/nf-mmdeviceapi-immdevice-getid
unsafe { unsafe {
struct IdRAII (LPWSTR); struct IdRAII(LPWSTR);
/// RAII for device IDs. /// RAII for device IDs.
impl Drop for IdRAII { impl Drop for IdRAII {
fn drop(&mut self) { fn drop(&mut self) {
unsafe {CoTaskMemFree(self.0 as *mut c_void)} unsafe { CoTaskMemFree(self.0 as *mut c_void) }
} }
} }
let mut id1: LPWSTR = ptr::null_mut(); let mut id1: LPWSTR = ptr::null_mut();
let rc1 = (*self.device).GetId(&mut id1); let rc1 = (*self.device).GetId(&mut id1);
// GetId only fails with E_OUTOFMEMORY and if it does, we're probably dead already. // GetId only fails with E_OUTOFMEMORY and if it does, we're probably dead already.
// Plus it won't do to change the device comparison logic unexpectedly. // Plus it won't do to change the device comparison logic unexpectedly.
if rc1 != winerror::S_OK {panic! ("cpal: GetId failure: {}", rc1)} if rc1 != winerror::S_OK {
panic!("cpal: GetId failure: {}", rc1)
}
let id1 = IdRAII(id1); let id1 = IdRAII(id1);
let mut id2: LPWSTR = ptr::null_mut(); let mut id2: LPWSTR = ptr::null_mut();
let rc2 = (*other.device).GetId(&mut id2); let rc2 = (*other.device).GetId(&mut id2);
if rc2 != winerror::S_OK {panic! ("cpal: GetId failure: {}", rc1)} if rc2 != winerror::S_OK {
panic!("cpal: GetId failure: {}", rc1)
}
let id2 = IdRAII(id2); let id2 = IdRAII(id2);
// 16-bit null-terminated comparison. // 16-bit null-terminated comparison.
let mut offset = 0; let mut offset = 0;
loop { loop {
let w1: WCHAR = *id1.0.offset(offset); let w1: WCHAR = *id1.0.offset(offset);
let w2: WCHAR = *id2.0.offset(offset); let w2: WCHAR = *id2.0.offset(offset);
if w1 == 0 && w2 == 0 {return true} if w1 == 0 && w2 == 0 {
if w1 != w2 {return false} return true;
}
if w1 != w2 {
return false;
}
offset += 1; offset += 1;
} }
} }
} }
} }
impl Eq for Device { impl Eq for Device {}
}
impl Clone for Device { impl Clone for Device {
#[inline] #[inline]
@ -1025,9 +1017,7 @@ impl From<*const IMMDevice> for Endpoint {
impl Endpoint { impl Endpoint {
fn data_flow(&self) -> EDataFlow { fn data_flow(&self) -> EDataFlow {
unsafe { unsafe { data_flow_from_immendpoint(self.endpoint) }
data_flow_from_immendpoint(self.endpoint)
}
} }
} }
@ -1058,10 +1048,8 @@ lazy_static! {
/// RAII object around `IMMDeviceEnumerator`. /// RAII object around `IMMDeviceEnumerator`.
struct Enumerator(*mut IMMDeviceEnumerator); struct Enumerator(*mut IMMDeviceEnumerator);
unsafe impl Send for Enumerator { unsafe impl Send for Enumerator {}
} unsafe impl Sync for Enumerator {}
unsafe impl Sync for Enumerator {
}
impl Drop for Enumerator { impl Drop for Enumerator {
#[inline] #[inline]
@ -1084,13 +1072,11 @@ impl Devices {
unsafe { unsafe {
let mut collection: *mut IMMDeviceCollection = mem::uninitialized(); let mut collection: *mut IMMDeviceCollection = mem::uninitialized();
// can fail because of wrong parameters (should never happen) or out of memory // can fail because of wrong parameters (should never happen) or out of memory
check_result_backend_specific( check_result_backend_specific((*ENUMERATOR.0).EnumAudioEndpoints(
(*ENUMERATOR.0).EnumAudioEndpoints( eAll,
eAll, DEVICE_STATE_ACTIVE,
DEVICE_STATE_ACTIVE, &mut collection,
&mut collection, ))?;
)
)?;
let mut count = mem::uninitialized(); let mut count = mem::uninitialized();
// can fail if the parameter is null, which should never happen // can fail if the parameter is null, which should never happen
@ -1105,10 +1091,8 @@ impl Devices {
} }
} }
unsafe impl Send for Devices { unsafe impl Send for Devices {}
} unsafe impl Sync for Devices {}
unsafe impl Sync for Devices {
}
impl Drop for Devices { impl Drop for Devices {
#[inline] #[inline]
@ -1148,8 +1132,7 @@ impl Iterator for Devices {
fn default_device(data_flow: EDataFlow) -> Option<Device> { fn default_device(data_flow: EDataFlow) -> Option<Device> {
unsafe { unsafe {
let mut device = mem::uninitialized(); let mut device = mem::uninitialized();
let hres = (*ENUMERATOR.0) let hres = (*ENUMERATOR.0).GetDefaultAudioEndpoint(data_flow, eConsole, &mut device);
.GetDefaultAudioEndpoint(data_flow, eConsole, &mut device);
if let Err(_err) = check_result(hres) { if let Err(_err) = check_result(hres) {
return None; // TODO: check specifically for `E_NOTFOUND`, and panic otherwise return None; // TODO: check specifically for `E_NOTFOUND`, and panic otherwise
} }
@ -1165,7 +1148,6 @@ pub fn default_output_device() -> Option<Device> {
default_device(eRender) default_device(eRender)
} }
// 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.
@ -1187,7 +1169,7 @@ fn format_to_waveformatextensible(format: &Format) -> Option<mmreg::WAVEFORMATEX
let extensible_size = mem::size_of::<mmreg::WAVEFORMATEXTENSIBLE>(); let extensible_size = mem::size_of::<mmreg::WAVEFORMATEXTENSIBLE>();
let ex_size = mem::size_of::<mmreg::WAVEFORMATEX>(); let ex_size = mem::size_of::<mmreg::WAVEFORMATEX>();
(extensible_size - ex_size) as WORD (extensible_size - ex_size) as WORD
}, }
SampleFormat::U16 => return None, SampleFormat::U16 => return None,
}; };
let waveformatex = mmreg::WAVEFORMATEX { let waveformatex = mmreg::WAVEFORMATEX {

View File

@ -1,12 +1,15 @@
extern crate winapi; extern crate winapi;
use BackendSpecificError; pub use self::device::{
use DevicesError; default_input_device, default_output_device, Device, Devices, SupportedInputFormats,
SupportedOutputFormats,
};
pub use self::stream::Stream;
use self::winapi::um::winnt::HRESULT; use self::winapi::um::winnt::HRESULT;
use std::io::Error as IoError; use std::io::Error as IoError;
use traits::{HostTrait}; use traits::HostTrait;
pub use self::device::{Device, Devices, SupportedInputFormats, SupportedOutputFormats, default_input_device, default_output_device}; use BackendSpecificError;
pub use self::stream::Stream; use DevicesError;
mod com; mod com;
mod device; mod device;
@ -60,10 +63,8 @@ fn check_result(result: HRESULT) -> Result<(), IoError> {
fn check_result_backend_specific(result: HRESULT) -> Result<(), BackendSpecificError> { fn check_result_backend_specific(result: HRESULT) -> Result<(), BackendSpecificError> {
match check_result(result) { match check_result(result) {
Ok(()) => Ok(()), Ok(()) => Ok(()),
Err(err) => { Err(err) => Err(BackendSpecificError {
Err(BackendSpecificError { description: format!("{}", err),
description: format!("{}", err), }),
})
}
} }
} }

View File

@ -10,11 +10,13 @@ use super::winapi::um::winnt;
use std::mem; use std::mem;
use std::ptr; use std::ptr;
use std::slice; use std::slice;
use std::sync::mpsc::{channel, Sender, Receiver}; use std::sync::mpsc::{channel, Receiver, Sender};
use std::{sync::{Arc},
thread::{self, JoinHandle}};
use crate::traits::StreamTrait; use crate::traits::StreamTrait;
use std::{
sync::Arc,
thread::{self, JoinHandle},
};
use BackendSpecificError; use BackendSpecificError;
use PauseStreamError; use PauseStreamError;
@ -22,8 +24,8 @@ use PlayStreamError;
use SampleFormat; use SampleFormat;
use StreamData; use StreamData;
use StreamError; use StreamError;
use UnknownTypeOutputBuffer;
use UnknownTypeInputBuffer; use UnknownTypeInputBuffer;
use UnknownTypeOutputBuffer;
pub struct Stream { pub struct Stream {
/// The high-priority audio processing thread calling callbacks. /// The high-priority audio processing thread calling callbacks.
@ -51,12 +53,12 @@ struct RunContext {
commands: Receiver<Command>, commands: Receiver<Command>,
} }
pub (crate) enum Command { pub(crate) enum Command {
PlayStream, PlayStream,
PauseStream, PauseStream,
} }
pub (crate) enum AudioClientFlow { pub(crate) enum AudioClientFlow {
Render { Render {
render_client: *mut audioclient::IAudioRenderClient, render_client: *mut audioclient::IAudioRenderClient,
}, },
@ -65,7 +67,7 @@ pub (crate) enum AudioClientFlow {
}, },
} }
pub (crate) struct StreamInner { pub(crate) struct StreamInner {
audio_client: *mut audioclient::IAudioClient, audio_client: *mut audioclient::IAudioClient,
client_flow: AudioClientFlow, client_flow: AudioClientFlow,
// Event that is signalled by WASAPI whenever audio data must be written. // Event that is signalled by WASAPI whenever audio data must be written.
@ -81,8 +83,15 @@ pub (crate) struct StreamInner {
} }
impl Stream { impl Stream {
pub (crate) fn new<D, E>(stream_inner: Arc<StreamInner>, mut data_callback: D, mut error_callback: E) -> Stream pub(crate) fn new<D, E>(
where D: FnMut(StreamData) + Send + 'static, E: FnMut(StreamError) + Send + 'static { stream_inner: Arc<StreamInner>,
mut data_callback: D,
mut error_callback: E,
) -> Stream
where
D: FnMut(StreamData) + Send + 'static,
E: FnMut(StreamError) + Send + 'static,
{
let pending_scheduled_event = let pending_scheduled_event =
unsafe { synchapi::CreateEventA(ptr::null_mut(), 0, 0, ptr::null()) }; unsafe { synchapi::CreateEventA(ptr::null_mut(), 0, 0, ptr::null()) };
let (tx, rx) = channel(); let (tx, rx) = channel();
@ -93,9 +102,8 @@ impl Stream {
commands: rx, commands: rx,
}; };
let thread = thread::spawn(move || { let thread =
run_inner(run_context, &mut data_callback, &mut error_callback) thread::spawn(move || run_inner(run_context, &mut data_callback, &mut error_callback));
});
Stream { Stream {
thread: Some(thread), thread: Some(thread),
@ -121,9 +129,9 @@ impl Drop for Stream {
unsafe { unsafe {
handleapi::CloseHandle(self.pending_scheduled_event); handleapi::CloseHandle(self.pending_scheduled_event);
} }
unsafe { unsafe {
let result = synchapi::SetEvent(self.pending_scheduled_event); let result = synchapi::SetEvent(self.pending_scheduled_event);
assert!(result != 0); assert!(result != 0);
} }
self.thread.take().unwrap().join().unwrap(); self.thread.take().unwrap().join().unwrap();
} }
@ -134,7 +142,7 @@ impl StreamTrait for Stream {
self.push_command(Command::PlayStream); self.push_command(Command::PlayStream);
Ok(()) Ok(())
} }
fn pause(&self)-> Result<(), PauseStreamError> { fn pause(&self) -> Result<(), PauseStreamError> {
self.push_command(Command::PauseStream); self.push_command(Command::PauseStream);
Ok(()) Ok(())
} }
@ -168,27 +176,23 @@ fn process_commands(run_context: &mut RunContext) -> Result<(), StreamError> {
match command { match command {
Command::PlayStream => { Command::PlayStream => {
if !run_context.stream.playing { if !run_context.stream.playing {
let hresult = unsafe { let hresult = unsafe { (*run_context.stream.audio_client).Start() };
(*run_context.stream.audio_client).Start()
};
if let Err(err) = stream_error_from_hresult(hresult) { if let Err(err) = stream_error_from_hresult(hresult) {
return Err(err); return Err(err);
} }
run_context.stream.playing = true; run_context.stream.playing = true;
} }
}, }
Command::PauseStream => { Command::PauseStream => {
if run_context.stream.playing { if run_context.stream.playing {
let hresult = unsafe { let hresult = unsafe { (*run_context.stream.audio_client).Stop() };
(*run_context.stream.audio_client).Stop()
};
if let Err(err) = stream_error_from_hresult(hresult) { if let Err(err) = stream_error_from_hresult(hresult) {
return Err(err); return Err(err);
} }
run_context.stream.playing = false; run_context.stream.playing = false;
} }
}, }
} }
} }
@ -208,15 +212,13 @@ fn wait_for_handle_signal(handles: &[winnt::HANDLE]) -> Result<usize, BackendSpe
synchapi::WaitForMultipleObjectsEx( synchapi::WaitForMultipleObjectsEx(
handles.len() as u32, handles.len() as u32,
handles.as_ptr(), handles.as_ptr(),
FALSE, // Don't wait for all, just wait for the first FALSE, // Don't wait for all, just wait for the first
winbase::INFINITE, // TODO: allow setting a timeout winbase::INFINITE, // TODO: allow setting a timeout
FALSE, // irrelevant parameter here FALSE, // irrelevant parameter here
) )
}; };
if result == winbase::WAIT_FAILED { if result == winbase::WAIT_FAILED {
let err = unsafe { let err = unsafe { winapi::um::errhandlingapi::GetLastError() };
winapi::um::errhandlingapi::GetLastError()
};
let description = format!("`WaitForMultipleObjectsEx failed: {}", err); let description = format!("`WaitForMultipleObjectsEx failed: {}", err);
let err = BackendSpecificError { description }; let err = BackendSpecificError { description };
return Err(err); return Err(err);
@ -250,7 +252,11 @@ fn stream_error_from_hresult(hresult: winnt::HRESULT) -> Result<(), StreamError>
Ok(()) Ok(())
} }
fn run_inner(run_context: RunContext, data_callback: &mut dyn FnMut(StreamData), error_callback: &mut dyn FnMut(StreamError)) { fn run_inner(
run_context: RunContext,
data_callback: &mut dyn FnMut(StreamData),
error_callback: &mut dyn FnMut(StreamError),
) {
unsafe { unsafe {
'stream_loop: loop { 'stream_loop: loop {
// Process queued commands. // Process queued commands.
@ -282,7 +288,6 @@ fn run_inner(run_context: RunContext, data_callback: &mut dyn FnMut(StreamData),
// Obtaining a pointer to the buffer. // Obtaining a pointer to the buffer.
match stream.client_flow { match stream.client_flow {
AudioClientFlow::Capture { capture_client } => { AudioClientFlow::Capture { capture_client } => {
let mut frames_available = 0; let mut frames_available = 0;
// Get the available data in the shared buffer. // Get the available data in the shared buffer.
@ -316,17 +321,21 @@ fn run_inner(run_context: RunContext, data_callback: &mut dyn FnMut(StreamData),
debug_assert!(!buffer.is_null()); debug_assert!(!buffer.is_null());
let buffer_len = frames_available as usize let buffer_len = frames_available as usize
* stream.bytes_per_frame as usize / sample_size; * stream.bytes_per_frame as usize
/ sample_size;
// Simplify the capture callback sample format branches. // Simplify the capture callback sample format branches.
macro_rules! capture_callback { macro_rules! capture_callback {
($T:ty, $Variant:ident) => {{ ($T:ty, $Variant:ident) => {{
let buffer_data = buffer as *mut _ as *const $T; let buffer_data = buffer as *mut _ as *const $T;
let slice = slice::from_raw_parts(buffer_data, buffer_len); let slice = slice::from_raw_parts(buffer_data, buffer_len);
let unknown_buffer = UnknownTypeInputBuffer::$Variant(::InputBuffer { let unknown_buffer =
buffer: slice, UnknownTypeInputBuffer::$Variant(::InputBuffer {
}); buffer: slice,
let data = StreamData::Input { buffer: unknown_buffer }; });
let data = StreamData::Input {
buffer: unknown_buffer,
};
data_callback(data); data_callback(data);
// Release the buffer. // Release the buffer.
let hresult = (*capture_client).ReleaseBuffer(frames_available); let hresult = (*capture_client).ReleaseBuffer(frames_available);
@ -343,7 +352,7 @@ fn run_inner(run_context: RunContext, data_callback: &mut dyn FnMut(StreamData),
SampleFormat::U16 => capture_callback!(u16, U16), SampleFormat::U16 => capture_callback!(u16, U16),
} }
} }
}, }
AudioClientFlow::Render { render_client } => { AudioClientFlow::Render { render_client } => {
// The number of frames available for writing. // The number of frames available for writing.
@ -357,10 +366,8 @@ fn run_inner(run_context: RunContext, data_callback: &mut dyn FnMut(StreamData),
}; };
let mut buffer: *mut BYTE = mem::uninitialized(); let mut buffer: *mut BYTE = mem::uninitialized();
let hresult = (*render_client).GetBuffer( let hresult =
frames_available, (*render_client).GetBuffer(frames_available, &mut buffer as *mut *mut _);
&mut buffer as *mut *mut _,
);
if let Err(err) = stream_error_from_hresult(hresult) { if let Err(err) = stream_error_from_hresult(hresult) {
error_callback(err); error_callback(err);
@ -368,26 +375,27 @@ fn run_inner(run_context: RunContext, data_callback: &mut dyn FnMut(StreamData),
} }
debug_assert!(!buffer.is_null()); debug_assert!(!buffer.is_null());
let buffer_len = frames_available as usize let buffer_len =
* stream.bytes_per_frame as usize / sample_size; frames_available as usize * stream.bytes_per_frame as usize / sample_size;
// Simplify the render callback sample format branches. // Simplify the render callback sample format branches.
macro_rules! render_callback { macro_rules! render_callback {
($T:ty, $Variant:ident) => {{ ($T:ty, $Variant:ident) => {{
let buffer_data = buffer as *mut $T; let buffer_data = buffer as *mut $T;
let slice = slice::from_raw_parts_mut(buffer_data, buffer_len); let slice = slice::from_raw_parts_mut(buffer_data, buffer_len);
let unknown_buffer = UnknownTypeOutputBuffer::$Variant(::OutputBuffer { let unknown_buffer =
buffer: slice UnknownTypeOutputBuffer::$Variant(::OutputBuffer { buffer: slice });
}); let data = StreamData::Output {
let data = StreamData::Output { buffer: unknown_buffer }; buffer: unknown_buffer,
};
data_callback(data); data_callback(data);
let hresult = (*render_client) let hresult =
.ReleaseBuffer(frames_available as u32, 0); (*render_client).ReleaseBuffer(frames_available as u32, 0);
if let Err(err) = stream_error_from_hresult(hresult) { if let Err(err) = stream_error_from_hresult(hresult) {
error_callback(err); error_callback(err);
break 'stream_loop; break 'stream_loop;
} }
}} }};
} }
match stream.sample_format { match stream.sample_format {
@ -395,7 +403,7 @@ fn run_inner(run_context: RunContext, data_callback: &mut dyn FnMut(StreamData),
SampleFormat::I16 => render_callback!(i16, I16), SampleFormat::I16 => render_callback!(i16, I16),
SampleFormat::U16 => render_callback!(u16, U16), SampleFormat::U16 => render_callback!(u16, U16),
} }
}, }
} }
} }
} }