VirtualBox

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

Last change on this file since 78352 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

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