mmdevapi: Send notifications to clients when the user-selected default device changes.
This commit is contained in:
parent
8d775ec09b
commit
d4e9b26cbb
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue