VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/AudioDriver.cpp

Last change on this file was 106061, checked in by vboxsync, 2 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.2 KB
Line 
1/* $Id: AudioDriver.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * VirtualBox audio base class for Main audio drivers.
4 */
5
6/*
7 * Copyright (C) 2018-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
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#define LOG_GROUP LOG_GROUP_DRV_HOST_AUDIO
33#include "LoggingNew.h"
34
35#include <VBox/log.h>
36#include <VBox/vmm/cfgm.h>
37#include <VBox/vmm/pdmaudioifs.h>
38#include <VBox/vmm/pdmapi.h>
39#include <VBox/vmm/pdmdrv.h>
40#include <VBox/vmm/vmmr3vtable.h>
41
42#include "AudioDriver.h"
43#include "ConsoleImpl.h"
44
45AudioDriver::AudioDriver(Console *pConsole)
46 : mpConsole(pConsole)
47 , mfAttached(false)
48{
49}
50
51
52AudioDriver::~AudioDriver(void)
53{
54}
55
56
57AudioDriver &AudioDriver::operator=(AudioDriver const &a_rThat) RT_NOEXCEPT
58{
59 mpConsole = a_rThat.mpConsole;
60 mCfg = a_rThat.mCfg;
61 mfAttached = a_rThat.mfAttached;
62
63 return *this;
64}
65
66
67/**
68 * Initializes the audio driver with a certain (device) configuration.
69 *
70 * @returns VBox status code.
71 * @param pCfg Audio driver configuration to use.
72 */
73int AudioDriver::InitializeConfig(AudioDriverCfg *pCfg)
74{
75 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
76
77 /* Sanity. */
78 AssertReturn(pCfg->strDev.isNotEmpty(), VERR_INVALID_PARAMETER);
79 AssertReturn(pCfg->uLUN != UINT8_MAX, VERR_INVALID_PARAMETER);
80 AssertReturn(pCfg->strName.isNotEmpty(), VERR_INVALID_PARAMETER);
81
82 /* Apply configuration. */
83 mCfg = *pCfg;
84
85 return VINF_SUCCESS;
86}
87
88
89/**
90 * Attaches the driver via EMT, if configured.
91 *
92 * @returns VBox status code.
93 * @param pUVM The user mode VM handle for talking to EMT.
94 * @param pVMM The VMM ring-3 vtable.
95 * @param pAutoLock The callers auto lock instance. Can be NULL if not
96 * locked.
97 */
98int AudioDriver::doAttachDriverViaEmt(PUVM pUVM, PCVMMR3VTABLE pVMM, util::AutoWriteLock *pAutoLock)
99{
100 if (!isConfigured())
101 return VINF_SUCCESS;
102
103 PVMREQ pReq;
104 int vrc = pVMM->pfnVMR3ReqCallU(pUVM, VMCPUID_ANY, &pReq, 0 /* no wait! */, VMREQFLAGS_VBOX_STATUS,
105 (PFNRT)attachDriverOnEmt, 1, this);
106 if (vrc == VERR_TIMEOUT)
107 {
108 /* Release the lock before a blocking VMR3* call (EMT might wait for it, @bugref{7648})! */
109 if (pAutoLock)
110 pAutoLock->release();
111
112 vrc = pVMM->pfnVMR3ReqWait(pReq, RT_INDEFINITE_WAIT);
113
114 if (pAutoLock)
115 pAutoLock->acquire();
116 }
117
118 AssertRC(vrc);
119 pVMM->pfnVMR3ReqFree(pReq);
120
121 return vrc;
122}
123
124
125/**
126 * Configures the audio driver (to CFGM) and attaches it to the audio chain.
127 * Does nothing if the audio driver already is attached.
128 *
129 * @returns VBox status code.
130 * @param pThis Audio driver to detach.
131 */
132/* static */
133DECLCALLBACK(int) AudioDriver::attachDriverOnEmt(AudioDriver *pThis)
134{
135 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
136
137 Console::SafeVMPtrQuiet ptrVM(pThis->mpConsole);
138 Assert(ptrVM.isOk());
139
140 if (pThis->mfAttached) /* Already attached? Bail out. */
141 {
142 LogFunc(("%s: Already attached\n", pThis->mCfg.strName.c_str()));
143 return VINF_SUCCESS;
144 }
145
146 AudioDriverCfg *pCfg = &pThis->mCfg;
147
148 LogFunc(("strName=%s, strDevice=%s, uInst=%u, uLUN=%u\n",
149 pCfg->strName.c_str(), pCfg->strDev.c_str(), pCfg->uInst, pCfg->uLUN));
150
151 /* Detach the driver chain from the audio device first. */
152 int vrc = ptrVM.vtable()->pfnPDMR3DeviceDetach(ptrVM.rawUVM(), pCfg->strDev.c_str(), pCfg->uInst, pCfg->uLUN, 0 /* fFlags */);
153 if (RT_SUCCESS(vrc))
154 {
155 vrc = pThis->configure(pCfg->uLUN, true /* Attach */);
156 if (RT_SUCCESS(vrc))
157 vrc = ptrVM.vtable()->pfnPDMR3DriverAttach(ptrVM.rawUVM(), pCfg->strDev.c_str(), pCfg->uInst, pCfg->uLUN,
158 0 /* fFlags */, NULL /* ppBase */);
159 }
160
161 if (RT_SUCCESS(vrc))
162 {
163 pThis->mfAttached = true;
164 LogRel2(("%s: Driver attached (LUN #%u)\n", pCfg->strName.c_str(), pCfg->uLUN));
165 }
166 else
167 LogRel(("%s: Failed to attach audio driver, vrc=%Rrc\n", pCfg->strName.c_str(), vrc));
168
169 LogFunc(("Returning %Rrc\n", vrc));
170 return vrc;
171}
172
173
174/**
175 * Detatches the driver via EMT, if configured.
176 *
177 * @returns VBox status code.
178 * @param pUVM The user mode VM handle for talking to EMT.
179 * @param pVMM The VMM ring-3 vtable.
180 * @param pAutoLock The callers auto lock instance. Can be NULL if not
181 * locked.
182 */
183int AudioDriver::doDetachDriverViaEmt(PUVM pUVM, PCVMMR3VTABLE pVMM, util::AutoWriteLock *pAutoLock)
184{
185 if (!isConfigured())
186 return VINF_SUCCESS;
187
188 PVMREQ pReq;
189 int vrc = pVMM->pfnVMR3ReqCallU(pUVM, VMCPUID_ANY, &pReq, 0 /* no wait! */, VMREQFLAGS_VBOX_STATUS,
190 (PFNRT)detachDriverOnEmt, 1, this);
191 if (vrc == VERR_TIMEOUT)
192 {
193 /* Release the lock before a blocking VMR3* call (EMT might wait for it, @bugref{7648})! */
194 if (pAutoLock)
195 pAutoLock->release();
196
197 vrc = pVMM->pfnVMR3ReqWait(pReq, RT_INDEFINITE_WAIT);
198
199 if (pAutoLock)
200 pAutoLock->acquire();
201 }
202
203 AssertRC(vrc);
204 pVMM->pfnVMR3ReqFree(pReq);
205
206 return vrc;
207}
208
209
210/**
211 * Detaches an already attached audio driver from the audio chain.
212 * Does nothing if the audio driver already is detached or not attached.
213 *
214 * @returns VBox status code.
215 * @param pThis Audio driver to detach.
216 */
217/* static */
218DECLCALLBACK(int) AudioDriver::detachDriverOnEmt(AudioDriver *pThis)
219{
220 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
221
222 if (!pThis->mfAttached) /* Not attached? Bail out. */
223 {
224 LogFunc(("%s: Not attached\n", pThis->mCfg.strName.c_str()));
225 return VINF_SUCCESS;
226 }
227
228 Console::SafeVMPtrQuiet ptrVM(pThis->mpConsole);
229 Assert(ptrVM.isOk());
230
231 AudioDriverCfg *pCfg = &pThis->mCfg;
232
233 Assert(pCfg->uLUN != UINT8_MAX);
234
235 LogFunc(("strName=%s, strDevice=%s, uInst=%u, uLUN=%u\n",
236 pCfg->strName.c_str(), pCfg->strDev.c_str(), pCfg->uInst, pCfg->uLUN));
237
238 /* Destroy the entire driver chain for the specified LUN.
239 *
240 * Start with the "AUDIO" driver, as this driver serves as the audio connector between
241 * the device emulation and the select backend(s). */
242 int vrc = ptrVM.vtable()->pfnPDMR3DriverDetach(ptrVM.rawUVM(), pCfg->strDev.c_str(), pCfg->uInst, pCfg->uLUN,
243 "AUDIO", 0 /* iOccurrence */, 0 /* fFlags */);
244 if (RT_SUCCESS(vrc))
245 vrc = pThis->configure(pCfg->uLUN, false /* Detach */);/** @todo r=bird: Illogical and from what I can tell pointless! */
246
247 if (RT_SUCCESS(vrc))
248 {
249 pThis->mfAttached = false;
250 LogRel2(("%s: Driver detached\n", pCfg->strName.c_str()));
251 }
252 else
253 LogRel(("%s: Failed to detach audio driver, vrc=%Rrc\n", pCfg->strName.c_str(), vrc));
254
255 LogFunc(("Returning %Rrc\n", vrc));
256 return vrc;
257}
258
259/**
260 * Configures the audio driver via CFGM.
261 *
262 * @returns VBox status code.
263 * @param uLUN LUN to attach driver to.
264 * @param fAttach Whether to attach or detach the driver configuration to CFGM.
265 *
266 * @thread EMT
267 */
268int AudioDriver::configure(unsigned uLUN, bool fAttach)
269{
270 Console::SafeVMPtrQuiet ptrVM(mpConsole);
271 AssertReturn(ptrVM.isOk(), VERR_INVALID_STATE);
272
273 PCFGMNODE pRoot = ptrVM.vtable()->pfnCFGMR3GetRootU(ptrVM.rawUVM());
274 AssertPtr(pRoot);
275 PCFGMNODE pDev0 = ptrVM.vtable()->pfnCFGMR3GetChildF(pRoot, "Devices/%s/%u/", mCfg.strDev.c_str(), mCfg.uInst);
276
277 if (!pDev0) /* No audio device configured? Bail out. */
278 {
279 LogRel2(("%s: No audio device configured, skipping to attach driver\n", mCfg.strName.c_str()));
280 return VINF_SUCCESS;
281 }
282
283 int vrc = VINF_SUCCESS;
284
285 PCFGMNODE pDevLun = ptrVM.vtable()->pfnCFGMR3GetChildF(pDev0, "LUN#%u/", uLUN);
286
287 if (fAttach)
288 {
289 do /* break "loop" */
290 {
291 AssertMsgBreakStmt(pDevLun, ("%s: Device LUN #%u not found\n", mCfg.strName.c_str(), uLUN), vrc = VERR_NOT_FOUND);
292
293 LogRel2(("%s: Configuring audio driver (to LUN #%u)\n", mCfg.strName.c_str(), uLUN));
294
295 ptrVM.vtable()->pfnCFGMR3RemoveNode(pDevLun); /* Remove LUN completely first. */
296
297 /* Insert new LUN configuration and build up the new driver chain. */
298 vrc = ptrVM.vtable()->pfnCFGMR3InsertNodeF(pDev0, &pDevLun, "LUN#%u/", uLUN); AssertRCBreak(vrc);
299 vrc = ptrVM.vtable()->pfnCFGMR3InsertString(pDevLun, "Driver", "AUDIO"); AssertRCBreak(vrc);
300
301 PCFGMNODE pLunCfg;
302 vrc = ptrVM.vtable()->pfnCFGMR3InsertNode(pDevLun, "Config", &pLunCfg); AssertRCBreak(vrc);
303
304 vrc = ptrVM.vtable()->pfnCFGMR3InsertStringF(pLunCfg, "DriverName", "%s", mCfg.strName.c_str()); AssertRCBreak(vrc);
305 vrc = ptrVM.vtable()->pfnCFGMR3InsertInteger(pLunCfg, "InputEnabled", mCfg.fEnabledIn); AssertRCBreak(vrc);
306 vrc = ptrVM.vtable()->pfnCFGMR3InsertInteger(pLunCfg, "OutputEnabled", mCfg.fEnabledOut); AssertRCBreak(vrc);
307
308 PCFGMNODE pAttachedDriver;
309 vrc = ptrVM.vtable()->pfnCFGMR3InsertNode(pDevLun, "AttachedDriver", &pAttachedDriver); AssertRCBreak(vrc);
310 vrc = ptrVM.vtable()->pfnCFGMR3InsertStringF(pAttachedDriver, "Driver", "%s", mCfg.strName.c_str()); AssertRCBreak(vrc);
311 PCFGMNODE pAttachedDriverCfg;
312 vrc = ptrVM.vtable()->pfnCFGMR3InsertNode(pAttachedDriver, "Config", &pAttachedDriverCfg); AssertRCBreak(vrc);
313
314 /* Call the (virtual) method for driver-specific configuration. */
315 vrc = configureDriver(pAttachedDriverCfg, ptrVM.vtable()); AssertRCBreak(vrc);
316
317 } while (0);
318 }
319 else /* Detach */
320 {
321 LogRel2(("%s: Unconfiguring audio driver\n", mCfg.strName.c_str()));
322 }
323
324 if (RT_SUCCESS(vrc))
325 {
326#ifdef LOG_ENABLED
327 LogFunc(("%s: fAttach=%RTbool\n", mCfg.strName.c_str(), fAttach));
328 ptrVM.vtable()->pfnCFGMR3Dump(pDevLun);
329#endif
330 }
331 else
332 LogRel(("%s: %s audio driver failed with vrc=%Rrc\n", mCfg.strName.c_str(), fAttach ? "Configuring" : "Unconfiguring", vrc));
333
334 LogFunc(("Returning %Rrc\n", vrc));
335 return vrc;
336}
337
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