Andrew Eikum : winmm: Rearrange device mapping when a new default device is chosen.
Alexandre Julliard
julliard at winehq.org
Wed Dec 26 14:05:17 CST 2012
Module: wine
Branch: master
Commit: 4ab4bc5d095647ad1e4ca30c2749f0e3c337ad9d
URL: http://source.winehq.org/git/wine.git/?a=commit;h=4ab4bc5d095647ad1e4ca30c2749f0e3c337ad9d
Author: Andrew Eikum <aeikum at codeweavers.com>
Date: Wed Dec 26 08:40:03 2012 -0600
winmm: Rearrange device mapping when a new default device is chosen.
---
dlls/winmm/waveform.c | 159 +++++++++++++++++++++++++++++++++++++++++++-----
1 files changed, 142 insertions(+), 17 deletions(-)
diff --git a/dlls/winmm/waveform.c b/dlls/winmm/waveform.c
index 18f3bb9..11ae66c 100644
--- a/dlls/winmm/waveform.c
+++ b/dlls/winmm/waveform.c
@@ -278,6 +278,15 @@ static void WINMM_InitDevice(WINMM_Device *device,
device->parent = parent;
}
+static inline WINMM_MMDevice *read_map(WINMM_MMDevice **map, UINT index)
+{
+ WINMM_MMDevice *ret;
+ EnterCriticalSection(&g_devthread_lock);
+ ret = map[index];
+ LeaveCriticalSection(&g_devthread_lock);
+ return ret;
+}
+
/* finds the first unused Device, marks it as "open", and returns
* a pointer to the device
*
@@ -290,9 +299,9 @@ static WINMM_Device *WINMM_FindUnusedDevice(BOOL is_out, UINT mmdevice_index)
UINT i;
if(is_out)
- mmdevice = g_out_map[mmdevice_index];
+ mmdevice = read_map(g_out_map, mmdevice_index);
else
- mmdevice = g_in_map[mmdevice_index];
+ mmdevice = read_map(g_in_map, mmdevice_index);
EnterCriticalSection(&mmdevice->lock);
for(i = 0; i < MAX_DEVICES; ++i){
@@ -629,6 +638,112 @@ static HRESULT WINMM_EnumDevices(WINMM_MMDevice **devices,
return S_OK;
}
+static HRESULT WINAPI notif_QueryInterface(IMMNotificationClient *iface,
+ const GUID *riid, void **obj)
+{
+ ERR("Unexpected QueryInterface call: %s\n", wine_dbgstr_guid(riid));
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI notif_AddRef(IMMNotificationClient *iface)
+{
+ return 2;
+}
+
+static ULONG WINAPI notif_Release(IMMNotificationClient *iface)
+{
+ return 1;
+}
+
+static HRESULT WINAPI notif_OnDeviceStateChanged(IMMNotificationClient *iface,
+ const WCHAR *device_id, DWORD new_state)
+{
+ TRACE("Ignoring OnDeviceStateChanged callback\n");
+ return S_OK;
+}
+
+static HRESULT WINAPI notif_OnDeviceAdded(IMMNotificationClient *iface,
+ const WCHAR *device_id)
+{
+ TRACE("Ignoring OnDeviceAdded callback\n");
+ return S_OK;
+}
+
+static HRESULT WINAPI notif_OnDeviceRemoved(IMMNotificationClient *iface,
+ const WCHAR *device_id)
+{
+ TRACE("Ignoring OnDeviceRemoved callback\n");
+ return S_OK;
+}
+
+static HRESULT WINAPI notif_OnDefaultDeviceChanged(IMMNotificationClient *iface,
+ EDataFlow flow, ERole role, const WCHAR *device_id)
+{
+ WINMM_MMDevice ***map;
+ WINMM_MMDevice *prev;
+ UINT count, i;
+
+ TRACE("%u %u %s\n", flow, role, wine_dbgstr_w(device_id));
+
+ if(role != eConsole)
+ return S_OK;
+
+ EnterCriticalSection(&g_devthread_lock);
+
+ if(flow == eRender){
+ map = &g_out_map;
+ count = g_outmmdevices_count;
+ }else{
+ map = &g_in_map;
+ count = g_inmmdevices_count;
+ }
+
+ prev = (*map)[0];
+ for(i = 0; i < count; ++i){
+ WINMM_MMDevice *tmp;
+
+ if(!lstrcmpW((*map)[i]->dev_id, device_id)){
+ (*map)[0] = (*map)[i];
+ (*map)[i] = prev;
+
+ LeaveCriticalSection(&g_devthread_lock);
+
+ return S_OK;
+ }
+
+ tmp = (*map)[i];
+ (*map)[i] = prev;
+ prev = tmp;
+ }
+
+ WARN("Couldn't find new default device! Rearranged map for no reason.\n");
+ (*map)[0] = prev;
+
+ LeaveCriticalSection(&g_devthread_lock);
+
+ return S_OK;
+}
+
+static HRESULT WINAPI notif_OnPropertyValueChanged(IMMNotificationClient *iface,
+ const WCHAR *device_id, const PROPERTYKEY key)
+{
+ TRACE("Ignoring OnPropertyValueChanged callback\n");
+ return S_OK;
+}
+
+static IMMNotificationClientVtbl g_notif_vtbl = {
+ notif_QueryInterface,
+ notif_AddRef,
+ notif_Release,
+ notif_OnDeviceStateChanged,
+ notif_OnDeviceAdded,
+ notif_OnDeviceRemoved,
+ notif_OnDefaultDeviceChanged,
+ notif_OnPropertyValueChanged
+};
+
+static IMMNotificationClient g_notif = { &g_notif_vtbl };
+
static HRESULT WINMM_InitMMDevices(void)
{
HRESULT hr, init_hr;
@@ -644,6 +759,10 @@ static HRESULT WINMM_InitMMDevices(void)
if(FAILED(hr))
goto exit;
+ hr = IMMDeviceEnumerator_RegisterEndpointNotificationCallback(devenum, &g_notif);
+ if(FAILED(hr))
+ WARN("RegisterEndpointNotificationCallback failed: %08x\n", hr);
+
hr = WINMM_EnumDevices(&g_out_mmdevices, &g_out_map, &g_outmmdevices_count,
eRender, devenum);
if(FAILED(hr)){
@@ -1087,7 +1206,7 @@ static LRESULT WOD_Open(WINMM_OpenInfo *info)
if(info->req_device >= g_outmmdevices_count)
return MMSYSERR_BADDEVICEID;
- mmdevice = g_out_map[info->req_device];
+ mmdevice = read_map(g_out_map, info->req_device);
if(!mmdevice->out_caps.szPname[0])
return MMSYSERR_NOTENABLED;
@@ -1160,7 +1279,7 @@ static LRESULT WID_Open(WINMM_OpenInfo *info)
if(info->req_device >= g_inmmdevices_count)
return MMSYSERR_BADDEVICEID;
- mmdevice = g_in_map[info->req_device];
+ mmdevice = read_map(g_in_map, info->req_device);
if(!mmdevice->in_caps.szPname[0])
return MMSYSERR_NOTENABLED;
@@ -1900,10 +2019,10 @@ static WINMM_MMDevice *WINMM_GetMixerMMDevice(HMIXEROBJ hmix, DWORD flags,
case MIXER_OBJECTF_MIXER: /* == 0 */
*out = HandleToULong(hmix);
if(*out < g_outmmdevices_count)
- return g_out_map[*out];
+ return read_map(g_out_map, *out);
if(*out - g_outmmdevices_count < g_inmmdevices_count){
*out -= g_outmmdevices_count;
- return g_in_map[*out];
+ return read_map(g_in_map, *out);
}
/* fall through -- if it's not a valid mixer device, then
* it could be a valid mixer handle. windows seems to do
@@ -1916,17 +2035,17 @@ static WINMM_MMDevice *WINMM_GetMixerMMDevice(HMIXEROBJ hmix, DWORD flags,
(!is_out && *out >= g_inmmdevices_count))
return NULL;
if(is_out)
- return g_out_map[*out];
- return g_in_map[*out];
+ return read_map(g_out_map, *out);
+ return read_map(g_in_map, *out);
case MIXER_OBJECTF_WAVEOUT:
*out = HandleToULong(hmix);
if(*out < g_outmmdevices_count)
- return g_out_map[*out];
+ return read_map(g_out_map, *out);
return NULL;
case MIXER_OBJECTF_WAVEIN:
*out = HandleToULong(hmix);
if(*out < g_inmmdevices_count)
- return g_in_map[*out];
+ return read_map(g_in_map, *out);
return NULL;
}
@@ -2440,7 +2559,7 @@ UINT WINAPI waveOutGetDevCapsW(UINT_PTR uDeviceID, LPWAVEOUTCAPSW lpCaps,
if(uDeviceID >= g_outmmdevices_count)
return MMSYSERR_BADDEVICEID;
- caps = &g_out_map[uDeviceID]->out_caps;
+ caps = &read_map(g_out_map, uDeviceID)->out_caps;
}
memcpy(lpCaps, caps, min(uSize, sizeof(*lpCaps)));
@@ -2939,7 +3058,9 @@ static UINT WINMM_QueryInstanceIDSize(UINT device, DWORD_PTR *len, BOOL is_out)
if(device >= count)
return MMSYSERR_INVALHANDLE;
+ EnterCriticalSection(&g_devthread_lock);
*len = (lstrlenW(devices[device]->dev_id) + 1) * sizeof(WCHAR);
+ LeaveCriticalSection(&g_devthread_lock);
return MMSYSERR_NOERROR;
}
@@ -2963,11 +3084,15 @@ static UINT WINMM_QueryInstanceID(UINT device, WCHAR *str, DWORD_PTR len,
if(device >= count)
return MMSYSERR_INVALHANDLE;
+ EnterCriticalSection(&g_devthread_lock);
id_len = (lstrlenW(devices[device]->dev_id) + 1) * sizeof(WCHAR);
- if(len < id_len)
+ if(len < id_len){
+ LeaveCriticalSection(&g_devthread_lock);
return MMSYSERR_ERROR;
+ }
memcpy(str, devices[device]->dev_id, id_len);
+ LeaveCriticalSection(&g_devthread_lock);
return MMSYSERR_NOERROR;
}
@@ -3082,7 +3207,7 @@ UINT WINAPI waveInGetDevCapsW(UINT_PTR uDeviceID, LPWAVEINCAPSW lpCaps, UINT uSi
if(uDeviceID >= g_inmmdevices_count)
return MMSYSERR_BADDEVICEID;
- caps = &g_in_map[uDeviceID]->in_caps;
+ caps = &read_map(g_in_map, uDeviceID)->in_caps;
}
memcpy(lpCaps, caps, min(uSize, sizeof(*lpCaps)));
@@ -3495,10 +3620,10 @@ UINT WINAPI mixerGetDevCapsW(UINT_PTR uDeviceID, LPMIXERCAPSW lpCaps, UINT uSize
return MMSYSERR_BADDEVICEID;
if(uDeviceID < g_outmmdevices_count){
- mmdevice = g_out_map[uDeviceID];
+ mmdevice = read_map(g_out_map, uDeviceID);
memcpy(caps.szPname, mmdevice->out_caps.szPname, sizeof(caps.szPname));
}else{
- mmdevice = g_in_map[uDeviceID - g_outmmdevices_count];
+ mmdevice = read_map(g_in_map, uDeviceID - g_outmmdevices_count);
memcpy(caps.szPname, mmdevice->in_caps.szPname, sizeof(caps.szPname));
}
@@ -3541,11 +3666,11 @@ UINT WINAPI mixerOpen(LPHMIXER lphMix, UINT uDeviceID, DWORD_PTR dwCallback,
return MMSYSERR_BADDEVICEID;
if(uDeviceID < g_outmmdevices_count){
- mmdevice = g_out_map[uDeviceID];
+ mmdevice = read_map(g_out_map, uDeviceID);
*lphMix = (HMIXER)WINMM_MakeHWAVE(uDeviceID, TRUE,
mmdevice->mixer_count);
}else{
- mmdevice = g_in_map[uDeviceID - g_outmmdevices_count];
+ mmdevice = read_map(g_in_map, uDeviceID - g_outmmdevices_count);
*lphMix = (HMIXER)WINMM_MakeHWAVE(uDeviceID - g_outmmdevices_count,
FALSE, mmdevice->mixer_count);
}
More information about the wine-cvs
mailing list