21 #include "../../SDL_internal.h"
28 #if SDL_AUDIO_DRIVER_WASAPI && defined(__WINRT__)
31 #include <windows.ui.core.h>
32 #include <windows.devices.enumeration.h>
33 #include <windows.media.devices.h>
34 #include <wrl/implements.h>
37 #include "../../core/windows/SDL_windows.h"
40 #include "../SDL_audio_c.h"
41 #include "../SDL_sysaudio.h"
45 #include <mmdeviceapi.h>
46 #include <audioclient.h>
50 using namespace Windows::Devices::Enumeration;
51 using namespace Windows::Media::Devices;
52 using namespace Windows::Foundation;
53 using namespace Microsoft::WRL;
55 class SDL_WasapiDeviceEventHandler
58 SDL_WasapiDeviceEventHandler(
const SDL_bool _iscapture);
59 ~SDL_WasapiDeviceEventHandler();
60 void OnDeviceAdded(DeviceWatcher^ sender, DeviceInformation^ args);
61 void OnDeviceRemoved(DeviceWatcher^ sender, DeviceInformationUpdate^ args);
62 void OnDeviceUpdated(DeviceWatcher^ sender, DeviceInformationUpdate^ args);
63 void OnEnumerationCompleted(DeviceWatcher^ sender, Platform::Object^ args);
64 void OnDefaultRenderDeviceChanged(Platform::Object^ sender, DefaultAudioRenderDeviceChangedEventArgs^ args);
65 void OnDefaultCaptureDeviceChanged(Platform::Object^ sender, DefaultAudioCaptureDeviceChangedEventArgs^ args);
70 DeviceWatcher^ watcher;
71 Windows::Foundation::EventRegistrationToken added_handler;
72 Windows::Foundation::EventRegistrationToken removed_handler;
73 Windows::Foundation::EventRegistrationToken updated_handler;
74 Windows::Foundation::EventRegistrationToken completed_handler;
75 Windows::Foundation::EventRegistrationToken default_changed_handler;
78 SDL_WasapiDeviceEventHandler::SDL_WasapiDeviceEventHandler(
const SDL_bool _iscapture)
79 : iscapture(_iscapture)
81 , watcher(DeviceInformation::CreateWatcher(_iscapture ? DeviceClass::AudioCapture : DeviceClass::AudioRender))
83 if (!watcher || !completed)
87 added_handler = watcher->Added +=
ref new TypedEventHandler<DeviceWatcher^, DeviceInformation^>([
this](DeviceWatcher^ sender, DeviceInformation^ args) { OnDeviceAdded(sender, args); } );
88 removed_handler = watcher->Removed +=
ref new TypedEventHandler<DeviceWatcher^, DeviceInformationUpdate^>([
this](DeviceWatcher^ sender, DeviceInformationUpdate^ args) { OnDeviceRemoved(sender, args); } );
89 updated_handler = watcher->Updated +=
ref new TypedEventHandler<DeviceWatcher^, DeviceInformationUpdate^>([
this](DeviceWatcher^ sender, DeviceInformationUpdate^ args) { OnDeviceUpdated(sender, args); } );
90 completed_handler = watcher->EnumerationCompleted +=
ref new TypedEventHandler<DeviceWatcher^, Platform::Object^>([
this](DeviceWatcher^ sender, Platform::Object^ args) { OnEnumerationCompleted(sender, args); } );
92 default_changed_handler = MediaDevice::DefaultAudioCaptureDeviceChanged +=
ref new TypedEventHandler<Platform::Object^, DefaultAudioCaptureDeviceChangedEventArgs^>([
this](Platform::Object^ sender, DefaultAudioCaptureDeviceChangedEventArgs^ args) { OnDefaultCaptureDeviceChanged(sender, args); } );
94 default_changed_handler = MediaDevice::DefaultAudioRenderDeviceChanged +=
ref new TypedEventHandler<Platform::Object^, DefaultAudioRenderDeviceChangedEventArgs^>([
this](Platform::Object^ sender, DefaultAudioRenderDeviceChangedEventArgs^ args) { OnDefaultRenderDeviceChanged(sender, args); } );
99 SDL_WasapiDeviceEventHandler::~SDL_WasapiDeviceEventHandler()
102 watcher->Added -= added_handler;
103 watcher->Removed -= removed_handler;
104 watcher->Updated -= updated_handler;
105 watcher->EnumerationCompleted -= completed_handler;
115 MediaDevice::DefaultAudioCaptureDeviceChanged -= default_changed_handler;
117 MediaDevice::DefaultAudioRenderDeviceChanged -= default_changed_handler;
122 SDL_WasapiDeviceEventHandler::OnDeviceAdded(DeviceWatcher^ sender, DeviceInformation^ info)
133 SDL_WasapiDeviceEventHandler::OnDeviceRemoved(DeviceWatcher^ sender, DeviceInformationUpdate^ info)
140 SDL_WasapiDeviceEventHandler::OnDeviceUpdated(DeviceWatcher^ sender, DeviceInformationUpdate^ args)
146 SDL_WasapiDeviceEventHandler::OnEnumerationCompleted(DeviceWatcher^ sender, Platform::Object^ args)
153 SDL_WasapiDeviceEventHandler::OnDefaultRenderDeviceChanged(Platform::Object^ sender, DefaultAudioRenderDeviceChangedEventArgs^ args)
160 SDL_WasapiDeviceEventHandler::OnDefaultCaptureDeviceChanged(Platform::Object^ sender, DefaultAudioCaptureDeviceChangedEventArgs^ args)
167 static SDL_WasapiDeviceEventHandler *playback_device_event_handler;
168 static SDL_WasapiDeviceEventHandler *capture_device_event_handler;
177 delete playback_device_event_handler;
178 playback_device_event_handler =
nullptr;
179 delete capture_device_event_handler;
180 capture_device_event_handler =
nullptr;
188 playback_device_event_handler =
new SDL_WasapiDeviceEventHandler(
SDL_FALSE);
189 capture_device_event_handler =
new SDL_WasapiDeviceEventHandler(
SDL_TRUE);
190 SDL_SemWait(playback_device_event_handler->completed);
191 SDL_SemWait(capture_device_event_handler->completed);
194 struct SDL_WasapiActivationHandler :
public RuntimeClass< RuntimeClassFlags< ClassicCom >, FtmBase, IActivateAudioInterfaceCompletionHandler >
196 SDL_WasapiActivationHandler() :
device(nullptr) {}
197 STDMETHOD(ActivateCompleted)(IActivateAudioInterfaceAsyncOperation *operation);
202 SDL_WasapiActivationHandler::ActivateCompleted(IActivateAudioInterfaceAsyncOperation *async)
213 ((SDL_WasapiActivationHandler *) handler)->Release();
219 LPCWSTR devid =
_this->hidden->devid;
220 Platform::String^ defdevid;
222 if (devid ==
nullptr) {
223 defdevid =
_this->iscapture ? MediaDevice::GetDefaultAudioCaptureId(AudioDeviceRole::Default) : MediaDevice::GetDefaultAudioRenderId(AudioDeviceRole::Default);
225 devid = defdevid->Data();
231 ComPtr<SDL_WasapiActivationHandler> handler = Make<SDL_WasapiActivationHandler>();
232 if (handler ==
nullptr) {
233 return SDL_SetError(
"Failed to allocate WASAPI activation handler");
236 handler.Get()->AddRef();
237 handler.Get()->device =
_this;
238 _this->hidden->activation_handler = handler.Get();
241 IActivateAudioInterfaceAsyncOperation *async =
nullptr;
242 const HRESULT ret = ActivateAudioInterfaceAsync(devid, __uuidof(IAudioClient),
nullptr, handler.Get(), &async);
244 if (
FAILED(ret) || async ==
nullptr) {
245 if (async !=
nullptr) {
248 handler.Get()->Release();
265 HRESULT activateRes =
S_OK;
266 IUnknown *iunknown =
nullptr;
267 const HRESULT getActivateRes = async->GetActivateResult(&activateRes, &iunknown);
269 if (
FAILED(getActivateRes)) {
271 }
else if (
FAILED(activateRes)) {
275 iunknown->QueryInterface(IID_PPV_ARGS(&
_this->hidden->client));
276 if (!
_this->hidden->client) {
277 return SDL_SetError(
"Failed to query WASAPI client interface");
#define SDL_assert(condition)
#define SDL_DestroySemaphore
#define SDL_CreateSemaphore
static SDL_VideoDevice * _this
void WASAPI_PlatformDeleteActivationHandler(void *handler)
void WASAPI_RemoveDevice(const SDL_bool iscapture, LPCWSTR devid)
SDL_atomic_t WASAPI_DefaultPlaybackGeneration
void WASAPI_PlatformThreadDeinit(_THIS)
int WASAPI_ActivateDevice(_THIS, const SDL_bool isrecovery)
void WASAPI_RefDevice(_THIS)
SDL_atomic_t WASAPI_DefaultCaptureGeneration
void WASAPI_PlatformThreadInit(_THIS)
int WASAPI_PlatformInit(void)
int WASAPI_PrepDevice(_THIS, const SDL_bool updatestream)
void WASAPI_EnumerateEndpoints(void)
void WASAPI_PlatformDeinit(void)
void WASAPI_AddDevice(const SDL_bool iscapture, const char *devname, LPCWSTR devid)
void WASAPI_UnrefDevice(_THIS)
#define WIN_StringToUTF8(S)
int WIN_SetErrorFromHRESULT(const char *prefix, HRESULT hr)
static SDL_AudioDeviceID device