VirtualBox

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

Last change on this file since 70579 was 70579, checked in by vboxsync, 7 years ago

Main/AudioDriver: Fixed crash trying to configure device when no audio device is present. Deduplicated attach/deatch code spread around ConsoleImpl.cpp, putting it into two methods doAttachDriverViaEmt and doDetachDriverViaEmt.

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