@@ -11,21 +11,20 @@ use std::mem;
11
11
use std:: os:: windows:: ffi:: OsStringExt ;
12
12
use std:: ptr;
13
13
use std:: slice;
14
- use std:: sync:: mpsc:: Sender ;
15
14
use std:: sync:: OnceLock ;
16
15
use std:: sync:: { Arc , Mutex , MutexGuard } ;
17
16
use std:: time:: Duration ;
18
17
19
18
use super :: com;
20
19
use super :: { windows_err_to_cpal_err, windows_err_to_cpal_err_message} ;
20
+ use windows:: core:: Interface ;
21
21
use windows:: core:: GUID ;
22
- use windows:: core:: { implement, IUnknown , Interface , HRESULT , PCWSTR } ;
23
22
use windows:: Win32 :: Devices :: Properties ;
24
23
use windows:: Win32 :: Foundation ;
25
24
use windows:: Win32 :: Media :: Audio :: IAudioRenderClient ;
26
25
use windows:: Win32 :: Media :: { Audio , KernelStreaming , Multimedia } ;
27
26
use windows:: Win32 :: System :: Com ;
28
- use windows:: Win32 :: System :: Com :: { CoTaskMemFree , StringFromIID , StructuredStorage , STGM_READ } ;
27
+ use windows:: Win32 :: System :: Com :: { StructuredStorage , STGM_READ } ;
29
28
use windows:: Win32 :: System :: Threading ;
30
29
use windows:: Win32 :: System :: Variant :: VT_LPWSTR ;
31
30
@@ -274,53 +273,50 @@ unsafe fn format_from_waveformatex_ptr(
274
273
Some ( format)
275
274
}
276
275
277
- #[ implement( Audio :: IActivateAudioInterfaceCompletionHandler ) ]
278
- struct CompletionHandler ( Sender < windows:: core:: Result < IUnknown > > ) ;
276
+ #[ cfg( feature = "wasapi-virtual-default-devices" ) ]
277
+ unsafe fn activate_audio_interface_sync (
278
+ deviceinterfacepath : windows:: core:: PWSTR ,
279
+ ) -> windows:: core:: Result < Audio :: IAudioClient > {
280
+ use windows:: core:: IUnknown ;
279
281
280
- fn retrieve_result (
281
- operation : & Audio :: IActivateAudioInterfaceAsyncOperation ,
282
- ) -> windows:: core:: Result < IUnknown > {
283
- let mut result = HRESULT :: default ( ) ;
284
- let mut interface: Option < IUnknown > = None ;
285
- unsafe {
286
- operation. GetActivateResult ( & mut result, & mut interface) ?;
282
+ #[ windows:: core:: implement( Audio :: IActivateAudioInterfaceCompletionHandler ) ]
283
+ struct CompletionHandler ( std:: sync:: mpsc:: Sender < windows:: core:: Result < IUnknown > > ) ;
284
+
285
+ fn retrieve_result (
286
+ operation : & Audio :: IActivateAudioInterfaceAsyncOperation ,
287
+ ) -> windows:: core:: Result < IUnknown > {
288
+ let mut result = windows:: core:: HRESULT :: default ( ) ;
289
+ let mut interface: Option < IUnknown > = None ;
290
+ unsafe {
291
+ operation. GetActivateResult ( & mut result, & mut interface) ?;
292
+ }
293
+ result. ok ( ) ?;
294
+ interface. ok_or_else ( || {
295
+ windows:: core:: Error :: new (
296
+ Audio :: AUDCLNT_E_DEVICE_INVALIDATED ,
297
+ "audio interface could not be retrieved during activation" ,
298
+ )
299
+ } )
287
300
}
288
- result. ok ( ) ?;
289
- interface. ok_or_else ( || {
290
- windows:: core:: Error :: new (
291
- Audio :: AUDCLNT_E_DEVICE_INVALIDATED ,
292
- "audio interface could not be retrieved during activation" ,
293
- )
294
- } )
295
- }
296
301
297
- impl Audio :: IActivateAudioInterfaceCompletionHandler_Impl for CompletionHandler_Impl {
298
- fn ActivateCompleted (
299
- & self ,
300
- operation : windows:: core:: Ref < Audio :: IActivateAudioInterfaceAsyncOperation > ,
301
- ) -> windows:: core:: Result < ( ) > {
302
- let result = operation. ok ( ) . and_then ( retrieve_result) ;
303
- let _ = self . 0 . send ( result) ;
304
- Ok ( ( ) )
302
+ impl Audio :: IActivateAudioInterfaceCompletionHandler_Impl for CompletionHandler_Impl {
303
+ fn ActivateCompleted (
304
+ & self ,
305
+ operation : windows:: core:: Ref < Audio :: IActivateAudioInterfaceAsyncOperation > ,
306
+ ) -> windows:: core:: Result < ( ) > {
307
+ let result = operation. ok ( ) . and_then ( retrieve_result) ;
308
+ let _ = self . 0 . send ( result) ;
309
+ Ok ( ( ) )
310
+ }
305
311
}
306
- }
307
312
308
- #[ allow( non_snake_case) ]
309
- unsafe fn ActivateAudioInterfaceSync < P0 , T > (
310
- deviceinterfacepath : P0 ,
311
- activationparams : Option < * const StructuredStorage :: PROPVARIANT > ,
312
- ) -> windows:: core:: Result < T >
313
- where
314
- P0 : windows:: core:: Param < PCWSTR > ,
315
- T : Interface ,
316
- {
317
313
let ( sender, receiver) = std:: sync:: mpsc:: channel ( ) ;
318
314
let completion: Audio :: IActivateAudioInterfaceCompletionHandler =
319
315
CompletionHandler ( sender) . into ( ) ;
320
316
Audio :: ActivateAudioInterfaceAsync (
321
317
deviceinterfacepath,
322
- & T :: IID ,
323
- activationparams ,
318
+ & Audio :: IAudioClient :: IID ,
319
+ None ,
324
320
& completion,
325
321
) ?;
326
322
let result = receiver. recv_timeout ( Duration :: from_secs ( 2 ) ) . unwrap ( ) ?;
@@ -439,18 +435,25 @@ impl Device {
439
435
return Ok ( lock) ;
440
436
}
441
437
438
+ // When using virtual default devices, we use `ActivateAudioInterfaceAsync` to get
439
+ // an `IAudioClient` for the default output or input device. When retrieved this way,
440
+ // streams will be automatically rerouted if the default device is changed.
441
+ //
442
+ // Otherwise, we use `Activate` to get an `IAudioClient` for the current device.
443
+
444
+ #[ cfg( feature = "wasapi-virtual-default-devices" ) ]
442
445
let audio_client: Audio :: IAudioClient = unsafe {
443
446
match & self . device {
444
447
DeviceType :: DefaultOutput => {
445
- let default_audio = StringFromIID ( & Audio :: DEVINTERFACE_AUDIO_RENDER ) ?;
446
- let result = ActivateAudioInterfaceSync ( PCWSTR ( default_audio. as_ptr ( ) ) , None ) ;
447
- CoTaskMemFree ( Some ( default_audio. as_ptr ( ) as _ ) ) ;
448
+ let default_audio = Com :: StringFromIID ( & Audio :: DEVINTERFACE_AUDIO_RENDER ) ?;
449
+ let result = activate_audio_interface_sync ( default_audio) ;
450
+ Com :: CoTaskMemFree ( Some ( default_audio. as_ptr ( ) as _ ) ) ;
448
451
result?
449
452
}
450
453
DeviceType :: DefaultInput => {
451
- let default_audio = StringFromIID ( & Audio :: DEVINTERFACE_AUDIO_CAPTURE ) ?;
452
- let result = ActivateAudioInterfaceSync ( PCWSTR ( default_audio. as_ptr ( ) ) , None ) ;
453
- CoTaskMemFree ( Some ( default_audio. as_ptr ( ) as _ ) ) ;
454
+ let default_audio = Com :: StringFromIID ( & Audio :: DEVINTERFACE_AUDIO_CAPTURE ) ?;
455
+ let result = activate_audio_interface_sync ( default_audio) ;
456
+ Com :: CoTaskMemFree ( Some ( default_audio. as_ptr ( ) as _ ) ) ;
454
457
result?
455
458
}
456
459
DeviceType :: Specific ( device) => {
@@ -461,6 +464,16 @@ impl Device {
461
464
}
462
465
} ;
463
466
467
+ #[ cfg( not( feature = "wasapi-virtual-default-devices" ) ) ]
468
+ let audio_client = unsafe {
469
+ self . immdevice ( )
470
+ . ok_or ( windows:: core:: Error :: new (
471
+ Audio :: AUDCLNT_E_DEVICE_INVALIDATED ,
472
+ "device not found while getting audio client" ,
473
+ ) ) ?
474
+ . Activate ( Com :: CLSCTX_ALL , None ) ?
475
+ } ;
476
+
464
477
* lock = Some ( IAudioClientWrapper ( audio_client) ) ;
465
478
Ok ( lock)
466
479
}
0 commit comments