VirtualBox

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

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

Main/DrvAudioVRDE: callback fixes

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