VirtualBox

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

Last change on this file since 55436 was 55269, checked in by vboxsync, 10 years ago

Main/DrvAudioVRDE: warning

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