devenum: Register waveIn devices as codec devices.

Signed-off-by: Zebediah Figura <z.figura12@gmail.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Zebediah Figura 2018-03-31 16:25:16 -05:00 committed by Alexandre Julliard
parent b7fdedd323
commit c64f6ad08d
2 changed files with 154 additions and 64 deletions

View File

@ -52,7 +52,6 @@ static const WCHAR wszDirection[] = {'D','i','r','e','c','t','i','o','n',0};
static const WCHAR wszIsRendered[] = {'I','s','R','e','n','d','e','r','e','d',0};
static const WCHAR wszTypes[] = {'T','y','p','e','s',0};
static const WCHAR wszFriendlyName[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0};
static const WCHAR wszWaveInID[] = {'W','a','v','e','I','n','I','D',0};
static const WCHAR wszFilterData[] = {'F','i','l','t','e','r','D','a','t','a',0};
static ULONG WINAPI DEVENUM_ICreateDevEnum_AddRef(ICreateDevEnum * iface);
@ -673,6 +672,72 @@ cleanup:
}
}
static void register_wavein_devices(void)
{
static const WCHAR waveinidW[] = {'W','a','v','e','I','n','I','d',0};
IPropertyBag *prop_bag = NULL;
REGFILTER2 rgf = {0};
WCHAR clsid[CHARS_IN_GUID];
IMoniker *mon = NULL;
WAVEINCAPSW caps;
int i, count;
VARIANT var;
HRESULT hr;
hr = DEVENUM_CreateAMCategoryKey(&CLSID_AudioRendererCategory);
if (FAILED(hr)) return;
count = waveInGetNumDevs();
for (i = 0; i < count; i++)
{
waveInGetDevCapsW(i, &caps, sizeof(caps));
V_VT(&var) = VT_BSTR;
V_BSTR(&var) = SysAllocString(caps.szPname);
if (!(V_BSTR(&var)))
goto cleanup;
hr = register_codec(&CLSID_AudioInputDeviceCategory, V_BSTR(&var), &mon);
if (FAILED(hr)) goto cleanup;
hr = IMoniker_BindToStorage(mon, NULL, NULL, &IID_IPropertyBag, (void **)&prop_bag);
if (FAILED(hr)) goto cleanup;
/* write friendly name */
hr = IPropertyBag_Write(prop_bag, wszFriendlyName, &var);
if (FAILED(hr)) goto cleanup;
VariantClear(&var);
/* write clsid */
V_VT(&var) = VT_BSTR;
StringFromGUID2(&CLSID_AudioRecord, clsid, CHARS_IN_GUID);
if (!(V_BSTR(&var) = SysAllocString(clsid)))
goto cleanup;
hr = IPropertyBag_Write(prop_bag, clsid_keyname, &var);
if (FAILED(hr)) goto cleanup;
VariantClear(&var);
/* write filter data */
rgf.dwVersion = 2;
rgf.dwMerit = MERIT_DO_NOT_USE;
write_filter_data(prop_bag, &rgf);
/* write WaveInId */
V_VT(&var) = VT_I4;
V_I4(&var) = i;
hr = IPropertyBag_Write(prop_bag, waveinidW, &var);
if (FAILED(hr)) goto cleanup;
cleanup:
VariantClear(&var);
if (prop_bag) IPropertyBag_Release(prop_bag);
if (mon) IMoniker_Release(mon);
}
}
/**********************************************************************
* DEVENUM_ICreateDevEnum_CreateClassEnumerator
*/
@ -696,6 +761,7 @@ static HRESULT WINAPI DEVENUM_ICreateDevEnum_CreateClassEnumerator(
hr = DirectSoundEnumerateW(&register_dsound_devices, NULL);
if (FAILED(hr)) return hr;
register_waveout_devices();
register_wavein_devices();
return create_EnumMoniker(clsidDeviceClass, ppEnumMoniker);
}
@ -832,73 +898,10 @@ static HRESULT register_codecs(void)
if (SUCCEEDED(res))
{
UINT i;
WAVEINCAPSW wicaps;
MIDIOUTCAPSW mocaps;
REGPINTYPES * pTypes;
IPropertyBag * pPropBag = NULL;
numDevs = waveInGetNumDevs();
res = DEVENUM_CreateAMCategoryKey(&CLSID_AudioInputDeviceCategory);
if (FAILED(res)) /* can't register any devices in this category */
numDevs = 0;
rfp2.dwFlags = REG_PINFLAG_B_OUTPUT;
for (i = 0; i < numDevs; i++)
{
if (waveInGetDevCapsW(i, &wicaps, sizeof(WAVEINCAPSW))
== MMSYSERR_NOERROR)
{
IMoniker * pMoniker = NULL;
rfp2.nMediaTypes = 1;
pTypes = CoTaskMemAlloc(rfp2.nMediaTypes * sizeof(REGPINTYPES));
if (!pTypes)
{
IFilterMapper2_Release(pMapper);
return E_OUTOFMEMORY;
}
/* FIXME: Not sure if these are correct */
pTypes[0].clsMajorType = &MEDIATYPE_Audio;
pTypes[0].clsMinorType = &MEDIASUBTYPE_PCM;
rfp2.lpMediaType = pTypes;
res = IFilterMapper2_RegisterFilter(pMapper,
&CLSID_AudioRecord,
wicaps.szPname,
&pMoniker,
&CLSID_AudioInputDeviceCategory,
wicaps.szPname,
&rf2);
if (pMoniker) {
VARIANT var;
V_VT(&var) = VT_I4;
V_I4(&var) = i;
res = IMoniker_BindToStorage(pMoniker, NULL, NULL, &IID_IPropertyBag, (LPVOID)&pPropBag);
if (SUCCEEDED(res))
res = IPropertyBag_Write(pPropBag, wszWaveInID, &var);
else
pPropBag = NULL;
V_VT(&var) = VT_LPWSTR;
V_BSTR(&var) = wicaps.szPname;
if (SUCCEEDED(res))
res = IPropertyBag_Write(pPropBag, wszFriendlyName, &var);
if (pPropBag)
IPropertyBag_Release(pPropBag);
IMoniker_Release(pMoniker);
}
CoTaskMemFree(pTypes);
}
}
numDevs = midiOutGetNumDevs();
res = DEVENUM_CreateAMCategoryKey(&CLSID_MidiRendererCategory);

View File

@ -726,6 +726,92 @@ static void test_waveout(void)
IParseDisplayName_Release(parser);
}
static void test_wavein(void)
{
static const WCHAR waveinidW[] = {'W','a','v','e','I','n','I','d',0};
IParseDisplayName *parser;
IPropertyBag *prop_bag;
IMoniker *mon;
WCHAR endpoint[200];
WCHAR buffer[200];
WAVEINCAPSW caps;
MMRESULT mmr;
int count, i;
VARIANT var;
HRESULT hr;
hr = CoCreateInstance(&CLSID_CDeviceMoniker, NULL, CLSCTX_INPROC, &IID_IParseDisplayName, (void **)&parser);
ok(hr == S_OK, "Failed to create ParseDisplayName: %#x\n", hr);
count = waveInGetNumDevs();
for (i = 0; i < count; i++)
{
waveInGetDevCapsW(i, &caps, sizeof(caps));
lstrcpyW(buffer, deviceW);
lstrcatW(buffer, cmW);
StringFromGUID2(&CLSID_AudioInputDeviceCategory, buffer + lstrlenW(buffer), CHARS_IN_GUID);
lstrcatW(buffer, backslashW);
lstrcatW(buffer, caps.szPname);
mon = check_display_name(parser, buffer);
hr = IMoniker_BindToStorage(mon, NULL, NULL, &IID_IPropertyBag, (void **)&prop_bag);
ok(hr == S_OK, "BindToStorage failed: %#x\n", hr);
VariantInit(&var);
hr = IPropertyBag_Read(prop_bag, friendly_name, &var, NULL);
if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
{
IPropertyBag_Release(prop_bag);
IMoniker_Release(mon);
/* Win8+ uses the endpoint GUID instead of the device name */
mmr = waveInMessage((HWAVEIN)(DWORD_PTR) i, DRV_QUERYFUNCTIONINSTANCEID,
(DWORD_PTR) endpoint, sizeof(endpoint));
ok(!mmr, "waveInMessage failed: %u\n", mmr);
lstrcpyW(buffer, deviceW);
lstrcatW(buffer, cmW);
StringFromGUID2(&CLSID_AudioInputDeviceCategory, buffer + lstrlenW(buffer), CHARS_IN_GUID);
lstrcatW(buffer, backslashW);
lstrcatW(buffer, waveW);
lstrcatW(buffer, strchrW(endpoint, '}') + 2);
mon = check_display_name(parser, buffer);
hr = IMoniker_BindToStorage(mon, NULL, NULL, &IID_IPropertyBag, (void **)&prop_bag);
ok(hr == S_OK, "BindToStorage failed: %#x\n", hr);
hr = IPropertyBag_Read(prop_bag, friendly_name, &var, NULL);
}
ok(hr == S_OK, "Read failed: %#x\n", hr);
ok(!strncmpW(caps.szPname, V_BSTR(&var), lstrlenW(caps.szPname)), "expected %s, got %s\n",
wine_dbgstr_w(caps.szPname), wine_dbgstr_w(V_BSTR(&var)));
VariantClear(&var);
hr = IPropertyBag_Read(prop_bag, clsidW, &var, NULL);
ok(hr == S_OK, "Read failed: %#x\n", hr);
StringFromGUID2(&CLSID_AudioRecord, buffer, CHARS_IN_GUID);
ok(!lstrcmpW(buffer, V_BSTR(&var)), "expected %s, got %s\n",
wine_dbgstr_w(buffer), wine_dbgstr_w(V_BSTR(&var)));
VariantClear(&var);
hr = IPropertyBag_Read(prop_bag, waveinidW, &var, NULL);
ok(hr == S_OK, "Read failed: %#x\n", hr);
ok(V_I4(&var) == i, "expected %d, got %d\n", i, V_I4(&var));
IPropertyBag_Release(prop_bag);
IMoniker_Release(mon);
}
IParseDisplayName_Release(parser);
}
START_TEST(devenum)
{
IBindCtx *bind_ctx = NULL;
@ -752,6 +838,7 @@ START_TEST(devenum)
hr = DirectSoundEnumerateW(test_dsound, NULL);
ok(hr == S_OK, "got %#x\n", hr);
test_waveout();
test_wavein();
CoUninitialize();
}