Andrew Eikum : mmdevapi: Send notifications to clients when the user-selected default device changes .

Alexandre Julliard julliard at winehq.org
Mon Dec 17 13:58:22 CST 2012


Module: wine
Branch: master
Commit: d4e9b26cbb757f0d12d4585acf5277e2dd2d2347
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=d4e9b26cbb757f0d12d4585acf5277e2dd2d2347

Author: Andrew Eikum <aeikum at codeweavers.com>
Date:   Fri Dec 14 11:41:56 2012 -0600

mmdevapi: Send notifications to clients when the user-selected default device changes.

---

 dlls/mmdevapi/devenum.c |  159 +++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 153 insertions(+), 6 deletions(-)

diff --git a/dlls/mmdevapi/devenum.c b/dlls/mmdevapi/devenum.c
index f9b9172..21a3530 100644
--- a/dlls/mmdevapi/devenum.c
+++ b/dlls/mmdevapi/devenum.c
@@ -59,6 +59,11 @@ static const WCHAR reg_devicestate[] =
     { 'D','e','v','i','c','e','S','t','a','t','e',0 };
 static const WCHAR reg_properties[] =
     { 'P','r','o','p','e','r','t','i','e','s',0 };
+static const WCHAR slashW[] = {'\\',0};
+static const WCHAR reg_out_nameW[] = {'D','e','f','a','u','l','t','O','u','t','p','u','t',0};
+static const WCHAR reg_vout_nameW[] = {'D','e','f','a','u','l','t','V','o','i','c','e','O','u','t','p','u','t',0};
+static const WCHAR reg_in_nameW[] = {'D','e','f','a','u','l','t','I','n','p','u','t',0};
+static const WCHAR reg_vin_nameW[] = {'D','e','f','a','u','l','t','V','o','i','c','e','I','n','p','u','t',0};
 
 static HKEY key_render;
 static HKEY key_capture;
@@ -916,12 +921,6 @@ static HRESULT WINAPI MMDevEnum_GetDefaultAudioEndpoint(IMMDeviceEnumerator *ifa
     HKEY key;
     HRESULT hr;
 
-    static const WCHAR slashW[] = {'\\',0};
-    static const WCHAR reg_out_nameW[] = {'D','e','f','a','u','l','t','O','u','t','p','u','t',0};
-    static const WCHAR reg_vout_nameW[] = {'D','e','f','a','u','l','t','V','o','i','c','e','O','u','t','p','u','t',0};
-    static const WCHAR reg_in_nameW[] = {'D','e','f','a','u','l','t','I','n','p','u','t',0};
-    static const WCHAR reg_vin_nameW[] = {'D','e','f','a','u','l','t','V','o','i','c','e','I','n','p','u','t',0};
-
     TRACE("(%p)->(%u,%u,%p)\n", This, flow, role, device);
 
     if (!device)
@@ -1042,6 +1041,7 @@ struct NotificationClientWrapper {
 };
 
 static struct list g_notif_clients = LIST_INIT(g_notif_clients);
+static HANDLE g_notif_thread;
 
 static CRITICAL_SECTION g_notif_lock;
 static CRITICAL_SECTION_DEBUG g_notif_lock_debug =
@@ -1052,6 +1052,147 @@ static CRITICAL_SECTION_DEBUG g_notif_lock_debug =
 };
 static CRITICAL_SECTION g_notif_lock = { &g_notif_lock_debug, -1, 0, 0, 0, 0 };
 
+static void notify_clients(EDataFlow flow, ERole role, const WCHAR *id)
+{
+    struct NotificationClientWrapper *wrapper;
+    LIST_FOR_EACH_ENTRY(wrapper, &g_notif_clients,
+            struct NotificationClientWrapper, entry)
+        IMMNotificationClient_OnDefaultDeviceChanged(wrapper->client, flow,
+                role, id);
+
+    /* Windows 7 treats changes to eConsole as changes to eMultimedia */
+    if(role == eConsole)
+        notify_clients(flow, eMultimedia, id);
+}
+
+static int notify_if_changed(EDataFlow flow, ERole role, HKEY key,
+        const WCHAR *val_name, WCHAR *old_val, IMMDevice *def_dev)
+{
+    WCHAR new_val[64], *id;
+    DWORD size;
+    HRESULT hr;
+
+    size = sizeof(new_val);
+    if(RegQueryValueExW(key, val_name, 0, NULL,
+                (BYTE*)new_val, &size) != ERROR_SUCCESS){
+        if(old_val[0] != 0){
+            /* set by user -> system default */
+            if(def_dev){
+                hr = IMMDevice_GetId(def_dev, &id);
+                if(FAILED(hr)){
+                    ERR("GetId failed: %08x\n", hr);
+                    return 0;
+                }
+            }else
+                id = NULL;
+
+            notify_clients(flow, role, id);
+            old_val[0] = 0;
+            CoTaskMemFree(id);
+
+            return 1;
+        }
+
+        /* system default -> system default, noop */
+        return 0;
+    }
+
+    if(!lstrcmpW(old_val, new_val)){
+        /* set by user -> same value */
+        return 0;
+    }
+
+    if(new_val[0] != 0){
+        /* set by user -> different value */
+        notify_clients(flow, role, new_val);
+        memcpy(old_val, new_val, sizeof(new_val));
+        return 1;
+    }
+
+    /* set by user -> system default */
+    if(def_dev){
+        hr = IMMDevice_GetId(def_dev, &id);
+        if(FAILED(hr)){
+            ERR("GetId failed: %08x\n", hr);
+            return 0;
+        }
+    }else
+        id = NULL;
+
+    notify_clients(flow, role, id);
+    old_val[0] = 0;
+    CoTaskMemFree(id);
+
+    return 1;
+}
+
+static DWORD WINAPI notif_thread_proc(void *user)
+{
+    HKEY key;
+    WCHAR reg_key[256];
+    WCHAR out_name[64], vout_name[64], in_name[64], vin_name[64];
+    DWORD size;
+
+    lstrcpyW(reg_key, drv_keyW);
+    lstrcatW(reg_key, slashW);
+    lstrcatW(reg_key, drvs.module_name);
+
+    if(RegCreateKeyExW(HKEY_CURRENT_USER, reg_key, 0, NULL, 0,
+                MAXIMUM_ALLOWED, NULL, &key, NULL) != ERROR_SUCCESS){
+        ERR("RegCreateKeyEx failed: %u\n", GetLastError());
+        return 1;
+    }
+
+    size = sizeof(out_name);
+    if(RegQueryValueExW(key, reg_out_nameW, 0, NULL,
+                (BYTE*)out_name, &size) != ERROR_SUCCESS)
+        out_name[0] = 0;
+
+    size = sizeof(vout_name);
+    if(RegQueryValueExW(key, reg_vout_nameW, 0, NULL,
+                (BYTE*)vout_name, &size) != ERROR_SUCCESS)
+        vout_name[0] = 0;
+
+    size = sizeof(in_name);
+    if(RegQueryValueExW(key, reg_in_nameW, 0, NULL,
+                (BYTE*)in_name, &size) != ERROR_SUCCESS)
+        in_name[0] = 0;
+
+    size = sizeof(vin_name);
+    if(RegQueryValueExW(key, reg_vin_nameW, 0, NULL,
+                (BYTE*)vin_name, &size) != ERROR_SUCCESS)
+        vin_name[0] = 0;
+
+    while(1){
+        if(RegNotifyChangeKeyValue(key, FALSE, REG_NOTIFY_CHANGE_LAST_SET,
+                    NULL, FALSE) != ERROR_SUCCESS){
+            ERR("RegNotifyChangeKeyValue failed: %u\n", GetLastError());
+            RegCloseKey(key);
+            g_notif_thread = NULL;
+            return 1;
+        }
+
+        EnterCriticalSection(&g_notif_lock);
+
+        notify_if_changed(eRender, eConsole, key, reg_out_nameW,
+                out_name, &MMDevice_def_play->IMMDevice_iface);
+        notify_if_changed(eRender, eCommunications, key, reg_vout_nameW,
+                vout_name, &MMDevice_def_play->IMMDevice_iface);
+        notify_if_changed(eCapture, eConsole, key, reg_in_nameW,
+                in_name, &MMDevice_def_rec->IMMDevice_iface);
+        notify_if_changed(eCapture, eCommunications, key, reg_vin_nameW,
+                vin_name, &MMDevice_def_rec->IMMDevice_iface);
+
+        LeaveCriticalSection(&g_notif_lock);
+    }
+
+    RegCloseKey(key);
+
+    g_notif_thread = NULL;
+
+    return 0;
+}
+
 static HRESULT WINAPI MMDevEnum_RegisterEndpointNotificationCallback(IMMDeviceEnumerator *iface, IMMNotificationClient *client)
 {
     MMDevEnumImpl *This = impl_from_IMMDeviceEnumerator(iface);
@@ -1072,6 +1213,12 @@ static HRESULT WINAPI MMDevEnum_RegisterEndpointNotificationCallback(IMMDeviceEn
 
     list_add_tail(&g_notif_clients, &wrapper->entry);
 
+    if(!g_notif_thread){
+        g_notif_thread = CreateThread(NULL, 0, notif_thread_proc, NULL, 0, NULL);
+        if(!g_notif_thread)
+            ERR("CreateThread failed: %u\n", GetLastError());
+    }
+
     LeaveCriticalSection(&g_notif_lock);
 
     return S_OK;




More information about the wine-cvs mailing list