VirtualBox

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

Last change on this file since 86223 was 82968, checked in by vboxsync, 5 years ago

Copyright year updates by scm.

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