VirtualBox

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

Last change on this file was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 28.8 KB
RevLine 
[25966]1/* $Id: DrvAudioVRDE.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
[1]2/** @file
[53442]3 * VRDE audio backend for Main.
[1]4 */
5
6/*
[98103]7 * Copyright (C) 2013-2023 Oracle and/or its affiliates.
[1]8 *
[96407]9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
[1]26 */
[54996]27
28
[57358]29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
[65694]32#define LOG_GROUP LOG_GROUP_DRV_HOST_AUDIO
[67914]33#include "LoggingNew.h"
34
[56648]35#include <VBox/log.h>
[50686]36#include "DrvAudioVRDE.h"
[1]37#include "ConsoleImpl.h"
38#include "ConsoleVRDPServer.h"
39
[53442]40#include <iprt/mem.h>
41#include <iprt/cdefs.h>
42#include <iprt/circbuf.h>
43
[88028]44#include <VBox/vmm/cfgm.h>
45#include <VBox/vmm/pdmdrv.h>
[50686]46#include <VBox/vmm/pdmaudioifs.h>
[88028]47#include <VBox/vmm/pdmaudioinline.h>
[93444]48#include <VBox/vmm/vmmr3vtable.h>
[33004]49#include <VBox/RemoteDesktop/VRDE.h>
[1]50#include <VBox/err.h>
51
[57358]52
53/*********************************************************************************************************************************
54* Structures and Typedefs *
55*********************************************************************************************************************************/
[53442]56/**
[88460]57 * VRDE stream.
[53442]58 */
[88460]59typedef struct VRDESTREAM
60{
[88718]61 /** Common part. */
62 PDMAUDIOBACKENDSTREAM Core;
[88460]63 /** The stream's acquired configuration. */
[88718]64 PDMAUDIOSTREAMCFG Cfg;
[88460]65 union
66 {
67 struct
68 {
69 /** Circular buffer for holding the recorded audio frames from the host. */
[88718]70 PRTCIRCBUF pCircBuf;
[88460]71 } In;
72 };
73} VRDESTREAM;
74/** Pointer to a VRDE stream. */
75typedef VRDESTREAM *PVRDESTREAM;
76
77/**
78 * VRDE (host) audio driver instance data.
79 */
[53442]80typedef struct DRVAUDIOVRDE
[50686]81{
[53442]82 /** Pointer to audio VRDE object. */
83 AudioVRDE *pAudioVRDE;
[63529]84 /** Pointer to the driver instance structure. */
[53442]85 PPDMDRVINS pDrvIns;
[54230]86 /** Pointer to the VRDP's console object. */
[53442]87 ConsoleVRDPServer *pConsoleVRDPServer;
[73370]88 /** Number of connected clients to this VRDE instance. */
89 uint32_t cClients;
[88885]90 /** Interface to the driver above us (DrvAudio). */
91 PDMIHOSTAUDIOPORT *pIHostAudioPort;
[88460]92 /** Pointer to host audio interface. */
93 PDMIHOSTAUDIO IHostAudio;
94} DRVAUDIOVRDE;
95/** Pointer to the instance data for an VRDE audio driver. */
96typedef DRVAUDIOVRDE *PDRVAUDIOVRDE;
[1]97
[65624]98
[88460]99/*********************************************************************************************************************************
100* Class AudioVRDE *
101*********************************************************************************************************************************/
102
103AudioVRDE::AudioVRDE(Console *pConsole)
104 : AudioDriver(pConsole)
105 , mpDrv(NULL)
[50686]106{
[88885]107 RTCritSectInit(&mCritSect);
[88460]108}
[50686]109
[73370]110
[88460]111AudioVRDE::~AudioVRDE(void)
112{
[88885]113 RTCritSectEnter(&mCritSect);
[88460]114 if (mpDrv)
[63529]115 {
[88460]116 mpDrv->pAudioVRDE = NULL;
117 mpDrv = NULL;
[63529]118 }
[88885]119 RTCritSectLeave(&mCritSect);
120 RTCritSectDelete(&mCritSect);
[54230]121}
122
[63360]123
[93444]124int AudioVRDE::configureDriver(PCFGMNODE pLunCfg, PCVMMR3VTABLE pVMM)
[50686]125{
[93444]126 return AudioDriver::configureDriver(pLunCfg, pVMM);
[50686]127}
128
[63360]129
[88460]130void AudioVRDE::onVRDEClientConnect(uint32_t uClientID)
[50686]131{
[88460]132 RT_NOREF(uClientID);
[50686]133
[88885]134 RTCritSectEnter(&mCritSect);
[88460]135 if (mpDrv)
[88885]136 {
[88460]137 mpDrv->cClients++;
[88885]138 LogRel2(("Audio: VRDE client connected (#%u)\n", mpDrv->cClients));
139
140#if 0 /* later, maybe */
141 /*
142 * The first client triggers a device change event in both directions
143 * so that can start talking to the audio device.
144 *
145 * Note! Should be okay to stay in the critical section here, as it's only
146 * used at construction and destruction time.
147 */
148 if (mpDrv->cClients == 1)
149 {
150 VMSTATE enmState = PDMDrvHlpVMState(mpDrv->pDrvIns);
151 if (enmState <= VMSTATE_POWERING_OFF)
152 {
153 PDMIHOSTAUDIOPORT *pIHostAudioPort = mpDrv->pIHostAudioPort;
154 AssertPtr(pIHostAudioPort);
155 pIHostAudioPort->pfnNotifyDeviceChanged(pIHostAudioPort, PDMAUDIODIR_OUT, NULL /*pvUser*/);
156 pIHostAudioPort->pfnNotifyDeviceChanged(pIHostAudioPort, PDMAUDIODIR_IN, NULL /*pvUser*/);
157 }
158 }
159#endif
160 }
161 RTCritSectLeave(&mCritSect);
[50686]162}
163
[63360]164
[88460]165void AudioVRDE::onVRDEClientDisconnect(uint32_t uClientID)
[61157]166{
[88460]167 RT_NOREF(uClientID);
[61157]168
[88885]169 RTCritSectEnter(&mCritSect);
[88460]170 if (mpDrv)
[88885]171 {
172 Assert(mpDrv->cClients > 0);
[88460]173 mpDrv->cClients--;
[88885]174 LogRel2(("Audio: VRDE client disconnected (%u left)\n", mpDrv->cClients));
175#if 0 /* later maybe */
176 /*
177 * The last client leaving triggers a device change event in both
178 * directions so the audio devices can stop wasting time trying to
179 * talk to us. (There is an additional safeguard in
180 * drvAudioVrdeHA_StreamGetStatus.)
181 */
182 if (mpDrv->cClients == 0)
183 {
184 VMSTATE enmState = PDMDrvHlpVMState(mpDrv->pDrvIns);
185 if (enmState <= VMSTATE_POWERING_OFF)
186 {
187 PDMIHOSTAUDIOPORT *pIHostAudioPort = mpDrv->pIHostAudioPort;
188 AssertPtr(pIHostAudioPort);
189 pIHostAudioPort->pfnNotifyDeviceChanged(pIHostAudioPort, PDMAUDIODIR_OUT, NULL /*pvUser*/);
190 pIHostAudioPort->pfnNotifyDeviceChanged(pIHostAudioPort, PDMAUDIODIR_IN, NULL /*pvUser*/);
191 }
192 }
193#endif
194 }
195 RTCritSectLeave(&mCritSect);
[88460]196}
[61157]197
[63973]198
[88460]199int AudioVRDE::onVRDEControl(bool fEnable, uint32_t uFlags)
200{
201 RT_NOREF(fEnable, uFlags);
202 LogFlowThisFunc(("fEnable=%RTbool, uFlags=0x%x\n", fEnable, uFlags));
[65586]203
[88460]204 if (mpDrv == NULL)
205 return VERR_INVALID_STATE;
[63973]206
[88460]207 return VINF_SUCCESS; /* Never veto. */
208}
[65586]209
[63973]210
[63360]211/**
[88460]212 * Marks the beginning of sending captured audio data from a connected
213 * RDP client.
214 *
215 * @returns VBox status code.
216 * @param pvContext The context; in this case a pointer to a
217 * VRDESTREAMIN structure.
218 * @param pVRDEAudioBegin Pointer to a VRDEAUDIOINBEGIN structure.
[1]219 */
[88460]220int AudioVRDE::onVRDEInputBegin(void *pvContext, PVRDEAUDIOINBEGIN pVRDEAudioBegin)
[1]221{
[88460]222 AssertPtrReturn(pvContext, VERR_INVALID_POINTER);
223 AssertPtrReturn(pVRDEAudioBegin, VERR_INVALID_POINTER);
224 PVRDESTREAM pVRDEStrmIn = (PVRDESTREAM)pvContext;
225 AssertPtrReturn(pVRDEStrmIn, VERR_INVALID_POINTER);
[1]226
[88460]227#ifdef LOG_ENABLED
228 VRDEAUDIOFORMAT const audioFmt = pVRDEAudioBegin->fmt;
229 LogFlowFunc(("cbSample=%RU32, iSampleHz=%d, cChannels=%d, cBits=%d, fUnsigned=%RTbool\n",
230 VRDE_AUDIO_FMT_BYTES_PER_SAMPLE(audioFmt), VRDE_AUDIO_FMT_SAMPLE_FREQ(audioFmt),
231 VRDE_AUDIO_FMT_CHANNELS(audioFmt), VRDE_AUDIO_FMT_BITS_PER_SAMPLE(audioFmt), VRDE_AUDIO_FMT_SIGNED(audioFmt)));
232#endif
[1]233
[65565]234 return VINF_SUCCESS;
[50686]235}
[1]236
[63360]237
[88460]238int AudioVRDE::onVRDEInputData(void *pvContext, const void *pvData, uint32_t cbData)
[50686]239{
[88460]240 PVRDESTREAM pStreamVRDE = (PVRDESTREAM)pvContext;
241 AssertPtrReturn(pStreamVRDE, VERR_INVALID_POINTER);
[89543]242 LogFlowFunc(("cbData=%#x\n", cbData));
[1]243
[88460]244 void *pvBuf = NULL;
245 size_t cbBuf = 0;
246 RTCircBufAcquireWriteBlock(pStreamVRDE->In.pCircBuf, cbData, &pvBuf, &cbBuf);
[65694]247
[88460]248 if (cbBuf)
249 memcpy(pvBuf, pvData, cbBuf);
[65694]250
[88460]251 RTCircBufReleaseWriteBlock(pStreamVRDE->In.pCircBuf, cbBuf);
[65694]252
[88460]253 if (cbBuf < cbData)
254 LogRelMax(999, ("VRDE: Capturing audio data lost %zu bytes\n", cbData - cbBuf)); /** @todo Use an error counter. */
[55650]255
[88460]256 return VINF_SUCCESS; /** @todo r=andy How to tell the caller if we were not able to handle *all* input data? */
257}
[50686]258
[53831]259
[88460]260int AudioVRDE::onVRDEInputEnd(void *pvContext)
261{
262 RT_NOREF(pvContext);
[88253]263 return VINF_SUCCESS;
[50686]264}
265
[63360]266
[88460]267int AudioVRDE::onVRDEInputIntercept(bool fEnabled)
[50686]268{
[88460]269 RT_NOREF(fEnabled);
270 return VINF_SUCCESS; /* Never veto. */
[50686]271}
272
[63360]273
[50686]274
[88460]275/*********************************************************************************************************************************
276* PDMIHOSTAUDIO *
277*********************************************************************************************************************************/
[50686]278
[63360]279/**
280 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetConfig}
281 */
[82255]282static DECLCALLBACK(int) drvAudioVrdeHA_GetConfig(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pBackendCfg)
[50686]283{
[65624]284 RT_NOREF(pInterface);
[63360]285 AssertPtrReturn(pBackendCfg, VERR_INVALID_POINTER);
[50686]286
[88460]287 RTStrCopy(pBackendCfg->szName, sizeof(pBackendCfg->szName), "VRDE");
[88534]288 pBackendCfg->cbStream = sizeof(VRDESTREAM);
289 pBackendCfg->fFlags = 0;
[63360]290 pBackendCfg->cMaxStreamsIn = UINT32_MAX;
291 pBackendCfg->cMaxStreamsOut = UINT32_MAX;
[53831]292
[53442]293 return VINF_SUCCESS;
[50686]294}
295
[63360]296
297/**
298 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetStatus}
299 */
[82255]300static DECLCALLBACK(PDMAUDIOBACKENDSTS) drvAudioVrdeHA_GetStatus(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
[61157]301{
[88460]302 RT_NOREF(pInterface, enmDir);
303 return PDMAUDIOBACKENDSTS_RUNNING;
304}
[73370]305
[50686]306
[63360]307/**
308 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCreate}
309 */
[82255]310static DECLCALLBACK(int) drvAudioVrdeHA_StreamCreate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
[89487]311 PCPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
[61157]312{
[88885]313 PDRVAUDIOVRDE pThis = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
314 PVRDESTREAM pStreamVRDE = (PVRDESTREAM)pStream;
[88460]315 AssertPtrReturn(pStreamVRDE, VERR_INVALID_POINTER);
316 AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
317 AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER);
[65624]318
[88885]319 /*
320 * Only create a stream if we have clients.
321 */
[94922]322 int vrc;
[88885]323 NOREF(pThis);
324#if 0 /* later maybe */
325 if (pThis->cClients == 0)
326 {
327 LogFunc(("No clients, failing with VERR_AUDIO_STREAM_COULD_NOT_CREATE.\n"));
[94922]328 vrc = VERR_AUDIO_STREAM_COULD_NOT_CREATE;
[88885]329 }
[61157]330 else
[88885]331#endif
332 {
[89543]333 /*
334 * The VRDP server does its own mixing and resampling because it may be
335 * sending the audio to any number of different clients all with different
336 * formats (including clients which hasn't yet connected). So, it desires
337 * the raw data from the mixer (somewhat akind to stereo signed 64-bit,
338 * see st_sample_t and PDMAUDIOFRAME).
339 */
340 PDMAudioPropsInitEx(&pCfgAcq->Props, 8 /*64-bit*/, true /*fSigned*/, 2 /*stereo*/,
341 22050 /*Hz - VRDP_AUDIO_CHUNK_INTERNAL_FREQ_HZ*/,
342 true /*fLittleEndian*/, true /*fRaw*/);
343
344 /* According to the VRDP docs (VRDP_AUDIO_CHUNK_TIME_MS), the VRDP server
345 stores audio in 200ms chunks. */
346 const uint32_t cFramesVrdpServer = PDMAudioPropsMilliToFrames(&pCfgAcq->Props, 200 /*ms*/);
347
[88885]348 if (pCfgReq->enmDir == PDMAUDIODIR_IN)
[89543]349 {
350 pCfgAcq->Backend.cFramesBufferSize = cFramesVrdpServer;
351 pCfgAcq->Backend.cFramesPeriod = cFramesVrdpServer / 4; /* This is utter non-sense, but whatever. */
352 pCfgAcq->Backend.cFramesPreBuffering = pCfgReq->Backend.cFramesPreBuffering * cFramesVrdpServer
353 / RT_MAX(pCfgReq->Backend.cFramesBufferSize, 1);
354
[94922]355 vrc = RTCircBufCreate(&pStreamVRDE->In.pCircBuf, PDMAudioPropsFramesToBytes(&pCfgAcq->Props, cFramesVrdpServer));
[89543]356 }
[88885]357 else
[89543]358 {
359 /** @todo r=bird: So, if VRDP does 200ms chunks, why do we report 100ms
360 * buffer and 20ms period? How does these parameters at all correlate
361 * with the above comment?!? */
362 pCfgAcq->Backend.cFramesPeriod = PDMAudioPropsMilliToFrames(&pCfgAcq->Props, 20 /*ms*/);
363 pCfgAcq->Backend.cFramesBufferSize = PDMAudioPropsMilliToFrames(&pCfgAcq->Props, 100 /*ms*/);
364 pCfgAcq->Backend.cFramesPreBuffering = pCfgAcq->Backend.cFramesPeriod * 2;
[94922]365 vrc = VINF_SUCCESS;
[89543]366 }
367
[88885]368 PDMAudioStrmCfgCopy(&pStreamVRDE->Cfg, pCfgAcq);
369 }
[94922]370 return vrc;
[61157]371}
372
[63360]373
374/**
375 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDestroy}
376 */
[89213]377static DECLCALLBACK(int) drvAudioVrdeHA_StreamDestroy(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
378 bool fImmediate)
[61157]379{
[65624]380 PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
381 PVRDESTREAM pStreamVRDE = (PVRDESTREAM)pStream;
[88460]382 AssertPtrReturn(pStreamVRDE, VERR_INVALID_POINTER);
[89213]383 RT_NOREF(fImmediate);
[65565]384
[89543]385 if (pStreamVRDE->Cfg.enmDir == PDMAUDIODIR_IN)
[88460]386 {
[89543]387 LogFlowFunc(("Calling SendAudioInputEnd\n"));
[88460]388 if (pDrv->pConsoleVRDPServer)
389 pDrv->pConsoleVRDPServer->SendAudioInputEnd(NULL);
[65624]390
[88460]391 if (pStreamVRDE->In.pCircBuf)
392 {
393 RTCircBufDestroy(pStreamVRDE->In.pCircBuf);
394 pStreamVRDE->In.pCircBuf = NULL;
395 }
[65565]396 }
[50686]397
[88460]398 return VINF_SUCCESS;
[50686]399}
400
[63360]401
402/**
[89510]403 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamEnable}
[63360]404 */
[88460]405static DECLCALLBACK(int) drvAudioVrdeHA_StreamEnable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
[53442]406{
[65624]407 PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
408 PVRDESTREAM pStreamVRDE = (PVRDESTREAM)pStream;
[59987]409
[94922]410 int vrc;
[88460]411 if (!pDrv->pConsoleVRDPServer)
412 {
413 LogRelMax(32, ("Audio: VRDP console not ready (enable)\n"));
[94922]414 vrc = VERR_AUDIO_STREAM_NOT_READY;
[88460]415 }
416 else if (pStreamVRDE->Cfg.enmDir == PDMAUDIODIR_IN)
417 {
[94922]418 vrc = pDrv->pConsoleVRDPServer->SendAudioInputBegin(NULL, pStreamVRDE,
419 PDMAudioPropsMilliToFrames(&pStreamVRDE->Cfg.Props, 200 /*ms*/),
420 PDMAudioPropsHz(&pStreamVRDE->Cfg.Props),
421 PDMAudioPropsChannels(&pStreamVRDE->Cfg.Props),
422 PDMAudioPropsSampleBits(&pStreamVRDE->Cfg.Props));
423 LogFlowFunc(("SendAudioInputBegin returns %Rrc\n", vrc));
424 if (vrc == VERR_NOT_SUPPORTED)
[88460]425 {
426 LogRelMax(64, ("Audio: No VRDE client connected, so no input recording available\n"));
[94922]427 vrc = VERR_AUDIO_STREAM_NOT_READY;
[88460]428 }
429 }
[61157]430 else
[94922]431 vrc = VINF_SUCCESS;
432 LogFlowFunc(("returns %Rrc\n", vrc));
433 return vrc;
[50686]434}
435
[63360]436
437/**
[89510]438 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDisable}
[65694]439 */
[88460]440static DECLCALLBACK(int) drvAudioVrdeHA_StreamDisable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
[65694]441{
[88460]442 PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
443 PVRDESTREAM pStreamVRDE = (PVRDESTREAM)pStream;
[65694]444
[94922]445 int vrc;
[88460]446 if (!pDrv->pConsoleVRDPServer)
[65733]447 {
[88460]448 LogRelMax(32, ("Audio: VRDP console not ready (disable)\n"));
[94922]449 vrc = VERR_AUDIO_STREAM_NOT_READY;
[65733]450 }
[88460]451 else if (pStreamVRDE->Cfg.enmDir == PDMAUDIODIR_IN)
452 {
[89543]453 LogFlowFunc(("Calling SendAudioInputEnd\n"));
[88460]454 pDrv->pConsoleVRDPServer->SendAudioInputEnd(NULL /* pvUserCtx */);
[94922]455 vrc = VINF_SUCCESS;
[88460]456 }
457 else
[94922]458 vrc = VINF_SUCCESS;
459 LogFlowFunc(("returns %Rrc\n", vrc));
460 return vrc;
[65694]461}
462
463
464/**
[89510]465 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamPause}
[65694]466 */
[88460]467static DECLCALLBACK(int) drvAudioVrdeHA_StreamPause(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
[65694]468{
[88255]469 PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
470 RT_NOREF(pStream);
[65694]471
[88460]472 if (!pDrv->pConsoleVRDPServer)
473 {
474 LogRelMax(32, ("Audio: VRDP console not ready (pause)\n"));
475 return VERR_AUDIO_STREAM_NOT_READY;
476 }
477 LogFlowFunc(("returns VINF_SUCCESS\n"));
478 return VINF_SUCCESS;
[65694]479}
480
481
482/**
[89510]483 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamResume}
[63360]484 */
[88460]485static DECLCALLBACK(int) drvAudioVrdeHA_StreamResume(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
[54491]486{
[73370]487 PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
488 RT_NOREF(pStream);
[54491]489
[88460]490 if (!pDrv->pConsoleVRDPServer)
491 {
492 LogRelMax(32, ("Audio: VRDP console not ready (resume)\n"));
493 return VERR_AUDIO_STREAM_NOT_READY;
494 }
495 LogFlowFunc(("returns VINF_SUCCESS\n"));
496 return VINF_SUCCESS;
497}
[73370]498
499
[88460]500/**
[89510]501 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDrain}
[88460]502 */
503static DECLCALLBACK(int) drvAudioVrdeHA_StreamDrain(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
504{
505 RT_NOREF(pInterface, pStream);
506 LogFlowFunc(("returns VINF_SUCCESS\n"));
507 return VINF_SUCCESS;
[54491]508}
509
[63360]510
511/**
[89504]512 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetState}
[88460]513 */
[89504]514static DECLCALLBACK(PDMHOSTAUDIOSTREAMSTATE) drvAudioVrdeHA_StreamGetState(PPDMIHOSTAUDIO pInterface,
515 PPDMAUDIOBACKENDSTREAM pStream)
[53442]516{
[89504]517 PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
518 AssertPtrReturn(pStream, PDMHOSTAUDIOSTREAMSTATE_INVALID);
[50686]519
[89504]520 return pDrv->cClients > 0 ? PDMHOSTAUDIOSTREAMSTATE_OKAY : PDMHOSTAUDIOSTREAMSTATE_INACTIVE;
[50686]521}
522
[63360]523
[70644]524/**
[88460]525 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetWritable}
[70644]526 */
[88460]527static DECLCALLBACK(uint32_t) drvAudioVrdeHA_StreamGetWritable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
[70535]528{
[89543]529 PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
530 PVRDESTREAM pStreamVRDE = (PVRDESTREAM)pStream;
[70644]531
[88460]532 /** @todo Find some sane value here. We probably need a VRDE API VRDE to specify this. */
533 if (pDrv->cClients)
[89543]534 return PDMAudioPropsFramesToBytes(&pStreamVRDE->Cfg.Props, pStreamVRDE->Cfg.Backend.cFramesBufferSize);
[88460]535 return 0;
[70535]536}
537
[70644]538
[88460]539/**
540 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamPlay}
541 */
542static DECLCALLBACK(int) drvAudioVrdeHA_StreamPlay(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
543 const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)
[50686]544{
[88460]545 PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
546 AssertPtr(pDrv);
547 AssertPtrReturn(pStream, VERR_INVALID_POINTER);
548 PVRDESTREAM pStreamVRDE = (PVRDESTREAM)pStream;
[88991]549 if (cbBuf)
550 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
[88460]551 AssertPtrReturn(pcbWritten, VERR_INVALID_POINTER);
[53831]552
[88460]553 if (!pDrv->pConsoleVRDPServer)
554 return VERR_NOT_AVAILABLE;
[55159]555
[88460]556 /* Prepate the format. */
557 PPDMAUDIOPCMPROPS pProps = &pStreamVRDE->Cfg.Props;
558 VRDEAUDIOFORMAT const uVrdpFormat = VRDE_AUDIO_FMT_MAKE(PDMAudioPropsHz(pProps),
559 PDMAudioPropsChannels(pProps),
560 PDMAudioPropsSampleBits(pProps),
561 pProps->fSigned);
562 Assert(uVrdpFormat == VRDE_AUDIO_FMT_MAKE(PDMAudioPropsHz(pProps), 2, 64, true));
[50686]563
[88460]564 /** @todo r=bird: there was some incoherent mumbling about "using the
565 * internal counter to track if we (still) can write to the VRDP
[88991]566 * server or if need to wait another round (time slot)". However it
[88460]567 * wasn't accessing any internal counter nor doing anything else
568 * sensible, so I've removed it. */
[50686]569
[89489]570 uint32_t cFrames = PDMAudioPropsBytesToFrames(&pStream->pStream->Cfg.Props, cbBuf);
[89415]571 Assert(cFrames == cbBuf / (sizeof(uint64_t) * 2));
572 pDrv->pConsoleVRDPServer->SendAudioSamples(pvBuf, cFrames, uVrdpFormat);
[50686]573
[89415]574 Log3Func(("cFramesWritten=%RU32\n", cFrames));
[89489]575 *pcbWritten = PDMAudioPropsFramesToBytes(&pStream->pStream->Cfg.Props, cFrames);
[89415]576 Assert(*pcbWritten == cbBuf);
[50686]577 return VINF_SUCCESS;
578}
[34906]579
[63360]580
[88460]581/**
[89504]582 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetReadable}
583 */
584static DECLCALLBACK(uint32_t) drvAudioVrdeHA_StreamGetReadable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
585{
586 RT_NOREF(pInterface);
587 PVRDESTREAM pStreamVRDE = (PVRDESTREAM)pStream;
588
[89543]589 AssertReturn(pStreamVRDE->Cfg.enmDir == PDMAUDIODIR_IN, 0);
590 uint32_t cbRet = (uint32_t)RTCircBufUsed(pStreamVRDE->In.pCircBuf);
591 Log4Func(("returns %#x\n", cbRet));
592 return cbRet;
[89504]593}
594
595
596/**
[88460]597 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCapture}
598 */
599static DECLCALLBACK(int) drvAudioVrdeHA_StreamCapture(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
600 void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
[50686]601{
[88460]602 RT_NOREF(pInterface);
603 PVRDESTREAM pStreamVRDE = (PVRDESTREAM)pStream;
[65565]604 AssertPtrReturn(pStreamVRDE, VERR_INVALID_POINTER);
[88460]605 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
606 AssertReturn(cbBuf, VERR_INVALID_PARAMETER);
607 AssertPtrReturn(pcbRead, VERR_INVALID_PARAMETER);
[50686]608
[89543]609 *pcbRead = 0;
610 while (cbBuf > 0 && RTCircBufUsed(pStreamVRDE->In.pCircBuf) > 0)
[88460]611 {
[89543]612 size_t cbData = 0;
613 void *pvData = NULL;
[88460]614 RTCircBufAcquireReadBlock(pStreamVRDE->In.pCircBuf, cbBuf, &pvData, &cbData);
[50686]615
[89543]616 memcpy(pvBuf, pvData, cbData);
[50686]617
[88460]618 RTCircBufReleaseReadBlock(pStreamVRDE->In.pCircBuf, cbData);
[89543]619
620 *pcbRead += (uint32_t)cbData;
621 cbBuf -= (uint32_t)cbData;
622 pvData = (uint8_t *)pvData + cbData;
[88460]623 }
[50686]624
[89543]625 LogFlowFunc(("returns %#x bytes\n", *pcbRead));
[88460]626 return VINF_SUCCESS;
627}
[65565]628
629
[88460]630/*********************************************************************************************************************************
631* PDMIBASE *
632*********************************************************************************************************************************/
[34906]633
[88460]634/**
635 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
636 */
637static DECLCALLBACK(void *) drvAudioVrdeQueryInterface(PPDMIBASE pInterface, const char *pszIID)
[50686]638{
[88460]639 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
640 PDRVAUDIOVRDE pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVRDE);
[34906]641
[88460]642 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
643 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
644 return NULL;
[1]645}
646
[63360]647
[88460]648/*********************************************************************************************************************************
649* PDMDRVREG *
650*********************************************************************************************************************************/
[54230]651
[1]652/**
[88382]653 * @interface_method_impl{PDMDRVREG,pfnPowerOff}
654 */
655/*static*/ DECLCALLBACK(void) AudioVRDE::drvPowerOff(PPDMDRVINS pDrvIns)
656{
657 PDRVAUDIOVRDE pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVRDE);
658 LogFlowFuncEnter();
659
660 if (pThis->pConsoleVRDPServer)
661 pThis->pConsoleVRDPServer->SendAudioInputEnd(NULL);
662}
663
664
665/**
666 * @interface_method_impl{PDMDRVREG,pfnDestruct}
667 */
668/*static*/ DECLCALLBACK(void) AudioVRDE::drvDestruct(PPDMDRVINS pDrvIns)
669{
670 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
671 PDRVAUDIOVRDE pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVRDE);
672 LogFlowFuncEnter();
673
674 /** @todo For runtime detach maybe:
675 if (pThis->pConsoleVRDPServer)
676 pThis->pConsoleVRDPServer->SendAudioInputEnd(NULL); */
677
678 /*
679 * If the AudioVRDE object is still alive, we must clear it's reference to
680 * us since we'll be invalid when we return from this method.
681 */
[88885]682 AudioVRDE *pAudioVRDE = pThis->pAudioVRDE;
683 if (pAudioVRDE)
[88382]684 {
[88885]685 RTCritSectEnter(&pAudioVRDE->mCritSect);
686 pAudioVRDE->mpDrv = NULL;
[88382]687 pThis->pAudioVRDE = NULL;
[88885]688 RTCritSectLeave(&pAudioVRDE->mCritSect);
[88382]689 }
690}
691
692
693/**
[53442]694 * Construct a VRDE audio driver instance.
[25893]695 *
[22277]696 * @copydoc FNPDMDRVCONSTRUCT
[1]697 */
[53442]698/* static */
699DECLCALLBACK(int) AudioVRDE::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
[1]700{
[54996]701 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
702 PDRVAUDIOVRDE pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVRDE);
[82255]703 RT_NOREF(fFlags);
[63360]704
[54230]705 AssertPtrReturn(pDrvIns, VERR_INVALID_POINTER);
706 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
707
[53442]708 LogRel(("Audio: Initializing VRDE driver\n"));
709 LogFlowFunc(("fFlags=0x%x\n", fFlags));
[1]710
[25893]711 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
[22277]712 ("Configuration error: Not possible to attach anything to this driver!\n"),
713 VERR_PDM_DRVINS_NO_ATTACH);
[1]714
715 /*
[50686]716 * Init the static parts.
[1]717 */
[54230]718 pThis->pDrvIns = pDrvIns;
[94327]719 pThis->cClients = 0;
[50686]720 /* IBase */
[82255]721 pDrvIns->IBase.pfnQueryInterface = drvAudioVrdeQueryInterface;
[54368]722 /* IHostAudio */
[88761]723 pThis->IHostAudio.pfnGetConfig = drvAudioVrdeHA_GetConfig;
724 pThis->IHostAudio.pfnGetDevices = NULL;
[89258]725 pThis->IHostAudio.pfnSetDevice = NULL;
[88761]726 pThis->IHostAudio.pfnGetStatus = drvAudioVrdeHA_GetStatus;
[88819]727 pThis->IHostAudio.pfnDoOnWorkerThread = NULL;
728 pThis->IHostAudio.pfnStreamConfigHint = NULL;
[88761]729 pThis->IHostAudio.pfnStreamCreate = drvAudioVrdeHA_StreamCreate;
[88819]730 pThis->IHostAudio.pfnStreamInitAsync = NULL;
[88761]731 pThis->IHostAudio.pfnStreamDestroy = drvAudioVrdeHA_StreamDestroy;
732 pThis->IHostAudio.pfnStreamNotifyDeviceChanged = NULL;
[89510]733 pThis->IHostAudio.pfnStreamEnable = drvAudioVrdeHA_StreamEnable;
734 pThis->IHostAudio.pfnStreamDisable = drvAudioVrdeHA_StreamDisable;
735 pThis->IHostAudio.pfnStreamPause = drvAudioVrdeHA_StreamPause;
736 pThis->IHostAudio.pfnStreamResume = drvAudioVrdeHA_StreamResume;
737 pThis->IHostAudio.pfnStreamDrain = drvAudioVrdeHA_StreamDrain;
[89504]738 pThis->IHostAudio.pfnStreamGetState = drvAudioVrdeHA_StreamGetState;
739 pThis->IHostAudio.pfnStreamGetPending = NULL;
[88761]740 pThis->IHostAudio.pfnStreamGetWritable = drvAudioVrdeHA_StreamGetWritable;
741 pThis->IHostAudio.pfnStreamPlay = drvAudioVrdeHA_StreamPlay;
[89504]742 pThis->IHostAudio.pfnStreamGetReadable = drvAudioVrdeHA_StreamGetReadable;
[88761]743 pThis->IHostAudio.pfnStreamCapture = drvAudioVrdeHA_StreamCapture;
[1]744
[54230]745 /*
[88885]746 * Resolve the interface to the driver above us.
747 */
748 pThis->pIHostAudioPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIHOSTAUDIOPORT);
749 AssertPtrReturn(pThis->pIHostAudioPort, VERR_PDM_MISSING_INTERFACE_ABOVE);
750
[94327]751 /* Get the Console object pointer. */
752 com::Guid ConsoleUuid(COM_IIDOF(IConsole));
753 IConsole *pIConsole = (IConsole *)PDMDrvHlpQueryGenericUserObject(pDrvIns, ConsoleUuid.raw());
754 AssertLogRelReturn(pIConsole, VERR_INTERNAL_ERROR_3);
755 Console *pConsole = static_cast<Console *>(pIConsole);
756 AssertLogRelReturn(pConsole, VERR_INTERNAL_ERROR_3);
[1]757
[94327]758 /* Get the console VRDP object pointer. */
759 pThis->pConsoleVRDPServer = pConsole->i_consoleVRDPServer();
[88460]760 AssertLogRelMsgReturn(RT_VALID_PTR(pThis->pConsoleVRDPServer) || !pThis->pConsoleVRDPServer,
761 ("pConsoleVRDPServer=%p\n", pThis->pConsoleVRDPServer), VERR_INVALID_POINTER);
[53442]762
[94327]763 /* Get the AudioVRDE object pointer. */
764 pThis->pAudioVRDE = pConsole->i_getAudioVRDE();
[88460]765 AssertLogRelMsgReturn(RT_VALID_PTR(pThis->pAudioVRDE), ("pAudioVRDE=%p\n", pThis->pAudioVRDE), VERR_INVALID_POINTER);
[88885]766 RTCritSectEnter(&pThis->pAudioVRDE->mCritSect);
[50686]767 pThis->pAudioVRDE->mpDrv = pThis;
[88885]768 RTCritSectLeave(&pThis->pAudioVRDE->mCritSect);
[53442]769
[1]770 return VINF_SUCCESS;
771}
772
[54996]773
774/**
[53442]775 * VRDE audio driver registration record.
[1]776 */
[53442]777const PDMDRVREG AudioVRDE::DrvReg =
[1]778{
[53442]779 PDM_DRVREG_VERSION,
780 /* szName */
[50686]781 "AudioVRDE",
[25893]782 /* szRCMod */
783 "",
784 /* szR0Mod */
785 "",
[1]786 /* pszDescription */
[53442]787 "Audio driver for VRDE backend",
[1]788 /* fFlags */
789 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
790 /* fClass. */
791 PDM_DRVREG_CLASS_AUDIO,
792 /* cMaxInstances */
[40282]793 ~0U,
[1]794 /* cbInstance */
[50686]795 sizeof(DRVAUDIOVRDE),
[1]796 /* pfnConstruct */
[53442]797 AudioVRDE::drvConstruct,
[1]798 /* pfnDestruct */
[53442]799 AudioVRDE::drvDestruct,
[25893]800 /* pfnRelocate */
801 NULL,
[1]802 /* pfnIOCtl */
803 NULL,
804 /* pfnPowerOn */
805 NULL,
806 /* pfnReset */
807 NULL,
808 /* pfnSuspend */
809 NULL,
810 /* pfnResume */
811 NULL,
[22277]812 /* pfnAttach */
[88382]813 NULL,
[1]814 /* pfnDetach */
[88382]815 NULL,
[22277]816 /* pfnPowerOff */
[88382]817 AudioVRDE::drvPowerOff,
[22277]818 /* pfnSoftReset */
819 NULL,
820 /* u32EndVersion */
821 PDM_DRVREG_VERSION
[1]822};
[50686]823
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use