VirtualBox

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

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

Audio: Implemented support for audio device enumeration handling, audio device information and audio backend notifications. This will enable to let the backends tell the audio subsystem that the host audio configuration has changed and react accordingly to it. For now only the Core Audio backend supports device enumeration. Further this also will get rid of the static initialization on the device emulation side, which, if at VM startup no audio input(s) / output(s) were available, was triggering a warning. The NULL backend therefore does not need to act as a (static) fallback anymore.

Work in progress.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.7 KB
Line 
1/* $Id: DrvAudioVRDE.cpp 63711 2016-09-05 12:04:01Z 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
366 return VINF_SUCCESS;
367}
368
369
370/**
371 * @interface_method_impl{PDMIHOSTAUDIO,pfnShutdown}
372 */
373static DECLCALLBACK(void) drvAudioVRDEShutdown(PPDMIHOSTAUDIO pInterface)
374{
375 PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
376 AssertPtrReturnVoid(pDrv);
377
378 if (pDrv->pConsoleVRDPServer)
379 pDrv->pConsoleVRDPServer->SendAudioInputEnd(NULL);
380}
381
382
383/**
384 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetStatus}
385 */
386static DECLCALLBACK(PDMAUDIOBACKENDSTS) drvAudioVRDEGetStatus(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
387{
388 RT_NOREF(enmDir);
389 AssertPtrReturn(pInterface, PDMAUDIOBACKENDSTS_UNKNOWN);
390
391 return PDMAUDIOBACKENDSTS_RUNNING;
392}
393
394
395/**
396 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCreate}
397 */
398static DECLCALLBACK(int) drvAudioVRDEStreamCreate(PPDMIHOSTAUDIO pInterface,
399 PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
400{
401 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
402 AssertPtrReturn(pStream, VERR_INVALID_POINTER);
403 AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
404 AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER);
405
406 int rc;
407 if (pCfgReq->enmDir == PDMAUDIODIR_IN)
408 rc = vrdeCreateStreamIn(pInterface, pStream, pCfgReq, pCfgAcq);
409 else
410 rc = vrdeCreateStreamOut(pInterface, pStream, pCfgReq, pCfgAcq);
411
412 return rc;
413}
414
415
416/**
417 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDestroy}
418 */
419static DECLCALLBACK(int) drvAudioVRDEStreamDestroy(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
420{
421 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
422 AssertPtrReturn(pStream, VERR_INVALID_POINTER);
423
424 int rc;
425 if (pStream->enmDir == PDMAUDIODIR_IN)
426 rc = vrdeDestroyStreamIn(pInterface, pStream);
427 else
428 rc = vrdeDestroyStreamOut(pInterface, pStream);
429
430 return rc;
431}
432
433
434/**
435 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamControl}
436 */
437static DECLCALLBACK(int) drvAudioVRDEStreamControl(PPDMIHOSTAUDIO pInterface,
438 PPDMAUDIOSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd)
439{
440 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
441 AssertPtrReturn(pStream, VERR_INVALID_POINTER);
442
443 Assert(pStream->enmCtx == PDMAUDIOSTREAMCTX_HOST);
444
445 int rc;
446 if (pStream->enmDir == PDMAUDIODIR_IN)
447 rc = vrdeControlStreamIn(pInterface, pStream, enmStreamCmd);
448 else
449 rc = vrdeControlStreamOut(pInterface, pStream, enmStreamCmd);
450
451 return rc;
452}
453
454
455/**
456 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetStatus}
457 */
458static DECLCALLBACK(PDMAUDIOSTRMSTS) drvAudioVRDEStreamGetStatus(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
459{
460 NOREF(pInterface);
461 NOREF(pStream);
462
463 return ( PDMAUDIOSTRMSTS_FLAG_INITIALIZED | PDMAUDIOSTRMSTS_FLAG_ENABLED
464 | PDMAUDIOSTRMSTS_FLAG_DATA_READABLE | PDMAUDIOSTRMSTS_FLAG_DATA_WRITABLE);
465}
466
467
468/**
469 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamIterate}
470 */
471static DECLCALLBACK(int) drvAudioVRDEStreamIterate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
472{
473 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
474 AssertPtrReturn(pStream, VERR_INVALID_POINTER);
475
476 LogFlowFuncEnter();
477
478 /* Nothing to do here for VRDE. */
479 return VINF_SUCCESS;
480}
481
482
483/**
484 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
485 */
486static DECLCALLBACK(void *) drvAudioVRDEQueryInterface(PPDMIBASE pInterface, const char *pszIID)
487{
488 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
489 PDRVAUDIOVRDE pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVRDE);
490
491 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
492 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
493 return NULL;
494}
495
496
497AudioVRDE::AudioVRDE(Console *pConsole)
498 : mpDrv(NULL),
499 mParent(pConsole)
500{
501}
502
503
504AudioVRDE::~AudioVRDE(void)
505{
506 if (mpDrv)
507 {
508 mpDrv->pAudioVRDE = NULL;
509 mpDrv = NULL;
510 }
511}
512
513
514int AudioVRDE::onVRDEControl(bool fEnable, uint32_t uFlags)
515{
516 RT_NOREF(fEnable, uFlags);
517 LogFlowThisFunc(("fEnable=%RTbool, uFlags=0x%x\n", fEnable, uFlags));
518
519 if (mpDrv == NULL)
520 return VERR_INVALID_STATE;
521
522 return VINF_SUCCESS; /* Never veto. */
523}
524
525
526/**
527 * Marks the beginning of sending captured audio data from a connected
528 * RDP client.
529 *
530 * @return IPRT status code.
531 * @param pvContext The context; in this case a pointer to a
532 * VRDESTREAMIN structure.
533 * @param pVRDEAudioBegin Pointer to a VRDEAUDIOINBEGIN structure.
534 */
535int AudioVRDE::onVRDEInputBegin(void *pvContext, PVRDEAUDIOINBEGIN pVRDEAudioBegin)
536{
537 AssertPtrReturn(pvContext, VERR_INVALID_POINTER);
538 AssertPtrReturn(pVRDEAudioBegin, VERR_INVALID_POINTER);
539
540 PVRDESTREAMIN pVRDEStrmIn = (PVRDESTREAMIN)pvContext;
541 AssertPtrReturn(pVRDEStrmIn, VERR_INVALID_POINTER);
542
543 VRDEAUDIOFORMAT audioFmt = pVRDEAudioBegin->fmt;
544
545 int iSampleHz = VRDE_AUDIO_FMT_SAMPLE_FREQ(audioFmt); NOREF(iSampleHz);
546 int cChannels = VRDE_AUDIO_FMT_CHANNELS(audioFmt); NOREF(cChannels);
547 int cBits = VRDE_AUDIO_FMT_BITS_PER_SAMPLE(audioFmt); NOREF(cBits);
548 bool fUnsigned = VRDE_AUDIO_FMT_SIGNED(audioFmt); NOREF(fUnsigned);
549
550 LogFlowFunc(("cbSample=%RU32, iSampleHz=%d, cChannels=%d, cBits=%d, fUnsigned=%RTbool\n",
551 VRDE_AUDIO_FMT_BYTES_PER_SAMPLE(audioFmt), iSampleHz, cChannels, cBits, fUnsigned));
552
553 return VINF_SUCCESS;
554}
555
556
557int AudioVRDE::onVRDEInputData(void *pvContext, const void *pvData, uint32_t cbData)
558{
559 PVRDESTREAMIN pVRDEStrmIn = (PVRDESTREAMIN)pvContext;
560 AssertPtrReturn(pVRDEStrmIn, VERR_INVALID_POINTER);
561
562 PPDMAUDIOSTREAM pStream = &pVRDEStrmIn->Stream;
563 AssertPtrReturn(pStream, VERR_INVALID_POINTER);
564
565 /** @todo Use CritSect! */
566
567 uint32_t cWritten;
568 int rc = AudioMixBufWriteCirc(&pStream->MixBuf, pvData, cbData, &cWritten);
569 if (RT_SUCCESS(rc))
570 pVRDEStrmIn->cSamplesCaptured += cWritten;
571
572 LogFlowFunc(("cbData=%RU32, cWritten=%RU32, cSamplesCaptured=%RU32, rc=%Rrc\n",
573 cbData, cWritten, pVRDEStrmIn->cSamplesCaptured, rc));
574 return rc;
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