VirtualBox

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

Last change on this file since 65565 was 65565, checked in by vboxsync, 8 years ago

Audio: Make use of pvBuf/cbBuf parameters in PDMIHOSTAUDIO::pfnStreamPlay() and PDMIHOSTAUDIO::pfnStreamCapture() to further abstract the backends from the audio connector. The backends now won't be allowed to operate on the audio connector's mixing buffers directly anymore that way.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.7 KB
Line 
1/* $Id: DrvAudioVRDE.cpp 65565 2017-02-01 14:11:10Z vboxsync $ */
2/** @file
3 * VRDE audio backend for Main.
4 */
5
6/*
7 * Copyright (C) 2013-2017 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
32#include <iprt/mem.h>
33#include <iprt/cdefs.h>
34#include <iprt/circbuf.h>
35
36#include <VBox/vmm/pdmaudioifs.h>
37#include <VBox/vmm/pdmdrv.h>
38#include <VBox/RemoteDesktop/VRDE.h>
39#include <VBox/vmm/cfgm.h>
40#include <VBox/err.h>
41
42
43/*********************************************************************************************************************************
44* Structures and Typedefs *
45*********************************************************************************************************************************/
46/**
47 * Audio VRDE driver instance data.
48 */
49typedef struct DRVAUDIOVRDE
50{
51 /** Pointer to audio VRDE object. */
52 AudioVRDE *pAudioVRDE;
53 /** Pointer to the driver instance structure. */
54 PPDMDRVINS pDrvIns;
55 /** Pointer to host audio interface. */
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} DRVAUDIOVRDE, *PDRVAUDIOVRDE;
62
63typedef struct VRDESTREAMIN
64{
65 /** Note: Always must come first! */
66 PDMAUDIOSTREAM Stream;
67 /** The PCM properties of this stream. */
68 PDMAUDIOPCMPROPS Props;
69 /** Number of samples this stream can handle at once. */
70 uint32_t cSamplesMax;
71 /** Circular buffer for holding the recorded audio samples from the host. */
72 PRTCIRCBUF pCircBuf;
73} VRDESTREAMIN, *PVRDESTREAMIN;
74
75typedef struct VRDESTREAMOUT
76{
77 /** Note: Always must come first! */
78 PDMAUDIOSTREAM Stream;
79 /** The PCM properties of this stream. */
80 PDMAUDIOPCMPROPS Props;
81 uint64_t old_ticks;
82 uint64_t cSamplesSentPerSec;
83} VRDESTREAMOUT, *PVRDESTREAMOUT;
84
85
86
87static int vrdeCreateStreamIn(PVRDESTREAMIN pStreamVRDE, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
88{
89 int rc = DrvAudioHlpStreamCfgToProps(pCfgReq, &pStreamVRDE->Props);
90 if (RT_SUCCESS(rc))
91 {
92 pStreamVRDE->cSamplesMax = _1K; /** @todo Make this configurable. */
93
94 rc = RTCircBufCreate(&pStreamVRDE->pCircBuf, pStreamVRDE->cSamplesMax * (pStreamVRDE->Props.cBits / 8) /* Bytes */);
95 if (RT_SUCCESS(rc))
96 {
97 if (pCfgAcq)
98 pCfgAcq->cSampleBufferSize = pStreamVRDE->cSamplesMax;
99 }
100 }
101
102 return rc;
103}
104
105
106static int vrdeCreateStreamOut(PVRDESTREAMOUT pStreamVRDE, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
107{
108 int rc = DrvAudioHlpStreamCfgToProps(pCfgReq, &pStreamVRDE->Props);
109 if (RT_SUCCESS(rc))
110 {
111 if (pCfgAcq)
112 pCfgAcq->cSampleBufferSize = _4K; /** @todo Make this configurable. */
113 }
114
115 return rc;
116}
117
118
119static int vrdeControlStreamOut(PDRVAUDIOVRDE pDrv, PVRDESTREAMOUT pStreamVRDE, PDMAUDIOSTREAMCMD enmStreamCmd)
120{
121 RT_NOREF(pDrv, pStreamVRDE, enmStreamCmd);
122
123 LogFlowFunc(("enmStreamCmd=%ld\n", enmStreamCmd));
124
125 return VINF_SUCCESS;
126}
127
128
129static int vrdeControlStreamIn(PDRVAUDIOVRDE pDrv, PVRDESTREAMIN pVRDEStrmIn, PDMAUDIOSTREAMCMD enmStreamCmd)
130{
131 LogFlowFunc(("enmStreamCmd=%ld\n", enmStreamCmd));
132
133 if (!pDrv->pConsoleVRDPServer)
134 return VINF_SUCCESS;
135
136 int rc;
137
138 /* Initialize only if not already done. */
139 switch (enmStreamCmd)
140 {
141 case PDMAUDIOSTREAMCMD_ENABLE:
142 {
143 rc = pDrv->pConsoleVRDPServer->SendAudioInputBegin(NULL, pVRDEStrmIn, pVRDEStrmIn->cSamplesMax,
144 pVRDEStrmIn->Props.uHz,
145 pVRDEStrmIn->Props.cChannels, pVRDEStrmIn->Props.cBits);
146 if (rc == VERR_NOT_SUPPORTED)
147 {
148 LogFunc(("No RDP client connected, so no input recording supported\n"));
149 rc = VINF_SUCCESS;
150 }
151 }
152
153 case PDMAUDIOSTREAMCMD_DISABLE:
154 {
155 pDrv->pConsoleVRDPServer->SendAudioInputEnd(NULL /* pvUserCtx */);
156 rc = VINF_SUCCESS;
157 }
158
159 case PDMAUDIOSTREAMCMD_PAUSE:
160 {
161 rc = VINF_SUCCESS;
162 break;
163 }
164
165 case PDMAUDIOSTREAMCMD_RESUME:
166 {
167 rc = VINF_SUCCESS;
168 break;
169 }
170
171 default:
172 {
173 rc = VERR_NOT_SUPPORTED;
174 break;
175 }
176 }
177
178 if (RT_FAILURE(rc))
179 LogFunc(("Failed with %Rrc\n", rc));
180
181 return rc;
182}
183
184
185/**
186 * @interface_method_impl{PDMIHOSTAUDIO,pfnInit}
187 */
188static DECLCALLBACK(int) drvAudioVRDEInit(PPDMIHOSTAUDIO pInterface)
189{
190 RT_NOREF(pInterface);
191 LogFlowFuncEnter();
192
193 return VINF_SUCCESS;
194}
195
196
197/**
198 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCapture}
199 */
200static DECLCALLBACK(int) drvAudioVRDEStreamCapture(PPDMIHOSTAUDIO pInterface,
201 PPDMAUDIOSTREAM pStream, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
202{
203 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
204 AssertPtrReturn(pStream, VERR_INVALID_POINTER);
205 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
206 AssertReturn(cbBuf, VERR_INVALID_PARAMETER);
207 /* pcbRead is optional. */
208
209 PVRDESTREAMIN pStreamVRDE = (PVRDESTREAMIN)pStream;
210
211 size_t cbData = 0;
212
213 if (RTCircBufUsed(pStreamVRDE->pCircBuf))
214 {
215 void *pvData;
216
217 RTCircBufAcquireReadBlock(pStreamVRDE->pCircBuf, cbBuf, &pvData, &cbData);
218
219 if (cbData)
220 memcpy(pvBuf, pvData, cbData);
221
222 RTCircBufReleaseReadBlock(pStreamVRDE->pCircBuf, cbData);
223 }
224
225 if (pcbRead)
226 *pcbRead = (uint32_t)cbData;
227
228 return VINF_SUCCESS;
229}
230
231
232/**
233 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamPlay}
234 */
235static DECLCALLBACK(int) drvAudioVRDEStreamPlay(PPDMIHOSTAUDIO pInterface,
236 PPDMAUDIOSTREAM pStream, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)
237{
238 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
239 AssertPtrReturn(pStream, VERR_INVALID_POINTER);
240 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
241 AssertReturn(cbBuf, VERR_INVALID_PARAMETER);
242 /* pcbWritten is optional. */
243
244 PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
245 PVRDESTREAMOUT pStreamVRDE = (PVRDESTREAMOUT)pStream;
246
247 uint32_t cbLive = cbBuf;
248
249 uint64_t now = PDMDrvHlpTMGetVirtualTime(pDrv->pDrvIns);
250 uint64_t ticks = now - pStreamVRDE->old_ticks;
251 uint64_t ticks_per_second = PDMDrvHlpTMGetVirtualFreq(pDrv->pDrvIns);
252
253 /* Minimize the rounding error: samples = int((ticks * freq) / ticks_per_second + 0.5). */
254 uint32_t cbToWrite = (int)((2 * ticks * pStreamVRDE->Props.uHz + ticks_per_second) / ticks_per_second / 2);
255
256 /* Remember when samples were consumed. */
257 pStreamVRDE->old_ticks = now;
258
259 VRDEAUDIOFORMAT format = VRDE_AUDIO_FMT_MAKE(pStreamVRDE->Props.uHz,
260 pStreamVRDE->Props.cChannels,
261 pStreamVRDE->Props.cBits,
262 pStreamVRDE->Props.fSigned);
263
264 Log2Func(("uFreq=%RU32, cChan=%RU8, cBits=%RU8, fSigned=%RTbool, enmFormat=%ld, cbLive=%RU32, cbToWrite=%RU32\n",
265 pStreamVRDE->Props.uHz, pStreamVRDE->Props.cChannels,
266 pStreamVRDE->Props.cBits, pStreamVRDE->Props.fSigned,
267 format, cbLive, cbToWrite));
268
269 /* Don't play more than available. */
270 if (cbToWrite > cbLive)
271 cbToWrite = cbLive;
272
273 int rc = VINF_SUCCESS;
274
275 /*
276 * Call the VRDP server with the data.
277 */
278 uint32_t cbWritten = 0;
279
280 while (cbToWrite)
281 {
282 uint32_t cbChunk = cbToWrite; /** @todo For now write all at once. */
283
284 pDrv->pConsoleVRDPServer->SendAudioSamples((uint8_t *)pvBuf + cbWritten, cbChunk, format);
285
286 cbWritten += cbChunk;
287 Assert(cbWritten <= cbBuf);
288
289 Assert(cbToWrite >= cbChunk);
290 cbToWrite -= cbChunk;
291 }
292
293 if (RT_SUCCESS(rc))
294 {
295 /*
296 * Always report back all samples acquired, regardless of whether the
297 * VRDP server actually did process those.
298 */
299 if (pcbWritten)
300 *pcbWritten = cbToWrite;
301 }
302
303 return rc;
304}
305
306
307static int vrdeDestroyStreamIn(PDRVAUDIOVRDE pDrv, PVRDESTREAMIN pStreamVRDE)
308{
309 if (pDrv->pConsoleVRDPServer)
310 pDrv->pConsoleVRDPServer->SendAudioInputEnd(NULL);
311
312 if (pStreamVRDE->pCircBuf)
313 {
314 RTCircBufDestroy(pStreamVRDE->pCircBuf);
315 pStreamVRDE->pCircBuf = NULL;
316 }
317
318 return VINF_SUCCESS;
319}
320
321
322static int vrdeDestroyStreamOut(PDRVAUDIOVRDE pDrv, PVRDESTREAMOUT pStreamVRDE)
323{
324 RT_NOREF(pDrv, pStreamVRDE);
325
326 return VINF_SUCCESS;
327}
328
329
330/**
331 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetConfig}
332 */
333static DECLCALLBACK(int) drvAudioVRDEGetConfig(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pBackendCfg)
334{
335 NOREF(pInterface);
336 AssertPtrReturn(pBackendCfg, VERR_INVALID_POINTER);
337
338 pBackendCfg->cbStreamOut = sizeof(VRDESTREAMOUT);
339 pBackendCfg->cbStreamIn = sizeof(VRDESTREAMIN);
340 pBackendCfg->cMaxStreamsIn = UINT32_MAX;
341 pBackendCfg->cMaxStreamsOut = UINT32_MAX;
342
343 return VINF_SUCCESS;
344}
345
346
347/**
348 * @interface_method_impl{PDMIHOSTAUDIO,pfnShutdown}
349 */
350static DECLCALLBACK(void) drvAudioVRDEShutdown(PPDMIHOSTAUDIO pInterface)
351{
352 PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
353 AssertPtrReturnVoid(pDrv);
354
355 if (pDrv->pConsoleVRDPServer)
356 pDrv->pConsoleVRDPServer->SendAudioInputEnd(NULL);
357}
358
359
360/**
361 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetStatus}
362 */
363static DECLCALLBACK(PDMAUDIOBACKENDSTS) drvAudioVRDEGetStatus(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
364{
365 RT_NOREF(enmDir);
366 AssertPtrReturn(pInterface, PDMAUDIOBACKENDSTS_UNKNOWN);
367
368 return PDMAUDIOBACKENDSTS_RUNNING;
369}
370
371
372/**
373 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCreate}
374 */
375static DECLCALLBACK(int) drvAudioVRDEStreamCreate(PPDMIHOSTAUDIO pInterface,
376 PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
377{
378 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
379 AssertPtrReturn(pStream, VERR_INVALID_POINTER);
380 AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
381 AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER);
382
383 RT_NOREF(pInterface);
384
385 int rc;
386 if (pCfgReq->enmDir == PDMAUDIODIR_IN)
387 {
388 PVRDESTREAMIN pStreamVRDE = (PVRDESTREAMIN)pStream;
389 rc = vrdeCreateStreamIn(pStreamVRDE, pCfgReq, pCfgAcq);
390 }
391 else
392 {
393 PVRDESTREAMOUT pStreamVRDE = (PVRDESTREAMOUT)pStream;
394 rc = vrdeCreateStreamOut(pStreamVRDE, pCfgReq, pCfgAcq);
395 }
396
397 return rc;
398}
399
400
401/**
402 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDestroy}
403 */
404static DECLCALLBACK(int) drvAudioVRDEStreamDestroy(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
405{
406 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
407 AssertPtrReturn(pStream, VERR_INVALID_POINTER);
408
409 PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
410
411 int rc;
412 if (pStream->enmDir == PDMAUDIODIR_IN)
413 {
414 PVRDESTREAMIN pStreamVRDE = (PVRDESTREAMIN)pStream;
415 rc = vrdeDestroyStreamIn(pDrv, pStreamVRDE);
416 }
417 else
418 {
419 PVRDESTREAMOUT pStreamVRDE = (PVRDESTREAMOUT)pStream;
420 rc = vrdeDestroyStreamOut(pDrv, pStreamVRDE);
421 }
422
423 return rc;
424}
425
426
427/**
428 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamControl}
429 */
430static DECLCALLBACK(int) drvAudioVRDEStreamControl(PPDMIHOSTAUDIO pInterface,
431 PPDMAUDIOSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd)
432{
433 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
434 AssertPtrReturn(pStream, VERR_INVALID_POINTER);
435
436 PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
437
438 int rc;
439 if (pStream->enmDir == PDMAUDIODIR_IN)
440 {
441 PVRDESTREAMIN pStreamVRDE = (PVRDESTREAMIN)pStream;
442 rc = vrdeControlStreamIn(pDrv, pStreamVRDE, enmStreamCmd);
443 }
444 else
445 {
446 PVRDESTREAMOUT pStreamVRDE = (PVRDESTREAMOUT)pStream;
447 rc = vrdeControlStreamOut(pDrv, pStreamVRDE, enmStreamCmd);
448 }
449
450 return rc;
451}
452
453
454/**
455 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetStatus}
456 */
457static DECLCALLBACK(PDMAUDIOSTRMSTS) drvAudioVRDEStreamGetStatus(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
458{
459 NOREF(pInterface);
460 NOREF(pStream);
461
462 return ( PDMAUDIOSTRMSTS_FLAG_INITIALIZED | PDMAUDIOSTRMSTS_FLAG_ENABLED
463 | PDMAUDIOSTRMSTS_FLAG_DATA_READABLE | PDMAUDIOSTRMSTS_FLAG_DATA_WRITABLE);
464}
465
466
467/**
468 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamIterate}
469 */
470static DECLCALLBACK(int) drvAudioVRDEStreamIterate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
471{
472 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
473 AssertPtrReturn(pStream, VERR_INVALID_POINTER);
474
475 LogFlowFuncEnter();
476
477 /* Nothing to do here for VRDE. */
478 return VINF_SUCCESS;
479}
480
481
482/**
483 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
484 */
485static DECLCALLBACK(void *) drvAudioVRDEQueryInterface(PPDMIBASE pInterface, const char *pszIID)
486{
487 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
488 PDRVAUDIOVRDE pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVRDE);
489
490 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
491 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
492 return NULL;
493}
494
495
496AudioVRDE::AudioVRDE(Console *pConsole)
497 : mpDrv(NULL),
498 mParent(pConsole)
499{
500}
501
502
503AudioVRDE::~AudioVRDE(void)
504{
505 if (mpDrv)
506 {
507 mpDrv->pAudioVRDE = NULL;
508 mpDrv = NULL;
509 }
510}
511
512
513int AudioVRDE::onVRDEControl(bool fEnable, uint32_t uFlags)
514{
515 RT_NOREF(fEnable, uFlags);
516 LogFlowThisFunc(("fEnable=%RTbool, uFlags=0x%x\n", fEnable, uFlags));
517
518 if (mpDrv == NULL)
519 return VERR_INVALID_STATE;
520
521 return VINF_SUCCESS; /* Never veto. */
522}
523
524
525/**
526 * Marks the beginning of sending captured audio data from a connected
527 * RDP client.
528 *
529 * @return IPRT status code.
530 * @param pvContext The context; in this case a pointer to a
531 * VRDESTREAMIN structure.
532 * @param pVRDEAudioBegin Pointer to a VRDEAUDIOINBEGIN structure.
533 */
534int AudioVRDE::onVRDEInputBegin(void *pvContext, PVRDEAUDIOINBEGIN pVRDEAudioBegin)
535{
536 AssertPtrReturn(pvContext, VERR_INVALID_POINTER);
537 AssertPtrReturn(pVRDEAudioBegin, VERR_INVALID_POINTER);
538
539 PVRDESTREAMIN pVRDEStrmIn = (PVRDESTREAMIN)pvContext;
540 AssertPtrReturn(pVRDEStrmIn, VERR_INVALID_POINTER);
541
542 VRDEAUDIOFORMAT audioFmt = pVRDEAudioBegin->fmt;
543
544 int iSampleHz = VRDE_AUDIO_FMT_SAMPLE_FREQ(audioFmt); NOREF(iSampleHz);
545 int cChannels = VRDE_AUDIO_FMT_CHANNELS(audioFmt); NOREF(cChannels);
546 int cBits = VRDE_AUDIO_FMT_BITS_PER_SAMPLE(audioFmt); NOREF(cBits);
547 bool fUnsigned = VRDE_AUDIO_FMT_SIGNED(audioFmt); NOREF(fUnsigned);
548
549 LogFlowFunc(("cbSample=%RU32, iSampleHz=%d, cChannels=%d, cBits=%d, fUnsigned=%RTbool\n",
550 VRDE_AUDIO_FMT_BYTES_PER_SAMPLE(audioFmt), iSampleHz, cChannels, cBits, fUnsigned));
551
552 return VINF_SUCCESS;
553}
554
555
556int AudioVRDE::onVRDEInputData(void *pvContext, const void *pvData, uint32_t cbData)
557{
558 PVRDESTREAMIN pStreamVRDE = (PVRDESTREAMIN)pvContext;
559 AssertPtrReturn(pStreamVRDE, VERR_INVALID_POINTER);
560
561 void *pvBuf;
562 size_t cbBuf;
563
564 RTCircBufAcquireWriteBlock(pStreamVRDE->pCircBuf, cbData, &pvBuf, &cbBuf);
565
566 if (cbBuf)
567 memcpy(pvBuf, pvData, cbBuf);
568
569 RTCircBufReleaseWriteBlock(pStreamVRDE->pCircBuf, cbBuf);
570
571 if (cbBuf < cbData)
572 LogRel(("VRDE: Capturing audio data lost %zu bytes\n", cbData - cbBuf)); /** @todo Use an error counter. */
573
574 return VINF_SUCCESS; /** @todo r=andy How to tell the caller if we were not able to handle *all* input data? */
575}
576
577
578int AudioVRDE::onVRDEInputEnd(void *pvContext)
579{
580 NOREF(pvContext);
581
582 return VINF_SUCCESS;
583}
584
585
586int AudioVRDE::onVRDEInputIntercept(bool fEnabled)
587{
588 RT_NOREF(fEnabled);
589 return VINF_SUCCESS; /* Never veto. */
590}
591
592
593/**
594 * Construct a VRDE audio driver instance.
595 *
596 * @copydoc FNPDMDRVCONSTRUCT
597 */
598/* static */
599DECLCALLBACK(int) AudioVRDE::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
600{
601 RT_NOREF(fFlags);
602
603 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
604 PDRVAUDIOVRDE pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVRDE);
605
606 AssertPtrReturn(pDrvIns, VERR_INVALID_POINTER);
607 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
608
609 LogRel(("Audio: Initializing VRDE driver\n"));
610 LogFlowFunc(("fFlags=0x%x\n", fFlags));
611
612 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
613 ("Configuration error: Not possible to attach anything to this driver!\n"),
614 VERR_PDM_DRVINS_NO_ATTACH);
615
616 /*
617 * Init the static parts.
618 */
619 pThis->pDrvIns = pDrvIns;
620 /* IBase */
621 pDrvIns->IBase.pfnQueryInterface = drvAudioVRDEQueryInterface;
622 /* IHostAudio */
623 PDMAUDIO_IHOSTAUDIO_CALLBACKS(drvAudioVRDE);
624
625 /*
626 * Get the ConsoleVRDPServer object pointer.
627 */
628 void *pvUser;
629 int rc = CFGMR3QueryPtr(pCfg, "ObjectVRDPServer", &pvUser); /** @todo r=andy Get rid of this hack and use IHostAudio::SetCallback. */
630 AssertMsgRCReturn(rc, ("Confguration error: No/bad \"ObjectVRDPServer\" value, rc=%Rrc\n", rc), rc);
631
632 /* CFGM tree saves the pointer to ConsoleVRDPServer in the Object node of AudioVRDE. */
633 pThis->pConsoleVRDPServer = (ConsoleVRDPServer *)pvUser;
634
635 /*
636 * Get the AudioVRDE object pointer.
637 */
638 pvUser = NULL;
639 rc = CFGMR3QueryPtr(pCfg, "Object", &pvUser); /** @todo r=andy Get rid of this hack and use IHostAudio::SetCallback. */
640 AssertMsgRCReturn(rc, ("Confguration error: No/bad \"Object\" value, rc=%Rrc\n", rc), rc);
641
642 pThis->pAudioVRDE = (AudioVRDE *)pvUser;
643 pThis->pAudioVRDE->mpDrv = pThis;
644
645 /*
646 * Get the interface for the above driver (DrvAudio) to make mixer/conversion calls.
647 * Described in CFGM tree.
648 */
649 pThis->pDrvAudio = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIAUDIOCONNECTOR);
650 AssertMsgReturn(pThis->pDrvAudio, ("Configuration error: No upper interface specified!\n"), VERR_PDM_MISSING_INTERFACE_ABOVE);
651
652 return VINF_SUCCESS;
653}
654
655
656/**
657 * @interface_method_impl{PDMDRVREG,pfnDestruct}
658 */
659/* static */
660DECLCALLBACK(void) AudioVRDE::drvDestruct(PPDMDRVINS pDrvIns)
661{
662 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
663 PDRVAUDIOVRDE pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVRDE);
664 LogFlowFuncEnter();
665
666 /*
667 * If the AudioVRDE object is still alive, we must clear it's reference to
668 * us since we'll be invalid when we return from this method.
669 */
670 if (pThis->pAudioVRDE)
671 {
672 pThis->pAudioVRDE->mpDrv = NULL;
673 pThis->pAudioVRDE = NULL;
674 }
675}
676
677
678/**
679 * VRDE audio driver registration record.
680 */
681const PDMDRVREG AudioVRDE::DrvReg =
682{
683 PDM_DRVREG_VERSION,
684 /* szName */
685 "AudioVRDE",
686 /* szRCMod */
687 "",
688 /* szR0Mod */
689 "",
690 /* pszDescription */
691 "Audio driver for VRDE backend",
692 /* fFlags */
693 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
694 /* fClass. */
695 PDM_DRVREG_CLASS_AUDIO,
696 /* cMaxInstances */
697 ~0U,
698 /* cbInstance */
699 sizeof(DRVAUDIOVRDE),
700 /* pfnConstruct */
701 AudioVRDE::drvConstruct,
702 /* pfnDestruct */
703 AudioVRDE::drvDestruct,
704 /* pfnRelocate */
705 NULL,
706 /* pfnIOCtl */
707 NULL,
708 /* pfnPowerOn */
709 NULL,
710 /* pfnReset */
711 NULL,
712 /* pfnSuspend */
713 NULL,
714 /* pfnResume */
715 NULL,
716 /* pfnAttach */
717 NULL,
718 /* pfnDetach */
719 NULL,
720 /* pfnPowerOff */
721 NULL,
722 /* pfnSoftReset */
723 NULL,
724 /* u32EndVersion */
725 PDM_DRVREG_VERSION
726};
727
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