VirtualBox

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

Last change on this file since 63534 was 63534, checked in by vboxsync, 9 years ago

Audio: Renaming.

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