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