From: Mark Harmstone Subject: [PATCH 1/5] mmdevapi: use struct for endpoint info in GetEndpointIDs Message-Id: <545CDDE9.9030903@burntcomma.com> Date: Fri, 07 Nov 2014 14:57:45 +0000 At present, the only information returned by GetEndpointIDs in the audio drivers is the GUID of each device, and its "id" (actually its name). This patch creates a new DeviceProps struct, and uses that to communicate the device information instead. The following patches allow drivers to additionally specify the form factor and vendor and product IDs of the device, which are used to create a fake device path. These patches are needed for the guitar cable detection in the Rocksmith games. --- dlls/mmdevapi/devenum.c | 21 +++++++++-------- dlls/mmdevapi/mmdevapi.h | 6 ++++- dlls/winealsa.drv/mmdevdrv.c | 48 +++++++++++++++++++++------------------ dlls/winecoreaudio.drv/mmdevdrv.c | 32 ++++++++++++++------------ dlls/wineoss.drv/mmdevdrv.c | 22 ++++++++++-------- 5 files changed, 73 insertions(+), 56 deletions(-) diff --git a/dlls/mmdevapi/devenum.c b/dlls/mmdevapi/devenum.c index e2a7cc5..6a20cac 100644 --- a/dlls/mmdevapi/devenum.c +++ b/dlls/mmdevapi/devenum.c @@ -268,7 +268,7 @@ static HRESULT MMDevice_SetPropValue(const GUID *devguid, DWORD flow, REFPROPERT * 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) +static MMDevice *MMDevice_Create(DeviceProps *props, GUID *id, EDataFlow flow, DWORD state, BOOL setdefault) { HKEY key, root; MMDevice *cur = NULL; @@ -309,7 +309,7 @@ static MMDevice *MMDevice_Create(WCHAR *name, GUID *id, EDataFlow flow, DWORD st WARN("Modifying an MMDevice with postitive reference count!\n"); HeapFree(GetProcessHeap(), 0, cur->drv_id); - cur->drv_id = name; + cur->drv_id = props->id; cur->flow = flow; cur->state = state; @@ -331,7 +331,7 @@ static MMDevice *MMDevice_Create(WCHAR *name, GUID *id, EDataFlow flow, DWORD st PROPVARIANT pv; pv.vt = VT_LPWSTR; - pv.u.pwszVal = name; + pv.u.pwszVal = props->id; MMDevice_SetPropValue(id, flow, (const PROPERTYKEY*)&DEVPKEY_Device_FriendlyName, &pv); MMDevice_SetPropValue(id, flow, (const PROPERTYKEY*)&DEVPKEY_Device_DeviceDesc, &pv); @@ -402,9 +402,10 @@ static HRESULT load_devices_from_reg(void) && 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, + DeviceProps props; + props.id = HeapAlloc(GetProcessHeap(), 0, size_bytes); + memcpy(props.id, pv.u.pwszVal, size_bytes); + MMDevice_Create(&props, &guid, curflow, DEVICE_STATE_NOTPRESENT, FALSE); CoTaskMemFree(pv.u.pwszVal); } @@ -445,7 +446,7 @@ static HRESULT set_format(MMDevice *dev) static HRESULT load_driver_devices(EDataFlow flow) { - WCHAR **ids; + DeviceProps *props; GUID *guids; UINT num, def, i; HRESULT hr; @@ -453,19 +454,19 @@ static HRESULT load_driver_devices(EDataFlow flow) if(!drvs.pGetEndpointIDs) return S_OK; - hr = drvs.pGetEndpointIDs(flow, &ids, &guids, &num, &def); + hr = drvs.pGetEndpointIDs(flow, &props, &guids, &num, &def); if(FAILED(hr)) return hr; for(i = 0; i < num; ++i){ MMDevice *dev; - dev = MMDevice_Create(ids[i], &guids[i], flow, DEVICE_STATE_ACTIVE, + dev = MMDevice_Create(&props[i], &guids[i], flow, DEVICE_STATE_ACTIVE, def == i); set_format(dev); } HeapFree(GetProcessHeap(), 0, guids); - HeapFree(GetProcessHeap(), 0, ids); + HeapFree(GetProcessHeap(), 0, props); return S_OK; } diff --git a/dlls/mmdevapi/mmdevapi.h b/dlls/mmdevapi/mmdevapi.h index 2a04780..87032ab 100644 --- a/dlls/mmdevapi/mmdevapi.h +++ b/dlls/mmdevapi/mmdevapi.h @@ -32,6 +32,10 @@ enum _DriverPriority { Priority_Preferred /* driver thinks it's correct */ }; +typedef struct { + WCHAR *id; +} DeviceProps; + typedef struct _DriverFuncs { HMODULE module; WCHAR module_name[64]; @@ -48,7 +52,7 @@ typedef struct _DriverFuncs { * in GetAudioEndpoint to identify the endpoint * it is the caller's responsibility to free both arrays, and * all of the elements in both arrays with HeapFree() */ - HRESULT (WINAPI *pGetEndpointIDs)(EDataFlow flow, WCHAR ***ids, + HRESULT (WINAPI *pGetEndpointIDs)(EDataFlow flow, DeviceProps **props, GUID **guids, UINT *num, UINT *default_index); HRESULT (WINAPI *pGetAudioEndpoint)(void *key, IMMDevice *dev, IAudioClient **out); diff --git a/dlls/winealsa.drv/mmdevdrv.c b/dlls/winealsa.drv/mmdevdrv.c index a4c02bf..a7d287f 100644 --- a/dlls/winealsa.drv/mmdevdrv.c +++ b/dlls/winealsa.drv/mmdevdrv.c @@ -254,6 +254,10 @@ enum DriverPriority { Priority_Preferred }; +typedef struct { + WCHAR *id; +} DeviceProps; + int WINAPI AUDDRV_GetPriority(void) { return Priority_Neutral; @@ -402,7 +406,7 @@ static WCHAR *construct_device_id(EDataFlow flow, const WCHAR *chunk1, const cha } static HRESULT alsa_get_card_devices(EDataFlow flow, snd_pcm_stream_t stream, - WCHAR ***ids, GUID **guids, UINT *num, snd_ctl_t *ctl, int card, + DeviceProps **props, GUID **guids, UINT *num, snd_ctl_t *ctl, int card, const WCHAR *cardnameW) { int err, device; @@ -438,10 +442,10 @@ static HRESULT alsa_get_card_devices(EDataFlow flow, snd_pcm_stream_t stream, continue; if(*num){ - *ids = HeapReAlloc(GetProcessHeap(), 0, *ids, sizeof(WCHAR *) * (*num + 1)); + *props = HeapReAlloc(GetProcessHeap(), 0, *props, sizeof(DeviceProps) * (*num + 1)); *guids = HeapReAlloc(GetProcessHeap(), 0, *guids, sizeof(GUID) * (*num + 1)); }else{ - *ids = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR *)); + *props = HeapAlloc(GetProcessHeap(), 0, sizeof(DeviceProps)); *guids = HeapAlloc(GetProcessHeap(), 0, sizeof(GUID)); } @@ -452,7 +456,7 @@ static HRESULT alsa_get_card_devices(EDataFlow flow, snd_pcm_stream_t stream, continue; } - (*ids)[*num] = construct_device_id(flow, cardnameW, devname); + (*props)[*num].id = construct_device_id(flow, cardnameW, devname); get_device_guid(flow, devnode, &(*guids)[*num]); ++(*num); @@ -467,7 +471,7 @@ static HRESULT alsa_get_card_devices(EDataFlow flow, snd_pcm_stream_t stream, return S_OK; } -static void get_reg_devices(EDataFlow flow, snd_pcm_stream_t stream, WCHAR ***ids, +static void get_reg_devices(EDataFlow flow, snd_pcm_stream_t stream, DeviceProps **props, GUID **guids, UINT *num) { static const WCHAR ALSAOutputDevices[] = {'A','L','S','A','O','u','t','p','u','t','D','e','v','i','c','e','s',0}; @@ -496,13 +500,13 @@ static void get_reg_devices(EDataFlow flow, snd_pcm_stream_t stream, WCHAR ***id if(alsa_try_open(devname, stream)){ if(*num){ - *ids = HeapReAlloc(GetProcessHeap(), 0, *ids, sizeof(WCHAR *) * (*num + 1)); + *props = HeapReAlloc(GetProcessHeap(), 0, *props, sizeof(DeviceProps) * (*num + 1)); *guids = HeapReAlloc(GetProcessHeap(), 0, *guids, sizeof(GUID) * (*num + 1)); }else{ - *ids = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR *)); + *props = HeapAlloc(GetProcessHeap(), 0, sizeof(DeviceProps)); *guids = HeapAlloc(GetProcessHeap(), 0, sizeof(GUID)); } - (*ids)[*num] = construct_device_id(flow, p, NULL); + (*props)[*num].id = construct_device_id(flow, p, NULL); get_device_guid(flow, devname, &(*guids)[*num]); ++*num; } @@ -515,7 +519,7 @@ static void get_reg_devices(EDataFlow flow, snd_pcm_stream_t stream, WCHAR ***id } } -static HRESULT alsa_enum_devices(EDataFlow flow, WCHAR ***ids, GUID **guids, +static HRESULT alsa_enum_devices(EDataFlow flow, DeviceProps **props, GUID **guids, UINT *num) { snd_pcm_stream_t stream = (flow == eRender ? SND_PCM_STREAM_PLAYBACK : @@ -526,14 +530,14 @@ static HRESULT alsa_enum_devices(EDataFlow flow, WCHAR ***ids, GUID **guids, *num = 0; if(alsa_try_open(defname, stream)){ - *ids = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR *)); - (*ids)[0] = construct_device_id(flow, defaultW, NULL); + *props = HeapAlloc(GetProcessHeap(), 0, sizeof(DeviceProps)); + (*props)[0].id = construct_device_id(flow, defaultW, NULL); *guids = HeapAlloc(GetProcessHeap(), 0, sizeof(GUID)); get_device_guid(flow, defname, &(*guids)[0]); ++*num; } - get_reg_devices(flow, stream, ids, guids, num); + get_reg_devices(flow, stream, props, guids, num); for(err = snd_card_next(&card); card != -1 && err >= 0; err = snd_card_next(&card)){ @@ -556,7 +560,7 @@ static HRESULT alsa_enum_devices(EDataFlow flow, WCHAR ***ids, GUID **guids, static const WCHAR nameW[] = {'U','n','k','n','o','w','n',' ','s','o','u','n','d','c','a','r','d',0}; WARN("Unable to get card name for ALSA device %s: %d (%s)\n", cardpath, err, snd_strerror(err)); - alsa_get_card_devices(flow, stream, ids, guids, num, ctl, card, nameW); + alsa_get_card_devices(flow, stream, props, guids, num, ctl, card, nameW); }else{ len = MultiByteToWideChar(CP_UNIXCP, 0, cardname, -1, NULL, 0); cardnameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); @@ -568,7 +572,7 @@ static HRESULT alsa_enum_devices(EDataFlow flow, WCHAR ***ids, GUID **guids, } MultiByteToWideChar(CP_UNIXCP, 0, cardname, -1, cardnameW, len); - alsa_get_card_devices(flow, stream, ids, guids, num, ctl, card, cardnameW); + alsa_get_card_devices(flow, stream, props, guids, num, ctl, card, cardnameW); HeapFree(GetProcessHeap(), 0, cardnameW); free(cardname); @@ -584,22 +588,22 @@ static HRESULT alsa_enum_devices(EDataFlow flow, WCHAR ***ids, GUID **guids, return S_OK; } -HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids, GUID **guids, +HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, DeviceProps **props, GUID **guids, UINT *num, UINT *def_index) { HRESULT hr; - TRACE("%d %p %p %p %p\n", flow, ids, guids, num, def_index); + TRACE("%d %p %p %p %p\n", flow, props, guids, num, def_index); - *ids = NULL; + *props = NULL; *guids = NULL; - hr = alsa_enum_devices(flow, ids, guids, num); + hr = alsa_enum_devices(flow, props, guids, num); if(FAILED(hr)){ UINT i; for(i = 0; i < *num; ++i) - HeapFree(GetProcessHeap(), 0, (*ids)[i]); - HeapFree(GetProcessHeap(), 0, *ids); + HeapFree(GetProcessHeap(), 0, (*props)[i].id); + HeapFree(GetProcessHeap(), 0, *props); HeapFree(GetProcessHeap(), 0, *guids); return E_OUTOFMEMORY; } @@ -607,8 +611,8 @@ HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids, GUID **guids, TRACE("Enumerated %u devices\n", *num); if(*num == 0){ - HeapFree(GetProcessHeap(), 0, *ids); - *ids = NULL; + HeapFree(GetProcessHeap(), 0, *props); + *props = NULL; HeapFree(GetProcessHeap(), 0, *guids); *guids = NULL; } diff --git a/dlls/winecoreaudio.drv/mmdevdrv.c b/dlls/winecoreaudio.drv/mmdevdrv.c index e58cda1..e39700a 100644 --- a/dlls/winecoreaudio.drv/mmdevdrv.c +++ b/dlls/winecoreaudio.drv/mmdevdrv.c @@ -291,6 +291,10 @@ enum DriverPriority { Priority_Preferred }; +typedef struct { + WCHAR *id; +} DeviceProps; + int WINAPI AUDDRV_GetPriority(void) { return Priority_Neutral; @@ -384,7 +388,7 @@ static void get_device_guid(EDataFlow flow, AudioDeviceID device, GUID *guid) RegCloseKey(key); } -HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids, +HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, DeviceProps **props, GUID **guids, UINT *num, UINT *def_index) { UInt32 devsize, size; @@ -394,7 +398,7 @@ HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids, OSStatus sc; int i, ndevices; - TRACE("%d %p %p %p\n", flow, ids, num, def_index); + TRACE("%d %p %p %p\n", flow, props, num, def_index); addr.mScope = kAudioObjectPropertyScopeGlobal; addr.mElement = kAudioObjectPropertyElementMaster; @@ -435,15 +439,15 @@ HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids, ndevices = devsize / sizeof(AudioDeviceID); - *ids = HeapAlloc(GetProcessHeap(), 0, ndevices * sizeof(WCHAR *)); - if(!*ids){ + *props = HeapAlloc(GetProcessHeap(), 0, ndevices * sizeof(DeviceProps)); + if(!*props){ HeapFree(GetProcessHeap(), 0, devices); return E_OUTOFMEMORY; } *guids = HeapAlloc(GetProcessHeap(), 0, ndevices * sizeof(GUID)); if(!*guids){ - HeapFree(GetProcessHeap(), 0, *ids); + HeapFree(GetProcessHeap(), 0, *props); HeapFree(GetProcessHeap(), 0, devices); return E_OUTOFMEMORY; } @@ -473,9 +477,9 @@ HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids, if(!buffers){ HeapFree(GetProcessHeap(), 0, devices); for(j = 0; j < *num; ++j) - HeapFree(GetProcessHeap(), 0, (*ids)[j]); + HeapFree(GetProcessHeap(), 0, (*props)[j].id); HeapFree(GetProcessHeap(), 0, *guids); - HeapFree(GetProcessHeap(), 0, *ids); + HeapFree(GetProcessHeap(), 0, *props); return E_OUTOFMEMORY; } @@ -511,18 +515,18 @@ HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids, } len = CFStringGetLength(name) + 1; - (*ids)[*num] = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); - if(!(*ids)[*num]){ + (*props)[*num].id = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); + if(!(*props)[*num].id){ CFRelease(name); HeapFree(GetProcessHeap(), 0, devices); for(j = 0; j < *num; ++j) - HeapFree(GetProcessHeap(), 0, (*ids)[j]); - HeapFree(GetProcessHeap(), 0, *ids); + HeapFree(GetProcessHeap(), 0, (*props)[j].id); + HeapFree(GetProcessHeap(), 0, *props); HeapFree(GetProcessHeap(), 0, *guids); return E_OUTOFMEMORY; } - CFStringGetCharacters(name, CFRangeMake(0, len - 1), (UniChar*)(*ids)[*num]); - ((*ids)[*num])[len - 1] = 0; + CFStringGetCharacters(name, CFRangeMake(0, len - 1), (UniChar*)(*props)[*num].id); + ((*props)[*num]).id[len - 1] = 0; CFRelease(name); get_device_guid(flow, devices[i], &(*guids)[*num]); @@ -530,7 +534,7 @@ HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids, if(*def_index == (UINT)-1 && devices[i] == default_id) *def_index = *num; - TRACE("device %u: id %s key %u%s\n", *num, debugstr_w((*ids)[*num]), + TRACE("device %u: id %s key %u%s\n", *num, debugstr_w((*props)[*num].id), (unsigned int)devices[i], (*def_index == *num) ? " (default)" : ""); (*num)++; diff --git a/dlls/wineoss.drv/mmdevdrv.c b/dlls/wineoss.drv/mmdevdrv.c index ce95138..426355e 100644 --- a/dlls/wineoss.drv/mmdevdrv.c +++ b/dlls/wineoss.drv/mmdevdrv.c @@ -267,6 +267,10 @@ enum DriverPriority { Priority_Preferred }; +typedef struct { + WCHAR *id; +} DeviceProps; + int WINAPI AUDDRV_GetPriority(void) { int mixer_fd; @@ -445,7 +449,7 @@ static UINT get_default_index(EDataFlow flow) return 0; } -HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids, GUID **guids, +HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, DeviceProps **props, GUID **guids, UINT *num, UINT *def_index) { int i, mixer_fd; @@ -455,7 +459,7 @@ HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids, GUID **guids, static const WCHAR outW[] = {'O','u','t',':',' ',0}; static const WCHAR inW[] = {'I','n',':',' ',0}; - TRACE("%d %p %p %p %p\n", flow, ids, guids, num, def_index); + TRACE("%d %p %p %p %p\n", flow, props, guids, num, def_index); mixer_fd = open("/dev/mixer", O_RDONLY, 0); if(mixer_fd < 0){ @@ -493,7 +497,7 @@ HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids, GUID **guids, return AUDCLNT_E_SERVICE_NOT_RUNNING; } - *ids = HeapAlloc(GetProcessHeap(), 0, sysinfo.numaudios * sizeof(WCHAR *)); + *props = HeapAlloc(GetProcessHeap(), 0, sysinfo.numaudios * sizeof(DeviceProps)); *guids = HeapAlloc(GetProcessHeap(), 0, sysinfo.numaudios * sizeof(GUID)); *num = 0; @@ -554,20 +558,20 @@ HRESULT WINAPI AUDDRV_GetEndpointIDs(EDataFlow flow, WCHAR ***ids, GUID **guids, prefix_len = (sizeof(inW) / sizeof(*inW)) - 1; len += prefix_len; } - (*ids)[*num] = HeapAlloc(GetProcessHeap(), 0, + (*props)[*num].id = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); - if(!(*ids)[*num]){ + if(!(*props)[*num].id){ for(i = 0; i < *num; ++i) - HeapFree(GetProcessHeap(), 0, (*ids)[i]); - HeapFree(GetProcessHeap(), 0, *ids); + HeapFree(GetProcessHeap(), 0, (*props)[i].id); + HeapFree(GetProcessHeap(), 0, *props); HeapFree(GetProcessHeap(), 0, *guids); HeapFree(GetProcessHeap(), 0, dev_item); close(mixer_fd); return E_OUTOFMEMORY; } - memcpy((*ids)[*num], prefix, prefix_len * sizeof(WCHAR)); + memcpy((*props)[*num].id, prefix, prefix_len * sizeof(WCHAR)); MultiByteToWideChar(CP_UNIXCP, 0, ai.name, -1, - (*ids)[*num] + prefix_len, len - prefix_len); + (*props)[*num].id + prefix_len, len - prefix_len); list_add_tail(&g_devices, &dev_item->entry);