VirtualBox

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

最後變更 在這個檔案從63360是 63360,由 vboxsync 提交於 9 年 前

Audio: Added more defines / documentation for the host interfaces to keep the maintenance effort to a minimum in the future, misc. cleanup.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette