VirtualBox

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

Last change on this file since 88232 was 88232, checked in by vboxsync, 4 years ago

Audio: Renamed DrvAudio.h to DrvAudioCommon.h and move the DrvAudio.h structures into DrvAudio.cpp. [fix] bugref:9890

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 6.8 KB
Line 
1/* $Id: VBoxMMNotificationClient.cpp 88232 2021-03-22 09:59:28Z 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#include <mmdeviceapi.h>
23#include <iprt/win/endpointvolume.h>
24#include <iprt/errcore.h>
25
26#ifdef LOG_GROUP /** @todo r=bird: wtf? Put it before all other includes like you're supposed to. */
27# undef LOG_GROUP
28#endif
29#define LOG_GROUP LOG_GROUP_DRV_HOST_AUDIO
30#include <VBox/log.h>
31
32VBoxMMNotificationClient::VBoxMMNotificationClient(void)
33 : m_fRegisteredClient(false)
34 , m_cRef(1)
35{
36}
37
38VBoxMMNotificationClient::~VBoxMMNotificationClient(void)
39{
40}
41
42/**
43 * Registers the mulitmedia notification client implementation.
44 */
45HRESULT VBoxMMNotificationClient::Register(void)
46{
47 HRESULT hr = m_pEnum->RegisterEndpointNotificationCallback(this);
48 if (SUCCEEDED(hr))
49 {
50 m_fRegisteredClient = true;
51
52 hr = AttachToDefaultEndpoint();
53 }
54
55 return hr;
56}
57
58/**
59 * Unregisters the mulitmedia notification client implementation.
60 */
61void VBoxMMNotificationClient::Unregister(void)
62{
63 DetachFromEndpoint();
64
65 if (m_fRegisteredClient)
66 {
67 m_pEnum->UnregisterEndpointNotificationCallback(this);
68
69 m_fRegisteredClient = false;
70 }
71}
72
73/**
74 * Initializes the mulitmedia notification client implementation.
75 *
76 * @return HRESULT
77 */
78HRESULT VBoxMMNotificationClient::Initialize(void)
79{
80 HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), 0, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator),
81 (void **)&m_pEnum);
82
83 LogFunc(("Returning %Rhrc\n", hr));
84 return hr;
85}
86
87/**
88 * Registration callback implementation for storing our (required) contexts.
89 *
90 * @return IPRT status code.
91 * @param pDrvIns Driver instance to register the notification client to.
92 * @param pfnCallback Audio callback to call by the notification client in case of new events.
93 */
94int VBoxMMNotificationClient::RegisterCallback(PPDMDRVINS pDrvIns, PFNPDMHOSTAUDIOCALLBACK pfnCallback)
95{
96 this->m_pDrvIns = pDrvIns;
97 this->m_pfnCallback = pfnCallback;
98
99 return VINF_SUCCESS;
100}
101
102/**
103 * Unregistration callback implementation for cleaning up our mess when we're done handling
104 * with notifications.
105 */
106void VBoxMMNotificationClient::UnregisterCallback(void)
107{
108 this->m_pDrvIns = NULL;
109 this->m_pfnCallback = NULL;
110}
111
112/**
113 * Stub being called when attaching to the default audio endpoint.
114 * Does nothing at the moment.
115 */
116HRESULT VBoxMMNotificationClient::AttachToDefaultEndpoint(void)
117{
118 return S_OK;
119}
120
121/**
122 * Stub being called when detaching from the default audio endpoint.
123 * Does nothing at the moment.
124 */
125void VBoxMMNotificationClient::DetachFromEndpoint(void)
126{
127
128}
129
130/**
131 * Helper function for invoking the audio connector callback (if any).
132 */
133void VBoxMMNotificationClient::doCallback(void)
134{
135#ifdef VBOX_WITH_AUDIO_CALLBACKS
136 AssertPtr(this->m_pDrvIns);
137 AssertPtr(this->m_pfnCallback);
138
139 if (this->m_pfnCallback)
140 /* Ignore rc */ this->m_pfnCallback(this->m_pDrvIns, PDMAUDIOBACKENDCBTYPE_DEVICES_CHANGED, NULL, 0);
141#endif
142}
143
144/**
145 * Handler implementation which is called when an audio device state
146 * has been changed.
147 *
148 * @return HRESULT
149 * @param pwstrDeviceId Device ID the state is announced for.
150 * @param dwNewState New state the device is now in.
151 */
152STDMETHODIMP VBoxMMNotificationClient::OnDeviceStateChanged(LPCWSTR pwstrDeviceId, DWORD dwNewState)
153{
154 char *pszState = "unknown";
155
156 switch (dwNewState)
157 {
158 case DEVICE_STATE_ACTIVE:
159 pszState = "active";
160 break;
161 case DEVICE_STATE_DISABLED:
162 pszState = "disabled";
163 break;
164 case DEVICE_STATE_NOTPRESENT:
165 pszState = "not present";
166 break;
167 case DEVICE_STATE_UNPLUGGED:
168 pszState = "unplugged";
169 break;
170 default:
171 break;
172 }
173
174 LogRel(("Audio: Device '%ls' has changed state to '%s'\n", pwstrDeviceId, pszState));
175
176 doCallback();
177
178 return S_OK;
179}
180
181/**
182 * Handler implementation which is called when a new audio device has been added.
183 *
184 * @return HRESULT
185 * @param pwstrDeviceId Device ID which has been added.
186 */
187STDMETHODIMP VBoxMMNotificationClient::OnDeviceAdded(LPCWSTR pwstrDeviceId)
188{
189 LogRel(("Audio: Device '%ls' has been added\n", pwstrDeviceId));
190
191 return S_OK;
192}
193
194/**
195 * Handler implementation which is called when an audio device has been removed.
196 *
197 * @return HRESULT
198 * @param pwstrDeviceId Device ID which has been removed.
199 */
200STDMETHODIMP VBoxMMNotificationClient::OnDeviceRemoved(LPCWSTR pwstrDeviceId)
201{
202 LogRel(("Audio: Device '%ls' has been removed\n", pwstrDeviceId));
203
204 return S_OK;
205}
206
207/**
208 * Handler implementation which is called when the device audio device has been
209 * changed.
210 *
211 * @return HRESULT
212 * @param eFlow Flow direction of the new default device.
213 * @param eRole Role of the new default device.
214 * @param pwstrDefaultDeviceId ID of the new default device.
215 */
216STDMETHODIMP VBoxMMNotificationClient::OnDefaultDeviceChanged(EDataFlow eFlow, ERole eRole, LPCWSTR pwstrDefaultDeviceId)
217{
218 RT_NOREF(eRole);
219
220 char *pszRole = "unknown";
221
222 if (eFlow == eRender)
223 pszRole = "output";
224 else if (eFlow == eCapture)
225 pszRole = "input";
226
227 LogRel(("Audio: Default %s device has been changed to '%ls'\n", pszRole, pwstrDefaultDeviceId));
228
229 doCallback();
230
231 return S_OK;
232}
233
234STDMETHODIMP VBoxMMNotificationClient::QueryInterface(REFIID interfaceID, void **ppvInterface)
235{
236 const IID MY_IID_IMMNotificationClient = __uuidof(IMMNotificationClient);
237
238 if ( IsEqualIID(interfaceID, IID_IUnknown)
239 || IsEqualIID(interfaceID, MY_IID_IMMNotificationClient))
240 {
241 *ppvInterface = static_cast<IMMNotificationClient*>(this);
242 AddRef();
243 return S_OK;
244 }
245
246 *ppvInterface = NULL;
247 return E_NOINTERFACE;
248}
249
250STDMETHODIMP_(ULONG) VBoxMMNotificationClient::AddRef(void)
251{
252 return InterlockedIncrement(&m_cRef);
253}
254
255STDMETHODIMP_(ULONG) VBoxMMNotificationClient::Release(void)
256{
257 long lRef = InterlockedDecrement(&m_cRef);
258 if (lRef == 0)
259 delete this;
260
261 return lRef;
262}
263
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