VirtualBox

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

Last change on this file since 94348 was 93444, checked in by vboxsync, 3 years ago

VMM,Main,HostServices: Use a function table for accessing the VBoxVMM.dll/so/dylib functionality, and load it dynamically when the Console object is initialized. Also converted a few drivers in Main to use device helpers to get config values and such. bugref:10074

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