`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 std::ptr;
use super::winapi::um::objbase::{COINIT_MULTITHREADED};
use super::winapi::um::combaseapi::{CoInitializeEx, CoUninitialize};
use super::winapi::um::objbase::COINIT_MULTITHREADED;
thread_local!(static COM_INITIALIZED: ComInitialized = {
unsafe {

View File

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

View File

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

View File

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