VirtualBox

source: vbox/trunk/src/VBox/Devices/Audio/DrvHostAudioDSoundMMNotifClient.cpp@ 107876

Last change on this file since 107876 was 107535, checked in by vboxsync, 6 weeks ago

src/VBox/Devices/Audio/DrvHostAudioDSoundMMNotifClient.cpp: Fixed warnings found by Parfait (uninitialized attributes). jiraref:VBP-1424

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 7.2 KB
Line 
1/* $Id: DrvHostAudioDSoundMMNotifClient.cpp 107535 2025-01-08 16:15:40Z vboxsync $ */
2/** @file
3 * Host audio driver - DSound - Implementation of the IMMNotificationClient interface to detect audio endpoint changes.
4 */
5
6/*
7 * Copyright (C) 2017-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28#include "DrvHostAudioDSoundMMNotifClient.h"
29
30#include <iprt/win/windows.h>
31#include <mmdeviceapi.h>
32#include <iprt/win/endpointvolume.h>
33#include <iprt/errcore.h>
34
35#ifdef LOG_GROUP /** @todo r=bird: wtf? Put it before all other includes like you're supposed to. */
36# undef LOG_GROUP
37#endif
38#define LOG_GROUP LOG_GROUP_DRV_HOST_AUDIO
39#include <VBox/log.h>
40
41
42DrvHostAudioDSoundMMNotifClient::DrvHostAudioDSoundMMNotifClient(PPDMIHOSTAUDIOPORT pInterface, bool fDefaultIn, bool fDefaultOut)
43 : m_fDefaultIn(fDefaultIn)
44 , m_fDefaultOut(fDefaultOut)
45 , m_fRegisteredClient(false)
46 , m_pEnum(NULL)
47 , m_pEndpoint(NULL)
48 , m_cRef(1)
49 , m_pIAudioNotifyFromHost(pInterface)
50{
51}
52
53DrvHostAudioDSoundMMNotifClient::~DrvHostAudioDSoundMMNotifClient(void)
54{
55}
56
57/**
58 * Registers the mulitmedia notification client implementation.
59 */
60HRESULT DrvHostAudioDSoundMMNotifClient::Register(void)
61{
62 HRESULT hr = m_pEnum->RegisterEndpointNotificationCallback(this);
63 if (SUCCEEDED(hr))
64 m_fRegisteredClient = true;
65
66 return hr;
67}
68
69/**
70 * Unregisters the mulitmedia notification client implementation.
71 */
72void DrvHostAudioDSoundMMNotifClient::Unregister(void)
73{
74 if (m_fRegisteredClient)
75 {
76 m_pEnum->UnregisterEndpointNotificationCallback(this);
77
78 m_fRegisteredClient = false;
79 }
80}
81
82/**
83 * Initializes the mulitmedia notification client implementation.
84 *
85 * @return HRESULT
86 */
87HRESULT DrvHostAudioDSoundMMNotifClient::Initialize(void)
88{
89 HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), 0, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator),
90 (void **)&m_pEnum);
91
92 LogFunc(("Returning %Rhrc\n", hr));
93 return hr;
94}
95
96/**
97 * Handler implementation which is called when an audio device state
98 * has been changed.
99 *
100 * @return HRESULT
101 * @param pwstrDeviceId Device ID the state is announced for.
102 * @param dwNewState New state the device is now in.
103 */
104STDMETHODIMP DrvHostAudioDSoundMMNotifClient::OnDeviceStateChanged(LPCWSTR pwstrDeviceId, DWORD dwNewState)
105{
106 const char *pszState = "unknown";
107
108 switch (dwNewState)
109 {
110 case DEVICE_STATE_ACTIVE:
111 pszState = "active";
112 break;
113 case DEVICE_STATE_DISABLED:
114 pszState = "disabled";
115 break;
116 case DEVICE_STATE_NOTPRESENT:
117 pszState = "not present";
118 break;
119 case DEVICE_STATE_UNPLUGGED:
120 pszState = "unplugged";
121 break;
122 default:
123 break;
124 }
125
126 LogRel(("Audio: Device '%ls' has changed state to '%s'\n", pwstrDeviceId, pszState));
127
128 if (m_pIAudioNotifyFromHost)
129 m_pIAudioNotifyFromHost->pfnNotifyDevicesChanged(m_pIAudioNotifyFromHost);
130
131 return S_OK;
132}
133
134/**
135 * Handler implementation which is called when a new audio device has been added.
136 *
137 * @return HRESULT
138 * @param pwstrDeviceId Device ID which has been added.
139 */
140STDMETHODIMP DrvHostAudioDSoundMMNotifClient::OnDeviceAdded(LPCWSTR pwstrDeviceId)
141{
142 LogRel(("Audio: Device '%ls' has been added\n", pwstrDeviceId));
143 /* Note! It is hard to properly support non-default devices when the backend is DSound,
144 as DSound talks GUID where-as the pwszDeviceId string we get here is something
145 completely different. So, ignorining that edge case here. The WasApi backend
146 supports this, though. */
147 if (m_pIAudioNotifyFromHost)
148 m_pIAudioNotifyFromHost->pfnNotifyDevicesChanged(m_pIAudioNotifyFromHost);
149 return S_OK;
150}
151
152/**
153 * Handler implementation which is called when an audio device has been removed.
154 *
155 * @return HRESULT
156 * @param pwstrDeviceId Device ID which has been removed.
157 */
158STDMETHODIMP DrvHostAudioDSoundMMNotifClient::OnDeviceRemoved(LPCWSTR pwstrDeviceId)
159{
160 LogRel(("Audio: Device '%ls' has been removed\n", pwstrDeviceId));
161 if (m_pIAudioNotifyFromHost)
162 m_pIAudioNotifyFromHost->pfnNotifyDevicesChanged(m_pIAudioNotifyFromHost);
163 return S_OK;
164}
165
166/**
167 * Handler implementation which is called when the device audio device has been
168 * changed.
169 *
170 * @return HRESULT
171 * @param eFlow Flow direction of the new default device.
172 * @param eRole Role of the new default device.
173 * @param pwstrDefaultDeviceId ID of the new default device.
174 */
175STDMETHODIMP DrvHostAudioDSoundMMNotifClient::OnDefaultDeviceChanged(EDataFlow eFlow, ERole eRole, LPCWSTR pwstrDefaultDeviceId)
176{
177 /* When the user triggers a default device change, we'll typically get two or
178 three notifications. Just pick up the one for the multimedia role for now
179 (dunno if DSound default equals eMultimedia or eConsole, and whether it make
180 any actual difference). */
181 if (eRole == eMultimedia)
182 {
183 PDMAUDIODIR enmDir = PDMAUDIODIR_INVALID;
184 const char *pszRole = "unknown";
185 if (eFlow == eRender)
186 {
187 pszRole = "output";
188 if (m_fDefaultOut)
189 enmDir = PDMAUDIODIR_OUT;
190 }
191 else if (eFlow == eCapture)
192 {
193 pszRole = "input";
194 if (m_fDefaultIn)
195 enmDir = PDMAUDIODIR_IN;
196 }
197
198 LogRel(("Audio: Default %s device has been changed to '%ls'\n", pszRole, pwstrDefaultDeviceId));
199
200 if (m_pIAudioNotifyFromHost)
201 {
202 if (enmDir != PDMAUDIODIR_INVALID)
203 m_pIAudioNotifyFromHost->pfnNotifyDeviceChanged(m_pIAudioNotifyFromHost, enmDir, NULL);
204 m_pIAudioNotifyFromHost->pfnNotifyDevicesChanged(m_pIAudioNotifyFromHost);
205 }
206 }
207 return S_OK;
208}
209
210STDMETHODIMP DrvHostAudioDSoundMMNotifClient::QueryInterface(REFIID interfaceID, void **ppvInterface)
211{
212 const IID MY_IID_IMMNotificationClient = __uuidof(IMMNotificationClient);
213
214 if ( IsEqualIID(interfaceID, IID_IUnknown)
215 || IsEqualIID(interfaceID, MY_IID_IMMNotificationClient))
216 {
217 *ppvInterface = static_cast<IMMNotificationClient*>(this);
218 AddRef();
219 return S_OK;
220 }
221
222 *ppvInterface = NULL;
223 return E_NOINTERFACE;
224}
225
226STDMETHODIMP_(ULONG) DrvHostAudioDSoundMMNotifClient::AddRef(void)
227{
228 return InterlockedIncrement(&m_cRef);
229}
230
231STDMETHODIMP_(ULONG) DrvHostAudioDSoundMMNotifClient::Release(void)
232{
233 long lRef = InterlockedDecrement(&m_cRef);
234 if (lRef == 0)
235 delete this;
236
237 return lRef;
238}
239
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