VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/DrvAudioVRDE.cpp@ 60034

Last change on this file since 60034 was 59987, checked in by vboxsync, 9 years ago

Audio: Decoupled backend sinks and sources from the maximum of concurrent streams a backend can handle. Also, added some more enumeration code to the ALSA, PulseAudio and OSS backends, which later also can be used for configuration change callbacks. Some function renaming.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 19.3 KB
Line 
1/* $Id: DrvAudioVRDE.cpp 59987 2016-03-11 12:03:37Z vboxsync $ */
2/** @file
3 * VRDE audio backend for Main.
4 */
5
6/*
7 * Copyright (C) 2013-2016 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_VRDE_AUDIO
23#include <VBox/log.h>
24#include "DrvAudioVRDE.h"
25#include "ConsoleImpl.h"
26#include "ConsoleVRDPServer.h"
27
28#include "Logging.h"
29
30#include "../../Devices/Audio/DrvAudio.h"
31#include "../../Devices/Audio/AudioMixBuffer.h"
32
33#include <iprt/mem.h>
34#include <iprt/cdefs.h>
35#include <iprt/circbuf.h>
36
37#include <VBox/vmm/pdmaudioifs.h>
38#include <VBox/vmm/pdmdrv.h>
39#include <VBox/RemoteDesktop/VRDE.h>
40#include <VBox/vmm/cfgm.h>
41#include <VBox/err.h>
42
43
44/*********************************************************************************************************************************
45* Structures and Typedefs *
46*********************************************************************************************************************************/
47/**
48 * Audio VRDE driver instance data.
49 */
50typedef struct DRVAUDIOVRDE
51{
52 /** Pointer to audio VRDE object. */
53 AudioVRDE *pAudioVRDE;
54 PPDMDRVINS pDrvIns;
55 /** Pointer to the driver instance structure. */
56 PDMIHOSTAUDIO IHostAudio;
57 /** Pointer to the VRDP's console object. */
58 ConsoleVRDPServer *pConsoleVRDPServer;
59 /** Pointer to the DrvAudio port interface that is above us. */
60 PPDMIAUDIOCONNECTOR pDrvAudio;
61 /** Whether this driver is enabled or not. */
62 bool fEnabled;
63} DRVAUDIOVRDE, *PDRVAUDIOVRDE;
64
65typedef struct VRDESTREAMIN
66{
67 /** Associated host input stream. */
68 PDMAUDIOHSTSTRMIN HstStrmIn;
69 /** Number of samples captured asynchronously in the
70 * onVRDEInputXXX callbacks. */
71 uint32_t cSamplesCaptured;
72 /** Critical section. */
73 RTCRITSECT CritSect;
74} VRDESTREAMIN, *PVRDESTREAMIN;
75
76typedef struct VRDESTREAMOUT
77{
78 /** Associated host output stream. */
79 PDMAUDIOHSTSTRMOUT HstStrmOut;
80 uint64_t old_ticks;
81 uint64_t cSamplesSentPerSec;
82} VRDESTREAMOUT, *PVRDESTREAMOUT;
83
84
85
86static DECLCALLBACK(int) drvAudioVRDEInit(PPDMIHOSTAUDIO pInterface)
87{
88 LogFlowFuncEnter();
89
90 return VINF_SUCCESS;
91}
92
93static DECLCALLBACK(int) drvAudioVRDEInitIn(PPDMIHOSTAUDIO pInterface,
94 PPDMAUDIOHSTSTRMIN pHstStrmIn, PPDMAUDIOSTREAMCFG pCfg,
95 PDMAUDIORECSOURCE enmRecSource,
96 uint32_t *pcSamples)
97{
98 PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
99 AssertPtrReturn(pDrv, VERR_INVALID_POINTER);
100
101 PVRDESTREAMIN pVRDEStrmIn = (PVRDESTREAMIN)pHstStrmIn;
102 AssertPtrReturn(pVRDEStrmIn, VERR_INVALID_POINTER);
103
104 if (pcSamples)
105 *pcSamples = _4K; /** @todo Make this configurable. */
106
107 return DrvAudioStreamCfgToProps(pCfg, &pVRDEStrmIn->HstStrmIn.Props);
108}
109
110static DECLCALLBACK(int) drvAudioVRDEInitOut(PPDMIHOSTAUDIO pInterface,
111 PPDMAUDIOHSTSTRMOUT pHstStrmOut, PPDMAUDIOSTREAMCFG pCfg,
112 uint32_t *pcSamples)
113{
114 PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
115 AssertPtrReturn(pDrv, VERR_INVALID_POINTER);
116
117 LogFlowFunc(("pHstStrmOut=%p, pCfg=%p\n", pHstStrmOut, pCfg));
118
119 PVRDESTREAMOUT pVRDEStrmOut = (PVRDESTREAMOUT)pHstStrmOut;
120 AssertPtrReturn(pVRDEStrmOut, VERR_INVALID_POINTER);
121
122 if (pcSamples)
123 *pcSamples = _4K; /** @todo Make this configurable. */
124
125 return DrvAudioStreamCfgToProps(pCfg, &pVRDEStrmOut->HstStrmOut.Props);
126}
127
128static DECLCALLBACK(bool) drvAudioVRDEIsEnabled(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
129{
130 PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
131 AssertPtrReturn(pDrv, false);
132
133 NOREF(enmDir);
134
135 if (!pDrv->fEnabled)
136 return false;
137
138 return true;
139}
140
141/**
142 * {FIXME - Missing brief description - FIXME}
143 *
144 * Transfers audio input formerly sent by a connected RDP client / VRDE backend
145 * (using the onVRDEInputXXX methods) over to the VRDE host (VM). The audio device
146 * emulation then will read and send the data to the guest.
147 *
148 * @return IPRT status code.
149 * @param pInterface
150 * @param pHstStrmIn
151 * @param pcSamplesCaptured
152 */
153static DECLCALLBACK(int) drvAudioVRDECaptureIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
154 uint32_t *pcSamplesCaptured)
155{
156 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
157 AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
158 AssertPtrReturn(pcSamplesCaptured, VERR_INVALID_POINTER);
159
160 PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
161 AssertPtrReturn(pDrv, VERR_INVALID_POINTER);
162
163 PVRDESTREAMIN pVRDEStrmIn = (PVRDESTREAMIN)pHstStrmIn;
164 AssertPtrReturn(pVRDEStrmIn, VERR_INVALID_POINTER);
165
166 /** @todo Use CritSect! */
167
168 int rc;
169
170 uint32_t cProcessed = 0;
171 if (pVRDEStrmIn->cSamplesCaptured)
172 {
173 rc = AudioMixBufMixToParent(&pVRDEStrmIn->HstStrmIn.MixBuf, pVRDEStrmIn->cSamplesCaptured,
174 &cProcessed);
175 }
176 else
177 rc = VINF_SUCCESS;
178
179 if (RT_SUCCESS(rc))
180 {
181 *pcSamplesCaptured = cProcessed;
182
183 Assert(pVRDEStrmIn->cSamplesCaptured >= cProcessed);
184 pVRDEStrmIn->cSamplesCaptured -= cProcessed;
185 }
186
187 LogFlowFunc(("cSamplesCaptured=%RU32, cProcessed=%RU32 rc=%Rrc\n", pVRDEStrmIn->cSamplesCaptured, cProcessed, rc));
188 return rc;
189}
190
191/**
192 * Transfers VM audio output to remote client.
193 *
194 * Transfers VM audio output over to the VRDE instance for playing remotely
195 * on the client.
196 *
197 * @return IPRT status code.
198 * @param pInterface
199 * @param pHstStrmOut
200 * @param pcSamplesPlayed
201 */
202static DECLCALLBACK(int) drvAudioVRDEPlayOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
203 uint32_t *pcSamplesPlayed)
204{
205 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
206 AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
207 /* pcSamplesPlayed is optional. */
208
209 PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
210 AssertPtrReturn(pDrv, VERR_INVALID_POINTER);
211
212 PVRDESTREAMOUT pVRDEStrmOut = (PVRDESTREAMOUT)pHstStrmOut;
213 AssertPtrReturn(pVRDEStrmOut, VERR_INVALID_POINTER);
214
215 uint32_t live = AudioMixBufAvail(&pHstStrmOut->MixBuf);
216 uint64_t now = PDMDrvHlpTMGetVirtualTime(pDrv->pDrvIns);
217 uint64_t ticks = now - pVRDEStrmOut->old_ticks;
218 uint64_t ticks_per_second = PDMDrvHlpTMGetVirtualFreq(pDrv->pDrvIns);
219
220 /* Minimize the rounding error: samples = int((ticks * freq) / ticks_per_second + 0.5). */
221 uint32_t cSamplesPlayed = (int)((2 * ticks * pHstStrmOut->Props.uHz + ticks_per_second) / ticks_per_second / 2);
222
223 /* Don't play more than available. */
224 if (cSamplesPlayed > live)
225 cSamplesPlayed = live;
226
227 /* Remember when samples were consumed. */
228 pVRDEStrmOut->old_ticks = now;
229
230 VRDEAUDIOFORMAT format = VRDE_AUDIO_FMT_MAKE(pHstStrmOut->Props.uHz,
231 pHstStrmOut->Props.cChannels,
232 pHstStrmOut->Props.cBits,
233 pHstStrmOut->Props.fSigned);
234
235 int cSamplesToSend = cSamplesPlayed;
236
237 LogFlowFunc(("uFreq=%RU32, cChan=%RU8, cBits=%RU8, fSigned=%RTbool, enmFormat=%ld, cSamplesToSend=%RU32\n",
238 pHstStrmOut->Props.uHz, pHstStrmOut->Props.cChannels,
239 pHstStrmOut->Props.cBits, pHstStrmOut->Props.fSigned,
240 format, cSamplesToSend));
241
242 /*
243 * Call the VRDP server with the data.
244 */
245 uint32_t cReadTotal = 0;
246
247 PPDMAUDIOSAMPLE pSamples;
248 uint32_t cRead;
249 int rc = AudioMixBufAcquire(&pHstStrmOut->MixBuf, cSamplesToSend,
250 &pSamples, &cRead);
251 if ( RT_SUCCESS(rc)
252 && cRead)
253 {
254 cReadTotal = cRead;
255 pDrv->pConsoleVRDPServer->SendAudioSamples(pSamples, cRead, format);
256
257 if (rc == VINF_TRY_AGAIN)
258 {
259 rc = AudioMixBufAcquire(&pHstStrmOut->MixBuf, cSamplesToSend - cRead,
260 &pSamples, &cRead);
261 if (RT_SUCCESS(rc))
262 pDrv->pConsoleVRDPServer->SendAudioSamples(pSamples, cRead, format);
263
264 cReadTotal += cRead;
265 }
266 }
267
268 AudioMixBufFinish(&pHstStrmOut->MixBuf, cSamplesToSend);
269
270 /*
271 * Always report back all samples acquired, regardless of whether the
272 * VRDP server actually did process those.
273 */
274 if (pcSamplesPlayed)
275 *pcSamplesPlayed = cReadTotal;
276
277 LogFlowFunc(("cReadTotal=%RU32, rc=%Rrc\n", cReadTotal, rc));
278 return rc;
279}
280
281static DECLCALLBACK(int) drvAudioVRDEFiniIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn)
282{
283 PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
284 AssertPtrReturn(pDrv, VERR_INVALID_POINTER);
285
286 if (pDrv->pConsoleVRDPServer)
287 pDrv->pConsoleVRDPServer->SendAudioInputEnd(NULL);
288
289 return VINF_SUCCESS;
290}
291
292static DECLCALLBACK(int) drvAudioVRDEFiniOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut)
293{
294 PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
295 AssertPtrReturn(pDrv, VERR_INVALID_POINTER);
296
297 return VINF_SUCCESS;
298}
299
300static DECLCALLBACK(int) drvAudioVRDEControlOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
301 PDMAUDIOSTREAMCMD enmStreamCmd)
302{
303 PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
304 AssertPtrReturn(pDrv, VERR_INVALID_POINTER);
305
306 PVRDESTREAMOUT pVRDEStrmOut = (PVRDESTREAMOUT)pHstStrmOut;
307 AssertPtrReturn(pVRDEStrmOut, VERR_INVALID_POINTER);
308
309 LogFlowFunc(("enmStreamCmd=%ld\n", enmStreamCmd));
310
311 AudioMixBufReset(&pHstStrmOut->MixBuf);
312
313 return VINF_SUCCESS;
314}
315
316static DECLCALLBACK(int) drvAudioVRDEControlIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
317 PDMAUDIOSTREAMCMD enmStreamCmd)
318{
319 PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
320 AssertPtrReturn(pDrv, VERR_INVALID_POINTER);
321
322 PVRDESTREAMIN pVRDEStrmIn = (PVRDESTREAMIN)pHstStrmIn;
323 AssertPtrReturn(pVRDEStrmIn, VERR_INVALID_POINTER);
324
325 PPDMAUDIOHSTSTRMIN pThisStrmIn = &pVRDEStrmIn->HstStrmIn;
326
327 LogFlowFunc(("enmStreamCmd=%ld\n", enmStreamCmd));
328
329 if (!pDrv->pConsoleVRDPServer)
330 return VINF_SUCCESS;
331
332 AudioMixBufReset(&pThisStrmIn->MixBuf);
333
334 /* Initialize only if not already done. */
335 int rc;
336 if (enmStreamCmd == PDMAUDIOSTREAMCMD_ENABLE)
337 {
338 rc = pDrv->pConsoleVRDPServer->SendAudioInputBegin(NULL, pVRDEStrmIn, AudioMixBufSize(&pThisStrmIn->MixBuf),
339 pThisStrmIn->Props.uHz,
340 pThisStrmIn->Props.cChannels, pThisStrmIn->Props.cBits);
341 if (rc == VERR_NOT_SUPPORTED)
342 {
343 LogFlowFunc(("No RDP client connected, so no input recording supported\n"));
344 rc = VINF_SUCCESS;
345 }
346 }
347 else if (enmStreamCmd == PDMAUDIOSTREAMCMD_DISABLE)
348 {
349 pDrv->pConsoleVRDPServer->SendAudioInputEnd(NULL /* pvUserCtx */);
350 rc = VINF_SUCCESS;
351 }
352 else
353 rc = VERR_INVALID_PARAMETER;
354
355 return rc;
356}
357
358static DECLCALLBACK(int) drvAudioVRDEGetConf(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pCfg)
359{
360 NOREF(pInterface);
361 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
362
363 pCfg->cbStreamOut = sizeof(VRDESTREAMOUT);
364 pCfg->cbStreamIn = sizeof(VRDESTREAMIN);
365 pCfg->cMaxStreamsIn = UINT32_MAX;
366 pCfg->cMaxStreamsOut = UINT32_MAX;
367 pCfg->cSources = 1;
368 pCfg->cSinks = 1;
369
370 return VINF_SUCCESS;
371}
372
373static DECLCALLBACK(void) drvAudioVRDEShutdown(PPDMIHOSTAUDIO pInterface)
374{
375 PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
376 AssertPtrReturnVoid(pDrv);
377
378 if (pDrv->pConsoleVRDPServer)
379 pDrv->pConsoleVRDPServer->SendAudioInputEnd(NULL);
380}
381
382/**
383 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
384 */
385static DECLCALLBACK(void *) drvAudioVRDEQueryInterface(PPDMIBASE pInterface, const char *pszIID)
386{
387 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
388 PDRVAUDIOVRDE pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVRDE);
389
390 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
391 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
392 return NULL;
393}
394
395AudioVRDE::AudioVRDE(Console *pConsole)
396 : mpDrv(NULL),
397 mParent(pConsole)
398{
399}
400
401AudioVRDE::~AudioVRDE(void)
402{
403 if (mpDrv)
404 {
405 mpDrv->pAudioVRDE = NULL;
406 mpDrv = NULL;
407 }
408}
409
410int AudioVRDE::onVRDEControl(bool fEnable, uint32_t uFlags)
411{
412 LogFlowThisFunc(("fEnable=%RTbool, uFlags=0x%x\n", fEnable, uFlags));
413
414 if (mpDrv == NULL)
415 return VERR_INVALID_STATE;
416
417 mpDrv->fEnabled = fEnable;
418
419 return VINF_SUCCESS; /* Never veto. */
420}
421
422/**
423 * Marks the beginning of sending captured audio data from a connected
424 * RDP client.
425 *
426 * @return IPRT status code.
427 * @param pvContext The context; in this case a pointer to a
428 * VRDESTREAMIN structure.
429 * @param pVRDEAudioBegin Pointer to a VRDEAUDIOINBEGIN structure.
430 */
431int AudioVRDE::onVRDEInputBegin(void *pvContext, PVRDEAUDIOINBEGIN pVRDEAudioBegin)
432{
433 AssertPtrReturn(pvContext, VERR_INVALID_POINTER);
434 AssertPtrReturn(pVRDEAudioBegin, VERR_INVALID_POINTER);
435
436 PVRDESTREAMIN pVRDEStrmIn = (PVRDESTREAMIN)pvContext;
437 AssertPtrReturn(pVRDEStrmIn, VERR_INVALID_POINTER);
438
439 VRDEAUDIOFORMAT audioFmt = pVRDEAudioBegin->fmt;
440
441 int iSampleHz = VRDE_AUDIO_FMT_SAMPLE_FREQ(audioFmt);
442 int cChannels = VRDE_AUDIO_FMT_CHANNELS(audioFmt);
443 int cBits = VRDE_AUDIO_FMT_BITS_PER_SAMPLE(audioFmt);
444 bool fUnsigned = VRDE_AUDIO_FMT_SIGNED(audioFmt);
445
446 LogFlowFunc(("cbSample=%RU32, iSampleHz=%d, cChannels=%d, cBits=%d, fUnsigned=%RTbool\n",
447 VRDE_AUDIO_FMT_BYTES_PER_SAMPLE(audioFmt), iSampleHz, cChannels, cBits, fUnsigned));
448
449 return VINF_SUCCESS;
450}
451
452int AudioVRDE::onVRDEInputData(void *pvContext, const void *pvData, uint32_t cbData)
453{
454 PVRDESTREAMIN pVRDEStrmIn = (PVRDESTREAMIN)pvContext;
455 AssertPtrReturn(pVRDEStrmIn, VERR_INVALID_POINTER);
456
457 PPDMAUDIOHSTSTRMIN pHstStrmIn = &pVRDEStrmIn->HstStrmIn;
458 AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
459
460 /** @todo Use CritSect! */
461
462 uint32_t cWritten;
463 int rc = AudioMixBufWriteCirc(&pHstStrmIn->MixBuf, pvData, cbData, &cWritten);
464 if (RT_SUCCESS(rc))
465 pVRDEStrmIn->cSamplesCaptured += cWritten;
466
467 LogFlowFunc(("cbData=%RU32, cWritten=%RU32, cSamplesCaptured=%RU32, rc=%Rrc\n",
468 cbData, cWritten, pVRDEStrmIn->cSamplesCaptured, rc));
469 return rc;
470}
471
472int AudioVRDE::onVRDEInputEnd(void *pvContext)
473{
474 NOREF(pvContext);
475
476 return VINF_SUCCESS;
477}
478
479int AudioVRDE::onVRDEInputIntercept(bool fEnabled)
480{
481 return VINF_SUCCESS; /* Never veto. */
482}
483
484/**
485 * Construct a VRDE audio driver instance.
486 *
487 * @copydoc FNPDMDRVCONSTRUCT
488 */
489/* static */
490DECLCALLBACK(int) AudioVRDE::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
491{
492 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
493 PDRVAUDIOVRDE pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVRDE);
494 AssertPtrReturn(pDrvIns, VERR_INVALID_POINTER);
495 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
496
497 LogRel(("Audio: Initializing VRDE driver\n"));
498 LogFlowFunc(("fFlags=0x%x\n", fFlags));
499
500 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
501 ("Configuration error: Not possible to attach anything to this driver!\n"),
502 VERR_PDM_DRVINS_NO_ATTACH);
503
504 /*
505 * Init the static parts.
506 */
507 pThis->pDrvIns = pDrvIns;
508 /* IBase */
509 pDrvIns->IBase.pfnQueryInterface = drvAudioVRDEQueryInterface;
510 /* IHostAudio */
511 PDMAUDIO_IHOSTAUDIO_CALLBACKS(drvAudioVRDE);
512
513 /* Init defaults. */
514 pThis->fEnabled = false;
515
516 /*
517 * Get the ConsoleVRDPServer object pointer.
518 */
519 void *pvUser;
520 int rc = CFGMR3QueryPtr(pCfg, "ObjectVRDPServer", &pvUser);
521 AssertMsgRCReturn(rc, ("Confguration error: No/bad \"ObjectVRDPServer\" value, rc=%Rrc\n", rc), rc);
522
523 /* CFGM tree saves the pointer to ConsoleVRDPServer in the Object node of AudioVRDE. */
524 pThis->pConsoleVRDPServer = (ConsoleVRDPServer *)pvUser;
525
526 /*
527 * Get the AudioVRDE object pointer.
528 */
529 pvUser = NULL;
530 rc = CFGMR3QueryPtr(pCfg, "Object", &pvUser);
531 AssertMsgRCReturn(rc, ("Confguration error: No/bad \"Object\" value, rc=%Rrc\n", rc), rc);
532
533 pThis->pAudioVRDE = (AudioVRDE *)pvUser;
534 pThis->pAudioVRDE->mpDrv = pThis;
535
536 /*
537 * Get the interface for the above driver (DrvAudio) to make mixer/conversion calls.
538 * Described in CFGM tree.
539 */
540 pThis->pDrvAudio = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIAUDIOCONNECTOR);
541 AssertMsgReturn(pThis->pDrvAudio, ("Configuration error: No upper interface specified!\n"), VERR_PDM_MISSING_INTERFACE_ABOVE);
542
543 return VINF_SUCCESS;
544}
545
546
547/**
548 * @interface_method_impl{PDMDRVREG,pfnDestruct}
549 */
550/* static */
551DECLCALLBACK(void) AudioVRDE::drvDestruct(PPDMDRVINS pDrvIns)
552{
553 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
554 PDRVAUDIOVRDE pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVRDE);
555 LogFlowFuncEnter();
556
557 /*
558 * If the AudioVRDE object is still alive, we must clear it's reference to
559 * us since we'll be invalid when we return from this method.
560 */
561 if (pThis->pAudioVRDE)
562 {
563 pThis->pAudioVRDE->mpDrv = NULL;
564 pThis->pAudioVRDE = NULL;
565 }
566}
567
568
569/**
570 * VRDE audio driver registration record.
571 */
572const PDMDRVREG AudioVRDE::DrvReg =
573{
574 PDM_DRVREG_VERSION,
575 /* szName */
576 "AudioVRDE",
577 /* szRCMod */
578 "",
579 /* szR0Mod */
580 "",
581 /* pszDescription */
582 "Audio driver for VRDE backend",
583 /* fFlags */
584 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
585 /* fClass. */
586 PDM_DRVREG_CLASS_AUDIO,
587 /* cMaxInstances */
588 ~0U,
589 /* cbInstance */
590 sizeof(DRVAUDIOVRDE),
591 /* pfnConstruct */
592 AudioVRDE::drvConstruct,
593 /* pfnDestruct */
594 AudioVRDE::drvDestruct,
595 /* pfnRelocate */
596 NULL,
597 /* pfnIOCtl */
598 NULL,
599 /* pfnPowerOn */
600 NULL,
601 /* pfnReset */
602 NULL,
603 /* pfnSuspend */
604 NULL,
605 /* pfnResume */
606 NULL,
607 /* pfnAttach */
608 NULL,
609 /* pfnDetach */
610 NULL,
611 /* pfnPowerOff */
612 NULL,
613 /* pfnSoftReset */
614 NULL,
615 /* u32EndVersion */
616 PDM_DRVREG_VERSION
617};
618
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