VirtualBox

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

Last change on this file since 88269 was 88269, checked in by vboxsync, 4 years ago

Audio: Made sure PDMAUDIOPCMPROPS is initialized using a helper function or the initializer macro, and that vital changes are made using setting helper functions. There are now two derived fields (frame size and shift count) that must be maintained, so this was the sanest way of doing it. Added a raw flag to PDMAUDIOPCMPROPS for VRDE/VRDP, since it wants the raw mixer content and we need a way of expressing this (PDMAUDIOSTREAMLAYOUT isn't the right place). The mixer buffers now uses PDMAUDIOPCMPROPS rather than the weird 32-bit format contraption for picking conversion functions. Simplify the drvAudioStreamPlay code by eliminating the PDMAUDIOSTREAMLAYOUT_RAW special case. bugref:9890

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.4 KB
Line 
1/* $Id: AudioDriver.cpp 88269 2021-03-24 11:45:54Z 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 */);/** @todo r=bird: Illogical and from what I can tell pointless! */
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