22#include "../../SDL_internal.h"
29#if SDL_AUDIO_DRIVER_WASAPI && defined(__WINRT__)
32#include <windows.ui.core.h>
33#include <windows.devices.enumeration.h>
34#include <windows.media.devices.h>
35#include <wrl/implements.h>
38#include "../../core/windows/SDL_windows.h"
41#include "../SDL_audio_c.h"
42#include "../SDL_sysaudio.h"
48#include <mmdeviceapi.h>
49#include <audioclient.h>
53using namespace Windows::Devices::Enumeration;
54using namespace Windows::Media::Devices;
55using namespace Windows::Foundation;
56using namespace Microsoft::WRL;
58class SDL_WasapiDeviceEventHandler
61 SDL_WasapiDeviceEventHandler(
const SDL_bool _iscapture);
62 ~SDL_WasapiDeviceEventHandler();
63 void OnDeviceAdded(DeviceWatcher^ sender, DeviceInformation^ args);
64 void OnDeviceRemoved(DeviceWatcher^ sender, DeviceInformationUpdate^ args);
65 void OnDeviceUpdated(DeviceWatcher^ sender, DeviceInformationUpdate^ args);
66 void OnDefaultRenderDeviceChanged(Platform::Object^ sender, DefaultAudioRenderDeviceChangedEventArgs^ args);
67 void OnDefaultCaptureDeviceChanged(Platform::Object^ sender, DefaultAudioCaptureDeviceChangedEventArgs^ args);
71 DeviceWatcher^ watcher;
72 Windows::Foundation::EventRegistrationToken added_handler;
73 Windows::Foundation::EventRegistrationToken removed_handler;
74 Windows::Foundation::EventRegistrationToken updated_handler;
75 Windows::Foundation::EventRegistrationToken default_changed_handler;
78SDL_WasapiDeviceEventHandler::SDL_WasapiDeviceEventHandler(
const SDL_bool _iscapture)
79 : iscapture(_iscapture)
80 , watcher(DeviceInformation::CreateWatcher(_iscapture ? DeviceClass::AudioCapture : DeviceClass::AudioRender))
86 added_handler = watcher->Added +=
ref new TypedEventHandler<DeviceWatcher^, DeviceInformation^>([
this](DeviceWatcher^ sender, DeviceInformation^ args) { OnDeviceAdded(sender, args); } );
87 removed_handler = watcher->Removed +=
ref new TypedEventHandler<DeviceWatcher^, DeviceInformationUpdate^>([
this](DeviceWatcher^ sender, DeviceInformationUpdate^ args) { OnDeviceRemoved(sender, args); } );
88 updated_handler = watcher->Updated +=
ref new TypedEventHandler<DeviceWatcher^, DeviceInformationUpdate^>([
this](DeviceWatcher^ sender, DeviceInformationUpdate^ args) { OnDeviceUpdated(sender, args); } );
90 default_changed_handler = MediaDevice::DefaultAudioCaptureDeviceChanged +=
ref new TypedEventHandler<Platform::Object^, DefaultAudioCaptureDeviceChangedEventArgs^>([
this](Platform::Object^ sender, DefaultAudioCaptureDeviceChangedEventArgs^ args) { OnDefaultCaptureDeviceChanged(sender, args); } );
92 default_changed_handler = MediaDevice::DefaultAudioRenderDeviceChanged +=
ref new TypedEventHandler<Platform::Object^, DefaultAudioRenderDeviceChangedEventArgs^>([
this](Platform::Object^ sender, DefaultAudioRenderDeviceChangedEventArgs^ args) { OnDefaultRenderDeviceChanged(sender, args); } );
97SDL_WasapiDeviceEventHandler::~SDL_WasapiDeviceEventHandler()
100 watcher->Added -= added_handler;
101 watcher->Removed -= removed_handler;
102 watcher->Updated -= updated_handler;
108 MediaDevice::DefaultAudioCaptureDeviceChanged -= default_changed_handler;
110 MediaDevice::DefaultAudioRenderDeviceChanged -= default_changed_handler;
115SDL_WasapiDeviceEventHandler::OnDeviceAdded(DeviceWatcher^ sender, DeviceInformation^ info)
126SDL_WasapiDeviceEventHandler::OnDeviceRemoved(DeviceWatcher^ sender, DeviceInformationUpdate^ info)
133SDL_WasapiDeviceEventHandler::OnDeviceUpdated(DeviceWatcher^ sender, DeviceInformationUpdate^ args)
139SDL_WasapiDeviceEventHandler::OnDefaultRenderDeviceChanged(Platform::Object^ sender, DefaultAudioRenderDeviceChangedEventArgs^ args)
146SDL_WasapiDeviceEventHandler::OnDefaultCaptureDeviceChanged(Platform::Object^ sender, DefaultAudioCaptureDeviceChangedEventArgs^ args)
153static SDL_WasapiDeviceEventHandler *playback_device_event_handler;
154static SDL_WasapiDeviceEventHandler *capture_device_event_handler;
163 delete playback_device_event_handler;
164 playback_device_event_handler =
nullptr;
165 delete capture_device_event_handler;
166 capture_device_event_handler =
nullptr;
174 playback_device_event_handler =
new SDL_WasapiDeviceEventHandler(
SDL_FALSE);
175 capture_device_event_handler =
new SDL_WasapiDeviceEventHandler(
SDL_TRUE);
178struct SDL_WasapiActivationHandler :
public RuntimeClass< RuntimeClassFlags< ClassicCom >, FtmBase, IActivateAudioInterfaceCompletionHandler >
180 SDL_WasapiActivationHandler() :
device(nullptr) {}
181 STDMETHOD(ActivateCompleted)(IActivateAudioInterfaceAsyncOperation *operation);
186SDL_WasapiActivationHandler::ActivateCompleted(IActivateAudioInterfaceAsyncOperation *async)
197 ((SDL_WasapiActivationHandler *) handler)->Release();
203 LPCWSTR devid =
_this->hidden->devid;
204 Platform::String^ defdevid;
206 if (devid ==
nullptr) {
207 defdevid =
_this->iscapture ? MediaDevice::GetDefaultAudioCaptureId(AudioDeviceRole::Default) : MediaDevice::GetDefaultAudioRenderId(AudioDeviceRole::Default);
209 devid = defdevid->Data();
215 ComPtr<SDL_WasapiActivationHandler> handler = Make<SDL_WasapiActivationHandler>();
216 if (handler ==
nullptr) {
217 return SDL_SetError(
"Failed to allocate WASAPI activation handler");
220 handler.Get()->AddRef();
221 handler.Get()->device =
_this;
222 _this->hidden->activation_handler = handler.Get();
225 IActivateAudioInterfaceAsyncOperation *async =
nullptr;
226 const HRESULT ret = ActivateAudioInterfaceAsync(devid, __uuidof(IAudioClient),
nullptr, handler.Get(), &async);
228 if (
FAILED(ret) || async ==
nullptr) {
229 if (async !=
nullptr) {
232 handler.Get()->Release();
249 HRESULT activateRes =
S_OK;
250 IUnknown *iunknown =
nullptr;
251 const HRESULT getActivateRes = async->GetActivateResult(&activateRes, &iunknown);
253 if (
FAILED(getActivateRes)) {
255 }
else if (
FAILED(activateRes)) {
259 iunknown->QueryInterface(IID_PPV_ARGS(&
_this->hidden->client));
260 if (!
_this->hidden->client) {
261 return SDL_SetError(
"Failed to query WASAPI client interface");
#define SDL_assert(condition)
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