VirtualBox

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

Last change on this file since 54803 was 54493, checked in by vboxsync, 10 years ago

Build fix.

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