From d68c8855e911949a7eb163572a461328a90ce910 Mon Sep 17 00:00:00 2001 From: sidit77 Date: Fri, 24 Feb 2023 10:20:17 +0100 Subject: [PATCH 1/4] use ActivateAudioInterfaceAsync to retrieve the default devices to enable automatic stream routing in case the default device changes --- Cargo.toml | 2 +- src/host/wasapi/device.rs | 284 +++++++++++++++++++++++++------------- 2 files changed, 188 insertions(+), 98 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5010ea8be..a1ac256d0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,7 +26,7 @@ clap = { version = "4.0", features = ["derive"] } ndk-glue = "0.7" [target.'cfg(target_os = "windows")'.dependencies] -windows = { version = "0.44.0", features = ["Win32_Media_Audio", "Win32_Foundation", "Win32_System_Com", "Win32_Devices_Properties", "Win32_Media_KernelStreaming", "Win32_System_Com_StructuredStorage", "Win32_System_Ole", "Win32_System_Threading", "Win32_Security", "Win32_System_SystemServices", "Win32_System_WindowsProgramming", "Win32_Media_Multimedia", "Win32_UI_Shell_PropertiesSystem"]} +windows = { version = "0.44.0", features = ["Win32_Media_Audio", "Win32_Foundation", "Win32_System_Com", "Win32_Devices_Properties", "Win32_Media_KernelStreaming", "Win32_System_Com_StructuredStorage", "Win32_System_Ole", "Win32_System_Threading", "Win32_Security", "Win32_System_SystemServices", "Win32_System_WindowsProgramming", "Win32_Media_Multimedia", "Win32_UI_Shell_PropertiesSystem", "implement"]} asio-sys = { version = "0.2", path = "asio-sys", optional = true } num-traits = { version = "0.2.6", optional = true } parking_lot = "0.12" diff --git a/src/host/wasapi/device.rs b/src/host/wasapi/device.rs index d670ea7b4..87b21abc9 100644 --- a/src/host/wasapi/device.rs +++ b/src/host/wasapi/device.rs @@ -14,18 +14,20 @@ use std::os::windows::ffi::OsStringExt; use std::ptr; use std::slice; use std::sync::{Arc, Mutex, MutexGuard}; +use std::sync::mpsc::Sender; use std::time::Duration; use super::com; use super::{windows_err_to_cpal_err, windows_err_to_cpal_err_message}; -use windows::core::Interface; +use windows::core::{Interface, PCWSTR, implement, IUnknown, HRESULT, Result as WinResult}; use windows::core::GUID; use windows::Win32::Devices::Properties; use windows::Win32::Foundation; -use windows::Win32::Media::Audio::IAudioRenderClient; +use windows::Win32::Media::Audio::{ActivateAudioInterfaceAsync, DEVINTERFACE_AUDIO_CAPTURE, DEVINTERFACE_AUDIO_RENDER, IActivateAudioInterfaceAsyncOperation, IActivateAudioInterfaceCompletionHandler, IActivateAudioInterfaceCompletionHandler_Impl, IAudioRenderClient}; use windows::Win32::Media::{Audio, KernelStreaming, Multimedia}; use windows::Win32::System::Com; -use windows::Win32::System::Com::{StructuredStorage, STGM_READ, VT_LPWSTR}; +use windows::Win32::System::Com::{StructuredStorage, STGM_READ, VT_LPWSTR, StringFromIID, CoTaskMemFree}; +use windows::Win32::System::Com::StructuredStorage::PROPVARIANT; use windows::Win32::System::Threading; use super::stream::{AudioClientFlow, Stream, StreamInner}; @@ -40,10 +42,17 @@ struct IAudioClientWrapper(Audio::IAudioClient); unsafe impl Send for IAudioClientWrapper {} unsafe impl Sync for IAudioClientWrapper {} +#[derive(Debug, Clone)] +enum DeviceType { + DefaultOutput, + DefaultInput, + Specific(Audio::IMMDevice) +} + /// An opaque type that identifies an end point. #[derive(Clone)] pub struct Device { - device: Audio::IMMDevice, + device: DeviceType, /// We cache an uninitialized `IAudioClient` so that we can call functions from it without /// having to create/destroy audio clients all the time. future_audio_client: Arc>>, // TODO: add NonZero around the ptr @@ -314,66 +323,115 @@ unsafe fn format_from_waveformatex_ptr( Some(format) } +#[implement(IActivateAudioInterfaceCompletionHandler)] +struct CompletionHandler(Sender>); + +fn retrieve_result(operation: &IActivateAudioInterfaceAsyncOperation) -> WinResult { + let mut result = HRESULT::default(); + let mut interface: Option = None; + unsafe { operation.GetActivateResult(&mut result, &mut interface)?; } + result.ok()?; + Ok(interface.unwrap()) +} + +impl IActivateAudioInterfaceCompletionHandler_Impl for CompletionHandler { + fn ActivateCompleted(&self, operation: &Option) -> WinResult<()> { + let result = retrieve_result(operation.as_ref().unwrap()); + let _ = self.0.send(result); + Ok(()) + } +} + +#[allow(non_snake_case)] +unsafe fn ActivateAudioInterfaceSync(deviceinterfacepath: P0, activationparams: Option<*const PROPVARIANT>) -> WinResult where + P0: Into<::windows::core::InParam>, + T: Interface { + let (sender, receiver) = std::sync::mpsc::channel(); + let completion: IActivateAudioInterfaceCompletionHandler = CompletionHandler(sender).into(); + ActivateAudioInterfaceAsync(deviceinterfacepath, &T::IID, activationparams, &completion)?; + let result = receiver.recv_timeout(Duration::from_secs(2)).unwrap()?; + result.cast() +} + unsafe impl Send for Device {} unsafe impl Sync for Device {} impl Device { pub fn name(&self) -> Result { - unsafe { - // Open the device's property store. - let property_store = self - .device - .OpenPropertyStore(STGM_READ) - .expect("could not open property store"); - - // Get the endpoint's friendly-name property. - let mut property_value = property_store - .GetValue(&Properties::DEVPKEY_Device_FriendlyName as *const _ as *const _) - .map_err(|err| { - let description = - format!("failed to retrieve name from property store: {}", err); - let err = BackendSpecificError { description }; - DeviceNameError::from(err) - })?; + match &self.device { + DeviceType::DefaultOutput => Ok("Default Ouput".to_string()), + DeviceType::DefaultInput => Ok("Default Input".to_string()), + DeviceType::Specific(device) => unsafe { + // Open the device's property store. + let property_store = device + .OpenPropertyStore(STGM_READ) + .expect("could not open property store"); + + // Get the endpoint's friendly-name property. + let mut property_value = property_store + .GetValue(&Properties::DEVPKEY_Device_FriendlyName as *const _ as *const _) + .map_err(|err| { + let description = + format!("failed to retrieve name from property store: {}", err); + let err = BackendSpecificError { description }; + DeviceNameError::from(err) + })?; - let prop_variant = &property_value.Anonymous.Anonymous; + let prop_variant = &property_value.Anonymous.Anonymous; - // Read the friendly-name from the union data field, expecting a *const u16. - if prop_variant.vt != VT_LPWSTR { - let description = format!( - "property store produced invalid data: {:?}", - prop_variant.vt - ); - let err = BackendSpecificError { description }; - return Err(err.into()); - } - let ptr_utf16 = *(&prop_variant.Anonymous as *const _ as *const *const u16); + // Read the friendly-name from the union data field, expecting a *const u16. + if prop_variant.vt != VT_LPWSTR { + let description = format!( + "property store produced invalid data: {:?}", + prop_variant.vt + ); + let err = BackendSpecificError { description }; + return Err(err.into()); + } + let ptr_utf16 = *(&prop_variant.Anonymous as *const _ as *const *const u16); - // Find the length of the friendly name. - let mut len = 0; - while *ptr_utf16.offset(len) != 0 { - len += 1; - } + // Find the length of the friendly name. + let mut len = 0; + while *ptr_utf16.offset(len) != 0 { + len += 1; + } - // Create the utf16 slice and convert it into a string. - let name_slice = slice::from_raw_parts(ptr_utf16, len as usize); - let name_os_string: OsString = OsStringExt::from_wide(name_slice); - let name_string = match name_os_string.into_string() { - Ok(string) => string, - Err(os_string) => os_string.to_string_lossy().into(), - }; + // Create the utf16 slice and convert it into a string. + let name_slice = slice::from_raw_parts(ptr_utf16, len as usize); + let name_os_string: OsString = OsStringExt::from_wide(name_slice); + let name_string = match name_os_string.into_string() { + Ok(string) => string, + Err(os_string) => os_string.to_string_lossy().into(), + }; - // Clean up the property. - StructuredStorage::PropVariantClear(&mut property_value).ok(); + // Clean up the property. + StructuredStorage::PropVariantClear(&mut property_value).ok(); - Ok(name_string) + Ok(name_string) + } } } #[inline] fn from_immdevice(device: Audio::IMMDevice) -> Self { Device { - device, + device: DeviceType::Specific(device), + future_audio_client: Arc::new(Mutex::new(None)), + } + } + + #[inline] + fn default_output() -> Self { + Device { + device: DeviceType::DefaultOutput, + future_audio_client: Arc::new(Mutex::new(None)), + } + } + + #[inline] + fn default_input() -> Self { + Device { + device: DeviceType::DefaultInput, future_audio_client: Arc::new(Mutex::new(None)), } } @@ -388,9 +446,26 @@ impl Device { } let audio_client: Audio::IAudioClient = unsafe { - // can fail if the device has been disconnected since we enumerated it, or if - // the device doesn't support playback for some reason - self.device.Activate(Com::CLSCTX_ALL, None)? + match &self.device { + DeviceType::DefaultOutput => { + let default_audio = StringFromIID(&DEVINTERFACE_AUDIO_RENDER)?; + let result = ActivateAudioInterfaceSync(PCWSTR(default_audio.as_ptr()), None); + CoTaskMemFree(Some(default_audio.as_ptr()as _)); + result? + } + DeviceType::DefaultInput => { + let default_audio = StringFromIID(&DEVINTERFACE_AUDIO_CAPTURE)?; + let result = ActivateAudioInterfaceSync(PCWSTR(default_audio.as_ptr()), None); + CoTaskMemFree(Some(default_audio.as_ptr() as _)); + result? + } + DeviceType::Specific(device) => { + // can fail if the device has been disconnected since we enumerated it, or if + // the device doesn't support playback for some reason + device.Activate(Com::CLSCTX_ALL, None)? + } + } + }; *lock = Some(IAudioClientWrapper(audio_client)); @@ -560,8 +635,14 @@ impl Device { } pub(crate) fn data_flow(&self) -> Audio::EDataFlow { - let endpoint = Endpoint::from(self.device.clone()); - endpoint.data_flow() + match &self.device { + DeviceType::DefaultOutput => Audio::eRender, + DeviceType::DefaultInput => Audio::eCapture, + DeviceType::Specific(device) => { + let endpoint = Endpoint::from(device.clone()); + endpoint.data_flow() + } + } } pub fn default_input_config(&self) -> Result { @@ -811,40 +892,47 @@ impl Device { impl PartialEq for Device { #[inline] fn eq(&self, other: &Device) -> bool { - // Use case: In order to check whether the default device has changed - // the client code might need to compare the previous default device with the current one. - // The pointer comparison (`self.device == other.device`) don't work there, - // because the pointers are different even when the default device stays the same. - // - // 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(windows::core::PWSTR); - /// RAII for device IDs. - impl Drop for IdRAII { - fn drop(&mut self) { - unsafe { Com::CoTaskMemFree(Some(self.0 .0 as *mut _)) } - } - } - // 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. - let id1 = self.device.GetId().expect("cpal: GetId failure"); - let id1 = IdRAII(id1); - let id2 = other.device.GetId().expect("cpal: GetId failure"); - let id2 = IdRAII(id2); - // 16-bit null-terminated comparison. - let mut offset = 0; - loop { - let w1: u16 = *(id1.0).0.offset(offset); - let w2: u16 = *(id2.0).0.offset(offset); - if w1 == 0 && w2 == 0 { - return true; - } - if w1 != w2 { - return false; + match (&self.device, &other.device) { + (DeviceType::DefaultOutput, DeviceType::DefaultOutput) => true, + (DeviceType::DefaultInput, DeviceType::DefaultInput) => true, + (DeviceType::Specific(dev1), DeviceType::Specific(dev2)) => { + // Use case: In order to check whether the default device has changed + // the client code might need to compare the previous default device with the current one. + // The pointer comparison (`self.device == other.device`) don't work there, + // because the pointers are different even when the default device stays the same. + // + // 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(windows::core::PWSTR); + /// RAII for device IDs. + impl Drop for IdRAII { + fn drop(&mut self) { + unsafe { Com::CoTaskMemFree(Some(self.0 .0 as *mut _)) } + } + } + // 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. + let id1 = dev1.GetId().expect("cpal: GetId failure"); + let id1 = IdRAII(id1); + let id2 = dev2.GetId().expect("cpal: GetId failure"); + let id2 = IdRAII(id2); + // 16-bit null-terminated comparison. + let mut offset = 0; + loop { + let w1: u16 = *(id1.0).0.offset(offset); + let w2: u16 = *(id2.0).0.offset(offset); + if w1 == 0 && w2 == 0 { + return true; + } + if w1 != w2 { + return false; + } + offset += 1; + } } - offset += 1; - } + }, + _ => false, } } } @@ -952,23 +1040,25 @@ impl Iterator for Devices { } } -fn default_device(data_flow: Audio::EDataFlow) -> Option { - unsafe { - let device = ENUMERATOR - .0 - .GetDefaultAudioEndpoint(data_flow, Audio::eConsole) - .ok()?; - // TODO: check specifically for `E_NOTFOUND`, and panic otherwise - Some(Device::from_immdevice(device)) - } -} +//fn default_device(data_flow: Audio::EDataFlow) -> Option { +// unsafe { +// let device = ENUMERATOR +// .0 +// .GetDefaultAudioEndpoint(data_flow, Audio::eConsole) +// .ok()?; +// // TODO: check specifically for `E_NOTFOUND`, and panic otherwise +// Some(Device::from_immdevice(device)) +// } +//} pub fn default_input_device() -> Option { - default_device(Audio::eCapture) + //default_device(Audio::eCapture) + Some(Device::default_input()) } pub fn default_output_device() -> Option { - default_device(Audio::eRender) + //default_device(Audio::eRender) + Some(Device::default_output()) } /// Get the audio clock used to produce `StreamInstant`s. From dd00d9edf6c8abb757e2730fbc9a6fd81a39577b Mon Sep 17 00:00:00 2001 From: sidit77 Date: Fri, 24 Feb 2023 10:37:07 +0100 Subject: [PATCH 2/4] applied rustfmt --- src/host/wasapi/device.rs | 61 +++++++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 21 deletions(-) diff --git a/src/host/wasapi/device.rs b/src/host/wasapi/device.rs index 87b21abc9..77cdef3af 100644 --- a/src/host/wasapi/device.rs +++ b/src/host/wasapi/device.rs @@ -13,21 +13,23 @@ use std::ops::{Deref, DerefMut}; use std::os::windows::ffi::OsStringExt; use std::ptr; use std::slice; -use std::sync::{Arc, Mutex, MutexGuard}; use std::sync::mpsc::Sender; +use std::sync::{Arc, Mutex, MutexGuard}; use std::time::Duration; use super::com; use super::{windows_err_to_cpal_err, windows_err_to_cpal_err_message}; -use windows::core::{Interface, PCWSTR, implement, IUnknown, HRESULT, Result as WinResult}; use windows::core::GUID; +use windows::core::{implement, IUnknown, Interface, Result as WinResult, HRESULT, PCWSTR}; use windows::Win32::Devices::Properties; use windows::Win32::Foundation; -use windows::Win32::Media::Audio::{ActivateAudioInterfaceAsync, DEVINTERFACE_AUDIO_CAPTURE, DEVINTERFACE_AUDIO_RENDER, IActivateAudioInterfaceAsyncOperation, IActivateAudioInterfaceCompletionHandler, IActivateAudioInterfaceCompletionHandler_Impl, IAudioRenderClient}; +use windows::Win32::Media::Audio::IAudioRenderClient; use windows::Win32::Media::{Audio, KernelStreaming, Multimedia}; use windows::Win32::System::Com; -use windows::Win32::System::Com::{StructuredStorage, STGM_READ, VT_LPWSTR, StringFromIID, CoTaskMemFree}; use windows::Win32::System::Com::StructuredStorage::PROPVARIANT; +use windows::Win32::System::Com::{ + CoTaskMemFree, StringFromIID, StructuredStorage, STGM_READ, VT_LPWSTR, +}; use windows::Win32::System::Threading; use super::stream::{AudioClientFlow, Stream, StreamInner}; @@ -46,7 +48,7 @@ unsafe impl Sync for IAudioClientWrapper {} enum DeviceType { DefaultOutput, DefaultInput, - Specific(Audio::IMMDevice) + Specific(Audio::IMMDevice), } /// An opaque type that identifies an end point. @@ -323,32 +325,50 @@ unsafe fn format_from_waveformatex_ptr( Some(format) } -#[implement(IActivateAudioInterfaceCompletionHandler)] +#[implement(Audio::IActivateAudioInterfaceCompletionHandler)] struct CompletionHandler(Sender>); -fn retrieve_result(operation: &IActivateAudioInterfaceAsyncOperation) -> WinResult { +fn retrieve_result( + operation: &Audio::IActivateAudioInterfaceAsyncOperation, +) -> WinResult { let mut result = HRESULT::default(); let mut interface: Option = None; - unsafe { operation.GetActivateResult(&mut result, &mut interface)?; } + unsafe { + operation.GetActivateResult(&mut result, &mut interface)?; + } result.ok()?; Ok(interface.unwrap()) } -impl IActivateAudioInterfaceCompletionHandler_Impl for CompletionHandler { - fn ActivateCompleted(&self, operation: &Option) -> WinResult<()> { +impl Audio::IActivateAudioInterfaceCompletionHandler_Impl for CompletionHandler { + fn ActivateCompleted( + &self, + operation: &Option, + ) -> WinResult<()> { let result = retrieve_result(operation.as_ref().unwrap()); - let _ = self.0.send(result); + let _ = self.0.send(result); Ok(()) } } #[allow(non_snake_case)] -unsafe fn ActivateAudioInterfaceSync(deviceinterfacepath: P0, activationparams: Option<*const PROPVARIANT>) -> WinResult where +unsafe fn ActivateAudioInterfaceSync( + deviceinterfacepath: P0, + activationparams: Option<*const PROPVARIANT>, +) -> WinResult +where P0: Into<::windows::core::InParam>, - T: Interface { + T: Interface, +{ let (sender, receiver) = std::sync::mpsc::channel(); - let completion: IActivateAudioInterfaceCompletionHandler = CompletionHandler(sender).into(); - ActivateAudioInterfaceAsync(deviceinterfacepath, &T::IID, activationparams, &completion)?; + let completion: Audio::IActivateAudioInterfaceCompletionHandler = + CompletionHandler(sender).into(); + Audio::ActivateAudioInterfaceAsync( + deviceinterfacepath, + &T::IID, + activationparams, + &completion, + )?; let result = receiver.recv_timeout(Duration::from_secs(2)).unwrap()?; result.cast() } @@ -408,7 +428,7 @@ impl Device { StructuredStorage::PropVariantClear(&mut property_value).ok(); Ok(name_string) - } + }, } } @@ -448,13 +468,13 @@ impl Device { let audio_client: Audio::IAudioClient = unsafe { match &self.device { DeviceType::DefaultOutput => { - let default_audio = StringFromIID(&DEVINTERFACE_AUDIO_RENDER)?; + let default_audio = StringFromIID(&Audio::DEVINTERFACE_AUDIO_RENDER)?; let result = ActivateAudioInterfaceSync(PCWSTR(default_audio.as_ptr()), None); - CoTaskMemFree(Some(default_audio.as_ptr()as _)); + CoTaskMemFree(Some(default_audio.as_ptr() as _)); result? } DeviceType::DefaultInput => { - let default_audio = StringFromIID(&DEVINTERFACE_AUDIO_CAPTURE)?; + let default_audio = StringFromIID(&Audio::DEVINTERFACE_AUDIO_CAPTURE)?; let result = ActivateAudioInterfaceSync(PCWSTR(default_audio.as_ptr()), None); CoTaskMemFree(Some(default_audio.as_ptr() as _)); result? @@ -465,7 +485,6 @@ impl Device { device.Activate(Com::CLSCTX_ALL, None)? } } - }; *lock = Some(IAudioClientWrapper(audio_client)); @@ -931,7 +950,7 @@ impl PartialEq for Device { offset += 1; } } - }, + } _ => false, } } From 7e82d99bfaa8036cf6e7c7d214254014ad050139 Mon Sep 17 00:00:00 2001 From: sidit77 Date: Tue, 2 May 2023 20:16:32 +0200 Subject: [PATCH 3/4] fixed merge conflicts --- src/host/wasapi/device.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/host/wasapi/device.rs b/src/host/wasapi/device.rs index 9ebd1dab7..ddff33402 100644 --- a/src/host/wasapi/device.rs +++ b/src/host/wasapi/device.rs @@ -344,9 +344,9 @@ fn retrieve_result( impl Audio::IActivateAudioInterfaceCompletionHandler_Impl for CompletionHandler { fn ActivateCompleted( &self, - operation: &Option, + operation: Option<&Audio::IActivateAudioInterfaceAsyncOperation>, ) -> WinResult<()> { - let result = retrieve_result(operation.as_ref().unwrap()); + let result = retrieve_result(operation.unwrap()); let _ = self.0.send(result); Ok(()) } @@ -358,8 +358,8 @@ unsafe fn ActivateAudioInterfaceSync( activationparams: Option<*const PROPVARIANT>, ) -> WinResult where - P0: Into<::windows::core::InParam>, - T: Interface, + P0: windows::core::IntoParam, + T: Interface + ComInterface, { let (sender, receiver) = std::sync::mpsc::channel(); let completion: Audio::IActivateAudioInterfaceCompletionHandler = From 66ed6bec97f25ec7f02a82f50d1aa9aef733a58e Mon Sep 17 00:00:00 2001 From: sidit77 Date: Wed, 29 May 2024 20:27:31 +0200 Subject: [PATCH 4/4] fixed merge conflicts --- Cargo.toml | 1 + src/host/wasapi/device.rs | 37 ++++++++++++++++++------------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7b00ce902..e1bbb0460 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,7 @@ ndk-glue = "0.7" [target.'cfg(target_os = "windows")'.dependencies] windows = { version = "0.54.0", features = [ + "implement", "Win32_Media_Audio", "Win32_Foundation", "Win32_Devices_Properties", diff --git a/src/host/wasapi/device.rs b/src/host/wasapi/device.rs index 8389071c8..6ab154dab 100644 --- a/src/host/wasapi/device.rs +++ b/src/host/wasapi/device.rs @@ -11,21 +11,21 @@ use std::mem; use std::os::windows::ffi::OsStringExt; use std::ptr; use std::slice; -use std::sync::OnceLock; use std::sync::mpsc::Sender; +use std::sync::OnceLock; use std::sync::{Arc, Mutex, MutexGuard}; use std::time::Duration; use super::com; use super::{windows_err_to_cpal_err, windows_err_to_cpal_err_message}; -use windows::core::Interface; use windows::core::GUID; +use windows::core::{implement, IUnknown, Interface, HRESULT, PCWSTR, PROPVARIANT}; use windows::Win32::Devices::Properties; use windows::Win32::Foundation; use windows::Win32::Media::Audio::IAudioRenderClient; use windows::Win32::Media::{Audio, KernelStreaming, Multimedia}; use windows::Win32::System::Com; -use windows::Win32::System::Com::{StructuredStorage, STGM_READ}; +use windows::Win32::System::Com::{CoTaskMemFree, StringFromIID, StructuredStorage, STGM_READ}; use windows::Win32::System::Threading; use windows::Win32::System::Variant::VT_LPWSTR; @@ -284,11 +284,11 @@ unsafe fn format_from_waveformatex_ptr( } #[implement(Audio::IActivateAudioInterfaceCompletionHandler)] -struct CompletionHandler(Sender>); +struct CompletionHandler(Sender>); fn retrieve_result( operation: &Audio::IActivateAudioInterfaceAsyncOperation, -) -> WinResult { +) -> windows::core::Result { let mut result = HRESULT::default(); let mut interface: Option = None; unsafe { @@ -302,7 +302,7 @@ impl Audio::IActivateAudioInterfaceCompletionHandler_Impl for CompletionHandler fn ActivateCompleted( &self, operation: Option<&Audio::IActivateAudioInterfaceAsyncOperation>, - ) -> WinResult<()> { + ) -> windows::core::Result<()> { let result = retrieve_result(operation.unwrap()); let _ = self.0.send(result); Ok(()) @@ -313,10 +313,10 @@ impl Audio::IActivateAudioInterfaceCompletionHandler_Impl for CompletionHandler unsafe fn ActivateAudioInterfaceSync( deviceinterfacepath: P0, activationparams: Option<*const PROPVARIANT>, -) -> WinResult +) -> windows::core::Result where P0: windows::core::IntoParam, - T: Interface + ComInterface, + T: Interface, { let (sender, receiver) = std::sync::mpsc::channel(); let completion: Audio::IActivateAudioInterfaceCompletionHandler = @@ -357,16 +357,16 @@ impl Device { let prop_variant = &property_value.as_raw().Anonymous.Anonymous; - // Read the friendly-name from the union data field, expecting a *const u16. - if prop_variant.vt != VT_LPWSTR.0 { - let description = format!( - "property store produced invalid data: {:?}", - prop_variant.vt - ); - let err = BackendSpecificError { description }; - return Err(err.into()); - } - let ptr_utf16 = *(&prop_variant.Anonymous as *const _ as *const *const u16); + // Read the friendly-name from the union data field, expecting a *const u16. + if prop_variant.vt != VT_LPWSTR.0 { + let description = format!( + "property store produced invalid data: {:?}", + prop_variant.vt + ); + let err = BackendSpecificError { description }; + return Err(err.into()); + } + let ptr_utf16 = *(&prop_variant.Anonymous as *const _ as *const *const u16); // Find the length of the friendly name. let mut len = 0; @@ -1029,7 +1029,6 @@ impl Iterator for Devices { // } //} - pub fn default_input_device() -> Option { //default_device(Audio::eCapture) Some(Device::default_input())