VirtualBox

source: vbox/trunk/src/VBox/Devices/Audio/VBoxMMNotificationClient.cpp@ 84343

Last change on this file since 84343 was 83812, checked in by vboxsync, 5 years ago

Devices/Audio: VC++ 14.1 warnings. bugref:8498

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 7.0 KB
Line 
1/* $Id: VBoxMMNotificationClient.cpp 83812 2020-04-19 00:21:56Z vboxsync $ */
2/** @file
3 * VBoxMMNotificationClient.cpp - Implementation of the IMMNotificationClient interface
4 * to detect audio endpoint changes.
5 */
6
7/*
8 * Copyright (C) 2017-2020 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19#include "VBoxMMNotificationClient.h"
20
21#include <iprt/win/windows.h>
22
23#pragma warning(push)
24#pragma warning(disable: 4201)
25#ifndef DOXYGEN_RUNNING
26# if RT_MSC_PREREQ(RT_MSC_VER_VC141)
27# pragma warning(disable: 4091) /* v7.1\include\ksmedia.h(4356): warning C4091: 'typedef ': ignored on left of '<unnamed-enum-KSEVENT_DYNAMIC_FORMAT_CHANGE>' when no variable is declared */
28# endif
29#endif
30#include <mmdeviceapi.h>
31#include <endpointvolume.h>
32#pragma warning(pop)
33
34#ifdef LOG_GROUP
35# undef LOG_GROUP
36#endif
37#define LOG_GROUP LOG_GROUP_DRV_HOST_AUDIO
38#include <VBox/log.h>
39
40VBoxMMNotificationClient::VBoxMMNotificationClient(void)
41 : m_fRegisteredClient(false)
42 , m_cRef(1)
43{
44}
45
46VBoxMMNotificationClient::~VBoxMMNotificationClient(void)
47{
48}
49
50/**
51 * Registers the mulitmedia notification client implementation.
52 */
53HRESULT VBoxMMNotificationClient::Register(void)
54{
55 HRESULT hr = m_pEnum->RegisterEndpointNotificationCallback(this);
56 if (SUCCEEDED(hr))
57 {
58 m_fRegisteredClient = true;
59
60 hr = AttachToDefaultEndpoint();
61 }
62
63 return hr;
64}
65
66/**
67 * Unregisters the mulitmedia notification client implementation.
68 */
69void VBoxMMNotificationClient::Unregister(void)
70{
71 DetachFromEndpoint();
72
73 if (m_fRegisteredClient)
74 {
75 m_pEnum->UnregisterEndpointNotificationCallback(this);
76
77 m_fRegisteredClient = false;
78 }
79}
80
81/**
82 * Initializes the mulitmedia notification client implementation.
83 *
84 * @return HRESULT
85 */
86HRESULT VBoxMMNotificationClient::Initialize(void)
87{
88 HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), 0, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator),
89 (void **)&m_pEnum);
90
91 LogFunc(("Returning %Rhrc\n", hr));
92 return hr;
93}
94
95/**
96 * Registration callback implementation for storing our (required) contexts.
97 *
98 * @return IPRT status code.
99 * @param pDrvIns Driver instance to register the notification client to.
100 * @param pfnCallback Audio callback to call by the notification client in case of new events.
101 */
102int VBoxMMNotificationClient::RegisterCallback(PPDMDRVINS pDrvIns, PFNPDMHOSTAUDIOCALLBACK pfnCallback)
103{
104 this->m_pDrvIns = pDrvIns;
105 this->m_pfnCallback = pfnCallback;
106
107 return VINF_SUCCESS;
108}
109
110/**
111 * Unregistration callback implementation for cleaning up our mess when we're done handling
112 * with notifications.
113 */
114void VBoxMMNotificationClient::UnregisterCallback(void)
115{
116 this->m_pDrvIns = NULL;
117 this->m_pfnCallback = NULL;
118}
119
120/**
121 * Stub being called when attaching to the default audio endpoint.
122 * Does nothing at the moment.
123 */
124HRESULT VBoxMMNotificationClient::AttachToDefaultEndpoint(void)
125{
126 return S_OK;
127}
128
129/**
130 * Stub being called when detaching from the default audio endpoint.
131 * Does nothing at the moment.
132 */
133void VBoxMMNotificationClient::DetachFromEndpoint(void)
134{
135
136}
137
138/**
139 * Helper function for invoking the audio connector callback (if any).
140 */
141void VBoxMMNotificationClient::doCallback(void)
142{
143#ifdef VBOX_WITH_AUDIO_CALLBACKS
144 AssertPtr(this->m_pDrvIns);
145 AssertPtr(this->m_pfnCallback);
146
147 if (this->m_pfnCallback)
148 /* Ignore rc */ this->m_pfnCallback(this->m_pDrvIns, PDMAUDIOBACKENDCBTYPE_DEVICES_CHANGED, NULL, 0);
149#endif
150}
151
152/**
153 * Handler implementation which is called when an audio device state
154 * has been changed.
155 *
156 * @return HRESULT
157 * @param pwstrDeviceId Device ID the state is announced for.
158 * @param dwNewState New state the device is now in.
159 */
160STDMETHODIMP VBoxMMNotificationClient::OnDeviceStateChanged(LPCWSTR pwstrDeviceId, DWORD dwNewState)
161{
162 char *pszState = "unknown";
163
164 switch (dwNewState)
165 {
166 case DEVICE_STATE_ACTIVE:
167 pszState = "active";
168 break;
169 case DEVICE_STATE_DISABLED:
170 pszState = "disabled";
171 break;
172 case DEVICE_STATE_NOTPRESENT:
173 pszState = "not present";
174 break;
175 case DEVICE_STATE_UNPLUGGED:
176 pszState = "unplugged";
177 break;
178 default:
179 break;
180 }
181
182 LogRel(("Audio: Device '%ls' has changed state to '%s'\n", pwstrDeviceId, pszState));
183
184 doCallback();
185
186 return S_OK;
187}
188
189/**
190 * Handler implementation which is called when a new audio device has been added.
191 *
192 * @return HRESULT
193 * @param pwstrDeviceId Device ID which has been added.
194 */
195STDMETHODIMP VBoxMMNotificationClient::OnDeviceAdded(LPCWSTR pwstrDeviceId)
196{
197 LogRel(("Audio: Device '%ls' has been added\n", pwstrDeviceId));
198
199 return S_OK;
200}
201
202/**
203 * Handler implementation which is called when an audio device has been removed.
204 *
205 * @return HRESULT
206 * @param pwstrDeviceId Device ID which has been removed.
207 */
208STDMETHODIMP VBoxMMNotificationClient::OnDeviceRemoved(LPCWSTR pwstrDeviceId)
209{
210 LogRel(("Audio: Device '%ls' has been removed\n", pwstrDeviceId));
211
212 return S_OK;
213}
214
215/**
216 * Handler implementation which is called when the device audio device has been
217 * changed.
218 *
219 * @return HRESULT
220 * @param eFlow Flow direction of the new default device.
221 * @param eRole Role of the new default device.
222 * @param pwstrDefaultDeviceId ID of the new default device.
223 */
224STDMETHODIMP VBoxMMNotificationClient::OnDefaultDeviceChanged(EDataFlow eFlow, ERole eRole, LPCWSTR pwstrDefaultDeviceId)
225{
226 RT_NOREF(eRole);
227
228 char *pszRole = "unknown";
229
230 if (eFlow == eRender)
231 pszRole = "output";
232 else if (eFlow == eCapture)
233 pszRole = "input";
234
235 LogRel(("Audio: Default %s device has been changed to '%ls'\n", pszRole, pwstrDefaultDeviceId));
236
237 doCallback();
238
239 return S_OK;
240}
241
242STDMETHODIMP VBoxMMNotificationClient::QueryInterface(REFIID interfaceID, void **ppvInterface)
243{
244 const IID MY_IID_IMMNotificationClient = __uuidof(IMMNotificationClient);
245
246 if ( IsEqualIID(interfaceID, IID_IUnknown)
247 || IsEqualIID(interfaceID, MY_IID_IMMNotificationClient))
248 {
249 *ppvInterface = static_cast<IMMNotificationClient*>(this);
250 AddRef();
251 return S_OK;
252 }
253
254 *ppvInterface = NULL;
255 return E_NOINTERFACE;
256}
257
258STDMETHODIMP_(ULONG) VBoxMMNotificationClient::AddRef(void)
259{
260 return InterlockedIncrement(&m_cRef);
261}
262
263STDMETHODIMP_(ULONG) VBoxMMNotificationClient::Release(void)
264{
265 long lRef = InterlockedDecrement(&m_cRef);
266 if (lRef == 0)
267 delete this;
268
269 return lRef;
270}
271
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette