Removed duplicate file in Android.mk file list.
[openal-soft/android.git] / Alc / backends / mmdevapi.c
blobf171c059c699559c054a2e85591de11dee4d79a9
1 /**
2 * OpenAL cross platform audio library
3 * Copyright (C) 2011 by authors.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 * Or go to http://www.gnu.org/copyleft/lgpl.html
21 #include "config.h"
23 #define COBJMACROS
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <memory.h>
28 #include <mmdeviceapi.h>
29 #include <audioclient.h>
30 #include <cguid.h>
31 #include <mmreg.h>
32 #ifndef _WAVEFORMATEXTENSIBLE_
33 #include <ks.h>
34 #include <ksmedia.h>
35 #endif
37 #include "alMain.h"
38 #include "AL/al.h"
39 #include "AL/alc.h"
42 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
43 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
45 #define MONO SPEAKER_FRONT_CENTER
46 #define STEREO (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT)
47 #define QUAD (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
48 #define X5DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_LEFT|SPEAKER_BACK_RIGHT)
49 #define X5DOT1SIDE (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
50 #define X6DOT1 (SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT|SPEAKER_FRONT_CENTER|SPEAKER_LOW_FREQUENCY|SPEAKER_BACK_CENTER|SPEAKER_SIDE_LEFT|SPEAKER_SIDE_RIGHT)
51 #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)
54 typedef struct {
55 IMMDevice *mmdev;
56 IAudioClient *client;
57 HANDLE hNotifyEvent;
59 HANDLE MsgEvent;
61 volatile int killNow;
62 ALvoid *thread;
63 } MMDevApiData;
66 static const ALCchar mmDevice[] = "WASAPI Default";
69 static HANDLE ThreadHdl;
70 static DWORD ThreadID;
72 typedef struct {
73 HANDLE FinishedEvt;
74 HRESULT result;
75 } ThreadRequest;
77 #define WM_USER_OpenDevice (WM_USER+0)
78 #define WM_USER_ResetDevice (WM_USER+1)
79 #define WM_USER_StopDevice (WM_USER+2)
80 #define WM_USER_CloseDevice (WM_USER+3)
82 static HRESULT WaitForResponse(ThreadRequest *req)
84 if(WaitForSingleObject(req->FinishedEvt, INFINITE) == WAIT_OBJECT_0)
85 return req->result;
86 ERR("Message response error: %lu\n", GetLastError());
87 return E_FAIL;
91 static ALuint MMDevApiProc(ALvoid *ptr)
93 ALCdevice *device = ptr;
94 MMDevApiData *data = device->ExtraData;
95 union {
96 IAudioRenderClient *iface;
97 void *ptr;
98 } render;
99 UINT32 written, len;
100 BYTE *buffer;
101 HRESULT hr;
103 hr = CoInitialize(NULL);
104 if(FAILED(hr))
106 ERR("CoInitialize(NULL) failed: 0x%08lx\n", hr);
107 aluHandleDisconnect(device);
108 return 0;
111 hr = IAudioClient_GetService(data->client, &IID_IAudioRenderClient, &render.ptr);
112 if(FAILED(hr))
114 ERR("Failed to get AudioRenderClient service: 0x%08lx\n", hr);
115 aluHandleDisconnect(device);
116 return 0;
119 SetRTPriority();
121 while(!data->killNow)
123 hr = IAudioClient_GetCurrentPadding(data->client, &written);
124 if(FAILED(hr))
126 ERR("Failed to get padding: 0x%08lx\n", hr);
127 aluHandleDisconnect(device);
128 break;
131 len = device->UpdateSize*device->NumUpdates - written;
132 if(len < device->UpdateSize)
134 DWORD res;
135 res = WaitForSingleObjectEx(data->hNotifyEvent, 2000, FALSE);
136 if(res != WAIT_OBJECT_0)
137 ERR("WaitForSingleObjectEx error: 0x%lx\n", res);
138 continue;
140 len -= len%device->UpdateSize;
142 hr = IAudioRenderClient_GetBuffer(render.iface, len, &buffer);
143 if(SUCCEEDED(hr))
145 aluMixData(device, buffer, len);
146 hr = IAudioRenderClient_ReleaseBuffer(render.iface, len, 0);
148 if(FAILED(hr))
150 ERR("Failed to buffer data: 0x%08lx\n", hr);
151 aluHandleDisconnect(device);
152 break;
156 IAudioRenderClient_Release(render.iface);
158 CoUninitialize();
159 return 0;
163 static ALCboolean MakeExtensible(WAVEFORMATEXTENSIBLE *out, const WAVEFORMATEX *in)
165 memset(out, 0, sizeof(*out));
166 if(in->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
167 *out = *(WAVEFORMATEXTENSIBLE*)in;
168 else if(in->wFormatTag == WAVE_FORMAT_PCM)
170 out->Format = *in;
171 out->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
172 out->Format.cbSize = sizeof(*out) - sizeof(*in);
173 if(out->Format.nChannels == 1)
174 out->dwChannelMask = MONO;
175 else if(out->Format.nChannels == 2)
176 out->dwChannelMask = STEREO;
177 else
178 ERR("Unhandled PCM channel count: %d\n", out->Format.nChannels);
179 out->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
181 else if(in->wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
183 out->Format = *in;
184 out->Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
185 out->Format.cbSize = sizeof(*out) - sizeof(*in);
186 if(out->Format.nChannels == 1)
187 out->dwChannelMask = MONO;
188 else if(out->Format.nChannels == 2)
189 out->dwChannelMask = STEREO;
190 else
191 ERR("Unhandled IEEE float channel count: %d\n", out->Format.nChannels);
192 out->SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
194 else
196 ERR("Unhandled format tag: 0x%04x\n", in->wFormatTag);
197 return ALC_FALSE;
199 return ALC_TRUE;
202 static HRESULT DoReset(ALCdevice *device)
204 MMDevApiData *data = device->ExtraData;
205 WAVEFORMATEXTENSIBLE OutputType;
206 WAVEFORMATEX *wfx = NULL;
207 REFERENCE_TIME min_per;
208 UINT32 buffer_len, min_len;
209 HRESULT hr;
211 hr = IAudioClient_GetMixFormat(data->client, &wfx);
212 if(FAILED(hr))
214 ERR("Failed to get mix format: 0x%08lx\n", hr);
215 return hr;
218 if(!MakeExtensible(&OutputType, wfx))
220 CoTaskMemFree(wfx);
221 return E_FAIL;
223 CoTaskMemFree(wfx);
224 wfx = NULL;
226 if(!(device->Flags&DEVICE_FREQUENCY_REQUEST))
227 device->Frequency = OutputType.Format.nSamplesPerSec;
228 if(!(device->Flags&DEVICE_CHANNELS_REQUEST))
230 if(OutputType.Format.nChannels == 1 && OutputType.dwChannelMask == MONO)
231 device->FmtChans = DevFmtMono;
232 else if(OutputType.Format.nChannels == 2 && OutputType.dwChannelMask == STEREO)
233 device->FmtChans = DevFmtStereo;
234 else if(OutputType.Format.nChannels == 4 && OutputType.dwChannelMask == QUAD)
235 device->FmtChans = DevFmtQuad;
236 else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1)
237 device->FmtChans = DevFmtX51;
238 else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1SIDE)
239 device->FmtChans = DevFmtX51Side;
240 else if(OutputType.Format.nChannels == 7 && OutputType.dwChannelMask == X6DOT1)
241 device->FmtChans = DevFmtX61;
242 else if(OutputType.Format.nChannels == 8 && OutputType.dwChannelMask == X7DOT1)
243 device->FmtChans = DevFmtX71;
244 else
245 ERR("Unhandled channel config: %d -- 0x%08lx\n", OutputType.Format.nChannels, OutputType.dwChannelMask);
248 switch(device->FmtChans)
250 case DevFmtMono:
251 OutputType.Format.nChannels = 1;
252 OutputType.dwChannelMask = MONO;
253 break;
254 case DevFmtStereo:
255 OutputType.Format.nChannels = 2;
256 OutputType.dwChannelMask = STEREO;
257 break;
258 case DevFmtQuad:
259 OutputType.Format.nChannels = 4;
260 OutputType.dwChannelMask = QUAD;
261 break;
262 case DevFmtX51:
263 OutputType.Format.nChannels = 6;
264 OutputType.dwChannelMask = X5DOT1;
265 break;
266 case DevFmtX51Side:
267 OutputType.Format.nChannels = 6;
268 OutputType.dwChannelMask = X5DOT1SIDE;
269 break;
270 case DevFmtX61:
271 OutputType.Format.nChannels = 7;
272 OutputType.dwChannelMask = X6DOT1;
273 break;
274 case DevFmtX71:
275 OutputType.Format.nChannels = 8;
276 OutputType.dwChannelMask = X7DOT1;
277 break;
279 switch(device->FmtType)
281 case DevFmtByte:
282 device->FmtType = DevFmtUByte;
283 /* fall-through */
284 case DevFmtUByte:
285 OutputType.Format.wBitsPerSample = 8;
286 OutputType.Samples.wValidBitsPerSample = 8;
287 OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
288 break;
289 case DevFmtUShort:
290 device->FmtType = DevFmtShort;
291 /* fall-through */
292 case DevFmtShort:
293 OutputType.Format.wBitsPerSample = 16;
294 OutputType.Samples.wValidBitsPerSample = 16;
295 OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
296 break;
297 case DevFmtFloat:
298 OutputType.Format.wBitsPerSample = 32;
299 OutputType.Samples.wValidBitsPerSample = 32;
300 OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
301 break;
303 OutputType.Format.nSamplesPerSec = device->Frequency;
305 OutputType.Format.nBlockAlign = OutputType.Format.nChannels *
306 OutputType.Format.wBitsPerSample / 8;
307 OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec *
308 OutputType.Format.nBlockAlign;
310 hr = IAudioClient_IsFormatSupported(data->client, AUDCLNT_SHAREMODE_SHARED, &OutputType.Format, &wfx);
311 if(FAILED(hr))
313 ERR("Failed to check format support: 0x%08lx\n", hr);
314 hr = IAudioClient_GetMixFormat(data->client, &wfx);
316 if(FAILED(hr))
318 ERR("Failed to find a supported format: 0x%08lx\n", hr);
319 return hr;
322 if(wfx != NULL)
324 if(!MakeExtensible(&OutputType, wfx))
326 CoTaskMemFree(wfx);
327 return E_FAIL;
329 CoTaskMemFree(wfx);
330 wfx = NULL;
332 device->Frequency = OutputType.Format.nSamplesPerSec;
333 if(OutputType.Format.nChannels == 1 && OutputType.dwChannelMask == MONO)
334 device->FmtChans = DevFmtMono;
335 else if(OutputType.Format.nChannels == 2 && OutputType.dwChannelMask == STEREO)
336 device->FmtChans = DevFmtStereo;
337 else if(OutputType.Format.nChannels == 4 && OutputType.dwChannelMask == QUAD)
338 device->FmtChans = DevFmtQuad;
339 else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1)
340 device->FmtChans = DevFmtX51;
341 else if(OutputType.Format.nChannels == 6 && OutputType.dwChannelMask == X5DOT1SIDE)
342 device->FmtChans = DevFmtX51Side;
343 else if(OutputType.Format.nChannels == 7 && OutputType.dwChannelMask == X6DOT1)
344 device->FmtChans = DevFmtX61;
345 else if(OutputType.Format.nChannels == 8 && OutputType.dwChannelMask == X7DOT1)
346 device->FmtChans = DevFmtX71;
347 else
349 ERR("Unhandled extensible channels: %d -- 0x%08lx\n", OutputType.Format.nChannels, OutputType.dwChannelMask);
350 device->FmtChans = DevFmtStereo;
351 OutputType.Format.nChannels = 2;
352 OutputType.dwChannelMask = STEREO;
355 if(IsEqualGUID(&OutputType.SubFormat, &KSDATAFORMAT_SUBTYPE_PCM))
357 if(OutputType.Format.wBitsPerSample == 8)
358 device->FmtType = DevFmtUByte;
359 else if(OutputType.Format.wBitsPerSample == 16)
360 device->FmtType = DevFmtShort;
361 else
363 device->FmtType = DevFmtShort;
364 OutputType.Format.wBitsPerSample = 16;
367 else if(IsEqualGUID(&OutputType.SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT))
369 device->FmtType = DevFmtFloat;
370 OutputType.Format.wBitsPerSample = 32;
372 else
374 ERR("Unhandled format sub-type\n");
375 device->FmtType = DevFmtShort;
376 OutputType.Format.wBitsPerSample = 16;
377 OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
379 OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample;
382 SetDefaultWFXChannelOrder(device);
384 hr = IAudioClient_GetDevicePeriod(data->client, &min_per, NULL);
385 if(SUCCEEDED(hr))
387 min_len = (min_per*device->Frequency + 10000000-1) / 10000000;
388 if(min_len < device->UpdateSize)
389 min_len *= (device->UpdateSize + min_len/2)/min_len;
391 device->NumUpdates = (device->NumUpdates*device->UpdateSize + min_len/2) /
392 min_len;
393 device->NumUpdates = maxu(device->NumUpdates, 2);
394 device->UpdateSize = min_len;
396 hr = IAudioClient_Initialize(data->client, AUDCLNT_SHAREMODE_SHARED,
397 AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
398 ((REFERENCE_TIME)device->UpdateSize*
399 device->NumUpdates*10000000 +
400 device->Frequency-1) / device->Frequency,
401 0, &OutputType.Format, NULL);
403 if(FAILED(hr))
405 ERR("Failed to initialize audio client: 0x%08lx\n", hr);
406 return hr;
409 hr = IAudioClient_GetBufferSize(data->client, &buffer_len);
410 if(FAILED(hr))
412 ERR("Failed to get audio buffer info: 0x%08lx\n", hr);
413 return hr;
416 device->NumUpdates = buffer_len / device->UpdateSize;
417 if(device->NumUpdates <= 1)
419 device->NumUpdates = 1;
420 ERR("Audio client returned buffer_len < period*2; expect break up\n");
423 ResetEvent(data->hNotifyEvent);
424 hr = IAudioClient_SetEventHandle(data->client, data->hNotifyEvent);
425 if(SUCCEEDED(hr))
426 hr = IAudioClient_Start(data->client);
427 if(FAILED(hr))
429 ERR("Failed to start audio client: 0x%08lx\n", hr);
430 return hr;
433 data->thread = StartThread(MMDevApiProc, device);
434 if(!data->thread)
436 IAudioClient_Stop(data->client);
437 ERR("Failed to start thread\n");
438 return E_FAIL;
441 return hr;
445 static DWORD CALLBACK MMDevApiMsgProc(void *ptr)
447 ThreadRequest *req = ptr;
448 IMMDeviceEnumerator *Enumerator;
449 ALuint deviceCount = 0;
450 MMDevApiData *data;
451 ALCdevice *device;
452 HRESULT hr;
453 MSG msg;
455 TRACE("Starting message thread\n");
457 hr = CoInitialize(NULL);
458 if(FAILED(hr))
460 WARN("Failed to initialize COM: 0x%08lx\n", hr);
461 req->result = hr;
462 SetEvent(req->FinishedEvt);
463 return 0;
466 hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, &ptr);
467 if(FAILED(hr))
469 WARN("Failed to create IMMDeviceEnumerator instance: 0x%08lx\n", hr);
470 CoUninitialize();
471 req->result = hr;
472 SetEvent(req->FinishedEvt);
473 return 0;
475 Enumerator = ptr;
476 IMMDeviceEnumerator_Release(Enumerator);
477 Enumerator = NULL;
479 CoUninitialize();
481 req->result = S_OK;
482 SetEvent(req->FinishedEvt);
484 TRACE("Starting message loop\n");
485 while(GetMessage(&msg, NULL, 0, 0))
487 TRACE("Got message %u\n", msg.message);
488 switch(msg.message)
490 case WM_USER_OpenDevice:
491 req = (ThreadRequest*)msg.wParam;
492 device = (ALCdevice*)msg.lParam;
493 data = device->ExtraData;
495 hr = S_OK;
496 if(++deviceCount == 1)
497 hr = CoInitialize(NULL);
498 if(SUCCEEDED(hr))
499 hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, &ptr);
500 if(SUCCEEDED(hr))
502 Enumerator = ptr;
503 hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(Enumerator, eRender, eMultimedia, &data->mmdev);
504 IMMDeviceEnumerator_Release(Enumerator);
505 Enumerator = NULL;
507 if(SUCCEEDED(hr))
508 hr = IMMDevice_Activate(data->mmdev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, &ptr);
509 if(SUCCEEDED(hr))
510 data->client = ptr;
512 if(FAILED(hr))
514 if(data->mmdev)
515 IMMDevice_Release(data->mmdev);
516 data->mmdev = NULL;
519 req->result = hr;
520 SetEvent(req->FinishedEvt);
521 continue;
523 case WM_USER_ResetDevice:
524 req = (ThreadRequest*)msg.wParam;
525 device = (ALCdevice*)msg.lParam;
527 req->result = DoReset(device);
528 SetEvent(req->FinishedEvt);
529 continue;
531 case WM_USER_StopDevice:
532 req = (ThreadRequest*)msg.wParam;
533 device = (ALCdevice*)msg.lParam;
534 data = device->ExtraData;
536 if(data->thread)
538 data->killNow = 1;
539 StopThread(data->thread);
540 data->thread = NULL;
542 data->killNow = 0;
544 IAudioClient_Stop(data->client);
547 req->result = S_OK;
548 SetEvent(req->FinishedEvt);
549 continue;
551 case WM_USER_CloseDevice:
552 req = (ThreadRequest*)msg.wParam;
553 device = (ALCdevice*)msg.lParam;
554 data = device->ExtraData;
556 IAudioClient_Release(data->client);
557 data->client = NULL;
559 IMMDevice_Release(data->mmdev);
560 data->mmdev = NULL;
562 if(--deviceCount == 0)
563 CoUninitialize();
565 req->result = S_OK;
566 SetEvent(req->FinishedEvt);
567 continue;
569 default:
570 ERR("Unexpected message: %u\n", msg.message);
571 continue;
574 TRACE("Message loop finished\n");
576 return 0;
580 static BOOL MMDevApiLoad(void)
582 static HRESULT InitResult;
583 if(!ThreadHdl)
585 ThreadRequest req;
586 InitResult = E_FAIL;
588 req.FinishedEvt = CreateEvent(NULL, FALSE, FALSE, NULL);
589 if(req.FinishedEvt == NULL)
590 ERR("Failed to create event: %lu\n", GetLastError());
591 else
593 ThreadHdl = CreateThread(NULL, 0, MMDevApiMsgProc, &req, 0, &ThreadID);
594 if(ThreadHdl != NULL)
595 InitResult = WaitForResponse(&req);
596 CloseHandle(req.FinishedEvt);
599 return SUCCEEDED(InitResult);
603 static ALCenum MMDevApiOpenPlayback(ALCdevice *device, const ALCchar *deviceName)
605 MMDevApiData *data = NULL;
606 HRESULT hr;
608 if(!deviceName)
609 deviceName = mmDevice;
610 else if(strcmp(deviceName, mmDevice) != 0)
611 return ALC_INVALID_VALUE;
613 //Initialise requested device
614 data = calloc(1, sizeof(MMDevApiData));
615 if(!data)
616 return ALC_OUT_OF_MEMORY;
617 device->ExtraData = data;
619 hr = S_OK;
620 data->hNotifyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
621 data->MsgEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
622 if(data->hNotifyEvent == NULL || data->MsgEvent == NULL)
623 hr = E_FAIL;
625 if(SUCCEEDED(hr))
627 ThreadRequest req = { data->MsgEvent, 0 };
629 hr = E_FAIL;
630 if(PostThreadMessage(ThreadID, WM_USER_OpenDevice, (WPARAM)&req, (LPARAM)device))
631 hr = WaitForResponse(&req);
634 if(FAILED(hr))
636 if(data->hNotifyEvent != NULL)
637 CloseHandle(data->hNotifyEvent);
638 data->hNotifyEvent = NULL;
639 if(data->MsgEvent != NULL)
640 CloseHandle(data->MsgEvent);
641 data->MsgEvent = NULL;
643 free(data);
644 device->ExtraData = NULL;
646 ERR("Device init failed: 0x%08lx\n", hr);
647 return ALC_INVALID_VALUE;
650 device->szDeviceName = strdup(deviceName);
651 return ALC_NO_ERROR;
654 static void MMDevApiClosePlayback(ALCdevice *device)
656 MMDevApiData *data = device->ExtraData;
657 ThreadRequest req = { data->MsgEvent, 0 };
659 if(PostThreadMessage(ThreadID, WM_USER_CloseDevice, (WPARAM)&req, (LPARAM)device))
660 (void)WaitForResponse(&req);
662 CloseHandle(data->MsgEvent);
663 data->MsgEvent = NULL;
665 CloseHandle(data->hNotifyEvent);
666 data->hNotifyEvent = NULL;
668 free(data);
669 device->ExtraData = NULL;
672 static ALCboolean MMDevApiResetPlayback(ALCdevice *device)
674 MMDevApiData *data = device->ExtraData;
675 ThreadRequest req = { data->MsgEvent, 0 };
676 HRESULT hr = E_FAIL;
678 if(PostThreadMessage(ThreadID, WM_USER_ResetDevice, (WPARAM)&req, (LPARAM)device))
679 hr = WaitForResponse(&req);
681 return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE;
684 static void MMDevApiStopPlayback(ALCdevice *device)
686 MMDevApiData *data = device->ExtraData;
687 ThreadRequest req = { data->MsgEvent, 0 };
689 if(PostThreadMessage(ThreadID, WM_USER_StopDevice, (WPARAM)&req, (LPARAM)device))
690 (void)WaitForResponse(&req);
694 static const BackendFuncs MMDevApiFuncs = {
695 MMDevApiOpenPlayback,
696 MMDevApiClosePlayback,
697 MMDevApiResetPlayback,
698 MMDevApiStopPlayback,
699 NULL,
700 NULL,
701 NULL,
702 NULL,
703 NULL,
704 NULL
708 ALCboolean alcMMDevApiInit(BackendFuncs *FuncList)
710 if(!MMDevApiLoad())
711 return ALC_FALSE;
712 *FuncList = MMDevApiFuncs;
713 return ALC_TRUE;
716 void alcMMDevApiDeinit(void)
718 if(ThreadHdl)
720 TRACE("Sending WM_QUIT to Thread %04lx\n", ThreadID);
721 PostThreadMessage(ThreadID, WM_QUIT, 0, 0);
722 CloseHandle(ThreadHdl);
723 ThreadHdl = NULL;
727 void alcMMDevApiProbe(enum DevProbe type)
729 switch(type)
731 case DEVICE_PROBE:
732 AppendDeviceList(mmDevice);
733 break;
734 case ALL_DEVICE_PROBE:
735 AppendAllDeviceList(mmDevice);
736 break;
737 case CAPTURE_DEVICE_PROBE:
738 break;