DrvAudioVRDE.cpp revision a708b5b81c81f03f13980efee2262d4290ba03be
/* $Id$ */
/** @file
* VRDE audio backend for Main.
*/
/*
* Copyright (C) 2013-2015 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#include "DrvAudioVRDE.h"
#include "ConsoleImpl.h"
#include "ConsoleVRDPServer.h"
#include "Logging.h"
#include "../../Devices/Audio/DrvAudio.h"
#include "../../Devices/Audio/AudioMixBuffer.h"
#define LOG_GROUP LOG_GROUP_DEV_AUDIO
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
/**
* Audio VRDE driver instance data.
*/
typedef struct DRVAUDIOVRDE
{
/** Pointer to audio VRDE object. */
/** Pointer to the driver instance structure. */
/** Pointer to the VRDP's console object. */
/** Pointer to the DrvAudio port interface that is above us. */
/** Whether this driver is enabled or not. */
bool fEnabled;
typedef struct VRDESTREAMIN
{
/** Associated host input stream. */
/** Number of samples captured asynchronously in the
* onVRDEInputXXX callbacks. */
/** Critical section. */
typedef struct VRDESTREAMOUT
{
/** Associated host output stream. */
{
return VINF_SUCCESS;
}
{
if (pcSamples)
}
{
if (pcSamples)
}
{
AssertPtrReturn(pDrv, false);
return false;
return true;
}
/**
* <Missing brief description>
*
* Transfers audio input formerly sent by a connected RDP client / VRDE backend
* (using the onVRDEInputXXX methods) over to the VRDE host (VM). The audio device
* emulation then will read and send the data to the guest.
*
* @return IPRT status code.
* @param pInterface
* @param pHstStrmIn
* @param pcSamplesCaptured
*/
static DECLCALLBACK(int) drvAudioVRDECaptureIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
{
/** @todo Use CritSect! */
int rc;
uint32_t cProcessed = 0;
if (pVRDEStrmIn->cSamplesCaptured)
{
&cProcessed);
}
else
rc = VINF_SUCCESS;
if (RT_SUCCESS(rc))
{
}
LogFlowFunc(("cSamplesCaptured=%RU32, cProcessed=%RU32\n",
return rc;
}
/**
* Transfers VM audio output to remote client.
*
* Transfers VM audio output over to the VRDE instance for playing remotely
* on the client.
*
* @return IPRT status code.
* @param pInterface
* @param pHstStrmOut
* @param pcSamplesPlayed
*/
static DECLCALLBACK(int) drvAudioVRDEPlayOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
{
/* pcSamplesPlayed is optional. */
/*
* Just call the VRDP server with the data.
*/
uint32_t cSamplesPlayed = (int)((2 * ticks * pHstStrmOut->Props.uHz + ticks_per_second) / ticks_per_second / 2);
if (!cSamplesPlayed)
int cSamplesToSend = live;
/* if (!cSamplesToSend)
{
if (pcSamplesPlayed)
pcSamplesPlayed = 0;
return 0;
}*/
LogFlowFunc(("uFreq=%RU32, cChan=%RU8, cBits=%RU8, fSigned=%RTbool, enmFormat=%ld, cSamplesToSend=%RU32\n",
format, cSamplesToSend));
uint32_t cReadTotal = 0;
if ( RT_SUCCESS(rc)
&& cRead)
{
cReadTotal = cRead;
if (rc == VINF_TRY_AGAIN)
{
if (RT_SUCCESS(rc))
cReadTotal += cRead;
}
}
/*
* Always report back all samples acquired, regardless of whether the
* VRDP server actually did process those.
*/
if (pcSamplesPlayed)
return rc;
}
static DECLCALLBACK(int) drvAudioVRDEFiniIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn)
{
if (pDrv->pConsoleVRDPServer)
return VINF_SUCCESS;
}
static DECLCALLBACK(int) drvAudioVRDEFiniOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut)
{
return VINF_SUCCESS;
}
static DECLCALLBACK(int) drvAudioVRDEControlOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
{
return VINF_SUCCESS;
}
static DECLCALLBACK(int) drvAudioVRDEControlIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
{
if (!pDrv->pConsoleVRDPServer)
return VINF_SUCCESS;
/* Initialize only if not already done. */
int rc;
if (enmStreamCmd == PDMAUDIOSTREAMCMD_ENABLE)
{
rc = pDrv->pConsoleVRDPServer->SendAudioInputBegin(NULL, pVRDEStrmIn, audioMixBufSize(&pThisStrmIn->MixBuf),
if (rc == VERR_NOT_SUPPORTED)
{
LogFlowFunc(("No RDP client connected, so no input recording supported\n"));
rc = VINF_SUCCESS;
}
}
else if (enmStreamCmd == PDMAUDIOSTREAMCMD_DISABLE)
{
rc = VINF_SUCCESS;
}
return rc;
}
{
return VINF_SUCCESS;
}
{
if (pDrv->pConsoleVRDPServer)
}
/**
* @interface_method_impl{PDMIBASE,pfnQueryInterface}
*/
{
return NULL;
}
{
}
{
if (mpDrv)
{
}
}
{
return VERR_INVALID_STATE;
return VINF_SUCCESS; /* Never veto. */
}
/**
* Marks the beginning of sending captured audio data from a connected
* RDP client.
*
* @return IPRT status code.
* @param pvContext The context; in this case a pointer to a
* VRDESTREAMIN structure.
* @param pVRDEAudioBegin Pointer to a VRDEAUDIOINBEGIN structure.
*/
{
LogFlowFunc(("cbSample=%RU32, iSampleHz=%d, cChannels=%d, cBits=%d, fUnsigned=%RTbool\n",
return VINF_SUCCESS;
}
{
/** @todo Use CritSect! */
if (RT_SUCCESS(rc))
LogFlowFunc(("cbData=%RU32, cWritten=%RU32, cSamplesCaptured=%RU32, rc=%Rrc\n",
return rc;
}
{
return VINF_SUCCESS;
}
{
return VINF_SUCCESS; /* Never veto. */
}
/**
* Construct a VRDE audio driver instance.
*
* @copydoc FNPDMDRVCONSTRUCT
*/
/* static */
{
LogRel(("Audio: Initializing VRDE driver\n"));
("Configuration error: Not possible to attach anything to this driver!\n"),
/*
* Init the static parts.
*/
/* IBase */
/* IHostAudio */
/* Init defaults. */
/*
* Get the ConsoleVRDPServer object pointer.
*/
void *pvUser;
AssertMsgRCReturn(rc, ("Confguration error: No/bad \"ObjectVRDPServer\" value, rc=%Rrc\n", rc), rc);
/* CFGM tree saves the pointer to ConsoleVRDPServer in the Object node of AudioVRDE. */
/*
* Get the AudioVRDE object pointer.
*/
/*
* Get the interface for the above driver (DrvAudio) to make mixer/conversion calls.
* Described in CFGM tree.
*/
AssertMsgReturn(pThis->pDrvAudio, ("Configuration error: No upper interface specified!\n"), VERR_PDM_MISSING_INTERFACE_ABOVE);
return VINF_SUCCESS;
}
/**
* @interface_method_impl{PDMDRVREG,pfnDestruct}
*/
/* static */
{
/*
* If the AudioVRDE object is still alive, we must clear it's reference to
* us since we'll be invalid when we return from this method.
*/
if (pThis->pAudioVRDE)
{
}
}
/**
* VRDE audio driver registration record.
*/
{
/* szName */
"AudioVRDE",
/* szRCMod */
"",
/* szR0Mod */
"",
/* pszDescription */
"Audio driver for VRDE backend",
/* fFlags */
/* fClass. */
/* cMaxInstances */
~0U,
/* cbInstance */
sizeof(DRVAUDIOVRDE),
/* pfnConstruct */
/* pfnDestruct */
/* pfnRelocate */
NULL,
/* pfnIOCtl */
NULL,
/* pfnPowerOn */
NULL,
/* pfnReset */
NULL,
/* pfnSuspend */
NULL,
/* pfnResume */
NULL,
/* pfnAttach */
NULL,
/* pfnDetach */
NULL,
/* pfnPowerOff */
NULL,
/* pfnSoftReset */
NULL,
/* u32EndVersion */
};