win32: map waveOut devices to mmdevices via endpoint id

This commit is contained in:
OV2 2023-11-18 22:19:58 +01:00
parent d30060cdc1
commit 5c65edbbca
1 changed files with 58 additions and 23 deletions

View File

@ -11,8 +11,10 @@
#include "../snes9x.h" #include "../snes9x.h"
#include "../apu/apu.h" #include "../apu/apu.h"
#include "wsnes9x.h" #include "wsnes9x.h"
#include <map>
#define DRV_QUERYFUNCTIONINSTANCEID (DRV_RESERVED + 17)
#define DRV_QUERYFUNCTIONINSTANCEIDSIZE (DRV_RESERVED + 18)
CWaveOut::CWaveOut(void) CWaveOut::CWaveOut(void)
{ {
@ -244,13 +246,16 @@ std::vector<std::wstring> CWaveOut::GetDeviceList()
device_list.push_back(_T("Default")); device_list.push_back(_T("Default"));
// try to enumerate devices via multimedia device enumerator, waveout has a 31 character limit on device names std::map<std::wstring, std::wstring> endpointId_deviceName_map;
// try to get device names via multimedia device enumerator, waveOut has a 31 character limit on device names
// save them in a map with their endpoint id to later match to waveOut devices
IMMDeviceEnumerator* deviceEnumerator; IMMDeviceEnumerator* deviceEnumerator;
HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), (LPVOID*)&deviceEnumerator); HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), (LPVOID*)&deviceEnumerator);
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
IMMDeviceCollection* renderDevices; IMMDeviceCollection* renderDevices;
hr = deviceEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &renderDevices); hr = deviceEnumerator->EnumAudioEndpoints(eRender, DEVICE_STATEMASK_ALL, &renderDevices);
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
UINT count; UINT count;
@ -262,19 +267,27 @@ std::vector<std::wstring> CWaveOut::GetDeviceList()
{ {
continue; continue;
} }
IPropertyStore* propStore; WCHAR* pstrEndpointId = NULL;
PROPVARIANT propVar; hr = renderDevice->GetId(&pstrEndpointId);
PropVariantInit(&propVar);
hr = renderDevice->OpenPropertyStore(STGM_READ, &propStore);
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
hr = propStore->GetValue(PKEY_Device_FriendlyName, &propVar); std::wstring strEndpoint = pstrEndpointId;
CoTaskMemFree(pstrEndpointId);
IPropertyStore* propStore;
PROPVARIANT propVar;
PropVariantInit(&propVar);
hr = renderDevice->OpenPropertyStore(STGM_READ, &propStore);
if (SUCCEEDED(hr))
{
hr = propStore->GetValue(PKEY_Device_FriendlyName, &propVar);
}
if (SUCCEEDED(hr) && propVar.vt == VT_LPWSTR)
{
endpointId_deviceName_map[strEndpoint] = propVar.pwszVal;
}
PropVariantClear(&propVar);
} }
if (SUCCEEDED(hr) && propVar.vt == VT_LPWSTR)
{
device_list.push_back(propVar.pwszVal);
}
PropVariantClear(&propVar);
renderDevice->Release(); renderDevice->Release();
} }
renderDevices->Release(); renderDevices->Release();
@ -282,19 +295,41 @@ std::vector<std::wstring> CWaveOut::GetDeviceList()
deviceEnumerator->Release(); deviceEnumerator->Release();
} }
// if we still only have "default" in the list, use old waveout enumeration // enum waveOut devices, using mapped names if available
if (device_list.size() == 1) UINT num_devices = waveOutGetNumDevs();
for (unsigned int i = 0; i < num_devices; i++)
{ {
UINT num_devices = waveOutGetNumDevs(); WAVEOUTCAPS caps;
MMRESULT mmr;
for (unsigned int i = 0; i < num_devices; i++) mmr = waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS));
if (mmr != MMSYSERR_NOERROR)
{ {
WAVEOUTCAPS caps; continue;
if (waveOutGetDevCaps(i, &caps, sizeof(WAVEOUTCAPS)) == MMSYSERR_NOERROR)
{
device_list.push_back(caps.szPname);
}
} }
// get endpoint id, called function instance id in waveOutMessage
size_t endpointIdSize = 0;
mmr = waveOutMessage((HWAVEOUT)IntToPtr(i), DRV_QUERYFUNCTIONINSTANCEIDSIZE, (DWORD_PTR)&endpointIdSize, NULL);
if (mmr != MMSYSERR_NOERROR)
{
continue;
}
std::vector<wchar_t> endpointIdBuffer(endpointIdSize);
mmr = waveOutMessage((HWAVEOUT)IntToPtr(i), DRV_QUERYFUNCTIONINSTANCEID, (DWORD_PTR)endpointIdBuffer.data(), endpointIdSize);
if (mmr != MMSYSERR_NOERROR)
{
continue;
}
std::wstring strEndpoint(endpointIdBuffer.data());
// use name retrieved from mmdevice above if available
std::wstring devName = caps.szPname;
if (endpointId_deviceName_map.count(strEndpoint))
{
devName = endpointId_deviceName_map[strEndpoint];
}
device_list.push_back(devName);
} }
return device_list; return device_list;