kodi
IMMNotificationClient.h
1 /*
2  * Copyright (C) 2014-2018 Team Kodi
3  * This file is part of Kodi - https://kodi.tv
4  *
5  * SPDX-License-Identifier: GPL-2.0-or-later
6  * See LICENSES/README.md for more information.
7  */
8 
9 #pragma once
10 
11 #include "ServiceBroker.h"
12 #include "cores/AudioEngine/Engines/ActiveAE/ActiveAE.h"
13 #include "utils/log.h"
14 
15 #include "platform/win32/CharsetConverter.h"
16 #include "platform/win32/powermanagement/Win32PowerSyscall.h"
17 
18 #include <mmdeviceapi.h>
19 #include <wrl/client.h>
20 
21 using KODI::PLATFORM::WINDOWS::FromW;
22 
23 class CMMNotificationClient : public IMMNotificationClient
24 {
25  LONG _cRef;
26  Microsoft::WRL::ComPtr<IMMDeviceEnumerator> _pEnumerator;
27 
28 
29 public:
30  CMMNotificationClient() : _cRef(1), _pEnumerator(nullptr)
31  {
32  }
33 
34  ~CMMNotificationClient() = default;
35 
36  // IUnknown methods -- AddRef, Release, and QueryInterface
37 
38  ULONG STDMETHODCALLTYPE AddRef()
39  {
40  return InterlockedIncrement(&_cRef);
41  }
42 
43  ULONG STDMETHODCALLTYPE Release()
44  {
45  ULONG ulRef = InterlockedDecrement(&_cRef);
46  if (0 == ulRef)
47  {
48  delete this;
49  }
50  return ulRef;
51  }
52 
53  HRESULT STDMETHODCALLTYPE QueryInterface(const IID & riid, void **ppvInterface)
54  {
55  if (IID_IUnknown == riid)
56  {
57  AddRef();
58  *ppvInterface = (IUnknown*)this;
59  }
60  else if (__uuidof(IMMNotificationClient) == riid)
61  {
62  AddRef();
63  *ppvInterface = (IMMNotificationClient*)this;
64  }
65  else
66  {
67  *ppvInterface = nullptr;
68  return E_NOINTERFACE;
69  }
70  return S_OK;
71  }
72 
73  // Callback methods for device-event notifications.
74 
75  HRESULT STDMETHODCALLTYPE OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR pwstrDeviceId)
76  {
77  // if the default device changes this function is called four times.
78  // therefore we call CServiceBroker::GetActiveAE()->DeviceChange() only for one role.
79  std::string pszFlow = "?????";
80  std::string pszRole = "?????";
81 
82  switch (flow)
83  {
84  case eRender:
85  pszFlow = "eRender";
86  break;
87  case eCapture:
88  pszFlow = "eCapture";
89  break;
90  }
91 
92  switch (role)
93  {
94  case eConsole:
95  pszRole = "eConsole";
96  break;
97  case eMultimedia:
98  pszRole = "eMultimedia";
99  break;
100  case eCommunications:
101  pszRole = "eCommunications";
102  NotifyAE();
103  break;
104  }
105 
106  CLog::Log(LOGDEBUG, "{}: New default device: flow = {}, role = {}", __FUNCTION__, pszFlow,
107  pszRole);
108  return S_OK;
109  }
110 
111  HRESULT STDMETHODCALLTYPE OnDeviceAdded(LPCWSTR pwstrDeviceId)
112  {
113  CLog::Log(LOGDEBUG, "{}: Added device: {}", __FUNCTION__, FromW(pwstrDeviceId));
114  NotifyAE();
115  return S_OK;
116  }
117 
118  HRESULT STDMETHODCALLTYPE OnDeviceRemoved(LPCWSTR pwstrDeviceId)
119  {
120  CLog::Log(LOGDEBUG, "{}: Removed device: {}", __FUNCTION__, FromW(pwstrDeviceId));
121  NotifyAE();
122  return S_OK;
123  }
124 
125  HRESULT STDMETHODCALLTYPE OnDeviceStateChanged(LPCWSTR pwstrDeviceId, DWORD dwNewState)
126  {
127  std::string pszState = "?????";
128 
129  switch (dwNewState)
130  {
131  case DEVICE_STATE_ACTIVE:
132  pszState = "ACTIVE";
133  break;
134  case DEVICE_STATE_DISABLED:
135  pszState = "DISABLED";
136  break;
137  case DEVICE_STATE_NOTPRESENT:
138  pszState = "NOTPRESENT";
139  break;
140  case DEVICE_STATE_UNPLUGGED:
141  pszState = "UNPLUGGED";
142  break;
143  }
144  CLog::Log(LOGDEBUG, "{}: New device state is DEVICE_STATE_{}", __FUNCTION__, pszState);
145  NotifyAE();
146  return S_OK;
147  }
148 
149  HRESULT STDMETHODCALLTYPE OnPropertyValueChanged(LPCWSTR pwstrDeviceId, const PROPERTYKEY key)
150  {
151  CLog::Log(LOGDEBUG,
152  "{}: Changed device property of {} is "
153  "({:08x}-{:04x}-{:04x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x})#{}",
154  __FUNCTION__, FromW(pwstrDeviceId), key.fmtid.Data1, key.fmtid.Data2, key.fmtid.Data3,
155  key.fmtid.Data4[0], key.fmtid.Data4[1], key.fmtid.Data4[2], key.fmtid.Data4[3],
156  key.fmtid.Data4[4], key.fmtid.Data4[5], key.fmtid.Data4[6], key.fmtid.Data4[7],
157  key.pid);
158  return S_OK;
159  }
160 
161  void STDMETHODCALLTYPE NotifyAE()
162  {
163  if(!CWin32PowerSyscall::IsSuspending())
164  CServiceBroker::GetActiveAE()->DeviceChange();
165  }
166 };
Definition: IMMNotificationClient.h:23
virtual void DeviceChange()
Instruct AE to re-initialize, e.g. after ELD change event.
Definition: AE.h:254