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