aboutsummaryrefslogtreecommitdiffstats
path: root/Alc/backends/mmdevapi.c
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2014-06-10 05:30:02 +0200
committerSven Gothel <[email protected]>2014-06-10 05:30:02 +0200
commitf95bf4457fbc31112fa82dacbc1b7e094b9fd1cf (patch)
tree965ba5b8e6fc8e6bfe7a981c1dfb1179bb9adcde /Alc/backends/mmdevapi.c
parent7297c3214a4c648aaee81a9877da15b88f798197 (diff)
parentc07fb7b45c1e345dbaa439882250de5b2213026f (diff)
Merge branch 'UPSTREAM' into UPSTREAM_MERGE
Diffstat (limited to 'Alc/backends/mmdevapi.c')
-rw-r--r--Alc/backends/mmdevapi.c1109
1 files changed, 617 insertions, 492 deletions
diff --git a/Alc/backends/mmdevapi.c b/Alc/backends/mmdevapi.c
index b93ff667..d732c3e1 100644
--- a/Alc/backends/mmdevapi.c
+++ b/Alc/backends/mmdevapi.c
@@ -42,6 +42,9 @@
#include "alu.h"
#include "threads.h"
#include "compat.h"
+#include "alstring.h"
+
+#include "backends/base.h"
DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
@@ -59,31 +62,27 @@ DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,
typedef struct {
+ al_string name;
WCHAR *devid;
+} DevMap;
+DECL_VECTOR(DevMap)
- IMMDevice *mmdev;
- IAudioClient *client;
- IAudioRenderClient *render;
- HANDLE NotifyEvent;
-
- HANDLE MsgEvent;
-
- volatile UINT32 Padding;
-
- volatile int killNow;
- althread_t thread;
-} MMDevApiData;
-
+static void clear_devlist(vector_DevMap *list)
+{
+ DevMap *iter, *end;
-typedef struct {
- ALCchar *name;
- WCHAR *devid;
-} DevMap;
+ iter = VECTOR_ITER_BEGIN(*list);
+ end = VECTOR_ITER_END(*list);
+ for(;iter != end;iter++)
+ {
+ AL_STRING_DEINIT(iter->name);
+ free(iter->devid);
+ }
+ VECTOR_RESIZE(*list, 0);
+}
-static DevMap *PlaybackDeviceList;
-static ALuint NumPlaybackDevices;
-static DevMap *CaptureDeviceList;
-static ALuint NumCaptureDevices;
+static vector_DevMap PlaybackDevices;
+static vector_DevMap CaptureDevices;
static HANDLE ThreadHdl;
@@ -103,6 +102,12 @@ typedef struct {
#define WM_USER_Enumerate (WM_USER+5)
#define WM_USER_Last (WM_USER+5)
+static inline void ReturnMsgResponse(ThreadRequest *req, HRESULT res)
+{
+ req->result = res;
+ SetEvent(req->FinishedEvt);
+}
+
static HRESULT WaitForResponse(ThreadRequest *req)
{
if(WaitForSingleObject(req->FinishedEvt, INFINITE) == WAIT_OBJECT_0)
@@ -112,45 +117,32 @@ static HRESULT WaitForResponse(ThreadRequest *req)
}
-static ALCchar *get_device_name(IMMDevice *device)
+static void get_device_name(IMMDevice *device, al_string *name)
{
- ALCchar *name = NULL;
IPropertyStore *ps;
PROPVARIANT pvname;
HRESULT hr;
- int len;
hr = IMMDevice_OpenPropertyStore(device, STGM_READ, &ps);
if(FAILED(hr))
{
WARN("OpenPropertyStore failed: 0x%08lx\n", hr);
- return calloc(1, 1);
+ return;
}
PropVariantInit(&pvname);
hr = IPropertyStore_GetValue(ps, (const PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &pvname);
if(FAILED(hr))
- {
WARN("GetValue failed: 0x%08lx\n", hr);
- name = calloc(1, 1);
- }
else
- {
- if((len=WideCharToMultiByte(CP_ACP, 0, pvname.pwszVal, -1, NULL, 0, NULL, NULL)) > 0)
- {
- name = calloc(1, len);
- WideCharToMultiByte(CP_ACP, 0, pvname.pwszVal, -1, name, len, NULL, NULL);
- }
- }
+ al_string_copy_wcstr(name, pvname.pwszVal);
PropVariantClear(&pvname);
IPropertyStore_Release(ps);
-
- return name;
}
-static void add_device(IMMDevice *device, DevMap *devmap)
+static void add_device(IMMDevice *device, vector_DevMap *list)
{
LPWSTR devid;
HRESULT hr;
@@ -158,48 +150,52 @@ static void add_device(IMMDevice *device, DevMap *devmap)
hr = IMMDevice_GetId(device, &devid);
if(SUCCEEDED(hr))
{
- devmap->devid = strdupW(devid);
- devmap->name = get_device_name(device);
- TRACE("Got device \"%s\", \"%ls\"\n", devmap->name, devmap->devid);
+ DevMap entry;
+ AL_STRING_INIT(entry.name);
+
+ entry.devid = strdupW(devid);
+ get_device_name(device, &entry.name);
+
CoTaskMemFree(devid);
+
+ TRACE("Got device \"%s\", \"%ls\"\n", al_string_get_cstr(entry.name), entry.devid);
+ VECTOR_PUSH_BACK(*list, entry);
}
}
-static DevMap *ProbeDevices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, ALuint *numdevs)
+static HRESULT probe_devices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, vector_DevMap *list)
{
IMMDeviceCollection *coll;
IMMDevice *defdev = NULL;
- DevMap *devlist = NULL;
HRESULT hr;
UINT count;
- UINT idx;
UINT i;
hr = IMMDeviceEnumerator_EnumAudioEndpoints(devenum, flowdir, DEVICE_STATE_ACTIVE, &coll);
if(FAILED(hr))
{
ERR("Failed to enumerate audio endpoints: 0x%08lx\n", hr);
- return NULL;
+ return hr;
}
- idx = count = 0;
+ count = 0;
hr = IMMDeviceCollection_GetCount(coll, &count);
if(SUCCEEDED(hr) && count > 0)
{
- devlist = calloc(count, sizeof(*devlist));
- if(!devlist)
+ clear_devlist(list);
+ if(!VECTOR_RESERVE(*list, count+1))
{
IMMDeviceCollection_Release(coll);
- return NULL;
+ return E_OUTOFMEMORY;
}
hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(devenum, flowdir,
eMultimedia, &defdev);
}
if(SUCCEEDED(hr) && defdev != NULL)
- add_device(defdev, &devlist[idx++]);
+ add_device(defdev, list);
- for(i = 0;i < count && idx < count;++i)
+ for(i = 0;i < count;++i)
{
IMMDevice *device;
@@ -207,7 +203,7 @@ static DevMap *ProbeDevices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, ALu
continue;
if(device != defdev)
- add_device(device, &devlist[idx++]);
+ add_device(device, list);
IMMDevice_Release(device);
}
@@ -215,15 +211,269 @@ static DevMap *ProbeDevices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, ALu
if(defdev) IMMDevice_Release(defdev);
IMMDeviceCollection_Release(coll);
- *numdevs = idx;
- return devlist;
+ return S_OK;
}
-FORCE_ALIGN static ALuint MMDevApiProc(ALvoid *ptr)
+/* Proxy interface used by the message handler. */
+struct ALCmmdevProxyVtable;
+
+typedef struct ALCmmdevProxy {
+ const struct ALCmmdevProxyVtable *vtbl;
+} ALCmmdevProxy;
+
+struct ALCmmdevProxyVtable {
+ HRESULT (*const openProxy)(ALCmmdevProxy*);
+ void (*const closeProxy)(ALCmmdevProxy*);
+
+ HRESULT (*const resetProxy)(ALCmmdevProxy*);
+ HRESULT (*const startProxy)(ALCmmdevProxy*);
+ void (*const stopProxy)(ALCmmdevProxy*);
+};
+
+#define DEFINE_ALCMMDEVPROXY_VTABLE(T) \
+DECLARE_THUNK(T, ALCmmdevProxy, HRESULT, openProxy) \
+DECLARE_THUNK(T, ALCmmdevProxy, void, closeProxy) \
+DECLARE_THUNK(T, ALCmmdevProxy, HRESULT, resetProxy) \
+DECLARE_THUNK(T, ALCmmdevProxy, HRESULT, startProxy) \
+DECLARE_THUNK(T, ALCmmdevProxy, void, stopProxy) \
+ \
+static const struct ALCmmdevProxyVtable T##_ALCmmdevProxy_vtable = { \
+ T##_ALCmmdevProxy_openProxy, \
+ T##_ALCmmdevProxy_closeProxy, \
+ T##_ALCmmdevProxy_resetProxy, \
+ T##_ALCmmdevProxy_startProxy, \
+ T##_ALCmmdevProxy_stopProxy, \
+}
+
+static void ALCmmdevProxy_Construct(ALCmmdevProxy* UNUSED(self)) { }
+static void ALCmmdevProxy_Destruct(ALCmmdevProxy* UNUSED(self)) { }
+
+static DWORD CALLBACK ALCmmdevProxy_messageHandler(void *ptr)
{
- ALCdevice *device = ptr;
- MMDevApiData *data = device->ExtraData;
+ ThreadRequest *req = ptr;
+ IMMDeviceEnumerator *Enumerator;
+ ALuint deviceCount = 0;
+ ALCmmdevProxy *proxy;
+ HRESULT hr, cohr;
+ MSG msg;
+
+ TRACE("Starting message thread\n");
+
+ cohr = CoInitialize(NULL);
+ if(FAILED(cohr))
+ {
+ WARN("Failed to initialize COM: 0x%08lx\n", cohr);
+ ReturnMsgResponse(req, cohr);
+ return 0;
+ }
+
+ hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, &ptr);
+ if(FAILED(hr))
+ {
+ WARN("Failed to create IMMDeviceEnumerator instance: 0x%08lx\n", hr);
+ CoUninitialize();
+ ReturnMsgResponse(req, hr);
+ return 0;
+ }
+ Enumerator = ptr;
+ IMMDeviceEnumerator_Release(Enumerator);
+ Enumerator = NULL;
+
+ CoUninitialize();
+
+ /* HACK: Force Windows to create a message queue for this thread before
+ * returning success, otherwise PostThreadMessage may fail if it gets
+ * called before GetMessage.
+ */
+ PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
+
+ TRACE("Message thread initialization complete\n");
+ ReturnMsgResponse(req, S_OK);
+
+ TRACE("Starting message loop\n");
+ while(GetMessage(&msg, NULL, WM_USER_First, WM_USER_Last))
+ {
+ TRACE("Got message %u\n", msg.message);
+ switch(msg.message)
+ {
+ case WM_USER_OpenDevice:
+ req = (ThreadRequest*)msg.wParam;
+ proxy = (ALCmmdevProxy*)msg.lParam;
+
+ hr = cohr = S_OK;
+ if(++deviceCount == 1)
+ hr = cohr = CoInitialize(NULL);
+ if(SUCCEEDED(hr))
+ hr = V0(proxy,openProxy)();
+ if(FAILED(hr))
+ {
+ if(--deviceCount == 0 && SUCCEEDED(cohr))
+ CoUninitialize();
+ }
+
+ ReturnMsgResponse(req, hr);
+ continue;
+
+ case WM_USER_ResetDevice:
+ req = (ThreadRequest*)msg.wParam;
+ proxy = (ALCmmdevProxy*)msg.lParam;
+
+ hr = V0(proxy,resetProxy)();
+ ReturnMsgResponse(req, hr);
+ continue;
+
+ case WM_USER_StartDevice:
+ req = (ThreadRequest*)msg.wParam;
+ proxy = (ALCmmdevProxy*)msg.lParam;
+
+ hr = V0(proxy,startProxy)();
+ ReturnMsgResponse(req, hr);
+ continue;
+
+ case WM_USER_StopDevice:
+ req = (ThreadRequest*)msg.wParam;
+ proxy = (ALCmmdevProxy*)msg.lParam;
+
+ V0(proxy,stopProxy)();
+ ReturnMsgResponse(req, S_OK);
+ continue;
+
+ case WM_USER_CloseDevice:
+ req = (ThreadRequest*)msg.wParam;
+ proxy = (ALCmmdevProxy*)msg.lParam;
+
+ V0(proxy,closeProxy)();
+ if(--deviceCount == 0)
+ CoUninitialize();
+
+ ReturnMsgResponse(req, S_OK);
+ continue;
+
+ case WM_USER_Enumerate:
+ req = (ThreadRequest*)msg.wParam;
+
+ hr = cohr = S_OK;
+ if(++deviceCount == 1)
+ hr = cohr = CoInitialize(NULL);
+ if(SUCCEEDED(hr))
+ hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, &ptr);
+ if(SUCCEEDED(hr))
+ {
+ Enumerator = ptr;
+
+ if(msg.lParam == ALL_DEVICE_PROBE)
+ hr = probe_devices(Enumerator, eRender, &PlaybackDevices);
+ else if(msg.lParam == CAPTURE_DEVICE_PROBE)
+ hr = probe_devices(Enumerator, eCapture, &CaptureDevices);
+
+ IMMDeviceEnumerator_Release(Enumerator);
+ Enumerator = NULL;
+ }
+
+ if(--deviceCount == 0 && SUCCEEDED(cohr))
+ CoUninitialize();
+
+ ReturnMsgResponse(req, hr);
+ continue;
+
+ default:
+ ERR("Unexpected message: %u\n", msg.message);
+ continue;
+ }
+ }
+ TRACE("Message loop finished\n");
+
+ return 0;
+}
+
+
+typedef struct ALCmmdevPlayback {
+ DERIVE_FROM_TYPE(ALCbackend);
+ DERIVE_FROM_TYPE(ALCmmdevProxy);
+
+ WCHAR *devid;
+
+ IMMDevice *mmdev;
+ IAudioClient *client;
+ IAudioRenderClient *render;
+ HANDLE NotifyEvent;
+
+ HANDLE MsgEvent;
+
+ volatile UINT32 Padding;
+
+ volatile int killNow;
+ althrd_t thread;
+} ALCmmdevPlayback;
+
+static int ALCmmdevPlayback_mixerProc(void *arg);
+
+static void ALCmmdevPlayback_Construct(ALCmmdevPlayback *self, ALCdevice *device);
+static void ALCmmdevPlayback_Destruct(ALCmmdevPlayback *self);
+static ALCenum ALCmmdevPlayback_open(ALCmmdevPlayback *self, const ALCchar *name);
+static HRESULT ALCmmdevPlayback_openProxy(ALCmmdevPlayback *self);
+static void ALCmmdevPlayback_close(ALCmmdevPlayback *self);
+static void ALCmmdevPlayback_closeProxy(ALCmmdevPlayback *self);
+static ALCboolean ALCmmdevPlayback_reset(ALCmmdevPlayback *self);
+static HRESULT ALCmmdevPlayback_resetProxy(ALCmmdevPlayback *self);
+static ALCboolean ALCmmdevPlayback_start(ALCmmdevPlayback *self);
+static HRESULT ALCmmdevPlayback_startProxy(ALCmmdevPlayback *self);
+static void ALCmmdevPlayback_stop(ALCmmdevPlayback *self);
+static void ALCmmdevPlayback_stopProxy(ALCmmdevPlayback *self);
+static DECLARE_FORWARD2(ALCmmdevPlayback, ALCbackend, ALCenum, captureSamples, ALCvoid*, ALCuint)
+static DECLARE_FORWARD(ALCmmdevPlayback, ALCbackend, ALCuint, availableSamples)
+static ALint64 ALCmmdevPlayback_getLatency(ALCmmdevPlayback *self);
+static DECLARE_FORWARD(ALCmmdevPlayback, ALCbackend, void, lock)
+static DECLARE_FORWARD(ALCmmdevPlayback, ALCbackend, void, unlock)
+DECLARE_DEFAULT_ALLOCATORS(ALCmmdevPlayback)
+
+DEFINE_ALCMMDEVPROXY_VTABLE(ALCmmdevPlayback);
+DEFINE_ALCBACKEND_VTABLE(ALCmmdevPlayback);
+
+
+static void ALCmmdevPlayback_Construct(ALCmmdevPlayback *self, ALCdevice *device)
+{
+ SET_VTABLE2(ALCmmdevPlayback, ALCbackend, self);
+ SET_VTABLE2(ALCmmdevPlayback, ALCmmdevProxy, self);
+ ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
+ ALCmmdevProxy_Construct(STATIC_CAST(ALCmmdevProxy, self));
+
+ self->devid = NULL;
+
+ self->mmdev = NULL;
+ self->client = NULL;
+ self->render = NULL;
+ self->NotifyEvent = NULL;
+
+ self->MsgEvent = NULL;
+
+ self->Padding = 0;
+
+ self->killNow = 0;
+}
+
+static void ALCmmdevPlayback_Destruct(ALCmmdevPlayback *self)
+{
+ if(self->NotifyEvent != NULL)
+ CloseHandle(self->NotifyEvent);
+ self->NotifyEvent = NULL;
+ if(self->MsgEvent != NULL)
+ CloseHandle(self->MsgEvent);
+ self->MsgEvent = NULL;
+
+ free(self->devid);
+ self->devid = NULL;
+
+ ALCmmdevProxy_Destruct(STATIC_CAST(ALCmmdevProxy, self));
+ ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
+}
+
+
+FORCE_ALIGN static int ALCmmdevPlayback_mixerProc(void *arg)
+{
+ ALCmmdevPlayback *self = arg;
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
UINT32 buffer_len, written;
ALuint update_size, len;
BYTE *buffer;
@@ -236,17 +486,17 @@ FORCE_ALIGN static ALuint MMDevApiProc(ALvoid *ptr)
ALCdevice_Lock(device);
aluHandleDisconnect(device);
ALCdevice_Unlock(device);
- return 0;
+ return 1;
}
SetRTPriority();
- SetThreadName(MIXER_THREAD_NAME);
+ althrd_setname(althrd_current(), MIXER_THREAD_NAME);
update_size = device->UpdateSize;
buffer_len = update_size * device->NumUpdates;
- while(!data->killNow)
+ while(!self->killNow)
{
- hr = IAudioClient_GetCurrentPadding(data->client, &written);
+ hr = IAudioClient_GetCurrentPadding(self->client, &written);
if(FAILED(hr))
{
ERR("Failed to get padding: 0x%08lx\n", hr);
@@ -255,27 +505,27 @@ FORCE_ALIGN static ALuint MMDevApiProc(ALvoid *ptr)
ALCdevice_Unlock(device);
break;
}
- data->Padding = written;
+ self->Padding = written;
len = buffer_len - written;
if(len < update_size)
{
DWORD res;
- res = WaitForSingleObjectEx(data->NotifyEvent, 2000, FALSE);
+ res = WaitForSingleObjectEx(self->NotifyEvent, 2000, FALSE);
if(res != WAIT_OBJECT_0)
ERR("WaitForSingleObjectEx error: 0x%lx\n", res);
continue;
}
len -= len%update_size;
- hr = IAudioRenderClient_GetBuffer(data->render, len, &buffer);
+ hr = IAudioRenderClient_GetBuffer(self->render, len, &buffer);
if(SUCCEEDED(hr))
{
ALCdevice_Lock(device);
aluMixData(device, buffer, len);
- data->Padding = written + len;
+ self->Padding = written + len;
ALCdevice_Unlock(device);
- hr = IAudioRenderClient_ReleaseBuffer(data->render, len, 0);
+ hr = IAudioRenderClient_ReleaseBuffer(self->render, len, 0);
}
if(FAILED(hr))
{
@@ -286,7 +536,7 @@ FORCE_ALIGN static ALuint MMDevApiProc(ALvoid *ptr)
break;
}
}
- data->Padding = 0;
+ self->Padding = 0;
CoUninitialize();
return 0;
@@ -332,16 +582,178 @@ static ALCboolean MakeExtensible(WAVEFORMATEXTENSIBLE *out, const WAVEFORMATEX *
return ALC_TRUE;
}
-static HRESULT DoReset(ALCdevice *device)
+
+static ALCenum ALCmmdevPlayback_open(ALCmmdevPlayback *self, const ALCchar *deviceName)
+{
+ HRESULT hr = S_OK;
+
+ self->NotifyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ self->MsgEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if(self->NotifyEvent == NULL || self->MsgEvent == NULL)
+ {
+ ERR("Failed to create message events: %lu\n", GetLastError());
+ hr = E_FAIL;
+ }
+
+ if(SUCCEEDED(hr))
+ {
+ if(deviceName)
+ {
+ const DevMap *iter, *end;
+
+ if(VECTOR_SIZE(PlaybackDevices) == 0)
+ {
+ ThreadRequest req = { self->MsgEvent, 0 };
+ if(PostThreadMessage(ThreadID, WM_USER_Enumerate, (WPARAM)&req, ALL_DEVICE_PROBE))
+ (void)WaitForResponse(&req);
+ }
+
+ hr = E_FAIL;
+ iter = VECTOR_ITER_BEGIN(PlaybackDevices);
+ end = VECTOR_ITER_END(PlaybackDevices);
+ for(;iter != end;iter++)
+ {
+ if(al_string_cmp_cstr(iter->name, deviceName) == 0)
+ {
+ self->devid = strdupW(iter->devid);
+ hr = S_OK;
+ break;
+ }
+ }
+ if(FAILED(hr))
+ WARN("Failed to find device name matching \"%s\"\n", deviceName);
+ }
+ }
+
+ if(SUCCEEDED(hr))
+ {
+ ThreadRequest req = { self->MsgEvent, 0 };
+
+ hr = E_FAIL;
+ if(PostThreadMessage(ThreadID, WM_USER_OpenDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCmmdevProxy, self)))
+ hr = WaitForResponse(&req);
+ else
+ ERR("Failed to post thread message: %lu\n", GetLastError());
+ }
+
+ if(FAILED(hr))
+ {
+ if(self->NotifyEvent != NULL)
+ CloseHandle(self->NotifyEvent);
+ self->NotifyEvent = NULL;
+ if(self->MsgEvent != NULL)
+ CloseHandle(self->MsgEvent);
+ self->MsgEvent = NULL;
+
+ free(self->devid);
+ self->devid = NULL;
+
+ ERR("Device init failed: 0x%08lx\n", hr);
+ return ALC_INVALID_VALUE;
+ }
+
+ return ALC_NO_ERROR;
+}
+
+static HRESULT ALCmmdevPlayback_openProxy(ALCmmdevPlayback *self)
+{
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
+ void *ptr;
+ HRESULT hr;
+
+ hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, &ptr);
+ if(SUCCEEDED(hr))
+ {
+ IMMDeviceEnumerator *Enumerator = ptr;
+ if(!self->devid)
+ hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(Enumerator, eRender, eMultimedia, &self->mmdev);
+ else
+ hr = IMMDeviceEnumerator_GetDevice(Enumerator, self->devid, &self->mmdev);
+ IMMDeviceEnumerator_Release(Enumerator);
+ Enumerator = NULL;
+ }
+ if(SUCCEEDED(hr))
+ hr = IMMDevice_Activate(self->mmdev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, &ptr);
+ if(SUCCEEDED(hr))
+ {
+ self->client = ptr;
+ get_device_name(self->mmdev, &device->DeviceName);
+ }
+
+ if(FAILED(hr))
+ {
+ if(self->mmdev)
+ IMMDevice_Release(self->mmdev);
+ self->mmdev = NULL;
+ }
+
+ return hr;
+}
+
+
+static void ALCmmdevPlayback_close(ALCmmdevPlayback *self)
+{
+ ThreadRequest req = { self->MsgEvent, 0 };
+
+ if(PostThreadMessage(ThreadID, WM_USER_CloseDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCmmdevProxy, self)))
+ (void)WaitForResponse(&req);
+
+ CloseHandle(self->MsgEvent);
+ self->MsgEvent = NULL;
+
+ CloseHandle(self->NotifyEvent);
+ self->NotifyEvent = NULL;
+
+ free(self->devid);
+ self->devid = NULL;
+}
+
+static void ALCmmdevPlayback_closeProxy(ALCmmdevPlayback *self)
{
- MMDevApiData *data = device->ExtraData;
+ if(self->client)
+ IAudioClient_Release(self->client);
+ self->client = NULL;
+
+ if(self->mmdev)
+ IMMDevice_Release(self->mmdev);
+ self->mmdev = NULL;
+}
+
+
+static ALCboolean ALCmmdevPlayback_reset(ALCmmdevPlayback *self)
+{
+ ThreadRequest req = { self->MsgEvent, 0 };
+ HRESULT hr = E_FAIL;
+
+ if(PostThreadMessage(ThreadID, WM_USER_ResetDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCmmdevProxy, self)))
+ hr = WaitForResponse(&req);
+
+ return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE;
+}
+
+static HRESULT ALCmmdevPlayback_resetProxy(ALCmmdevPlayback *self)
+{
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
WAVEFORMATEXTENSIBLE OutputType;
WAVEFORMATEX *wfx = NULL;
REFERENCE_TIME min_per, buf_time;
UINT32 buffer_len, min_len;
+ void *ptr = NULL;
HRESULT hr;
- hr = IAudioClient_GetMixFormat(data->client, &wfx);
+ if(self->client)
+ IAudioClient_Release(self->client);
+ self->client = NULL;
+
+ hr = IMMDevice_Activate(self->mmdev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, &ptr);
+ if(FAILED(hr))
+ {
+ ERR("Failed to reactivate audio client: 0x%08lx\n", hr);
+ return hr;
+ }
+ self->client = ptr;
+
+ hr = IAudioClient_GetMixFormat(self->client, &wfx);
if(FAILED(hr))
{
ERR("Failed to get mix format: 0x%08lx\n", hr);
@@ -451,11 +863,11 @@ static HRESULT DoReset(ALCdevice *device)
OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec *
OutputType.Format.nBlockAlign;
- hr = IAudioClient_IsFormatSupported(data->client, AUDCLNT_SHAREMODE_SHARED, &OutputType.Format, &wfx);
+ hr = IAudioClient_IsFormatSupported(self->client, AUDCLNT_SHAREMODE_SHARED, &OutputType.Format, &wfx);
if(FAILED(hr))
{
ERR("Failed to check format support: 0x%08lx\n", hr);
- hr = IAudioClient_GetMixFormat(data->client, &wfx);
+ hr = IAudioClient_GetMixFormat(self->client, &wfx);
}
if(FAILED(hr))
{
@@ -527,7 +939,7 @@ static HRESULT DoReset(ALCdevice *device)
SetDefaultWFXChannelOrder(device);
- hr = IAudioClient_Initialize(data->client, AUDCLNT_SHAREMODE_SHARED,
+ hr = IAudioClient_Initialize(self->client, AUDCLNT_SHAREMODE_SHARED,
AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
buf_time, 0, &OutputType.Format, NULL);
if(FAILED(hr))
@@ -536,14 +948,14 @@ static HRESULT DoReset(ALCdevice *device)
return hr;
}
- hr = IAudioClient_GetDevicePeriod(data->client, &min_per, NULL);
+ hr = IAudioClient_GetDevicePeriod(self->client, &min_per, NULL);
if(SUCCEEDED(hr))
{
min_len = (UINT32)((min_per*device->Frequency + 10000000-1) / 10000000);
/* Find the nearest multiple of the period size to the update size */
if(min_len < device->UpdateSize)
min_len *= (device->UpdateSize + min_len/2)/min_len;
- hr = IAudioClient_GetBufferSize(data->client, &buffer_len);
+ hr = IAudioClient_GetBufferSize(self->client, &buffer_len);
}
if(FAILED(hr))
{
@@ -560,247 +972,106 @@ static HRESULT DoReset(ALCdevice *device)
device->UpdateSize = buffer_len / device->NumUpdates;
}
+ hr = IAudioClient_SetEventHandle(self->client, self->NotifyEvent);
+ if(FAILED(hr))
+ {
+ ERR("Failed to set event handle: 0x%08lx\n", hr);
+ return hr;
+ }
+
return hr;
}
-static DWORD CALLBACK MMDevApiMsgProc(void *ptr)
+static ALCboolean ALCmmdevPlayback_start(ALCmmdevPlayback *self)
{
- ThreadRequest *req = ptr;
- IMMDeviceEnumerator *Enumerator;
- ALuint deviceCount = 0;
- MMDevApiData *data;
- ALCdevice *device;
- HRESULT hr, cohr;
- MSG msg;
-
- TRACE("Starting message thread\n");
-
- cohr = CoInitialize(NULL);
- if(FAILED(cohr))
- {
- WARN("Failed to initialize COM: 0x%08lx\n", cohr);
- req->result = cohr;
- SetEvent(req->FinishedEvt);
- return 0;
- }
+ ThreadRequest req = { self->MsgEvent, 0 };
+ HRESULT hr = E_FAIL;
- hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, &ptr);
- if(FAILED(hr))
- {
- WARN("Failed to create IMMDeviceEnumerator instance: 0x%08lx\n", hr);
- CoUninitialize();
- req->result = hr;
- SetEvent(req->FinishedEvt);
- return 0;
- }
- Enumerator = ptr;
- IMMDeviceEnumerator_Release(Enumerator);
- Enumerator = NULL;
+ if(PostThreadMessage(ThreadID, WM_USER_StartDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCmmdevProxy, self)))
+ hr = WaitForResponse(&req);
- CoUninitialize();
+ return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE;
+}
- /* HACK: Force Windows to create a message queue for this thread before
- * returning success, otherwise PostThreadMessage may fail if it gets
- * called before GetMessage.
- */
- PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
+static HRESULT ALCmmdevPlayback_startProxy(ALCmmdevPlayback *self)
+{
+ HRESULT hr;
+ void *ptr;
- TRACE("Message thread initialization complete\n");
- req->result = S_OK;
- SetEvent(req->FinishedEvt);
+ ResetEvent(self->NotifyEvent);
+ hr = IAudioClient_Start(self->client);
+ if(FAILED(hr))
+ ERR("Failed to start audio client: 0x%08lx\n", hr);
- TRACE("Starting message loop\n");
- while(GetMessage(&msg, NULL, WM_USER_First, WM_USER_Last))
+ if(SUCCEEDED(hr))
+ hr = IAudioClient_GetService(self->client, &IID_IAudioRenderClient, &ptr);
+ if(SUCCEEDED(hr))
{
- TRACE("Got message %u\n", msg.message);
- switch(msg.message)
+ self->render = ptr;
+ self->killNow = 0;
+ if(althrd_create(&self->thread, ALCmmdevPlayback_mixerProc, self) != althrd_success)
{
- case WM_USER_OpenDevice:
- req = (ThreadRequest*)msg.wParam;
- device = (ALCdevice*)msg.lParam;
- data = device->ExtraData;
-
- hr = cohr = S_OK;
- if(++deviceCount == 1)
- hr = cohr = CoInitialize(NULL);
- if(SUCCEEDED(hr))
- hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, &ptr);
- if(SUCCEEDED(hr))
- {
- Enumerator = ptr;
- if(!data->devid)
- hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(Enumerator, eRender, eMultimedia, &data->mmdev);
- else
- hr = IMMDeviceEnumerator_GetDevice(Enumerator, data->devid, &data->mmdev);
- IMMDeviceEnumerator_Release(Enumerator);
- Enumerator = NULL;
- }
- if(SUCCEEDED(hr))
- hr = IMMDevice_Activate(data->mmdev, &IID_IAudioClient, CLSCTX_INPROC_SERVER, NULL, &ptr);
- if(SUCCEEDED(hr))
- {
- data->client = ptr;
- device->DeviceName = get_device_name(data->mmdev);
- }
-
- if(FAILED(hr))
- {
- if(data->mmdev)
- IMMDevice_Release(data->mmdev);
- data->mmdev = NULL;
- if(--deviceCount == 0 && SUCCEEDED(cohr))
- CoUninitialize();
- }
-
- req->result = hr;
- SetEvent(req->FinishedEvt);
- continue;
-
- case WM_USER_ResetDevice:
- req = (ThreadRequest*)msg.wParam;
- device = (ALCdevice*)msg.lParam;
-
- req->result = DoReset(device);
- SetEvent(req->FinishedEvt);
- continue;
-
- case WM_USER_StartDevice:
- req = (ThreadRequest*)msg.wParam;
- device = (ALCdevice*)msg.lParam;
- data = device->ExtraData;
-
- ResetEvent(data->NotifyEvent);
- hr = IAudioClient_SetEventHandle(data->client, data->NotifyEvent);
- if(FAILED(hr))
- ERR("Failed to set event handle: 0x%08lx\n", hr);
- else
- {
- hr = IAudioClient_Start(data->client);
- if(FAILED(hr))
- ERR("Failed to start audio client: 0x%08lx\n", hr);
- }
-
- if(SUCCEEDED(hr))
- hr = IAudioClient_GetService(data->client, &IID_IAudioRenderClient, &ptr);
- if(SUCCEEDED(hr))
- {
- data->render = ptr;
- if(!StartThread(&data->thread, MMDevApiProc, device))
- {
- if(data->render)
- IAudioRenderClient_Release(data->render);
- data->render = NULL;
- IAudioClient_Stop(data->client);
- ERR("Failed to start thread\n");
- hr = E_FAIL;
- }
- }
-
- req->result = hr;
- SetEvent(req->FinishedEvt);
- continue;
-
- case WM_USER_StopDevice:
- req = (ThreadRequest*)msg.wParam;
- device = (ALCdevice*)msg.lParam;
- data = device->ExtraData;
-
- if(data->thread)
- {
- data->killNow = 1;
- StopThread(data->thread);
- data->thread = NULL;
-
- data->killNow = 0;
-
- IAudioRenderClient_Release(data->render);
- data->render = NULL;
- IAudioClient_Stop(data->client);
- }
+ if(self->render)
+ IAudioRenderClient_Release(self->render);
+ self->render = NULL;
+ IAudioClient_Stop(self->client);
+ ERR("Failed to start thread\n");
+ hr = E_FAIL;
+ }
+ }
- req->result = S_OK;
- SetEvent(req->FinishedEvt);
- continue;
+ return hr;
+}
- case WM_USER_CloseDevice:
- req = (ThreadRequest*)msg.wParam;
- device = (ALCdevice*)msg.lParam;
- data = device->ExtraData;
- IAudioClient_Release(data->client);
- data->client = NULL;
+static void ALCmmdevPlayback_stop(ALCmmdevPlayback *self)
+{
+ ThreadRequest req = { self->MsgEvent, 0 };
+ if(PostThreadMessage(ThreadID, WM_USER_StopDevice, (WPARAM)&req, (LPARAM)STATIC_CAST(ALCmmdevProxy, self)))
+ (void)WaitForResponse(&req);
+}
- IMMDevice_Release(data->mmdev);
- data->mmdev = NULL;
+static void ALCmmdevPlayback_stopProxy(ALCmmdevPlayback *self)
+{
+ int res;
- if(--deviceCount == 0)
- CoUninitialize();
+ if(!self->render)
+ return;
- req->result = S_OK;
- SetEvent(req->FinishedEvt);
- continue;
+ self->killNow = 1;
+ althrd_join(self->thread, &res);
- case WM_USER_Enumerate:
- req = (ThreadRequest*)msg.wParam;
-
- hr = cohr = S_OK;
- if(++deviceCount == 1)
- hr = cohr = CoInitialize(NULL);
- if(SUCCEEDED(hr))
- hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, &ptr);
- if(SUCCEEDED(hr))
- {
- EDataFlow flowdir;
- DevMap **devlist;
- ALuint *numdevs;
- ALuint i;
-
- Enumerator = ptr;
- if(msg.lParam == CAPTURE_DEVICE_PROBE)
- {
- flowdir = eCapture;
- devlist = &CaptureDeviceList;
- numdevs = &NumCaptureDevices;
- }
- else
- {
- flowdir = eRender;
- devlist = &PlaybackDeviceList;
- numdevs = &NumPlaybackDevices;
- }
+ IAudioRenderClient_Release(self->render);
+ self->render = NULL;
+ IAudioClient_Stop(self->client);
+}
- for(i = 0;i < *numdevs;i++)
- {
- free((*devlist)[i].name);
- free((*devlist)[i].devid);
- }
- free(*devlist);
- *devlist = NULL;
- *numdevs = 0;
- *devlist = ProbeDevices(Enumerator, flowdir, numdevs);
+static ALint64 ALCmmdevPlayback_getLatency(ALCmmdevPlayback *self)
+{
+ ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
+ return (ALint64)self->Padding * 1000000000 / device->Frequency;
+}
- IMMDeviceEnumerator_Release(Enumerator);
- Enumerator = NULL;
- }
- if(--deviceCount == 0 && SUCCEEDED(cohr))
- CoUninitialize();
+static inline void AppendAllDevicesList2(const DevMap *entry)
+{ AppendAllDevicesList(al_string_get_cstr(entry->name)); }
+static inline void AppendCaptureDeviceList2(const DevMap *entry)
+{ AppendCaptureDeviceList(al_string_get_cstr(entry->name)); }
- req->result = S_OK;
- SetEvent(req->FinishedEvt);
- continue;
+typedef struct ALCmmdevBackendFactory {
+ DERIVE_FROM_TYPE(ALCbackendFactory);
+} ALCmmdevBackendFactory;
+#define ALCMMDEVBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCmmdevBackendFactory, ALCbackendFactory) } }
- default:
- ERR("Unexpected message: %u\n", msg.message);
- continue;
- }
- }
- TRACE("Message loop finished\n");
+static ALCboolean ALCmmdevBackendFactory_init(ALCmmdevBackendFactory *self);
+static void ALCmmdevBackendFactory_deinit(ALCmmdevBackendFactory *self);
+static ALCboolean ALCmmdevBackendFactory_querySupport(ALCmmdevBackendFactory *self, ALCbackend_Type type);
+static void ALCmmdevBackendFactory_probe(ALCmmdevBackendFactory *self, enum DevProbe type);
+static ALCbackend* ALCmmdevBackendFactory_createBackend(ALCmmdevBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
- return 0;
-}
+DEFINE_ALCBACKENDFACTORY_VTABLE(ALCmmdevBackendFactory);
static BOOL MMDevApiLoad(void)
@@ -816,7 +1087,7 @@ static BOOL MMDevApiLoad(void)
ERR("Failed to create event: %lu\n", GetLastError());
else
{
- ThreadHdl = CreateThread(NULL, 0, MMDevApiMsgProc, &req, 0, &ThreadID);
+ ThreadHdl = CreateThread(NULL, 0, ALCmmdevProxy_messageHandler, &req, 0, &ThreadID);
if(ThreadHdl != NULL)
InitResult = WaitForResponse(&req);
CloseHandle(req.FinishedEvt);
@@ -825,196 +1096,23 @@ static BOOL MMDevApiLoad(void)
return SUCCEEDED(InitResult);
}
-
-static ALCenum MMDevApiOpenPlayback(ALCdevice *device, const ALCchar *deviceName)
-{
- MMDevApiData *data = NULL;
- HRESULT hr;
-
- //Initialise requested device
- data = calloc(1, sizeof(MMDevApiData));
- if(!data)
- return ALC_OUT_OF_MEMORY;
- device->ExtraData = data;
-
- hr = S_OK;
- data->NotifyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
- data->MsgEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
- if(data->NotifyEvent == NULL || data->MsgEvent == NULL)
- {
- ERR("Failed to create message events: %lu\n", GetLastError());
- hr = E_FAIL;
- }
-
- if(SUCCEEDED(hr))
- {
- if(deviceName)
- {
- ALuint i;
-
- if(!PlaybackDeviceList)
- {
- ThreadRequest req = { data->MsgEvent, 0 };
- if(PostThreadMessage(ThreadID, WM_USER_Enumerate, (WPARAM)&req, ALL_DEVICE_PROBE))
- (void)WaitForResponse(&req);
- }
-
- hr = E_FAIL;
- for(i = 0;i < NumPlaybackDevices;i++)
- {
- if(strcmp(deviceName, PlaybackDeviceList[i].name) == 0)
- {
- data->devid = strdupW(PlaybackDeviceList[i].devid);
- hr = S_OK;
- break;
- }
- }
- if(FAILED(hr))
- WARN("Failed to find device name matching \"%s\"\n", deviceName);
- }
- }
-
- if(SUCCEEDED(hr))
- {
- ThreadRequest req = { data->MsgEvent, 0 };
-
- hr = E_FAIL;
- if(PostThreadMessage(ThreadID, WM_USER_OpenDevice, (WPARAM)&req, (LPARAM)device))
- hr = WaitForResponse(&req);
- else
- ERR("Failed to post thread message: %lu\n", GetLastError());
- }
-
- if(FAILED(hr))
- {
- if(data->NotifyEvent != NULL)
- CloseHandle(data->NotifyEvent);
- data->NotifyEvent = NULL;
- if(data->MsgEvent != NULL)
- CloseHandle(data->MsgEvent);
- data->MsgEvent = NULL;
-
- free(data->devid);
- data->devid = NULL;
-
- free(data);
- device->ExtraData = NULL;
-
- ERR("Device init failed: 0x%08lx\n", hr);
- return ALC_INVALID_VALUE;
- }
-
- return ALC_NO_ERROR;
-}
-
-static void MMDevApiClosePlayback(ALCdevice *device)
-{
- MMDevApiData *data = device->ExtraData;
- ThreadRequest req = { data->MsgEvent, 0 };
-
- if(PostThreadMessage(ThreadID, WM_USER_CloseDevice, (WPARAM)&req, (LPARAM)device))
- (void)WaitForResponse(&req);
-
- CloseHandle(data->MsgEvent);
- data->MsgEvent = NULL;
-
- CloseHandle(data->NotifyEvent);
- data->NotifyEvent = NULL;
-
- free(data->devid);
- data->devid = NULL;
-
- free(data);
- device->ExtraData = NULL;
-}
-
-static ALCboolean MMDevApiResetPlayback(ALCdevice *device)
-{
- MMDevApiData *data = device->ExtraData;
- ThreadRequest req = { data->MsgEvent, 0 };
- HRESULT hr = E_FAIL;
-
- if(PostThreadMessage(ThreadID, WM_USER_ResetDevice, (WPARAM)&req, (LPARAM)device))
- hr = WaitForResponse(&req);
-
- return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE;
-}
-
-static ALCboolean MMDevApiStartPlayback(ALCdevice *device)
+static ALCboolean ALCmmdevBackendFactory_init(ALCmmdevBackendFactory* UNUSED(self))
{
- MMDevApiData *data = device->ExtraData;
- ThreadRequest req = { data->MsgEvent, 0 };
- HRESULT hr = E_FAIL;
-
- if(PostThreadMessage(ThreadID, WM_USER_StartDevice, (WPARAM)&req, (LPARAM)device))
- hr = WaitForResponse(&req);
-
- return SUCCEEDED(hr) ? ALC_TRUE : ALC_FALSE;
-}
-
-static void MMDevApiStopPlayback(ALCdevice *device)
-{
- MMDevApiData *data = device->ExtraData;
- ThreadRequest req = { data->MsgEvent, 0 };
-
- if(PostThreadMessage(ThreadID, WM_USER_StopDevice, (WPARAM)&req, (LPARAM)device))
- (void)WaitForResponse(&req);
-}
-
-
-static ALint64 MMDevApiGetLatency(ALCdevice *device)
-{
- MMDevApiData *data = device->ExtraData;
-
- return (ALint64)data->Padding * 1000000000 / device->Frequency;
-}
-
-
-static const BackendFuncs MMDevApiFuncs = {
- MMDevApiOpenPlayback,
- MMDevApiClosePlayback,
- MMDevApiResetPlayback,
- MMDevApiStartPlayback,
- MMDevApiStopPlayback,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- MMDevApiGetLatency
-};
+ VECTOR_INIT(PlaybackDevices);
+ VECTOR_INIT(CaptureDevices);
-
-ALCboolean alcMMDevApiInit(BackendFuncs *FuncList)
-{
if(!MMDevApiLoad())
return ALC_FALSE;
- *FuncList = MMDevApiFuncs;
return ALC_TRUE;
}
-void alcMMDevApiDeinit(void)
+static void ALCmmdevBackendFactory_deinit(ALCmmdevBackendFactory* UNUSED(self))
{
- ALuint i;
+ clear_devlist(&PlaybackDevices);
+ VECTOR_DEINIT(PlaybackDevices);
- for(i = 0;i < NumPlaybackDevices;i++)
- {
- free(PlaybackDeviceList[i].name);
- free(PlaybackDeviceList[i].devid);
- }
- free(PlaybackDeviceList);
- PlaybackDeviceList = NULL;
- NumPlaybackDevices = 0;
-
- for(i = 0;i < NumCaptureDevices;i++)
- {
- free(CaptureDeviceList[i].name);
- free(CaptureDeviceList[i].devid);
- }
- free(CaptureDeviceList);
- CaptureDeviceList = NULL;
- NumCaptureDevices = 0;
+ clear_devlist(&CaptureDevices);
+ VECTOR_DEINIT(CaptureDevices);
if(ThreadHdl)
{
@@ -1025,34 +1123,61 @@ void alcMMDevApiDeinit(void)
}
}
-void alcMMDevApiProbe(enum DevProbe type)
+static ALCboolean ALCmmdevBackendFactory_querySupport(ALCmmdevBackendFactory* UNUSED(self), ALCbackend_Type type)
+{
+ if(type == ALCbackend_Playback)
+ return ALC_TRUE;
+ return ALC_FALSE;
+}
+
+static void ALCmmdevBackendFactory_probe(ALCmmdevBackendFactory* UNUSED(self), enum DevProbe type)
{
ThreadRequest req = { NULL, 0 };
- HRESULT hr = E_FAIL;
- switch(type)
+ req.FinishedEvt = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if(req.FinishedEvt == NULL)
+ ERR("Failed to create event: %lu\n", GetLastError());
+ else
{
+ HRESULT hr = E_FAIL;
+ if(PostThreadMessage(ThreadID, WM_USER_Enumerate, (WPARAM)&req, type))
+ hr = WaitForResponse(&req);
+ if(SUCCEEDED(hr)) switch(type)
+ {
case ALL_DEVICE_PROBE:
- req.FinishedEvt = CreateEvent(NULL, FALSE, FALSE, NULL);
- if(req.FinishedEvt == NULL)
- ERR("Failed to create event: %lu\n", GetLastError());
- else if(PostThreadMessage(ThreadID, WM_USER_Enumerate, (WPARAM)&req, type))
- hr = WaitForResponse(&req);
- if(SUCCEEDED(hr))
- {
- ALuint i;
- for(i = 0;i < NumPlaybackDevices;i++)
- {
- if(PlaybackDeviceList[i].name)
- AppendAllDevicesList(PlaybackDeviceList[i].name);
- }
- }
+ VECTOR_FOR_EACH(const DevMap, PlaybackDevices, AppendAllDevicesList2);
break;
case CAPTURE_DEVICE_PROBE:
+ VECTOR_FOR_EACH(const DevMap, CaptureDevices, AppendCaptureDeviceList2);
break;
- }
- if(req.FinishedEvt != NULL)
+ }
CloseHandle(req.FinishedEvt);
- req.FinishedEvt = NULL;
+ req.FinishedEvt = NULL;
+ }
+}
+
+static ALCbackend* ALCmmdevBackendFactory_createBackend(ALCmmdevBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
+{
+ if(type == ALCbackend_Playback)
+ {
+ ALCmmdevPlayback *backend;
+
+ backend = ALCmmdevPlayback_New(sizeof(*backend));
+ if(!backend) return NULL;
+ memset(backend, 0, sizeof(*backend));
+
+ ALCmmdevPlayback_Construct(backend, device);
+
+ return STATIC_CAST(ALCbackend, backend);
+ }
+
+ return NULL;
+}
+
+
+ALCbackendFactory *ALCmmdevBackendFactory_getFactory(void)
+{
+ static ALCmmdevBackendFactory factory = ALCMMDEVBACKENDFACTORY_INITIALIZER;
+ return STATIC_CAST(ALCbackendFactory, &factory);
}