VirtualBox

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

最後變更 在這個檔案從108416是 108350,由 vboxsync 提交於 3 週 前

Audio/DrvHostAudioDSoundMMNotifClient: Resolved a @todo (reordered includes).

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 7.9 KB
 
1/* $Id: DrvHostAudioDSoundMMNotifClient.cpp 108350 2025-02-24 13:22:00Z 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.alldomusa.eu.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
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#define LOG_GROUP LOG_GROUP_DRV_HOST_AUDIO
33#include <VBox/log.h>
34
35#include "DrvHostAudioDSoundMMNotifClient.h"
36
37#include <mmdeviceapi.h>
38
39#include <iprt/win/windows.h>
40#include <iprt/win/endpointvolume.h>
41#include <iprt/errcore.h>
42
43
44/*********************************************************************************************************************************
45* IMMNotificationClient interface implementation *
46*********************************************************************************************************************************/
47DrvHostAudioDSoundMMNotifClient::DrvHostAudioDSoundMMNotifClient(PPDMIHOSTAUDIOPORT pInterface, bool fDefaultIn, bool fDefaultOut)
48 : m_fDefaultIn(fDefaultIn)
49 , m_fDefaultOut(fDefaultOut)
50 , m_fRegisteredClient(false)
51 , m_pEnum(NULL)
52 , m_pEndpoint(NULL)
53 , m_cRef(1)
54 , m_pIAudioNotifyFromHost(pInterface)
55{
56}
57
58DrvHostAudioDSoundMMNotifClient::~DrvHostAudioDSoundMMNotifClient(void)
59{
60}
61
62/**
63 * Registers the mulitmedia notification client implementation.
64 */
65HRESULT DrvHostAudioDSoundMMNotifClient::Register(void)
66{
67 HRESULT hr = m_pEnum->RegisterEndpointNotificationCallback(this);
68 if (SUCCEEDED(hr))
69 m_fRegisteredClient = true;
70
71 return hr;
72}
73
74/**
75 * Unregisters the mulitmedia notification client implementation.
76 */
77void DrvHostAudioDSoundMMNotifClient::Unregister(void)
78{
79 if (m_fRegisteredClient)
80 {
81 m_pEnum->UnregisterEndpointNotificationCallback(this);
82
83 m_fRegisteredClient = false;
84 }
85}
86
87/**
88 * Initializes the mulitmedia notification client implementation.
89 *
90 * @return HRESULT
91 */
92HRESULT DrvHostAudioDSoundMMNotifClient::Initialize(void)
93{
94 HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), 0, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator),
95 (void **)&m_pEnum);
96
97 LogFunc(("Returning %Rhrc\n", hr));
98 return hr;
99}
100
101/**
102 * Handler implementation which is called when an audio device state
103 * has been changed.
104 *
105 * @return HRESULT
106 * @param pwstrDeviceId Device ID the state is announced for.
107 * @param dwNewState New state the device is now in.
108 */
109STDMETHODIMP DrvHostAudioDSoundMMNotifClient::OnDeviceStateChanged(LPCWSTR pwstrDeviceId, DWORD dwNewState)
110{
111 const char *pszState = "unknown";
112
113 switch (dwNewState)
114 {
115 case DEVICE_STATE_ACTIVE:
116 pszState = "active";
117 break;
118 case DEVICE_STATE_DISABLED:
119 pszState = "disabled";
120 break;
121 case DEVICE_STATE_NOTPRESENT:
122 pszState = "not present";
123 break;
124 case DEVICE_STATE_UNPLUGGED:
125 pszState = "unplugged";
126 break;
127 default:
128 break;
129 }
130
131 LogRel(("Audio: Device '%ls' has changed state to '%s'\n", pwstrDeviceId, pszState));
132
133 if (m_pIAudioNotifyFromHost)
134 m_pIAudioNotifyFromHost->pfnNotifyDevicesChanged(m_pIAudioNotifyFromHost);
135
136 return S_OK;
137}
138
139/**
140 * Handler implementation which is called when a new audio device has been added.
141 *
142 * @return HRESULT
143 * @param pwstrDeviceId Device ID which has been added.
144 */
145STDMETHODIMP DrvHostAudioDSoundMMNotifClient::OnDeviceAdded(LPCWSTR pwstrDeviceId)
146{
147 LogRel(("Audio: Device '%ls' has been added\n", pwstrDeviceId));
148 /* Note! It is hard to properly support non-default devices when the backend is DSound,
149 as DSound talks GUID where-as the pwszDeviceId string we get here is something
150 completely different. So, ignorining that edge case here. The WasApi backend
151 supports this, though. */
152 if (m_pIAudioNotifyFromHost)
153 m_pIAudioNotifyFromHost->pfnNotifyDevicesChanged(m_pIAudioNotifyFromHost);
154 return S_OK;
155}
156
157/**
158 * Handler implementation which is called when an audio device has been removed.
159 *
160 * @return HRESULT
161 * @param pwstrDeviceId Device ID which has been removed.
162 */
163STDMETHODIMP DrvHostAudioDSoundMMNotifClient::OnDeviceRemoved(LPCWSTR pwstrDeviceId)
164{
165 LogRel(("Audio: Device '%ls' has been removed\n", pwstrDeviceId));
166 if (m_pIAudioNotifyFromHost)
167 m_pIAudioNotifyFromHost->pfnNotifyDevicesChanged(m_pIAudioNotifyFromHost);
168 return S_OK;
169}
170
171/**
172 * Handler implementation which is called when the device audio device has been
173 * changed.
174 *
175 * @return HRESULT
176 * @param eFlow Flow direction of the new default device.
177 * @param eRole Role of the new default device.
178 * @param pwstrDefaultDeviceId ID of the new default device.
179 */
180STDMETHODIMP DrvHostAudioDSoundMMNotifClient::OnDefaultDeviceChanged(EDataFlow eFlow, ERole eRole, LPCWSTR pwstrDefaultDeviceId)
181{
182 /* When the user triggers a default device change, we'll typically get two or
183 three notifications. Just pick up the one for the multimedia role for now
184 (dunno if DSound default equals eMultimedia or eConsole, and whether it make
185 any actual difference). */
186 if (eRole == eMultimedia)
187 {
188 PDMAUDIODIR enmDir = PDMAUDIODIR_INVALID;
189 const char *pszRole = "unknown";
190 if (eFlow == eRender)
191 {
192 pszRole = "output";
193 if (m_fDefaultOut)
194 enmDir = PDMAUDIODIR_OUT;
195 }
196 else if (eFlow == eCapture)
197 {
198 pszRole = "input";
199 if (m_fDefaultIn)
200 enmDir = PDMAUDIODIR_IN;
201 }
202
203 LogRel(("Audio: Default %s device has been changed to '%ls'\n", pszRole, pwstrDefaultDeviceId));
204
205 if (m_pIAudioNotifyFromHost)
206 {
207 if (enmDir != PDMAUDIODIR_INVALID)
208 m_pIAudioNotifyFromHost->pfnNotifyDeviceChanged(m_pIAudioNotifyFromHost, enmDir, NULL);
209 m_pIAudioNotifyFromHost->pfnNotifyDevicesChanged(m_pIAudioNotifyFromHost);
210 }
211 }
212 return S_OK;
213}
214
215STDMETHODIMP DrvHostAudioDSoundMMNotifClient::QueryInterface(REFIID interfaceID, void **ppvInterface)
216{
217 const IID MY_IID_IMMNotificationClient = __uuidof(IMMNotificationClient);
218
219 if ( IsEqualIID(interfaceID, IID_IUnknown)
220 || IsEqualIID(interfaceID, MY_IID_IMMNotificationClient))
221 {
222 *ppvInterface = static_cast<IMMNotificationClient*>(this);
223 AddRef();
224 return S_OK;
225 }
226
227 *ppvInterface = NULL;
228 return E_NOINTERFACE;
229}
230
231STDMETHODIMP_(ULONG) DrvHostAudioDSoundMMNotifClient::AddRef(void)
232{
233 return InterlockedIncrement(&m_cRef);
234}
235
236STDMETHODIMP_(ULONG) DrvHostAudioDSoundMMNotifClient::Release(void)
237{
238 long lRef = InterlockedDecrement(&m_cRef);
239 if (lRef == 0)
240 delete this;
241
242 return lRef;
243}
244
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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