VirtualBox

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

Last change on this file since 56268 was 55921, checked in by vboxsync, 10 years ago

Whops, forgot to commit this.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 18.9 KB
Line 
1/* $Id: DrvAudioVRDE.cpp 55921 2015-05-18 19:15:35Z 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 uint32_t live = drvAudioHstOutSamplesLive(pHstStrmOut, NULL /* pcStreamsLive */);
219 uint64_t now = PDMDrvHlpTMGetVirtualTime(pDrv->pDrvIns);
220 uint64_t ticks = now - pVRDEStrmOut->old_ticks;
221 uint64_t ticks_per_second = PDMDrvHlpTMGetVirtualFreq(pDrv->pDrvIns);
222
223 /* Minimize the rounding error: samples = int((ticks * freq) / ticks_per_second + 0.5). */
224 uint32_t cSamplesPlayed = (int)((2 * ticks * pHstStrmOut->Props.uHz + ticks_per_second) / ticks_per_second / 2);
225
226 /* Don't play more than available. */
227 if (cSamplesPlayed > live)
228 cSamplesPlayed = live;
229
230 /* Remember when samples were consumed. */
231 pVRDEStrmOut->old_ticks = now;
232
233 VRDEAUDIOFORMAT format = VRDE_AUDIO_FMT_MAKE(pHstStrmOut->Props.uHz,
234 pHstStrmOut->Props.cChannels,
235 pHstStrmOut->Props.cBits,
236 pHstStrmOut->Props.fSigned);
237
238 int cSamplesToSend = cSamplesPlayed;
239
240 LogFlowFunc(("uFreq=%RU32, cChan=%RU8, cBits=%RU8, fSigned=%RTbool, enmFormat=%ld, cSamplesToSend=%RU32\n",
241 pHstStrmOut->Props.uHz, pHstStrmOut->Props.cChannels,
242 pHstStrmOut->Props.cBits, pHstStrmOut->Props.fSigned,
243 format, cSamplesToSend));
244
245 /*
246 * Call the VRDP server with the data.
247 */
248 uint32_t cReadTotal = 0;
249
250 PPDMAUDIOSAMPLE pSamples;
251 uint32_t cRead;
252 int rc = AudioMixBufAcquire(&pHstStrmOut->MixBuf, cSamplesToSend,
253 &pSamples, &cRead);
254 if ( RT_SUCCESS(rc)
255 && cRead)
256 {
257 cReadTotal = cRead;
258 pDrv->pConsoleVRDPServer->SendAudioSamples(pSamples, cRead, format);
259
260 if (rc == VINF_TRY_AGAIN)
261 {
262 rc = AudioMixBufAcquire(&pHstStrmOut->MixBuf, cSamplesToSend - cRead,
263 &pSamples, &cRead);
264 if (RT_SUCCESS(rc))
265 pDrv->pConsoleVRDPServer->SendAudioSamples(pSamples, cRead, format);
266
267 cReadTotal += cRead;
268 }
269 }
270
271 AudioMixBufFinish(&pHstStrmOut->MixBuf, cSamplesToSend);
272
273 /*
274 * Always report back all samples acquired, regardless of whether the
275 * VRDP server actually did process those.
276 */
277 if (pcSamplesPlayed)
278 *pcSamplesPlayed = cReadTotal;
279
280 LogFlowFunc(("cReadTotal=%RU32, rc=%Rrc\n", cReadTotal, rc));
281 return rc;
282}
283
284static DECLCALLBACK(int) drvAudioVRDEFiniIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn)
285{
286 PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
287 AssertPtrReturn(pDrv, VERR_INVALID_POINTER);
288
289 if (pDrv->pConsoleVRDPServer)
290 pDrv->pConsoleVRDPServer->SendAudioInputEnd(NULL);
291
292 return VINF_SUCCESS;
293}
294
295static DECLCALLBACK(int) drvAudioVRDEFiniOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut)
296{
297 PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
298 AssertPtrReturn(pDrv, VERR_INVALID_POINTER);
299
300 return VINF_SUCCESS;
301}
302
303static DECLCALLBACK(int) drvAudioVRDEControlOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
304 PDMAUDIOSTREAMCMD enmStreamCmd)
305{
306 PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
307 AssertPtrReturn(pDrv, VERR_INVALID_POINTER);
308
309 PVRDESTREAMIN pVRDEStrmOut = (PVRDESTREAMIN)pHstStrmOut;
310 AssertPtrReturn(pVRDEStrmOut, VERR_INVALID_POINTER);
311
312 LogFlowFunc(("enmStreamCmd=%ld\n", enmStreamCmd));
313
314 AudioMixBufReset(&pHstStrmOut->MixBuf);
315
316 return VINF_SUCCESS;
317}
318
319static DECLCALLBACK(int) drvAudioVRDEControlIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
320 PDMAUDIOSTREAMCMD enmStreamCmd)
321{
322 PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
323 AssertPtrReturn(pDrv, VERR_INVALID_POINTER);
324
325 PVRDESTREAMIN pVRDEStrmIn = (PVRDESTREAMIN)pHstStrmIn;
326 AssertPtrReturn(pVRDEStrmIn, VERR_INVALID_POINTER);
327
328 PPDMAUDIOHSTSTRMIN pThisStrmIn = &pVRDEStrmIn->HstStrmIn;
329
330 LogFlowFunc(("enmStreamCmd=%ld\n", enmStreamCmd));
331
332 if (!pDrv->pConsoleVRDPServer)
333 return VINF_SUCCESS;
334
335 AudioMixBufReset(&pThisStrmIn->MixBuf);
336
337 /* Initialize only if not already done. */
338 int rc;
339 if (enmStreamCmd == PDMAUDIOSTREAMCMD_ENABLE)
340 {
341 rc = pDrv->pConsoleVRDPServer->SendAudioInputBegin(NULL, pVRDEStrmIn, AudioMixBufSize(&pThisStrmIn->MixBuf),
342 pThisStrmIn->Props.uHz,
343 pThisStrmIn->Props.cChannels, pThisStrmIn->Props.cBits);
344 if (rc == VERR_NOT_SUPPORTED)
345 {
346 LogFlowFunc(("No RDP client connected, so no input recording supported\n"));
347 rc = VINF_SUCCESS;
348 }
349 }
350 else if (enmStreamCmd == PDMAUDIOSTREAMCMD_DISABLE)
351 {
352 pDrv->pConsoleVRDPServer->SendAudioInputEnd(NULL /* pvUserCtx */);
353 rc = VINF_SUCCESS;
354 }
355 else
356 rc = VERR_INVALID_PARAMETER;
357
358 return rc;
359}
360
361static DECLCALLBACK(int) drvAudioVRDEGetConf(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pCfg)
362{
363 pCfg->cbStreamOut = sizeof(VRDESTREAMOUT);
364 pCfg->cbStreamIn = sizeof(VRDESTREAMIN);
365 pCfg->cMaxHstStrmsOut = 1;
366 pCfg->cMaxHstStrmsIn = 2; /* Microphone in + Line in. */
367
368 return VINF_SUCCESS;
369}
370
371static DECLCALLBACK(void) drvAudioVRDEShutdown(PPDMIHOSTAUDIO pInterface)
372{
373 PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
374 AssertPtrReturnVoid(pDrv);
375
376 if (pDrv->pConsoleVRDPServer)
377 pDrv->pConsoleVRDPServer->SendAudioInputEnd(NULL);
378}
379
380/**
381 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
382 */
383static DECLCALLBACK(void *) drvAudioVRDEQueryInterface(PPDMIBASE pInterface, const char *pszIID)
384{
385 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
386 PDRVAUDIOVRDE pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVRDE);
387
388 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
389 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
390 return NULL;
391}
392
393AudioVRDE::AudioVRDE(Console *pConsole)
394 : mpDrv(NULL),
395 mParent(pConsole)
396{
397}
398
399AudioVRDE::~AudioVRDE(void)
400{
401 if (mpDrv)
402 {
403 mpDrv->pAudioVRDE = NULL;
404 mpDrv = NULL;
405 }
406}
407
408int AudioVRDE::onVRDEControl(bool fEnable, uint32_t uFlags)
409{
410 LogFlowThisFunc(("fEnable=%RTbool, uFlags=0x%x\n", fEnable, uFlags));
411
412 if (mpDrv == NULL)
413 return VERR_INVALID_STATE;
414
415 mpDrv->fEnabled = fEnable;
416
417 return VINF_SUCCESS; /* Never veto. */
418}
419
420/**
421 * Marks the beginning of sending captured audio data from a connected
422 * RDP client.
423 *
424 * @return IPRT status code.
425 * @param pvContext The context; in this case a pointer to a
426 * VRDESTREAMIN structure.
427 * @param pVRDEAudioBegin Pointer to a VRDEAUDIOINBEGIN structure.
428 */
429int AudioVRDE::onVRDEInputBegin(void *pvContext, PVRDEAUDIOINBEGIN pVRDEAudioBegin)
430{
431 AssertPtrReturn(pvContext, VERR_INVALID_POINTER);
432 AssertPtrReturn(pVRDEAudioBegin, VERR_INVALID_POINTER);
433
434 PVRDESTREAMIN pVRDEStrmIn = (PVRDESTREAMIN)pvContext;
435 AssertPtrReturn(pVRDEStrmIn, VERR_INVALID_POINTER);
436
437 VRDEAUDIOFORMAT audioFmt = pVRDEAudioBegin->fmt;
438
439 int iSampleHz = VRDE_AUDIO_FMT_SAMPLE_FREQ(audioFmt);
440 int cChannels = VRDE_AUDIO_FMT_CHANNELS(audioFmt);
441 int cBits = VRDE_AUDIO_FMT_BITS_PER_SAMPLE(audioFmt);
442 bool fUnsigned = VRDE_AUDIO_FMT_SIGNED(audioFmt);
443
444 LogFlowFunc(("cbSample=%RU32, iSampleHz=%d, cChannels=%d, cBits=%d, fUnsigned=%RTbool\n",
445 VRDE_AUDIO_FMT_BYTES_PER_SAMPLE(audioFmt), iSampleHz, cChannels, cBits, fUnsigned));
446
447 return VINF_SUCCESS;
448}
449
450int AudioVRDE::onVRDEInputData(void *pvContext, const void *pvData, uint32_t cbData)
451{
452 PVRDESTREAMIN pVRDEStrmIn = (PVRDESTREAMIN)pvContext;
453 AssertPtrReturn(pVRDEStrmIn, VERR_INVALID_POINTER);
454
455 PPDMAUDIOHSTSTRMIN pHstStrmIn = &pVRDEStrmIn->HstStrmIn;
456 AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
457
458 /** @todo Use CritSect! */
459
460 uint32_t cWritten;
461 int rc = AudioMixBufWriteCirc(&pHstStrmIn->MixBuf, pvData, cbData, &cWritten);
462 if (RT_SUCCESS(rc))
463 pVRDEStrmIn->cSamplesCaptured += cWritten;
464
465 LogFlowFunc(("cbData=%RU32, cWritten=%RU32, cSamplesCaptured=%RU32, rc=%Rrc\n",
466 cbData, cWritten, pVRDEStrmIn->cSamplesCaptured, rc));
467 return rc;
468}
469
470int AudioVRDE::onVRDEInputEnd(void *pvContext)
471{
472 NOREF(pvContext);
473
474 return VINF_SUCCESS;
475}
476
477int AudioVRDE::onVRDEInputIntercept(bool fEnabled)
478{
479 return VINF_SUCCESS; /* Never veto. */
480}
481
482/**
483 * Construct a VRDE audio driver instance.
484 *
485 * @copydoc FNPDMDRVCONSTRUCT
486 */
487/* static */
488DECLCALLBACK(int) AudioVRDE::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
489{
490 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
491 PDRVAUDIOVRDE pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVRDE);
492 AssertPtrReturn(pDrvIns, VERR_INVALID_POINTER);
493 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
494
495 LogRel(("Audio: Initializing VRDE driver\n"));
496 LogFlowFunc(("fFlags=0x%x\n", fFlags));
497
498 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
499 ("Configuration error: Not possible to attach anything to this driver!\n"),
500 VERR_PDM_DRVINS_NO_ATTACH);
501
502 /*
503 * Init the static parts.
504 */
505 pThis->pDrvIns = pDrvIns;
506 /* IBase */
507 pDrvIns->IBase.pfnQueryInterface = drvAudioVRDEQueryInterface;
508 /* IHostAudio */
509 PDMAUDIO_IHOSTAUDIO_CALLBACKS(drvAudioVRDE);
510
511 /* Init defaults. */
512 pThis->fEnabled = false;
513
514 /*
515 * Get the ConsoleVRDPServer object pointer.
516 */
517 void *pvUser;
518 int rc = CFGMR3QueryPtr(pCfg, "ObjectVRDPServer", &pvUser);
519 AssertMsgRCReturn(rc, ("Confguration error: No/bad \"ObjectVRDPServer\" value, rc=%Rrc\n", rc), rc);
520
521 /* CFGM tree saves the pointer to ConsoleVRDPServer in the Object node of AudioVRDE. */
522 pThis->pConsoleVRDPServer = (ConsoleVRDPServer *)pvUser;
523
524 /*
525 * Get the AudioVRDE object pointer.
526 */
527 pvUser = NULL;
528 rc = CFGMR3QueryPtr(pCfg, "Object", &pvUser);
529 AssertMsgRCReturn(rc, ("Confguration error: No/bad \"Object\" value, rc=%Rrc\n", rc), rc);
530
531 pThis->pAudioVRDE = (AudioVRDE *)pvUser;
532 pThis->pAudioVRDE->mpDrv = pThis;
533
534 /*
535 * Get the interface for the above driver (DrvAudio) to make mixer/conversion calls.
536 * Described in CFGM tree.
537 */
538 pThis->pDrvAudio = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIAUDIOCONNECTOR);
539 AssertMsgReturn(pThis->pDrvAudio, ("Configuration error: No upper interface specified!\n"), VERR_PDM_MISSING_INTERFACE_ABOVE);
540
541 return VINF_SUCCESS;
542}
543
544
545/**
546 * @interface_method_impl{PDMDRVREG,pfnDestruct}
547 */
548/* static */
549DECLCALLBACK(void) AudioVRDE::drvDestruct(PPDMDRVINS pDrvIns)
550{
551 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
552 PDRVAUDIOVRDE pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVRDE);
553 LogFlowFuncEnter();
554
555 /*
556 * If the AudioVRDE object is still alive, we must clear it's reference to
557 * us since we'll be invalid when we return from this method.
558 */
559 if (pThis->pAudioVRDE)
560 {
561 pThis->pAudioVRDE->mpDrv = NULL;
562 pThis->pAudioVRDE = NULL;
563 }
564}
565
566
567/**
568 * VRDE audio driver registration record.
569 */
570const PDMDRVREG AudioVRDE::DrvReg =
571{
572 PDM_DRVREG_VERSION,
573 /* szName */
574 "AudioVRDE",
575 /* szRCMod */
576 "",
577 /* szR0Mod */
578 "",
579 /* pszDescription */
580 "Audio driver for VRDE backend",
581 /* fFlags */
582 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
583 /* fClass. */
584 PDM_DRVREG_CLASS_AUDIO,
585 /* cMaxInstances */
586 ~0U,
587 /* cbInstance */
588 sizeof(DRVAUDIOVRDE),
589 /* pfnConstruct */
590 AudioVRDE::drvConstruct,
591 /* pfnDestruct */
592 AudioVRDE::drvDestruct,
593 /* pfnRelocate */
594 NULL,
595 /* pfnIOCtl */
596 NULL,
597 /* pfnPowerOn */
598 NULL,
599 /* pfnReset */
600 NULL,
601 /* pfnSuspend */
602 NULL,
603 /* pfnResume */
604 NULL,
605 /* pfnAttach */
606 NULL,
607 /* pfnDetach */
608 NULL,
609 /* pfnPowerOff */
610 NULL,
611 /* pfnSoftReset */
612 NULL,
613 /* u32EndVersion */
614 PDM_DRVREG_VERSION
615};
616
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