| /* |
| Simple DirectMedia Layer |
| Copyright (C) 1997-2023 Sam Lantinga <slouken@libsdl.org> |
| |
| This software is provided 'as-is', without any express or implied |
| warranty. In no event will the authors be held liable for any damages |
| arising from the use of this software. |
| |
| Permission is granted to anyone to use this software for any purpose, |
| including commercial applications, and to alter it and redistribute it |
| freely, subject to the following restrictions: |
| |
| 1. The origin of this software must not be misrepresented; you must not |
| claim that you wrote the original software. If you use this software |
| in a product, an acknowledgment in the product documentation would be |
| appreciated but is not required. |
| 2. Altered source versions must be plainly marked as such, and must not be |
| misrepresented as being the original software. |
| 3. This notice may not be removed or altered from any source distribution. |
| */ |
| #include "../../SDL_internal.h" |
| |
| /* This is code that Windows uses to talk to WASAPI-related system APIs. |
| This is for non-WinRT desktop apps. The C++/CX implementation of these |
| functions, exclusive to WinRT, are in SDL_wasapi_winrt.cpp. |
| The code in SDL_wasapi.c is used by both standard Windows and WinRT builds |
| to deal with audio and calls into these functions. */ |
| |
| #if SDL_AUDIO_DRIVER_WASAPI && !defined(__WINRT__) |
| |
| #include "../../core/windows/SDL_windows.h" |
| #include "../../core/windows/SDL_immdevice.h" |
| #include "SDL_audio.h" |
| #include "SDL_timer.h" |
| #include "../SDL_audio_c.h" |
| #include "../SDL_sysaudio.h" |
| |
| #include <audioclient.h> |
| |
| #include "SDL_wasapi.h" |
| |
| /* handle to Avrt.dll--Vista and later!--for flagging the callback thread as "Pro Audio" (low latency). */ |
| static HMODULE libavrt = NULL; |
| typedef HANDLE(WINAPI *pfnAvSetMmThreadCharacteristicsW)(LPCWSTR, LPDWORD); |
| typedef BOOL(WINAPI *pfnAvRevertMmThreadCharacteristics)(HANDLE); |
| static pfnAvSetMmThreadCharacteristicsW pAvSetMmThreadCharacteristicsW = NULL; |
| static pfnAvRevertMmThreadCharacteristics pAvRevertMmThreadCharacteristics = NULL; |
| |
| /* Some GUIDs we need to know without linking to libraries that aren't available before Vista. */ |
| static const IID SDL_IID_IAudioClient = { 0x1cb9ad4c, 0xdbfa, 0x4c32, { 0xb1, 0x78, 0xc2, 0xf5, 0x68, 0xa7, 0x03, 0xb2 } }; |
| |
| int WASAPI_PlatformInit(void) |
| { |
| if (SDL_IMMDevice_Init() < 0) { |
| return -1; /* This is set by SDL_IMMDevice_Init */ |
| } |
| |
| libavrt = LoadLibrary(TEXT("avrt.dll")); /* this library is available in Vista and later. No WinXP, so have to LoadLibrary to use it for now! */ |
| if (libavrt) { |
| pAvSetMmThreadCharacteristicsW = (pfnAvSetMmThreadCharacteristicsW)GetProcAddress(libavrt, "AvSetMmThreadCharacteristicsW"); |
| pAvRevertMmThreadCharacteristics = (pfnAvRevertMmThreadCharacteristics)GetProcAddress(libavrt, "AvRevertMmThreadCharacteristics"); |
| } |
| |
| return 0; |
| } |
| |
| void WASAPI_PlatformDeinit(void) |
| { |
| if (libavrt) { |
| FreeLibrary(libavrt); |
| libavrt = NULL; |
| } |
| |
| pAvSetMmThreadCharacteristicsW = NULL; |
| pAvRevertMmThreadCharacteristics = NULL; |
| |
| SDL_IMMDevice_Quit(); |
| } |
| |
| void WASAPI_PlatformThreadInit(_THIS) |
| { |
| /* this thread uses COM. */ |
| if (SUCCEEDED(WIN_CoInitialize())) { /* can't report errors, hope it worked! */ |
| this->hidden->coinitialized = SDL_TRUE; |
| } |
| |
| /* Set this thread to very high "Pro Audio" priority. */ |
| if (pAvSetMmThreadCharacteristicsW) { |
| DWORD idx = 0; |
| this->hidden->task = pAvSetMmThreadCharacteristicsW(L"Pro Audio", &idx); |
| } |
| } |
| |
| void WASAPI_PlatformThreadDeinit(_THIS) |
| { |
| /* Set this thread back to normal priority. */ |
| if (this->hidden->task && pAvRevertMmThreadCharacteristics) { |
| pAvRevertMmThreadCharacteristics(this->hidden->task); |
| this->hidden->task = NULL; |
| } |
| |
| if (this->hidden->coinitialized) { |
| WIN_CoUninitialize(); |
| this->hidden->coinitialized = SDL_FALSE; |
| } |
| } |
| |
| int WASAPI_ActivateDevice(_THIS, const SDL_bool isrecovery) |
| { |
| IMMDevice *device = NULL; |
| HRESULT ret; |
| |
| if (SDL_IMMDevice_Get(this->hidden->devid, &device, this->iscapture) < 0) { |
| this->hidden->client = NULL; |
| return -1; /* This is already set by SDL_IMMDevice_Get */ |
| } |
| |
| /* this is not async in standard win32, yay! */ |
| ret = IMMDevice_Activate(device, &SDL_IID_IAudioClient, CLSCTX_ALL, NULL, (void **)&this->hidden->client); |
| IMMDevice_Release(device); |
| |
| if (FAILED(ret)) { |
| SDL_assert(this->hidden->client == NULL); |
| return WIN_SetErrorFromHRESULT("WASAPI can't activate audio endpoint", ret); |
| } |
| |
| SDL_assert(this->hidden->client != NULL); |
| if (WASAPI_PrepDevice(this, isrecovery) == -1) { /* not async, fire it right away. */ |
| return -1; |
| } |
| |
| return 0; /* good to go. */ |
| } |
| |
| void WASAPI_EnumerateEndpoints(void) |
| { |
| SDL_IMMDevice_EnumerateEndpoints(SDL_FALSE); |
| } |
| |
| int WASAPI_GetDefaultAudioInfo(char **name, SDL_AudioSpec *spec, int iscapture) |
| { |
| return SDL_IMMDevice_GetDefaultAudioInfo(name, spec, iscapture); |
| } |
| |
| void WASAPI_PlatformDeleteActivationHandler(void *handler) |
| { |
| /* not asynchronous. */ |
| SDL_assert(!"This function should have only been called on WinRT."); |
| } |
| |
| #endif /* SDL_AUDIO_DRIVER_WASAPI && !defined(__WINRT__) */ |
| |
| /* vi: set ts=4 sw=4 expandtab: */ |