Support device enumeration with mmdevapi
This commit is contained in:
parent
deee6a73f0
commit
10257f485a
@ -29,6 +29,9 @@
|
|||||||
#include <audioclient.h>
|
#include <audioclient.h>
|
||||||
#include <cguid.h>
|
#include <cguid.h>
|
||||||
#include <mmreg.h>
|
#include <mmreg.h>
|
||||||
|
#include <propsys.h>
|
||||||
|
#include <propkey.h>
|
||||||
|
#include <devpkey.h>
|
||||||
#ifndef _WAVEFORMATEXTENSIBLE_
|
#ifndef _WAVEFORMATEXTENSIBLE_
|
||||||
#include <ks.h>
|
#include <ks.h>
|
||||||
#include <ksmedia.h>
|
#include <ksmedia.h>
|
||||||
@ -52,6 +55,7 @@ DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0
|
|||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
GUID guid;
|
||||||
IMMDevice *mmdev;
|
IMMDevice *mmdev;
|
||||||
IAudioClient *client;
|
IAudioClient *client;
|
||||||
HANDLE hNotifyEvent;
|
HANDLE hNotifyEvent;
|
||||||
@ -63,7 +67,16 @@ typedef struct {
|
|||||||
} MMDevApiData;
|
} MMDevApiData;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ALCchar *name;
|
||||||
|
GUID guid;
|
||||||
|
} DevMap;
|
||||||
|
|
||||||
static const ALCchar mmDevice[] = "WASAPI Default";
|
static const ALCchar mmDevice[] = "WASAPI Default";
|
||||||
|
static DevMap *PlaybackDeviceList;
|
||||||
|
static ALuint NumPlaybackDevices;
|
||||||
|
static DevMap *CaptureDeviceList;
|
||||||
|
static ALuint NumCaptureDevices;
|
||||||
|
|
||||||
|
|
||||||
static HANDLE ThreadHdl;
|
static HANDLE ThreadHdl;
|
||||||
@ -78,6 +91,7 @@ typedef struct {
|
|||||||
#define WM_USER_ResetDevice (WM_USER+1)
|
#define WM_USER_ResetDevice (WM_USER+1)
|
||||||
#define WM_USER_StopDevice (WM_USER+2)
|
#define WM_USER_StopDevice (WM_USER+2)
|
||||||
#define WM_USER_CloseDevice (WM_USER+3)
|
#define WM_USER_CloseDevice (WM_USER+3)
|
||||||
|
#define WM_USER_Enumerate (WM_USER+4)
|
||||||
|
|
||||||
static HRESULT WaitForResponse(ThreadRequest *req)
|
static HRESULT WaitForResponse(ThreadRequest *req)
|
||||||
{
|
{
|
||||||
@ -88,6 +102,165 @@ static HRESULT WaitForResponse(ThreadRequest *req)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static HRESULT get_mmdevice_by_guid(IMMDeviceEnumerator *devenum, EDataFlow flowdir, const GUID *guid, IMMDevice **out)
|
||||||
|
{
|
||||||
|
IMMDeviceCollection *coll;
|
||||||
|
DWORD count, i;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
|
hr = IMMDeviceEnumerator_EnumAudioEndpoints(devenum, flowdir, DEVICE_STATE_ACTIVE, &coll);
|
||||||
|
if(FAILED(hr))
|
||||||
|
{
|
||||||
|
ERR("Failed to enumerate audio endpoints: 0x%08lx\n", hr);
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
count = 0;
|
||||||
|
IMMDeviceCollection_GetCount(coll, &count);
|
||||||
|
for(i = 0;i < count;++i)
|
||||||
|
{
|
||||||
|
IMMDevice *device;
|
||||||
|
IPropertyStore *ps;
|
||||||
|
PROPVARIANT pv;
|
||||||
|
GUID devid;
|
||||||
|
|
||||||
|
if(FAILED(IMMDeviceCollection_Item(coll, i, &device)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
hr = IMMDevice_OpenPropertyStore(device, STGM_READ, &ps);
|
||||||
|
if(FAILED(hr))
|
||||||
|
{
|
||||||
|
WARN("OpenPropertyStore failed: 0x%08lx\n", hr);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
PropVariantInit(&pv);
|
||||||
|
|
||||||
|
hr = IPropertyStore_GetValue(ps, &PKEY_AudioEndpoint_GUID, &pv);
|
||||||
|
if(FAILED(hr))
|
||||||
|
{
|
||||||
|
PropVariantClear(&pv);
|
||||||
|
IPropertyStore_Release(ps);
|
||||||
|
WARN("GetValue failed: 0x%08lx\n", hr);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
CLSIDFromString(pv.pwszVal, &devid);
|
||||||
|
|
||||||
|
PropVariantClear(&pv);
|
||||||
|
IPropertyStore_Release(ps);
|
||||||
|
|
||||||
|
if(IsEqualGUID(&devid, guid))
|
||||||
|
{
|
||||||
|
*out = device;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
IMMDevice_Release(device);
|
||||||
|
}
|
||||||
|
hr = ((i==count) ? E_FAIL : S_OK);
|
||||||
|
|
||||||
|
IMMDeviceCollection_Release(coll);
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void add_device(IMMDevice *device, DevMap *devmap)
|
||||||
|
{
|
||||||
|
IPropertyStore *ps;
|
||||||
|
PROPVARIANT pvguid;
|
||||||
|
PROPVARIANT pvname;
|
||||||
|
HRESULT hr;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
hr = IMMDevice_OpenPropertyStore(device, STGM_READ, &ps);
|
||||||
|
if(FAILED(hr))
|
||||||
|
{
|
||||||
|
WARN("OpenPropertyStore failed: 0x%08lx\n", hr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PropVariantInit(&pvguid);
|
||||||
|
PropVariantInit(&pvname);
|
||||||
|
|
||||||
|
hr = IPropertyStore_GetValue(ps, &PKEY_AudioEndpoint_GUID, &pvguid);
|
||||||
|
if(FAILED(hr))
|
||||||
|
WARN("GetValue failed: 0x%08lx\n", hr);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hr = IPropertyStore_GetValue(ps, (const PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &pvname);
|
||||||
|
if(FAILED(hr))
|
||||||
|
WARN("GetValue failed: 0x%08lx\n", hr);
|
||||||
|
}
|
||||||
|
if(SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
CLSIDFromString(pvguid.pwszVal, &devmap->guid);
|
||||||
|
if((len=WideCharToMultiByte(CP_ACP, 0, pvname.pwszVal, -1, NULL, 0, NULL, NULL)) > 0)
|
||||||
|
{
|
||||||
|
devmap->name = calloc(1, len);
|
||||||
|
WideCharToMultiByte(CP_ACP, 0, pvname.pwszVal, -1, devmap->name, len, NULL, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PropVariantClear(&pvname);
|
||||||
|
PropVariantClear(&pvguid);
|
||||||
|
IPropertyStore_Release(ps);
|
||||||
|
}
|
||||||
|
|
||||||
|
static DevMap *ProbeDevices(IMMDeviceEnumerator *devenum, EDataFlow flowdir, ALuint *numdevs)
|
||||||
|
{
|
||||||
|
IMMDeviceCollection *coll;
|
||||||
|
IMMDevice *defdev = NULL;
|
||||||
|
DevMap *devlist;
|
||||||
|
DWORD count;
|
||||||
|
HRESULT hr;
|
||||||
|
DWORD idx;
|
||||||
|
DWORD 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
count = 0;
|
||||||
|
hr = IMMDeviceCollection_GetCount(coll, &count);
|
||||||
|
if(SUCCEEDED(hr) && count > 0)
|
||||||
|
{
|
||||||
|
devlist = calloc(count, sizeof(*devlist));
|
||||||
|
if(!devlist)
|
||||||
|
{
|
||||||
|
IMMDeviceCollection_Release(coll);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(devenum, flowdir,
|
||||||
|
eMultimedia, &defdev);
|
||||||
|
}
|
||||||
|
if(SUCCEEDED(hr) && defdev != NULL)
|
||||||
|
add_device(defdev, &devlist[idx++]);
|
||||||
|
|
||||||
|
for(i = 0;i < count && idx < count;++i)
|
||||||
|
{
|
||||||
|
IMMDevice *device;
|
||||||
|
|
||||||
|
if(FAILED(IMMDeviceCollection_Item(coll, i, &device)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(device != defdev)
|
||||||
|
add_device(device, &devlist[idx++]);
|
||||||
|
|
||||||
|
IMMDevice_Release(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(defdev) IMMDevice_Release(defdev);
|
||||||
|
IMMDeviceCollection_Release(coll);
|
||||||
|
|
||||||
|
*numdevs = idx;
|
||||||
|
return devlist;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static ALuint MMDevApiProc(ALvoid *ptr)
|
static ALuint MMDevApiProc(ALvoid *ptr)
|
||||||
{
|
{
|
||||||
ALCdevice *device = ptr;
|
ALCdevice *device = ptr;
|
||||||
@ -495,16 +668,18 @@ static DWORD CALLBACK MMDevApiMsgProc(void *ptr)
|
|||||||
device = (ALCdevice*)msg.lParam;
|
device = (ALCdevice*)msg.lParam;
|
||||||
data = device->ExtraData;
|
data = device->ExtraData;
|
||||||
|
|
||||||
cohr = S_OK;
|
hr = cohr = S_OK;
|
||||||
hr = E_FAIL;
|
|
||||||
if(++deviceCount == 1)
|
if(++deviceCount == 1)
|
||||||
cohr = CoInitialize(NULL);
|
hr = cohr = CoInitialize(NULL);
|
||||||
if(SUCCEEDED(cohr))
|
if(SUCCEEDED(hr))
|
||||||
hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, &ptr);
|
hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, &IID_IMMDeviceEnumerator, &ptr);
|
||||||
if(SUCCEEDED(hr))
|
if(SUCCEEDED(hr))
|
||||||
{
|
{
|
||||||
Enumerator = ptr;
|
Enumerator = ptr;
|
||||||
|
if(IsEqualGUID(&data->guid, &GUID_NULL))
|
||||||
hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(Enumerator, eRender, eMultimedia, &data->mmdev);
|
hr = IMMDeviceEnumerator_GetDefaultAudioEndpoint(Enumerator, eRender, eMultimedia, &data->mmdev);
|
||||||
|
else
|
||||||
|
hr = get_mmdevice_by_guid(Enumerator, eRender, &data->guid, &data->mmdev);
|
||||||
IMMDeviceEnumerator_Release(Enumerator);
|
IMMDeviceEnumerator_Release(Enumerator);
|
||||||
Enumerator = NULL;
|
Enumerator = NULL;
|
||||||
}
|
}
|
||||||
@ -572,6 +747,54 @@ static DWORD CALLBACK MMDevApiMsgProc(void *ptr)
|
|||||||
SetEvent(req->FinishedEvt);
|
SetEvent(req->FinishedEvt);
|
||||||
continue;
|
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))
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 0;i < *numdevs;i++)
|
||||||
|
free((*devlist)[i].name);
|
||||||
|
free(*devlist);
|
||||||
|
*devlist = NULL;
|
||||||
|
*numdevs = 0;
|
||||||
|
|
||||||
|
*devlist = ProbeDevices(Enumerator, flowdir, numdevs);
|
||||||
|
|
||||||
|
IMMDeviceEnumerator_Release(Enumerator);
|
||||||
|
Enumerator = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(--deviceCount == 0 && SUCCEEDED(cohr))
|
||||||
|
CoUninitialize();
|
||||||
|
|
||||||
|
req->result = S_OK;
|
||||||
|
SetEvent(req->FinishedEvt);
|
||||||
|
continue;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ERR("Unexpected message: %u\n", msg.message);
|
ERR("Unexpected message: %u\n", msg.message);
|
||||||
continue;
|
continue;
|
||||||
@ -611,11 +834,6 @@ static ALCenum MMDevApiOpenPlayback(ALCdevice *device, const ALCchar *deviceName
|
|||||||
MMDevApiData *data = NULL;
|
MMDevApiData *data = NULL;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
if(!deviceName)
|
|
||||||
deviceName = mmDevice;
|
|
||||||
else if(strcmp(deviceName, mmDevice) != 0)
|
|
||||||
return ALC_INVALID_VALUE;
|
|
||||||
|
|
||||||
//Initialise requested device
|
//Initialise requested device
|
||||||
data = calloc(1, sizeof(MMDevApiData));
|
data = calloc(1, sizeof(MMDevApiData));
|
||||||
if(!data)
|
if(!data)
|
||||||
@ -628,6 +846,38 @@ static ALCenum MMDevApiOpenPlayback(ALCdevice *device, const ALCchar *deviceName
|
|||||||
if(data->hNotifyEvent == NULL || data->MsgEvent == NULL)
|
if(data->hNotifyEvent == NULL || data->MsgEvent == NULL)
|
||||||
hr = E_FAIL;
|
hr = E_FAIL;
|
||||||
|
|
||||||
|
if(SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
data->guid = GUID_NULL;
|
||||||
|
|
||||||
|
if(!deviceName)
|
||||||
|
deviceName = mmDevice;
|
||||||
|
else if(strcmp(deviceName, mmDevice) != 0)
|
||||||
|
{
|
||||||
|
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(PlaybackDeviceList[i].name &&
|
||||||
|
strcmp(deviceName, PlaybackDeviceList[i].name) == 0)
|
||||||
|
{
|
||||||
|
data->guid = PlaybackDeviceList[i].guid;
|
||||||
|
hr = S_OK;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(SUCCEEDED(hr))
|
if(SUCCEEDED(hr))
|
||||||
{
|
{
|
||||||
ThreadRequest req = { data->MsgEvent, 0 };
|
ThreadRequest req = { data->MsgEvent, 0 };
|
||||||
@ -732,14 +982,34 @@ void alcMMDevApiDeinit(void)
|
|||||||
|
|
||||||
void alcMMDevApiProbe(enum DevProbe type)
|
void alcMMDevApiProbe(enum DevProbe type)
|
||||||
{
|
{
|
||||||
|
ThreadRequest req;
|
||||||
|
HRESULT hr = E_FAIL;
|
||||||
|
|
||||||
switch(type)
|
switch(type)
|
||||||
{
|
{
|
||||||
case DEVICE_PROBE:
|
case DEVICE_PROBE:
|
||||||
AppendDeviceList(mmDevice);
|
AppendDeviceList(mmDevice);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ALL_DEVICE_PROBE:
|
case ALL_DEVICE_PROBE:
|
||||||
AppendAllDeviceList(mmDevice);
|
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)
|
||||||
|
AppendAllDeviceList(PlaybackDeviceList[i].name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(req.FinishedEvt != NULL)
|
||||||
|
CloseHandle(req.FinishedEvt);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CAPTURE_DEVICE_PROBE:
|
case CAPTURE_DEVICE_PROBE:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -44,6 +44,14 @@ DEFINE_GUID(IID_IMMDeviceEnumerator, 0xa95664d2, 0x9614, 0x4f35, 0xa7,0x46, 0xd
|
|||||||
DEFINE_GUID(IID_IAudioClient, 0x1cb9ad4c, 0xdbfa, 0x4c32, 0xb1,0x78, 0xc2,0xf5,0x68,0xa7,0x03,0xb2);
|
DEFINE_GUID(IID_IAudioClient, 0x1cb9ad4c, 0xdbfa, 0x4c32, 0xb1,0x78, 0xc2,0xf5,0x68,0xa7,0x03,0xb2);
|
||||||
DEFINE_GUID(IID_IAudioRenderClient, 0xf294acfc, 0x3146, 0x4483, 0xa7,0xbf, 0xad,0xdc,0xa7,0xc2,0x60,0xe2);
|
DEFINE_GUID(IID_IAudioRenderClient, 0xf294acfc, 0x3146, 0x4483, 0xa7,0xbf, 0xad,0xdc,0xa7,0xc2,0x60,0xe2);
|
||||||
|
|
||||||
|
#ifdef HAVE_MMDEVAPI
|
||||||
|
#include <propkeydef.h>
|
||||||
|
#include <devpropdef.h>
|
||||||
|
|
||||||
|
DEFINE_PROPERTYKEY(PKEY_AudioEndpoint_GUID, 0x1da5d803, 0xd492, 0x4edd, 0x8c,0x23, 0xe0,0xc0,0xff,0xee,0x7f,0x0e, 4);
|
||||||
|
DEFINE_DEVPROPKEY(DEVPKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,0x20, 0x67,0xd1,0x46,0xa8,0x50,0xe0, 14);
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "alMain.h"
|
#include "alMain.h"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user