VirtualBox

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

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

Audio/DrvAudioVRDE.cpp: Handle PDMAUDIOSTREAMCMD_PAUSE and PDMAUDIOSTREAMCMD_RESUME as well.

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