static HRESULT load_devices_from_reg(void) { DWORD i = 0; HKEY root, cur; LONG ret; DWORD curflow; ret = RegCreateKeyExW(HKEY_LOCAL_MACHINE, software_mmdevapi, 0, NULL, 0, KEY_WRITE|KEY_READ|KEY_WOW64_64KEY, NULL, &root, NULL); if (ret == ERROR_SUCCESS) ret = RegCreateKeyExW(root, reg_capture, 0, NULL, 0, KEY_READ|KEY_WRITE|KEY_WOW64_64KEY, NULL, &key_capture, NULL); if (ret == ERROR_SUCCESS) ret = RegCreateKeyExW(root, reg_render, 0, NULL, 0, KEY_READ|KEY_WRITE|KEY_WOW64_64KEY, NULL, &key_render, NULL); RegCloseKey(root); cur = key_capture; curflow = eCapture; if (ret != ERROR_SUCCESS) { RegCloseKey(key_capture); key_render = key_capture = NULL; WARN("Couldn't create key: %u\n", ret); return E_FAIL; } do { WCHAR guidvalue[39]; GUID guid; DWORD len; PROPVARIANT pv = { VT_EMPTY }; len = sizeof(guidvalue)/sizeof(guidvalue[0]); ret = RegEnumKeyExW(cur, i++, guidvalue, &len, NULL, NULL, NULL, NULL); if (ret == ERROR_NO_MORE_ITEMS) { if (cur == key_capture) { cur = key_render; curflow = eRender; i = 0; continue; } break; } if (ret != ERROR_SUCCESS) continue; if (SUCCEEDED(CLSIDFromString(guidvalue, &guid)) && SUCCEEDED(MMDevice_GetPropValue(&guid, curflow, (const PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &pv)) && pv.vt == VT_LPWSTR) { DWORD size_bytes = (strlenW(pv.u.pwszVal) + 1) * sizeof(WCHAR); WCHAR *name = HeapAlloc(GetProcessHeap(), 0, size_bytes); memcpy(name, pv.u.pwszVal, size_bytes); MMDevice_Create(name, &guid, curflow, DEVICE_STATE_NOTPRESENT, FALSE); CoTaskMemFree(pv.u.pwszVal); } } while (1); return S_OK; }
static void openal_setformat(MMDevice *This, DWORD freq) { HRESULT hr; PROPVARIANT pv = { VT_EMPTY }; hr = MMDevice_GetPropValue(&This->devguid, This->flow, &PKEY_AudioEngine_DeviceFormat, &pv); if (SUCCEEDED(hr) && pv.vt == VT_BLOB) { WAVEFORMATEX *pwfx; pwfx = (WAVEFORMATEX*)pv.u.blob.pBlobData; if (pwfx->nSamplesPerSec != freq) { pwfx->nSamplesPerSec = freq; pwfx->nAvgBytesPerSec = freq * pwfx->nBlockAlign; MMDevice_SetPropValue(&This->devguid, This->flow, &PKEY_AudioEngine_DeviceFormat, &pv); } CoTaskMemFree(pwfx); } else { WAVEFORMATEXTENSIBLE wfxe; wfxe.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; wfxe.Format.nChannels = 2; wfxe.Format.wBitsPerSample = 32; wfxe.Format.nBlockAlign = wfxe.Format.nChannels * wfxe.Format.wBitsPerSample/8; wfxe.Format.nSamplesPerSec = freq; wfxe.Format.nAvgBytesPerSec = wfxe.Format.nSamplesPerSec * wfxe.Format.nBlockAlign; wfxe.Format.cbSize = sizeof(wfxe)-sizeof(WAVEFORMATEX); wfxe.Samples.wValidBitsPerSample = 32; wfxe.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; wfxe.dwChannelMask = SPEAKER_FRONT_LEFT|SPEAKER_FRONT_RIGHT; pv.vt = VT_BLOB; pv.u.blob.cbSize = sizeof(wfxe); pv.u.blob.pBlobData = (BYTE*)&wfxe; MMDevice_SetPropValue(&This->devguid, This->flow, &PKEY_AudioEngine_DeviceFormat, &pv); MMDevice_SetPropValue(&This->devguid, This->flow, &PKEY_AudioEngine_OEMFormat, &pv); } }
static HRESULT WINAPI MMDevPropStore_GetValue(IPropertyStore *iface, REFPROPERTYKEY key, PROPVARIANT *pv) { MMDevPropStore *This = impl_from_IPropertyStore(iface); TRACE("(%p)->(\"%s,%u\", %p\n", This, debugstr_guid(&key->fmtid), key ? key->pid : 0, pv); if (!key || !pv) return E_POINTER; if (This->access != STGM_READ && This->access != STGM_READWRITE) return STG_E_ACCESSDENIED; /* Special case */ if (IsEqualPropertyKey(*key, PKEY_AudioEndpoint_GUID)) { pv->vt = VT_LPWSTR; pv->u.pwszVal = CoTaskMemAlloc(39 * sizeof(WCHAR)); if (!pv->u.pwszVal) return E_OUTOFMEMORY; StringFromGUID2(&This->parent->devguid, pv->u.pwszVal, 39); return S_OK; } return MMDevice_GetPropValue(&This->parent->devguid, This->parent->flow, key, pv); }
/* Creates or updates the state of a device * If GUID is null, a random guid will be assigned * and the device will be created */ static MMDevice *MMDevice_Create(WCHAR *name, GUID *id, EDataFlow flow, DWORD state, BOOL setdefault) { HKEY key, root; MMDevice *cur = NULL; WCHAR guidstr[39]; DWORD i; static const PROPERTYKEY deviceinterface_key = { {0x233164c8, 0x1b2c, 0x4c7d, {0xbc, 0x68, 0xb6, 0x71, 0x68, 0x7a, 0x25, 0x67}}, 1 }; static const PROPERTYKEY devicepath_key = { {0xb3f8fa53, 0x0004, 0x438e, {0x90, 0x03, 0x51, 0xa4, 0x6e, 0x13, 0x9b, 0xfc}}, 2 }; for (i = 0; i < MMDevice_count; ++i) { MMDevice *device = MMDevice_head[i]; if (device->flow == flow && IsEqualGUID(&device->devguid, id)){ cur = device; break; } } if(!cur){ /* No device found, allocate new one */ cur = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*cur)); if (!cur) return NULL; cur->IMMDevice_iface.lpVtbl = &MMDeviceVtbl; cur->IMMEndpoint_iface.lpVtbl = &MMEndpointVtbl; InitializeCriticalSection(&cur->crst); cur->crst.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": MMDevice.crst"); if (!MMDevice_head) MMDevice_head = HeapAlloc(GetProcessHeap(), 0, sizeof(*MMDevice_head)); else MMDevice_head = HeapReAlloc(GetProcessHeap(), 0, MMDevice_head, sizeof(*MMDevice_head)*(1+MMDevice_count)); MMDevice_head[MMDevice_count++] = cur; }else if(cur->ref > 0) WARN("Modifying an MMDevice with postitive reference count!\n"); HeapFree(GetProcessHeap(), 0, cur->drv_id); cur->drv_id = name; cur->flow = flow; cur->state = state; cur->devguid = *id; StringFromGUID2(&cur->devguid, guidstr, sizeof(guidstr)/sizeof(*guidstr)); if (flow == eRender) root = key_render; else root = key_capture; if (RegCreateKeyExW(root, guidstr, 0, NULL, 0, KEY_WRITE|KEY_READ|KEY_WOW64_64KEY, NULL, &key, NULL) == ERROR_SUCCESS) { HKEY keyprop; RegSetValueExW(key, reg_devicestate, 0, REG_DWORD, (const BYTE*)&state, sizeof(DWORD)); if (!RegCreateKeyExW(key, reg_properties, 0, NULL, 0, KEY_WRITE|KEY_READ|KEY_WOW64_64KEY, NULL, &keyprop, NULL)) { PROPVARIANT pv; pv.vt = VT_LPWSTR; pv.u.pwszVal = name; MMDevice_SetPropValue(id, flow, (const PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &pv); MMDevice_SetPropValue(id, flow, (const PROPERTYKEY*)&DEVPKEY_DeviceInterface_FriendlyName, &pv); MMDevice_SetPropValue(id, flow, (const PROPERTYKEY*)&DEVPKEY_Device_DeviceDesc, &pv); pv.u.pwszVal = guidstr; MMDevice_SetPropValue(id, flow, &deviceinterface_key, &pv); set_driver_prop_value(id, flow, &devicepath_key); if (FAILED(set_driver_prop_value(id, flow, &PKEY_AudioEndpoint_FormFactor))) { pv.vt = VT_UI4; pv.u.ulVal = (flow == eCapture) ? Microphone : Speakers; MMDevice_SetPropValue(id, flow, &PKEY_AudioEndpoint_FormFactor, &pv); } if (flow != eCapture) { PROPVARIANT pv2; PropVariantInit(&pv2); /* make read-write by not overwriting if already set */ if (FAILED(MMDevice_GetPropValue(id, flow, &PKEY_AudioEndpoint_PhysicalSpeakers, &pv2)) || pv2.vt != VT_UI4) set_driver_prop_value(id, flow, &PKEY_AudioEndpoint_PhysicalSpeakers); PropVariantClear(&pv2); } RegCloseKey(keyprop); } RegCloseKey(key); } if (setdefault) { if (flow == eRender) MMDevice_def_play = cur; else MMDevice_def_rec = cur; } return cur; }
HRESULT MMDevEnum_Create(REFIID riid, void **ppv) { MMDevEnumImpl *This = MMDevEnumerator; if (!This) { DWORD i = 0; HKEY root, cur; LONG ret; DWORD curflow; This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); *ppv = NULL; if (!This) return E_OUTOFMEMORY; This->ref = 1; This->IMMDeviceEnumerator_iface.lpVtbl = &MMDevEnumVtbl; MMDevEnumerator = This; ret = RegCreateKeyExW(HKEY_LOCAL_MACHINE, software_mmdevapi, 0, NULL, 0, KEY_WRITE|KEY_READ, NULL, &root, NULL); if (ret == ERROR_SUCCESS) ret = RegCreateKeyExW(root, reg_capture, 0, NULL, 0, KEY_READ|KEY_WRITE, NULL, &key_capture, NULL); if (ret == ERROR_SUCCESS) ret = RegCreateKeyExW(root, reg_render, 0, NULL, 0, KEY_READ|KEY_WRITE, NULL, &key_render, NULL); RegCloseKey(root); cur = key_capture; curflow = eCapture; if (ret != ERROR_SUCCESS) { RegCloseKey(key_capture); key_render = key_capture = NULL; WARN("Couldn't create key: %u\n", ret); return E_FAIL; } else do { WCHAR guidvalue[39]; GUID guid; DWORD len; PROPVARIANT pv = { VT_EMPTY }; len = sizeof(guidvalue)/sizeof(guidvalue[0]); ret = RegEnumKeyExW(cur, i++, guidvalue, &len, NULL, NULL, NULL, NULL); if (ret == ERROR_NO_MORE_ITEMS) { if (cur == key_capture) { cur = key_render; curflow = eRender; i = 0; continue; } break; } if (ret != ERROR_SUCCESS) continue; if (SUCCEEDED(CLSIDFromString(guidvalue, &guid)) && SUCCEEDED(MMDevice_GetPropValue(&guid, curflow, (const PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &pv)) && pv.vt == VT_LPWSTR) { MMDevice_Create(NULL, pv.u.pwszVal, &guid, curflow, DEVICE_STATE_NOTPRESENT, FALSE); CoTaskMemFree(pv.u.pwszVal); } } while (1); #ifdef HAVE_OPENAL if (openal_loaded) { openal_scanrender(); openal_scancapture(); } else FIXME("OpenAL support not enabled, application will not find sound devices\n"); #else ERR("OpenAL support not compiled in, application will not find sound devices\n"); #endif /*HAVE_OPENAL*/ } return IUnknown_QueryInterface((IUnknown*)This, riid, ppv); }