28 #include <mmdeviceapi.h>
29 #include <audioclient.h>
31 #include <devpropdef.h>
36 #ifndef _WAVEFORMATEXTENSIBLE_
45 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
46 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
48 DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,0x20, 0x67,0xd1,0x46,0xa8,0x50,0xe0, 14);
50 #define MONO SPEAKER_FRONT_CENTER
51 #define STEREO (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT)
52 #define QUAD (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
53 #define X5DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
54 #define X5DOT1SIDE (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
55 #define X6DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_CENTER|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
56 #define X7DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
64 IAudioRenderClient *
render;
69 volatile UINT32 Padding;
95 #define WM_USER_OpenDevice (WM_USER+0)
96 #define WM_USER_ResetDevice (WM_USER+1)
97 #define WM_USER_StartDevice (WM_USER+2)
98 #define WM_USER_StopDevice (WM_USER+3)
99 #define WM_USER_CloseDevice (WM_USER+4)
100 #define WM_USER_Enumerate (WM_USER+5)
104 if(WaitForSingleObject(req->FinishedEvt, INFINITE) == WAIT_OBJECT_0)
106 ERR(
"Message response error: %lu\n", GetLastError());
119 hr = IMMDevice_OpenPropertyStore(device, STGM_READ, &ps);
122 WARN(
"OpenPropertyStore failed: 0x%08lx\n", hr);
126 PropVariantInit(&pvname);
128 hr = IPropertyStore_GetValue(ps, (
const PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &pvname);
131 WARN(
"GetValue failed: 0x%08lx\n", hr);
136 if((len=WideCharToMultiByte(CP_ACP, 0, pvname.pwszVal, -1,
NULL, 0,
NULL,
NULL)) > 0)
139 WideCharToMultiByte(CP_ACP, 0, pvname.pwszVal, -1, name, len,
NULL,
NULL);
143 PropVariantClear(&pvname);
144 IPropertyStore_Release(ps);
154 hr = IMMDevice_GetId(device, &devid);
157 devmap->devid = strdupW(devid);
159 TRACE(
"Got device \"%s\", \"%ls\"\n", devmap->name, devmap->devid);
160 CoTaskMemFree(devid);
166 IMMDeviceCollection *coll;
167 IMMDevice *defdev =
NULL;
168 DevMap *devlist =
NULL;
174 hr = IMMDeviceEnumerator_EnumAudioEndpoints(devenum, flowdir, DEVICE_STATE_ACTIVE, &coll);
177 ERR(
"Failed to enumerate audio endpoints: 0x%08lx\n", hr);
182 hr = IMMDeviceCollection_GetCount(coll, &count);
183 if(SUCCEEDED(hr) && count > 0)
185 devlist =
calloc(count,
sizeof(*devlist));
188 IMMDeviceCollection_Release(coll);
192 hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(devenum, flowdir,
193 eMultimedia, &defdev);
195 if(SUCCEEDED(hr) && defdev !=
NULL)
198 for(i = 0;i < count && idx <
count;++
i)
202 if(FAILED(IMMDeviceCollection_Item(coll, i, &device)))
208 IMMDevice_Release(device);
211 if(defdev) IMMDevice_Release(defdev);
212 IMMDeviceCollection_Release(coll);
223 UINT32 buffer_len, written;
228 hr = CoInitialize(
NULL);
231 ERR(
"CoInitialize(NULL) failed: 0x%08lx\n", hr);
241 buffer_len = update_size * device->
NumUpdates;
242 while(!data->killNow)
244 hr = IAudioClient_GetCurrentPadding(data->client, &written);
247 ERR(
"Failed to get padding: 0x%08lx\n", hr);
253 data->Padding = written;
255 len = buffer_len - written;
256 if(len < update_size)
259 res = WaitForSingleObjectEx(data->NotifyEvent, 2000,
FALSE);
260 if(res != WAIT_OBJECT_0)
261 ERR(
"WaitForSingleObjectEx error: 0x%lx\n", res);
264 len -= len%update_size;
266 hr = IAudioRenderClient_GetBuffer(data->render, len, &buffer);
271 data->Padding = written +
len;
273 hr = IAudioRenderClient_ReleaseBuffer(data->render, len, 0);
277 ERR(
"Failed to buffer data: 0x%08lx\n", hr);
293 memset(out, 0,
sizeof(*out));
307 out->
SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
320 out->
SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
335 REFERENCE_TIME min_per, buf_time;
336 UINT32 buffer_len, min_len;
339 hr = IAudioClient_GetMixFormat(data->client, &wfx);
342 ERR(
"Failed to get mix format: 0x%08lx\n", hr);
418 OutputType.
SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
426 OutputType.
SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
434 OutputType.
SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
439 OutputType.
SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
449 hr = IAudioClient_IsFormatSupported(data->client, AUDCLNT_SHAREMODE_SHARED, &OutputType.
Format, &wfx);
452 ERR(
"Failed to check format support: 0x%08lx\n", hr);
453 hr = IAudioClient_GetMixFormat(data->client, &wfx);
457 ERR(
"Failed to find a supported format: 0x%08lx\n", hr);
494 if(IsEqualGUID(&OutputType.
SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))
508 else if(IsEqualGUID(&OutputType.
SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))
515 ERR(
"Unhandled format sub-type\n");
518 OutputType.
SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
525 hr = IAudioClient_Initialize(data->client, AUDCLNT_SHAREMODE_SHARED,
526 AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
530 ERR(
"Failed to initialize audio client: 0x%08lx\n", hr);
534 hr = IAudioClient_GetDevicePeriod(data->client, &min_per,
NULL);
537 min_len = (UINT32)((min_per*device->
Frequency + 10000000-1) / 10000000);
539 if(min_len < device->UpdateSize)
540 min_len *= (device->
UpdateSize + min_len/2)/min_len;
541 hr = IAudioClient_GetBufferSize(data->client, &buffer_len);
545 ERR(
"Failed to get audio buffer info: 0x%08lx\n", hr);
553 ERR(
"Audio client returned buffer_len < period*2; expect break up\n");
564 ThreadRequest *req = ptr;
565 IMMDeviceEnumerator *Enumerator;
572 TRACE(
"Starting message thread\n");
574 cohr = CoInitialize(
NULL);
577 WARN(
"Failed to initialize COM: 0x%08lx\n", cohr);
579 SetEvent(req->FinishedEvt);
583 hr = CoCreateInstance(&CLSID_MMDeviceEnumerator,
NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, &ptr);
586 WARN(
"Failed to create IMMDeviceEnumerator instance: 0x%08lx\n", hr);
589 SetEvent(req->FinishedEvt);
593 IMMDeviceEnumerator_Release(Enumerator);
599 SetEvent(req->FinishedEvt);
601 TRACE(
"Starting message loop\n");
602 while(GetMessage(&msg,
NULL, 0, 0))
604 TRACE(
"Got message %u\n", msg.message);
608 req = (ThreadRequest*)msg.wParam;
613 if(++deviceCount == 1)
614 hr = cohr = CoInitialize(
NULL);
616 hr = CoCreateInstance(&CLSID_MMDeviceEnumerator,
NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, &ptr);
621 hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(Enumerator, eRender, eMultimedia, &data->mmdev);
623 hr = IMMDeviceEnumerator_GetDevice(Enumerator, data->devid, &data->mmdev);
624 IMMDeviceEnumerator_Release(Enumerator);
628 hr = IMMDevice_Activate(data->mmdev, &IID_IAudioClient, CLSCTX_INPROC_SERVER,
NULL, &ptr);
638 IMMDevice_Release(data->mmdev);
640 if(--deviceCount == 0 && SUCCEEDED(cohr))
645 SetEvent(req->FinishedEvt);
649 req = (ThreadRequest*)msg.wParam;
653 SetEvent(req->FinishedEvt);
657 req = (ThreadRequest*)msg.wParam;
661 ResetEvent(data->NotifyEvent);
662 hr = IAudioClient_SetEventHandle(data->client, data->NotifyEvent);
664 ERR(
"Failed to set event handle: 0x%08lx\n", hr);
667 hr = IAudioClient_Start(data->client);
669 ERR(
"Failed to start audio client: 0x%08lx\n", hr);
673 hr = IAudioClient_GetService(data->client, &IID_IAudioRenderClient, &ptr);
681 IAudioRenderClient_Release(data->render);
683 IAudioClient_Stop(data->client);
684 ERR(
"Failed to start thread\n");
690 SetEvent(req->FinishedEvt);
694 req = (ThreadRequest*)msg.wParam;
706 IAudioRenderClient_Release(data->render);
708 IAudioClient_Stop(data->client);
712 SetEvent(req->FinishedEvt);
716 req = (ThreadRequest*)msg.wParam;
720 IAudioClient_Release(data->client);
723 IMMDevice_Release(data->mmdev);
726 if(--deviceCount == 0)
730 SetEvent(req->FinishedEvt);
734 req = (ThreadRequest*)msg.wParam;
737 if(++deviceCount == 1)
738 hr = cohr = CoInitialize(
NULL);
740 hr = CoCreateInstance(&CLSID_MMDeviceEnumerator,
NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, &ptr);
762 for(i = 0;i < *numdevs;i++)
765 free((*devlist)[i].devid);
773 IMMDeviceEnumerator_Release(Enumerator);
777 if(--deviceCount == 0 && SUCCEEDED(cohr))
781 SetEvent(req->FinishedEvt);
785 ERR(
"Unexpected message: %u\n", msg.message);
789 TRACE(
"Message loop finished\n");
804 if(req.FinishedEvt ==
NULL)
805 ERR(
"Failed to create event: %lu\n", GetLastError());
811 CloseHandle(req.FinishedEvt);
814 return SUCCEEDED(InitResult);
824 data =
calloc(1,
sizeof(MMDevApiData));
832 if(data->NotifyEvent ==
NULL || data->MsgEvent ==
NULL)
843 ThreadRequest req = { data->MsgEvent, 0 };
863 ThreadRequest req = { data->MsgEvent, 0 };
872 if(data->NotifyEvent !=
NULL)
873 CloseHandle(data->NotifyEvent);
874 data->NotifyEvent =
NULL;
875 if(data->MsgEvent !=
NULL)
876 CloseHandle(data->MsgEvent);
877 data->MsgEvent =
NULL;
882 ERR(
"Device init failed: 0x%08lx\n", hr);
892 ThreadRequest req = { data->MsgEvent, 0 };
897 CloseHandle(data->MsgEvent);
898 data->MsgEvent =
NULL;
900 CloseHandle(data->NotifyEvent);
901 data->NotifyEvent =
NULL;
907 device->ExtraData =
NULL;
913 ThreadRequest req = { data->MsgEvent, 0 };
925 ThreadRequest req = { data->MsgEvent, 0 };
937 ThreadRequest req = { data->MsgEvent, 0 };
948 return (ALint64)data->Padding * 1000000000 / device->
Frequency;
989 NumPlaybackDevices = 0;
998 NumCaptureDevices = 0;
1003 PostThreadMessage(
ThreadID, WM_QUIT, 0, 0);
1011 ThreadRequest req = {
NULL, 0 };
1018 if(req.FinishedEvt ==
NULL)
1019 ERR(
"Failed to create event: %lu\n", GetLastError());
1036 if(req.FinishedEvt !=
NULL)
1037 CloseHandle(req.FinishedEvt);
1038 req.FinishedEvt =
NULL;
#define DEVICE_FREQUENCY_REQUEST
GLint GLenum GLsizei GLsizei GLsizei GLint GLenum GLenum type
GLvoid **typedef void(GLAPIENTRY *PFNGLGETVERTEXATTRIBDVPROC)(GLuint
typedef HRESULT(WINAPI *LPD3DXIMTSIGNALCALLBACK)(CONST D3DXVECTOR2 *uv
static void MMDevApiClosePlayback(ALCdevice *device)
void alcMMDevApiDeinit(void)
static void render(const Vertex_Buffer_Macrorenderer ¯orenderer, std::vector< Vertex_Buffer::Vertex_Buffer_Range * > &descriptors)
ALvoid aluMixData(ALCdevice *device, ALvoid *buffer, ALsizei size)
EGLImageKHR EGLint * name
static ALCboolean MakeExtensible(WAVEFORMATEXTENSIBLE *out, const WAVEFORMATEX *in)
typedef UINT(WINAPI *PFNWGLGETCONTEXTGPUIDAMDPROC)(HGLRC hglrc)
static HRESULT DoReset(ALCdevice *device)
static DWORD CALLBACK MMDevApiMsgProc(void *ptr)
ALvoid aluHandleDisconnect(ALCdevice *device)
static DevMap * CaptureDeviceList
static ALuint NumCaptureDevices
static BOOL MMDevApiLoad(void)
static HRESULT WaitForResponse(ThreadRequest *req)
#define ALCdevice_Unlock(a)
#define WAVE_FORMAT_EXTENSIBLE
void alcMMDevApiProbe(enum DevProbe type)
EGLContext EGLenum EGLClientBuffer buffer
typedef HANDLE(WINAPI *PFNWGLCREATEBUFFERREGIONARBPROC)(HDC hDC
ALuint StopThread(ALvoid *thread)
static ALCchar * get_device_name(IMMDevice *device)
void SetDefaultWFXChannelOrder(ALCdevice *device)
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
static ALuint NumPlaybackDevices
static ALCenum MMDevApiOpenPlayback(ALCdevice *device, const ALCchar *deviceName)
static ALCboolean MMDevApiStartPlayback(ALCdevice *device)
static ALint64 MMDevApiGetLatency(ALCdevice *device)
#define WM_USER_StopDevice
ALCboolean alcMMDevApiInit(BackendFuncs *FuncList)
DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71)
#define WM_USER_StartDevice
static const BackendFuncs MMDevApiFuncs
union WAVEFORMATEXTENSIBLE::@63 Samples
static DevMap * PlaybackDeviceList
enum DevFmtChannels FmtChans
#define DEVICE_CHANNELS_REQUEST
static SDL_Thread * thread
static ALuint MMDevApiProc(ALvoid *ptr)
void ALCdevice_LockDefault(ALCdevice *device)
#define WAVE_FORMAT_IEEE_FLOAT
#define WM_USER_Enumerate
#define WM_USER_OpenDevice
typedef DWORD(WINAPI *XInputGetState_t)(DWORD dwUserIndex
static void add_device(IMMDevice *device, DevMap *devmap)
static void MMDevApiStopPlayback(ALCdevice *device)
#define ALC_INVALID_VALUE
#define ALC_OUT_OF_MEMORY
#define WM_USER_ResetDevice
static ALCboolean MMDevApiResetPlayback(ALCdevice *device)
#define WM_USER_CloseDevice
DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 14)
void ALCdevice_UnlockDefault(ALCdevice *device)
static DevMap * ProbeDevices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, ALuint *numdevs)
#define ALCdevice_Lock(a)
void AppendAllDevicesList(const ALCchar *name)
ALvoid * StartThread(ALuint(*func)(ALvoid *), ALvoid *ptr)
typedef BOOL(WINAPI *PFNWGLSETSTEREOEMITTERSTATE3DLPROC)(HDC hDC