5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync/* $Id$ */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync/** @file
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * VRDE audio backend for Main.
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync/*
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync * Copyright (C) 2013-2015 Oracle Corporation
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync *
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync * available from http://www.virtualbox.org. This file is free software;
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync * you can redistribute it and/or modify it under the terms of the GNU
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync * General Public License (GPL) as published by the Free Software
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync */
0fed4ca8109741ca612d88f527b04c4b9289cd7fvboxsync
0fed4ca8109741ca612d88f527b04c4b9289cd7fvboxsync
0fed4ca8109741ca612d88f527b04c4b9289cd7fvboxsync/*******************************************************************************
0fed4ca8109741ca612d88f527b04c4b9289cd7fvboxsync* Header Files *
0fed4ca8109741ca612d88f527b04c4b9289cd7fvboxsync*******************************************************************************/
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#include "DrvAudioVRDE.h"
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#include "ConsoleImpl.h"
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#include "ConsoleVRDPServer.h"
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#include "Logging.h"
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync#include "../../Devices/Audio/DrvAudio.h"
174f3dff60f96d89b320f9a322307118676db1dbvboxsync#include "../../Devices/Audio/AudioMixBuffer.h"
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync#include <iprt/mem.h>
174f3dff60f96d89b320f9a322307118676db1dbvboxsync#include <iprt/cdefs.h>
174f3dff60f96d89b320f9a322307118676db1dbvboxsync#include <iprt/circbuf.h>
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#include <VBox/vmm/pdmaudioifs.h>
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#include <VBox/vmm/pdmdrv.h>
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#include <VBox/RemoteDesktop/VRDE.h>
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#include <VBox/vmm/cfgm.h>
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync#include <VBox/err.h>
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
0fed4ca8109741ca612d88f527b04c4b9289cd7fvboxsync#undef LOG_GROUP
174f3dff60f96d89b320f9a322307118676db1dbvboxsync#define LOG_GROUP LOG_GROUP_DEV_AUDIO
174f3dff60f96d89b320f9a322307118676db1dbvboxsync#include <VBox/log.h>
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
0fed4ca8109741ca612d88f527b04c4b9289cd7fvboxsync
0fed4ca8109741ca612d88f527b04c4b9289cd7fvboxsync/*******************************************************************************
0fed4ca8109741ca612d88f527b04c4b9289cd7fvboxsync* Structures and Typedefs *
0fed4ca8109741ca612d88f527b04c4b9289cd7fvboxsync*******************************************************************************/
174f3dff60f96d89b320f9a322307118676db1dbvboxsync/**
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * Audio VRDE driver instance data.
174f3dff60f96d89b320f9a322307118676db1dbvboxsync */
174f3dff60f96d89b320f9a322307118676db1dbvboxsynctypedef struct DRVAUDIOVRDE
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync{
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /** Pointer to audio VRDE object. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync AudioVRDE *pAudioVRDE;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PPDMDRVINS pDrvIns;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /** Pointer to the driver instance structure. */
8a204879c937e7c55da35682a0e5d2e1df91c856vboxsync PDMIHOSTAUDIO IHostAudio;
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync /** Pointer to the VRDP's console object. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync ConsoleVRDPServer *pConsoleVRDPServer;
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync /** Pointer to the DrvAudio port interface that is above us. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PPDMIAUDIOCONNECTOR pDrvAudio;
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync /** Whether this driver is enabled or not. */
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync bool fEnabled;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync} DRVAUDIOVRDE, *PDRVAUDIOVRDE;
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsynctypedef struct VRDESTREAMIN
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync{
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /** Associated host input stream. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PDMAUDIOHSTSTRMIN HstStrmIn;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /** Number of samples captured asynchronously in the
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * onVRDEInputXXX callbacks. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync uint32_t cSamplesCaptured;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /** Critical section. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync RTCRITSECT CritSect;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync} VRDESTREAMIN, *PVRDESTREAMIN;
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsynctypedef struct VRDESTREAMOUT
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync{
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /** Associated host output stream. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PDMAUDIOHSTSTRMOUT HstStrmOut;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync uint64_t old_ticks;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync uint64_t cSamplesSentPerSec;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync} VRDESTREAMOUT, *PVRDESTREAMOUT;
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
0fed4ca8109741ca612d88f527b04c4b9289cd7fvboxsync
0fed4ca8109741ca612d88f527b04c4b9289cd7fvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic DECLCALLBACK(int) drvAudioVRDEInit(PPDMIHOSTAUDIO pInterface)
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync{
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogFlowFuncEnter();
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return VINF_SUCCESS;
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync}
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsyncstatic DECLCALLBACK(int) drvAudioVRDEInitIn(PPDMIHOSTAUDIO pInterface,
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync PPDMAUDIOHSTSTRMIN pHstStrmIn, PPDMAUDIOSTREAMCFG pCfg,
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync PDMAUDIORECSOURCE enmRecSource,
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync uint32_t *pcSamples)
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync{
8a204879c937e7c55da35682a0e5d2e1df91c856vboxsync PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync AssertPtrReturn(pDrv, VERR_INVALID_POINTER);
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync PVRDESTREAMIN pVRDEStrmIn = (PVRDESTREAMIN)pHstStrmIn;
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync AssertPtrReturn(pVRDEStrmIn, VERR_INVALID_POINTER);
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync if (pcSamples)
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync *pcSamples = _4K; /** @todo Make this configurable. */
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync return drvAudioStreamCfgToProps(pCfg, &pVRDEStrmIn->HstStrmIn.Props);
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync}
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic DECLCALLBACK(int) drvAudioVRDEInitOut(PPDMIHOSTAUDIO pInterface,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PPDMAUDIOHSTSTRMOUT pHstStrmOut, PPDMAUDIOSTREAMCFG pCfg,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync uint32_t *pcSamples)
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync{
8a204879c937e7c55da35682a0e5d2e1df91c856vboxsync PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync AssertPtrReturn(pDrv, VERR_INVALID_POINTER);
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogFlowFunc(("pHstStrmOut=%p, pCfg=%p\n", pHstStrmOut, pCfg));
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PVRDESTREAMOUT pVRDEStrmOut = (PVRDESTREAMOUT)pHstStrmOut;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync AssertPtrReturn(pVRDEStrmOut, VERR_INVALID_POINTER);
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync if (pcSamples)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync *pcSamples = _4K; /** @todo Make this configurable. */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return drvAudioStreamCfgToProps(pCfg, &pVRDEStrmOut->HstStrmOut.Props);
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync}
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsyncstatic DECLCALLBACK(bool) drvAudioVRDEIsEnabled(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync{
8a204879c937e7c55da35682a0e5d2e1df91c856vboxsync PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync AssertPtrReturn(pDrv, false);
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync NOREF(enmDir);
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync if (!pDrv->fEnabled)
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync return false;
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync return true;
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync}
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync/**
0fed4ca8109741ca612d88f527b04c4b9289cd7fvboxsync * <Missing brief description>
0fed4ca8109741ca612d88f527b04c4b9289cd7fvboxsync *
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * Transfers audio input formerly sent by a connected RDP client / VRDE backend
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * (using the onVRDEInputXXX methods) over to the VRDE host (VM). The audio device
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * emulation then will read and send the data to the guest.
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync *
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * @return IPRT status code.
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * @param pInterface
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * @param pHstStrmIn
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * @param pcSamplesCaptured
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync */
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic DECLCALLBACK(int) drvAudioVRDECaptureIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync uint32_t *pcSamplesCaptured)
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync{
174f3dff60f96d89b320f9a322307118676db1dbvboxsync AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync AssertPtrReturn(pcSamplesCaptured, VERR_INVALID_POINTER);
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
8a204879c937e7c55da35682a0e5d2e1df91c856vboxsync PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync AssertPtrReturn(pDrv, VERR_INVALID_POINTER);
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PVRDESTREAMIN pVRDEStrmIn = (PVRDESTREAMIN)pHstStrmIn;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync AssertPtrReturn(pVRDEStrmIn, VERR_INVALID_POINTER);
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /** @todo Use CritSect! */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync int rc;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync uint32_t cProcessed = 0;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync if (pVRDEStrmIn->cSamplesCaptured)
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync {
174f3dff60f96d89b320f9a322307118676db1dbvboxsync rc = audioMixBufMixToParent(&pVRDEStrmIn->HstStrmIn.MixBuf, pVRDEStrmIn->cSamplesCaptured,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync &cProcessed);
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync }
174f3dff60f96d89b320f9a322307118676db1dbvboxsync else
174f3dff60f96d89b320f9a322307118676db1dbvboxsync rc = VINF_SUCCESS;
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync if (RT_SUCCESS(rc))
174f3dff60f96d89b320f9a322307118676db1dbvboxsync {
174f3dff60f96d89b320f9a322307118676db1dbvboxsync *pcSamplesCaptured = cProcessed;
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync Assert(pVRDEStrmIn->cSamplesCaptured >= cProcessed);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pVRDEStrmIn->cSamplesCaptured -= cProcessed;
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync }
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogFlowFunc(("cSamplesCaptured=%RU32, cProcessed=%RU32\n",
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pVRDEStrmIn->cSamplesCaptured, cProcessed, rc));
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return rc;
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync}
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync/**
0fed4ca8109741ca612d88f527b04c4b9289cd7fvboxsync * Transfers VM audio output to remote client.
0fed4ca8109741ca612d88f527b04c4b9289cd7fvboxsync *
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * Transfers VM audio output over to the VRDE instance for playing remotely
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * on the client.
174f3dff60f96d89b320f9a322307118676db1dbvboxsync *
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * @return IPRT status code.
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * @param pInterface
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * @param pHstStrmOut
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * @param pcSamplesPlayed
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync */
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic DECLCALLBACK(int) drvAudioVRDEPlayOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync uint32_t *pcSamplesPlayed)
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync{
174f3dff60f96d89b320f9a322307118676db1dbvboxsync AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync AssertPtrReturn(pHstStrmOut, VERR_INVALID_POINTER);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* pcSamplesPlayed is optional. */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
8a204879c937e7c55da35682a0e5d2e1df91c856vboxsync PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync AssertPtrReturn(pDrv, VERR_INVALID_POINTER);
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PVRDESTREAMOUT pVRDEStrmOut = (PVRDESTREAMOUT)pHstStrmOut;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync AssertPtrReturn(pVRDEStrmOut, VERR_INVALID_POINTER);
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /*
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * Just call the VRDP server with the data.
174f3dff60f96d89b320f9a322307118676db1dbvboxsync */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync uint32_t live = drvAudioHstOutSamplesLive(pHstStrmOut, NULL /* pcStreamsLive */);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync uint64_t now = PDMDrvHlpTMGetVirtualTime(pDrv->pDrvIns);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync uint64_t ticks = now - pVRDEStrmOut->old_ticks;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync uint64_t ticks_per_second = PDMDrvHlpTMGetVirtualFreq(pDrv->pDrvIns);
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync uint32_t cSamplesPlayed = (int)((2 * ticks * pHstStrmOut->Props.uHz + ticks_per_second) / ticks_per_second / 2);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync if (!cSamplesPlayed)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync cSamplesPlayed = live;
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync VRDEAUDIOFORMAT format = VRDE_AUDIO_FMT_MAKE(pHstStrmOut->Props.uHz,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pHstStrmOut->Props.cChannels,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pHstStrmOut->Props.cBits,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pHstStrmOut->Props.fSigned);
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
6e4f0a21de35da7e77586bc1fab65d1bbf611eeevboxsync pVRDEStrmOut->old_ticks = now;
6e4f0a21de35da7e77586bc1fab65d1bbf611eeevboxsync
6e4f0a21de35da7e77586bc1fab65d1bbf611eeevboxsync int cSamplesToSend = live;
6e4f0a21de35da7e77586bc1fab65d1bbf611eeevboxsync
6e4f0a21de35da7e77586bc1fab65d1bbf611eeevboxsync/* if (!cSamplesToSend)
6e4f0a21de35da7e77586bc1fab65d1bbf611eeevboxsync {
6e4f0a21de35da7e77586bc1fab65d1bbf611eeevboxsync if (pcSamplesPlayed)
6e4f0a21de35da7e77586bc1fab65d1bbf611eeevboxsync pcSamplesPlayed = 0;
6e4f0a21de35da7e77586bc1fab65d1bbf611eeevboxsync
6e4f0a21de35da7e77586bc1fab65d1bbf611eeevboxsync return 0;
6e4f0a21de35da7e77586bc1fab65d1bbf611eeevboxsync }*/
6e4f0a21de35da7e77586bc1fab65d1bbf611eeevboxsync
6e4f0a21de35da7e77586bc1fab65d1bbf611eeevboxsync LogFlowFunc(("uFreq=%RU32, cChan=%RU8, cBits=%RU8, fSigned=%RTbool, enmFormat=%ld, cSamplesToSend=%RU32\n",
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pHstStrmOut->Props.uHz, pHstStrmOut->Props.cChannels,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pHstStrmOut->Props.cBits, pHstStrmOut->Props.fSigned,
6e4f0a21de35da7e77586bc1fab65d1bbf611eeevboxsync format, cSamplesToSend));
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync uint32_t cReadTotal = 0;
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PPDMAUDIOSAMPLE pSamples;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync uint32_t cRead;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync int rc = audioMixBufAcquire(&pHstStrmOut->MixBuf, cSamplesToSend,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync &pSamples, &cRead);
6e4f0a21de35da7e77586bc1fab65d1bbf611eeevboxsync if ( RT_SUCCESS(rc)
6e4f0a21de35da7e77586bc1fab65d1bbf611eeevboxsync && cRead)
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync {
174f3dff60f96d89b320f9a322307118676db1dbvboxsync cReadTotal = cRead;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pDrv->pConsoleVRDPServer->SendAudioSamples(pSamples, cRead, format);
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync if (rc == VINF_TRY_AGAIN)
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync {
174f3dff60f96d89b320f9a322307118676db1dbvboxsync rc = audioMixBufAcquire(&pHstStrmOut->MixBuf, cSamplesToSend - cRead,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync &pSamples, &cRead);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync if (RT_SUCCESS(rc))
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pDrv->pConsoleVRDPServer->SendAudioSamples(pSamples, cRead, format);
6e4f0a21de35da7e77586bc1fab65d1bbf611eeevboxsync
6e4f0a21de35da7e77586bc1fab65d1bbf611eeevboxsync cReadTotal += cRead;
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync }
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync }
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
6e4f0a21de35da7e77586bc1fab65d1bbf611eeevboxsync audioMixBufFinish(&pHstStrmOut->MixBuf, cSamplesToSend);
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
6e4f0a21de35da7e77586bc1fab65d1bbf611eeevboxsync /*
6e4f0a21de35da7e77586bc1fab65d1bbf611eeevboxsync * Always report back all samples acquired, regardless of whether the
6e4f0a21de35da7e77586bc1fab65d1bbf611eeevboxsync * VRDP server actually did process those.
6e4f0a21de35da7e77586bc1fab65d1bbf611eeevboxsync */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync if (pcSamplesPlayed)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync *pcSamplesPlayed = cReadTotal;
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
6e4f0a21de35da7e77586bc1fab65d1bbf611eeevboxsync LogFlowFunc(("cReadTotal=%RU32, rc=%Rrc\n", cReadTotal, rc));
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return rc;
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync}
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic DECLCALLBACK(int) drvAudioVRDEFiniIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn)
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync{
8a204879c937e7c55da35682a0e5d2e1df91c856vboxsync PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync AssertPtrReturn(pDrv, VERR_INVALID_POINTER);
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync if (pDrv->pConsoleVRDPServer)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pDrv->pConsoleVRDPServer->SendAudioInputEnd(NULL);
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return VINF_SUCCESS;
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync}
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic DECLCALLBACK(int) drvAudioVRDEFiniOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut)
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync{
8a204879c937e7c55da35682a0e5d2e1df91c856vboxsync PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync AssertPtrReturn(pDrv, VERR_INVALID_POINTER);
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return VINF_SUCCESS;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync}
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic DECLCALLBACK(int) drvAudioVRDEControlOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PDMAUDIOSTREAMCMD enmStreamCmd)
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync{
8a204879c937e7c55da35682a0e5d2e1df91c856vboxsync PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync AssertPtrReturn(pDrv, VERR_INVALID_POINTER);
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
6e4f0a21de35da7e77586bc1fab65d1bbf611eeevboxsync PVRDESTREAMIN pVRDEStrmOut = (PVRDESTREAMIN)pHstStrmOut;
6e4f0a21de35da7e77586bc1fab65d1bbf611eeevboxsync AssertPtrReturn(pVRDEStrmOut, VERR_INVALID_POINTER);
6e4f0a21de35da7e77586bc1fab65d1bbf611eeevboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogFlowFunc(("enmStreamCmd=%ld\n", enmStreamCmd));
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
6e4f0a21de35da7e77586bc1fab65d1bbf611eeevboxsync audioMixBufReset(&pHstStrmOut->MixBuf);
6e4f0a21de35da7e77586bc1fab65d1bbf611eeevboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return VINF_SUCCESS;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync}
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
6e4f0a21de35da7e77586bc1fab65d1bbf611eeevboxsyncstatic DECLCALLBACK(int) drvAudioVRDEControlIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PDMAUDIOSTREAMCMD enmStreamCmd)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync{
8a204879c937e7c55da35682a0e5d2e1df91c856vboxsync PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync AssertPtrReturn(pDrv, VERR_INVALID_POINTER);
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
6e4f0a21de35da7e77586bc1fab65d1bbf611eeevboxsync PVRDESTREAMIN pVRDEStrmIn = (PVRDESTREAMIN)pHstStrmIn;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync AssertPtrReturn(pVRDEStrmIn, VERR_INVALID_POINTER);
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
6e4f0a21de35da7e77586bc1fab65d1bbf611eeevboxsync PPDMAUDIOHSTSTRMIN pThisStrmIn = &pVRDEStrmIn->HstStrmIn;
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogFlowFunc(("enmStreamCmd=%ld\n", enmStreamCmd));
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
6e4f0a21de35da7e77586bc1fab65d1bbf611eeevboxsync if (!pDrv->pConsoleVRDPServer)
6e4f0a21de35da7e77586bc1fab65d1bbf611eeevboxsync return VINF_SUCCESS;
6e4f0a21de35da7e77586bc1fab65d1bbf611eeevboxsync
6e4f0a21de35da7e77586bc1fab65d1bbf611eeevboxsync audioMixBufReset(&pThisStrmIn->MixBuf);
6e4f0a21de35da7e77586bc1fab65d1bbf611eeevboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* Initialize only if not already done. */
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync int rc;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync if (enmStreamCmd == PDMAUDIOSTREAMCMD_ENABLE)
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync {
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync rc = pDrv->pConsoleVRDPServer->SendAudioInputBegin(NULL, pVRDEStrmIn, audioMixBufSize(&pThisStrmIn->MixBuf),
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync pThisStrmIn->Props.uHz,
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync pThisStrmIn->Props.cChannels, pThisStrmIn->Props.cBits);
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync if (rc == VERR_NOT_SUPPORTED)
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync {
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogFlowFunc(("No RDP client connected, so no input recording supported\n"));
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync rc = VINF_SUCCESS;
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync }
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync }
174f3dff60f96d89b320f9a322307118676db1dbvboxsync else if (enmStreamCmd == PDMAUDIOSTREAMCMD_DISABLE)
6e4f0a21de35da7e77586bc1fab65d1bbf611eeevboxsync {
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pDrv->pConsoleVRDPServer->SendAudioInputEnd(NULL /* pvUserCtx */);
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync rc = VINF_SUCCESS;
6e4f0a21de35da7e77586bc1fab65d1bbf611eeevboxsync }
97a3cb3696a8e4509f9de8372fd629f814fe8f61vboxsync else
97a3cb3696a8e4509f9de8372fd629f814fe8f61vboxsync rc = VERR_INVALID_PARAMETER;
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync return rc;
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync}
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic DECLCALLBACK(int) drvAudioVRDEGetConf(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pCfg)
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync{
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pCfg->cbStreamOut = sizeof(VRDESTREAMOUT);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pCfg->cbStreamIn = sizeof(VRDESTREAMIN);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pCfg->cMaxHstStrmsOut = 1;
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync pCfg->cMaxHstStrmsIn = 2; /* Microphone in + Line in. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync return VINF_SUCCESS;
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync}
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
1705f7565ed8533058b8541d72d6c5d4453de00fvboxsyncstatic DECLCALLBACK(void) drvAudioVRDEShutdown(PPDMIHOSTAUDIO pInterface)
1705f7565ed8533058b8541d72d6c5d4453de00fvboxsync{
1705f7565ed8533058b8541d72d6c5d4453de00fvboxsync PDRVAUDIOVRDE pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVRDE, IHostAudio);
cfca7f1a17f0e05ad6cdf19639a812b2a2512c1evboxsync AssertPtrReturnVoid(pDrv);
1705f7565ed8533058b8541d72d6c5d4453de00fvboxsync
1705f7565ed8533058b8541d72d6c5d4453de00fvboxsync if (pDrv->pConsoleVRDPServer)
1705f7565ed8533058b8541d72d6c5d4453de00fvboxsync pDrv->pConsoleVRDPServer->SendAudioInputEnd(NULL);
1705f7565ed8533058b8541d72d6c5d4453de00fvboxsync}
1705f7565ed8533058b8541d72d6c5d4453de00fvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync/**
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * @interface_method_impl{PDMIBASE,pfnQueryInterface}
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync */
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic DECLCALLBACK(void *) drvAudioVRDEQueryInterface(PPDMIBASE pInterface, const char *pszIID)
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync{
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PDRVAUDIOVRDE pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVRDE);
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
8a204879c937e7c55da35682a0e5d2e1df91c856vboxsync PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return NULL;
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync}
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncAudioVRDE::AudioVRDE(Console *pConsole)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync : mpDrv(NULL),
174f3dff60f96d89b320f9a322307118676db1dbvboxsync mParent(pConsole)
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync{
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync}
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncAudioVRDE::~AudioVRDE(void)
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync{
174f3dff60f96d89b320f9a322307118676db1dbvboxsync if (mpDrv)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync {
174f3dff60f96d89b320f9a322307118676db1dbvboxsync mpDrv->pAudioVRDE = NULL;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync mpDrv = NULL;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync }
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync}
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsyncint AudioVRDE::onVRDEControl(bool fEnable, uint32_t uFlags)
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync{
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync LogFlowThisFunc(("fEnable=%RTbool, uFlags=0x%x\n", fEnable, uFlags));
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync
a708b5b81c81f03f13980efee2262d4290ba03bevboxsync if (mpDrv == NULL)
a708b5b81c81f03f13980efee2262d4290ba03bevboxsync return VERR_INVALID_STATE;
a708b5b81c81f03f13980efee2262d4290ba03bevboxsync
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync mpDrv->fEnabled = fEnable;
6e4f0a21de35da7e77586bc1fab65d1bbf611eeevboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return VINF_SUCCESS; /* Never veto. */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync}
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync/**
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * Marks the beginning of sending captured audio data from a connected
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * RDP client.
174f3dff60f96d89b320f9a322307118676db1dbvboxsync *
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * @return IPRT status code.
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * @param pvContext The context; in this case a pointer to a
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * VRDESTREAMIN structure.
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * @param pVRDEAudioBegin Pointer to a VRDEAUDIOINBEGIN structure.
174f3dff60f96d89b320f9a322307118676db1dbvboxsync */
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncint AudioVRDE::onVRDEInputBegin(void *pvContext, PVRDEAUDIOINBEGIN pVRDEAudioBegin)
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync{
174f3dff60f96d89b320f9a322307118676db1dbvboxsync AssertPtrReturn(pvContext, VERR_INVALID_POINTER);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync AssertPtrReturn(pVRDEAudioBegin, VERR_INVALID_POINTER);
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PVRDESTREAMIN pVRDEStrmIn = (PVRDESTREAMIN)pvContext;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync AssertPtrReturn(pVRDEStrmIn, VERR_INVALID_POINTER);
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync VRDEAUDIOFORMAT audioFmt = pVRDEAudioBegin->fmt;
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync int iSampleHz = VRDE_AUDIO_FMT_SAMPLE_FREQ(audioFmt);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync int cChannels = VRDE_AUDIO_FMT_CHANNELS(audioFmt);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync int cBits = VRDE_AUDIO_FMT_BITS_PER_SAMPLE(audioFmt);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync bool fUnsigned = VRDE_AUDIO_FMT_SIGNED(audioFmt);
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogFlowFunc(("cbSample=%RU32, iSampleHz=%d, cChannels=%d, cBits=%d, fUnsigned=%RTbool\n",
174f3dff60f96d89b320f9a322307118676db1dbvboxsync VRDE_AUDIO_FMT_BYTES_PER_SAMPLE(audioFmt), iSampleHz, cChannels, cBits, fUnsigned));
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync return VINF_SUCCESS;
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync}
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncint AudioVRDE::onVRDEInputData(void *pvContext, const void *pvData, uint32_t cbData)
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync{
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PVRDESTREAMIN pVRDEStrmIn = (PVRDESTREAMIN)pvContext;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync AssertPtrReturn(pVRDEStrmIn, VERR_INVALID_POINTER);
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PPDMAUDIOHSTSTRMIN pHstStrmIn = &pVRDEStrmIn->HstStrmIn;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync AssertPtrReturn(pHstStrmIn, VERR_INVALID_POINTER);
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /** @todo Use CritSect! */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync uint32_t cWritten;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync int rc = audioMixBufWriteCirc(&pHstStrmIn->MixBuf, pvData, cbData, &cWritten);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync if (RT_SUCCESS(rc))
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pVRDEStrmIn->cSamplesCaptured += cWritten;
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogFlowFunc(("cbData=%RU32, cWritten=%RU32, cSamplesCaptured=%RU32, rc=%Rrc\n",
174f3dff60f96d89b320f9a322307118676db1dbvboxsync cbData, cWritten, pVRDEStrmIn->cSamplesCaptured, rc));
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return rc;
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync}
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncint AudioVRDE::onVRDEInputEnd(void *pvContext)
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync{
174f3dff60f96d89b320f9a322307118676db1dbvboxsync NOREF(pvContext);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return VINF_SUCCESS;
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync}
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsyncint AudioVRDE::onVRDEInputIntercept(bool fEnabled)
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync{
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync return VINF_SUCCESS; /* Never veto. */
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync}
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync/**
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * Construct a VRDE audio driver instance.
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync *
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync * @copydoc FNPDMDRVCONSTRUCT
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync/* static */
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncDECLCALLBACK(int) AudioVRDE::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync{
0fed4ca8109741ca612d88f527b04c4b9289cd7fvboxsync PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
0fed4ca8109741ca612d88f527b04c4b9289cd7fvboxsync PDRVAUDIOVRDE pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVRDE);
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync AssertPtrReturn(pDrvIns, VERR_INVALID_POINTER);
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogRel(("Audio: Initializing VRDE driver\n"));
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogFlowFunc(("fFlags=0x%x\n", fFlags));
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync ("Configuration error: Not possible to attach anything to this driver!\n"),
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync VERR_PDM_DRVINS_NO_ATTACH);
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /*
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync * Init the static parts.
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync */
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync pThis->pDrvIns = pDrvIns;
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /* IBase */
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync pDrvIns->IBase.pfnQueryInterface = drvAudioVRDEQueryInterface;
8a204879c937e7c55da35682a0e5d2e1df91c856vboxsync /* IHostAudio */
8a204879c937e7c55da35682a0e5d2e1df91c856vboxsync PDMAUDIO_IHOSTAUDIO_CALLBACKS(drvAudioVRDE);
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync /* Init defaults. */
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync pThis->fEnabled = false;
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync /*
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync * Get the ConsoleVRDPServer object pointer.
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync void *pvUser;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync int rc = CFGMR3QueryPtr(pCfg, "ObjectVRDPServer", &pvUser);
0fed4ca8109741ca612d88f527b04c4b9289cd7fvboxsync AssertMsgRCReturn(rc, ("Confguration error: No/bad \"ObjectVRDPServer\" value, rc=%Rrc\n", rc), rc);
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* CFGM tree saves the pointer to ConsoleVRDPServer in the Object node of AudioVRDE. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pThis->pConsoleVRDPServer = (ConsoleVRDPServer *)pvUser;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync /*
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync * Get the AudioVRDE object pointer.
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pvUser = NULL;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync rc = CFGMR3QueryPtr(pCfg, "Object", &pvUser);
0fed4ca8109741ca612d88f527b04c4b9289cd7fvboxsync AssertMsgRCReturn(rc, ("Confguration error: No/bad \"Object\" value, rc=%Rrc\n", rc), rc);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pThis->pAudioVRDE = (AudioVRDE *)pvUser;
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync pThis->pAudioVRDE->mpDrv = pThis;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /*
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * Get the interface for the above driver (DrvAudio) to make mixer/conversion calls.
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync * Described in CFGM tree.
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pThis->pDrvAudio = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIAUDIOCONNECTOR);
0fed4ca8109741ca612d88f527b04c4b9289cd7fvboxsync AssertMsgReturn(pThis->pDrvAudio, ("Configuration error: No upper interface specified!\n"), VERR_PDM_MISSING_INTERFACE_ABOVE);
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync return VINF_SUCCESS;
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync}
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
0fed4ca8109741ca612d88f527b04c4b9289cd7fvboxsync
0fed4ca8109741ca612d88f527b04c4b9289cd7fvboxsync/**
0fed4ca8109741ca612d88f527b04c4b9289cd7fvboxsync * @interface_method_impl{PDMDRVREG,pfnDestruct}
0fed4ca8109741ca612d88f527b04c4b9289cd7fvboxsync */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync/* static */
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncDECLCALLBACK(void) AudioVRDE::drvDestruct(PPDMDRVINS pDrvIns)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync{
0fed4ca8109741ca612d88f527b04c4b9289cd7fvboxsync PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
0fed4ca8109741ca612d88f527b04c4b9289cd7fvboxsync PDRVAUDIOVRDE pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVRDE);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogFlowFuncEnter();
0fed4ca8109741ca612d88f527b04c4b9289cd7fvboxsync
0fed4ca8109741ca612d88f527b04c4b9289cd7fvboxsync /*
0fed4ca8109741ca612d88f527b04c4b9289cd7fvboxsync * If the AudioVRDE object is still alive, we must clear it's reference to
0fed4ca8109741ca612d88f527b04c4b9289cd7fvboxsync * us since we'll be invalid when we return from this method.
0fed4ca8109741ca612d88f527b04c4b9289cd7fvboxsync */
0fed4ca8109741ca612d88f527b04c4b9289cd7fvboxsync if (pThis->pAudioVRDE)
0fed4ca8109741ca612d88f527b04c4b9289cd7fvboxsync {
0fed4ca8109741ca612d88f527b04c4b9289cd7fvboxsync pThis->pAudioVRDE->mpDrv = NULL;
0fed4ca8109741ca612d88f527b04c4b9289cd7fvboxsync pThis->pAudioVRDE = NULL;
0fed4ca8109741ca612d88f527b04c4b9289cd7fvboxsync }
174f3dff60f96d89b320f9a322307118676db1dbvboxsync}
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync
0fed4ca8109741ca612d88f527b04c4b9289cd7fvboxsync
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync/**
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * VRDE audio driver registration record.
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync */
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncconst PDMDRVREG AudioVRDE::DrvReg =
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync{
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PDM_DRVREG_VERSION,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* szName */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync "AudioVRDE",
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /* szRCMod */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync "",
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /* szR0Mod */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync "",
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /* pszDescription */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync "Audio driver for VRDE backend",
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /* fFlags */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /* fClass. */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync PDM_DRVREG_CLASS_AUDIO,
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /* cMaxInstances */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync ~0U,
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /* cbInstance */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync sizeof(DRVAUDIOVRDE),
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /* pfnConstruct */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync AudioVRDE::drvConstruct,
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /* pfnDestruct */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync AudioVRDE::drvDestruct,
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /* pfnRelocate */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync NULL,
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /* pfnIOCtl */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync NULL,
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /* pfnPowerOn */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync NULL,
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /* pfnReset */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync NULL,
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /* pfnSuspend */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync NULL,
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /* pfnResume */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync NULL,
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /* pfnAttach */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync NULL,
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /* pfnDetach */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync NULL,
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /* pfnPowerOff */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync NULL,
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /* pfnSoftReset */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync NULL,
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync /* u32EndVersion */
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync PDM_DRVREG_VERSION
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync};
5f80794f0fac6c6ae43bf4d2baaef60babb2a7c7vboxsync