static HRESULT set_format(MMDevice *dev) { HRESULT hr; IAudioClient *client; WAVEFORMATEX *fmt; PROPVARIANT pv = { VT_EMPTY }; hr = drvs.pGetAudioEndpoint(&dev->devguid, &dev->IMMDevice_iface, &client); if(FAILED(hr)) return hr; hr = IAudioClient_GetMixFormat(client, &fmt); if(FAILED(hr)){ IAudioClient_Release(client); return hr; } IAudioClient_Release(client); pv.vt = VT_BLOB; pv.u.blob.cbSize = sizeof(WAVEFORMATEX) + fmt->cbSize; pv.u.blob.pBlobData = (BYTE*)fmt; MMDevice_SetPropValue(&dev->devguid, dev->flow, &PKEY_AudioEngine_DeviceFormat, &pv); MMDevice_SetPropValue(&dev->devguid, dev->flow, &PKEY_AudioEngine_OEMFormat, &pv); CoTaskMemFree(fmt); return S_OK; }
static HRESULT WINAPI MMDevPropStore_SetValue(IPropertyStore *iface, REFPROPERTYKEY key, REFPROPVARIANT pv) { MMDevPropStore *This = impl_from_IPropertyStore(iface); if (!key || !pv) return E_POINTER; if (This->access != STGM_WRITE && This->access != STGM_READWRITE) return STG_E_ACCESSDENIED; return MMDevice_SetPropValue(&This->parent->devguid, This->parent->flow, key, pv); }
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 set_driver_prop_value(GUID *id, const EDataFlow flow, const PROPERTYKEY *prop) { HRESULT hr; PROPVARIANT pv; if (!drvs.pGetPropValue) return E_NOTIMPL; hr = drvs.pGetPropValue(id, prop, &pv); if (SUCCEEDED(hr)) { MMDevice_SetPropValue(id, flow, prop, &pv); PropVariantClear(&pv); } return hr; }
/* 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; }
/* 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 }; 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, 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, 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_Device_DeviceDesc, &pv); pv.u.pwszVal = guidstr; MMDevice_SetPropValue(id, flow, &deviceinterface_key, &pv); RegCloseKey(keyprop); } RegCloseKey(key); } if (setdefault) { if (flow == eRender) MMDevice_def_play = cur; else MMDevice_def_rec = cur; } return cur; }
/* 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 void MMDevice_Create(MMDevice **dev, WCHAR *name, GUID *id, EDataFlow flow, DWORD state, BOOL setdefault) { HKEY key, root; MMDevice *cur; WCHAR guidstr[39]; DWORD i; for (i = 0; i < MMDevice_count; ++i) { cur = MMDevice_head[i]; if (cur->flow == flow && !lstrcmpW(cur->alname, name)) { LONG ret; /* Same device, update state */ cur->state = state; StringFromGUID2(&cur->devguid, guidstr, sizeof(guidstr)/sizeof(*guidstr)); ret = RegOpenKeyExW(flow == eRender ? key_render : key_capture, guidstr, 0, KEY_WRITE, &key); if (ret == ERROR_SUCCESS) { RegSetValueExW(key, reg_devicestate, 0, REG_DWORD, (const BYTE*)&state, sizeof(DWORD)); RegCloseKey(key); } goto done; } } /* No device found, allocate new one */ cur = HeapAlloc(GetProcessHeap(), 0, sizeof(*cur)); if (!cur) return; cur->alname = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(name)+1)*sizeof(WCHAR)); if (!cur->alname) { HeapFree(GetProcessHeap(), 0, cur); return; } lstrcpyW(cur->alname, name); cur->IMMDevice_iface.lpVtbl = &MMDeviceVtbl; cur->IMMEndpoint_iface.lpVtbl = &MMEndpointVtbl; cur->ref = 0; InitializeCriticalSection(&cur->crst); cur->crst.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": MMDevice.crst"); cur->flow = flow; cur->state = state; cur->device = NULL; if (!id) { id = &cur->devguid; CoCreateGuid(id); } cur->devguid = *id; StringFromGUID2(id, 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, NULL, &key, NULL)) { 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, 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_Device_DeviceDesc, &pv); RegCloseKey(keyprop); } RegCloseKey(key); } 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; done: if (setdefault) { if (flow == eRender) MMDevice_def_play = cur; else MMDevice_def_rec = cur; } if (dev) *dev = cur; }