DrvAudioVideoRec.cpp revision e95cc69731ec79cf167e6167808e1c9b275ea007
174f3dff60f96d89b320f9a322307118676db1dbvboxsync/* $Id$ */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync/** @file
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * Video recording audio backend for Main.
174f3dff60f96d89b320f9a322307118676db1dbvboxsync */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync/*
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync * Copyright (C) 2014-2015 Oracle Corporation
174f3dff60f96d89b320f9a322307118676db1dbvboxsync *
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * available from http://www.virtualbox.org. This file is free software;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * you can redistribute it and/or modify it under the terms of the GNU
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * General Public License (GPL) as published by the Free Software
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
174f3dff60f96d89b320f9a322307118676db1dbvboxsync */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync#include "DrvAudioVideoRec.h"
174f3dff60f96d89b320f9a322307118676db1dbvboxsync#include "ConsoleImpl.h"
174f3dff60f96d89b320f9a322307118676db1dbvboxsync#include "ConsoleVRDPServer.h"
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync#include "Logging.h"
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync#include <iprt/mem.h>
174f3dff60f96d89b320f9a322307118676db1dbvboxsync#include <iprt/cdefs.h>
174f3dff60f96d89b320f9a322307118676db1dbvboxsync#include <iprt/circbuf.h>
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync#include <VBox/vmm/pdmaudioifs.h>
174f3dff60f96d89b320f9a322307118676db1dbvboxsync#include <VBox/vmm/pdmdrv.h>
174f3dff60f96d89b320f9a322307118676db1dbvboxsync#include <VBox/RemoteDesktop/VRDE.h>
174f3dff60f96d89b320f9a322307118676db1dbvboxsync#include <VBox/vmm/cfgm.h>
174f3dff60f96d89b320f9a322307118676db1dbvboxsync#include <VBox/err.h>
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync#ifdef LOG_GROUP
174f3dff60f96d89b320f9a322307118676db1dbvboxsync #undef LOG_GROUP
174f3dff60f96d89b320f9a322307118676db1dbvboxsync#endif
174f3dff60f96d89b320f9a322307118676db1dbvboxsync#define LOG_GROUP LOG_GROUP_DEV_AUDIO
174f3dff60f96d89b320f9a322307118676db1dbvboxsync#include <VBox/log.h>
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync/* Initialization status indicator used for the recreation of the AudioUnits. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync#define CA_STATUS_UNINIT UINT32_C(0) /* The device is uninitialized */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync#define CA_STATUS_IN_INIT UINT32_C(1) /* The device is currently initializing */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync#define CA_STATUS_INIT UINT32_C(2) /* The device is initialized */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync#define CA_STATUS_IN_UNINIT UINT32_C(3) /* The device is currently uninitializing */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync//@todo move t_sample as a PDM interface
174f3dff60f96d89b320f9a322307118676db1dbvboxsync//typedef struct { int mute; uint32_t r; uint32_t l; } volume_t;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync#define INT_MAX 0x7fffffff
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncvolume_t videorec_nominal_volume = {
174f3dff60f96d89b320f9a322307118676db1dbvboxsync 0,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync INT_MAX,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync INT_MAX
174f3dff60f96d89b320f9a322307118676db1dbvboxsync};
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync/* The desired buffer length in milliseconds. Will be the target total stream
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * latency on newer version of pulse. Apparent latency can be less (or more.)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * In case its need to be used. Currently its not used.
174f3dff60f96d89b320f9a322307118676db1dbvboxsync */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync#if 0
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic struct
174f3dff60f96d89b320f9a322307118676db1dbvboxsync{
174f3dff60f96d89b320f9a322307118676db1dbvboxsync int buffer_msecs_out;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync int buffer_msecs_in;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync} confAudioVideoRec
174f3dff60f96d89b320f9a322307118676db1dbvboxsync=
174f3dff60f96d89b320f9a322307118676db1dbvboxsync{
174f3dff60f96d89b320f9a322307118676db1dbvboxsync INIT_FIELD (.buffer_msecs_out = ) 100,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync INIT_FIELD (.buffer_msecs_in = ) 100,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync};
174f3dff60f96d89b320f9a322307118676db1dbvboxsync#endif
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync/**
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * Audio video recording driver instance data.
174f3dff60f96d89b320f9a322307118676db1dbvboxsync *
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * @extends PDMIAUDIOSNIFFERCONNECTOR
174f3dff60f96d89b320f9a322307118676db1dbvboxsync */
174f3dff60f96d89b320f9a322307118676db1dbvboxsynctypedef struct DRVAUDIOVIDEOREC
174f3dff60f96d89b320f9a322307118676db1dbvboxsync{
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /** Pointer to audio video recording object. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync AudioVideoRec *pAudioVideoRec;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PPDMDRVINS pDrvIns;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /** Pointer to the driver instance structure. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PDMIHOSTAUDIO IHostAudioR3;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync ConsoleVRDPServer *pConsoleVRDPServer;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /** Pointer to the DrvAudio port interface that is above it. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PPDMIAUDIOCONNECTOR pUpPort;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync} DRVAUDIOVIDEOREC, *PDRVAUDIOVIDEOREC;
174f3dff60f96d89b320f9a322307118676db1dbvboxsynctypedef struct PDMAUDIOHSTSTRMOUT PDMAUDIOHSTSTRMOUT;
174f3dff60f96d89b320f9a322307118676db1dbvboxsynctypedef PDMAUDIOHSTSTRMOUT *PPDMAUDIOHSTSTRMOUT;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsynctypedef struct VIDEORECAUDIOIN
174f3dff60f96d89b320f9a322307118676db1dbvboxsync{
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* Audio and audio details for recording */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PDMAUDIOHSTSTRMIN pHostVoiceIn;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync void * pvUserCtx;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* Number of bytes per frame (bitsPerSample * channels) of the actual input format. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync uint32_t cBytesPerFrame;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* Frequency of the actual audio format. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync uint32_t uFrequency;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* If the actual format frequence differs from the requested format, this is not NULL. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync void *rate;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* Temporary buffer for st_sample_t representation of the input audio data. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync void *pvSamplesBuffer;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* buffer for bytes of samples (not rate converted) */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync uint32_t cbSamplesBufferAllocated;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* Temporary buffer for frequency conversion. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync void *pvRateBuffer;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* buffer for bytes rate converted samples */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync uint32_t cbRateBufferAllocated;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* A ring buffer for transferring data to the playback thread */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PRTCIRCBUF pRecordedVoiceBuf;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync t_sample * convAudioDevFmtToStSampl;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync uint32_t fIsInit;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync uint32_t status;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync} VIDEORECAUDIOIN, *PVIDEORECAUDIOIN;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsynctypedef struct VIDEORECAUDIOOUT
174f3dff60f96d89b320f9a322307118676db1dbvboxsync{
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PDMAUDIOHSTSTRMOUT pHostVoiceOut;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync uint64_t old_ticks;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync uint64_t cSamplesSentPerSec;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync} VIDEORECAUDIOOUT, *PVIDEORECAUDIOOUT;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic DECLCALLBACK(int) drvAudioVideoRecInit(PPDMIHOSTAUDIO pInterface)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync{
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogFlowFuncEnter();
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return VINF_SUCCESS;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync}
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync/** @todo Replace this with drvAudioHlpPcmPropsFromCfg(). */
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic int drvAudioVideoRecPcmInitInfo(PDMPCMPROPS * pProps, PPDMAUDIOSTREAMCFG as)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync{
174f3dff60f96d89b320f9a322307118676db1dbvboxsync int rc = VINF_SUCCESS;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync uint8_t cBits = 8, cShift = 0;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync bool fSigned = false;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync switch (as->enmFormat)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync {
174f3dff60f96d89b320f9a322307118676db1dbvboxsync case AUD_FMT_S8:
174f3dff60f96d89b320f9a322307118676db1dbvboxsync fSigned = 1;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync case AUD_FMT_U8:
174f3dff60f96d89b320f9a322307118676db1dbvboxsync break;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync case AUD_FMT_S16:
174f3dff60f96d89b320f9a322307118676db1dbvboxsync fSigned = 1;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync case AUD_FMT_U16:
174f3dff60f96d89b320f9a322307118676db1dbvboxsync cBits = 16;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync cShift = 1;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync break;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync case AUD_FMT_S32:
174f3dff60f96d89b320f9a322307118676db1dbvboxsync fSigned = 1;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync case AUD_FMT_U32:
174f3dff60f96d89b320f9a322307118676db1dbvboxsync cBits = 32;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync cShift = 2;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync break;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync default:
174f3dff60f96d89b320f9a322307118676db1dbvboxsync rc = VERR_NOT_SUPPORTED;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync break;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync }
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pProps->uHz = as->uHz;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pProps->cBits = cBits;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pProps->fSigned = fSigned;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pProps->cChannels = as->cChannels;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pProps->cShift = (as->cChannels == 2) + cShift;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pProps->uAlign = (1 << pProps->cShift) - 1;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pProps->cbPerSec = pProps->uHz << pProps->cShift;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pProps->fSwapEndian = (as->enmEndianness != PDMAUDIOHOSTENDIANESS);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return rc;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync}
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync/*
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * Hard voice (playback)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync */
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic int audio_pcm_hw_find_min_out (PPDMAUDIOHSTSTRMOUT hw, int *nb_livep)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync{
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PPDMAUDIOGSTSTRMOUT sw;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PPDMAUDIOGSTSTRMOUT pIter;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync int m = INT_MAX;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync int nb_live = 0;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync RTListForEach(&hw->lstGstStrmOut, pIter, PDMAUDIOGSTSTRMOUT, Node)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync {
174f3dff60f96d89b320f9a322307118676db1dbvboxsync sw = pIter;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync if (sw->State.fActive || !sw->State.fEmpty)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync {
174f3dff60f96d89b320f9a322307118676db1dbvboxsync m = RT_MIN (m, sw->cTotalSamplesWritten);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync nb_live += 1;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync }
174f3dff60f96d89b320f9a322307118676db1dbvboxsync }
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync *nb_livep = nb_live;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return m;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync}
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic int audio_pcm_hw_get_live_out2 (PPDMAUDIOHSTSTRMOUT hw, int *nb_live)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync{
174f3dff60f96d89b320f9a322307118676db1dbvboxsync int smin;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync smin = audio_pcm_hw_find_min_out (hw, nb_live);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync if (!*nb_live) {
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return 0;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync }
174f3dff60f96d89b320f9a322307118676db1dbvboxsync else
174f3dff60f96d89b320f9a322307118676db1dbvboxsync {
174f3dff60f96d89b320f9a322307118676db1dbvboxsync int live = smin;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync if (live < 0 || live > hw->cSamples)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync {
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogFlowFunc(("Error: live=%d hw->samples=%d\n", live, hw->cSamples));
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return 0;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync }
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return live;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync }
174f3dff60f96d89b320f9a322307118676db1dbvboxsync}
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic int audio_pcm_hw_get_live_out (PPDMAUDIOHSTSTRMOUT hw)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync{
174f3dff60f96d89b320f9a322307118676db1dbvboxsync int nb_live;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync int live;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync live = audio_pcm_hw_get_live_out2 (hw, &nb_live);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync if (live < 0 || live > hw->cSamples)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync {
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogFlowFunc(("Error: live=%d hw->samples=%d\n", live, hw->cSamples));
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return 0;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync }
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return live;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync}
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync/*
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * Hard voice (capture)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync */
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic int audio_pcm_hw_find_min_in (PPDMAUDIOHSTSTRMIN hw)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync{
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PPDMAUDIOGSTSTRMIN pIter;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync int m = hw->cTotalSamplesCaptured;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync RTListForEach(&hw->lstGstStreamsIn, pIter, PDMAUDIOGSTSTRMIN, Node)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync {
174f3dff60f96d89b320f9a322307118676db1dbvboxsync if (pIter->State.fActive)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync {
174f3dff60f96d89b320f9a322307118676db1dbvboxsync m = RT_MIN (m, pIter->cTotalHostSamplesRead);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync }
174f3dff60f96d89b320f9a322307118676db1dbvboxsync }
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return m;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync}
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncint audio_pcm_hw_get_live_in (PPDMAUDIOHSTSTRMIN hw)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync{
174f3dff60f96d89b320f9a322307118676db1dbvboxsync int live = hw->cTotalSamplesCaptured - audio_pcm_hw_find_min_in (hw);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync if (live < 0 || live > hw->cSamples)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync {
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogFlowFunc(("Error: live=%d hw->samples=%d\n", live, hw->cSamples));
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return 0;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync }
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return live;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync}
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic inline void *advance (void *p, int incr)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync{
174f3dff60f96d89b320f9a322307118676db1dbvboxsync uint8_t *d = (uint8_t*)p;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return (d + incr);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync}
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic int vrdeReallocSampleBuf(PVIDEORECAUDIOIN pVRDEVoice, uint32_t cSamples)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync{
174f3dff60f96d89b320f9a322307118676db1dbvboxsync uint32_t cbBuffer = cSamples * sizeof(PDMAUDIOSAMPLE);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync if (cbBuffer > pVRDEVoice->cbSamplesBufferAllocated)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync {
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /** @todo r=andy Why not using RTMemReAlloc? */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync if (pVRDEVoice->pvSamplesBuffer)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync {
174f3dff60f96d89b320f9a322307118676db1dbvboxsync RTMemFree(pVRDEVoice->pvSamplesBuffer);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pVRDEVoice->pvSamplesBuffer = NULL;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync }
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pVRDEVoice->pvSamplesBuffer = RTMemAlloc(cbBuffer);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync if (pVRDEVoice->pvSamplesBuffer)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pVRDEVoice->cbSamplesBufferAllocated = cbBuffer;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync else
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pVRDEVoice->cbSamplesBufferAllocated = 0;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync }
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return VINF_SUCCESS;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync}
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic int vrdeReallocRateAdjSampleBuf(PVIDEORECAUDIOIN pVRDEVoice, uint32_t cSamples)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync{
174f3dff60f96d89b320f9a322307118676db1dbvboxsync uint32_t cbBuffer = cSamples * sizeof(PDMAUDIOSAMPLE);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync if (cbBuffer > pVRDEVoice->cbRateBufferAllocated)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync {
174f3dff60f96d89b320f9a322307118676db1dbvboxsync RTMemFree(pVRDEVoice->pvRateBuffer);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pVRDEVoice->pvRateBuffer = RTMemAlloc(cbBuffer);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync if (pVRDEVoice->pvRateBuffer)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pVRDEVoice->cbRateBufferAllocated = cbBuffer;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync else
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pVRDEVoice->cbRateBufferAllocated = 0;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync }
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return VINF_SUCCESS;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync}
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync/*******************************************************************************
174f3dff60f96d89b320f9a322307118676db1dbvboxsync *
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * AudioVideoRec input section
174f3dff60f96d89b320f9a322307118676db1dbvboxsync *
174f3dff60f96d89b320f9a322307118676db1dbvboxsync ******************************************************************************/
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync/*
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * Callback to feed audio input buffer. Samples format is be the same as
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * in the voice. The caller prepares st_sample_t.
174f3dff60f96d89b320f9a322307118676db1dbvboxsync *
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * @param cbSamples Size of pvSamples array in bytes.
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * @param pvSamples Points to an array of samples.
174f3dff60f96d89b320f9a322307118676db1dbvboxsync *
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * @return IPRT status code.
174f3dff60f96d89b320f9a322307118676db1dbvboxsync */
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic int vrdeRecordingCallback(PVIDEORECAUDIOIN pVRDEVoice, uint32_t cbSamples, const void *pvSamples)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync{
174f3dff60f96d89b320f9a322307118676db1dbvboxsync int rc = VINF_SUCCESS;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync size_t csWritten = 0;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync Assert((cbSamples % sizeof(PDMAUDIOSAMPLE)) == 0);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync if (!pVRDEVoice->fIsInit)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return VINF_SUCCESS;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* If nothing is pending return immediately. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync if (cbSamples == 0)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return VINF_SUCCESS;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* How much space is free in the ring buffer? */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync size_t csAvail = RTCircBufFree(pVRDEVoice->pRecordedVoiceBuf) / sizeof(PDMAUDIOSAMPLE); /* bytes -> samples */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* How much space is used in the audio buffer. Use the smaller size of the too. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync csAvail = RT_MIN(csAvail, cbSamples / sizeof(PDMAUDIOSAMPLE));
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* Iterate as long as data is available. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync while (csWritten < csAvail)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync {
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* How much is left? */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync size_t csToWrite = csAvail - csWritten;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync size_t cbToWrite = csToWrite * sizeof(PDMAUDIOSAMPLE);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* Try to acquire the necessary space from the ring buffer. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync void *pcDst;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync RTCircBufAcquireWriteBlock(pVRDEVoice->pRecordedVoiceBuf, cbToWrite, &pcDst, &cbToWrite);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* How much do we get? */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync csToWrite = cbToWrite / sizeof(PDMAUDIOSAMPLE);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* Copy the data from the audio buffer to the ring buffer in PVRDEVoice. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync if (csToWrite)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync {
174f3dff60f96d89b320f9a322307118676db1dbvboxsync memcpy(pcDst, (uint8_t *)pvSamples + (csWritten * sizeof(PDMAUDIOSAMPLE)), cbToWrite);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync csWritten += csToWrite;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync }
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* Release the ring buffer, so the main thread could start reading this data. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync RTCircBufReleaseWriteBlock(pVRDEVoice->pRecordedVoiceBuf, cbToWrite);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync if (RT_UNLIKELY(csToWrite == 0))
174f3dff60f96d89b320f9a322307118676db1dbvboxsync break;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync }
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogFlowFunc(("Finished writing buffer with %RU32 samples (%RU32 bytes)\n",
174f3dff60f96d89b320f9a322307118676db1dbvboxsync csWritten, csWritten * sizeof(PDMAUDIOSAMPLE)));
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return rc;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync}
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic DECLCALLBACK(int) drvAudioVideoRecInitOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHostVoiceOut, PPDMAUDIOSTREAMCFG pCfg)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync{
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogFlowFuncEnter();
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PDRVAUDIOVIDEOREC pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVIDEOREC, IHostAudioR3);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PVIDEORECAUDIOOUT pVRDEVoiceOut = (PVIDEORECAUDIOOUT)pHostVoiceOut;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pHostVoiceOut->cSamples = _4K; /* 4096 samples * 4 = 16K bytes total. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return drvAudioVideoRecPcmInitInfo(&pVRDEVoiceOut->pHostVoiceOut.Props, pCfg);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync}
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic DECLCALLBACK(int) drvAudioVideoRecInitIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHostVoiceIn, PPDMAUDIOSTREAMCFG pCfg)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync{
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogFlowFuncEnter();
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PDRVAUDIOVIDEOREC pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVIDEOREC, IHostAudioR3);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PVIDEORECAUDIOIN pVRDEVoice = (PVIDEORECAUDIOIN)pHostVoiceIn;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pHostVoiceIn->cSamples = _4K; /* 4096 samples * 4 = 16K bytes total. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return drvAudioVideoRecPcmInitInfo(&pVRDEVoice->pHostVoiceIn.Props, pCfg);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync}
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic DECLCALLBACK(int) drvAudioVideoRecCaptureIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHostVoiceIn,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync uint32_t *pcSamplesCaptured)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync{
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /** @todo Take care of the size of the buffer allocated to pHostVoiceIn. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PVIDEORECAUDIOIN pVRDEVoice = (PVIDEORECAUDIOIN)pHostVoiceIn;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* use this from DrvHostCoreAudio.c */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync if (ASMAtomicReadU32(&pVRDEVoice->status) != CA_STATUS_INIT)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync {
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogFlowFunc(("VRDE voice not initialized\n"));
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync *pcSamplesCaptured = 0;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return VERR_GENERAL_FAILURE; /** @todo Fudge! */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync }
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* how much space is used in the ring buffer in pRecordedVocieBuf with pAudioVideoRec . Bytes-> samples*/
174f3dff60f96d89b320f9a322307118676db1dbvboxsync size_t cSamplesRingBuffer = RTCircBufUsed(pVRDEVoice->pRecordedVoiceBuf) / sizeof(PDMAUDIOSAMPLE);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* How much space is available in the mix buffer. Use the smaller size of the too. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync cSamplesRingBuffer = RT_MIN(cSamplesRingBuffer, (uint32_t)(pVRDEVoice->pHostVoiceIn.cSamples -
174f3dff60f96d89b320f9a322307118676db1dbvboxsync audio_pcm_hw_get_live_in (&pVRDEVoice->pHostVoiceIn)));
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogFlowFunc(("Start reading buffer with %d samples (%d bytes)\n", cSamplesRingBuffer,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync cSamplesRingBuffer * sizeof(PDMAUDIOSAMPLE)));
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* Iterate as long as data is available */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync size_t cSamplesRead = 0;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync while (cSamplesRead < cSamplesRingBuffer)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync {
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* How much is left? Split request at the end of our samples buffer. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync size_t cSamplesToRead = RT_MIN(cSamplesRingBuffer - cSamplesRead,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync (uint32_t)(pVRDEVoice->pHostVoiceIn.cSamples - pVRDEVoice->pHostVoiceIn.offSamplesWritten));
174f3dff60f96d89b320f9a322307118676db1dbvboxsync size_t cbToRead = cSamplesToRead * sizeof(PDMAUDIOSAMPLE);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogFlowFunc(("Try reading %zu samples (%zu bytes)\n", cSamplesToRead, cbToRead));
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* Try to acquire the necessary block from the ring buffer. Remeber in fltRecrodCallback we
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * we are filling this buffer with the audio data available from VRDP. Here we are reading it
174f3dff60f96d89b320f9a322307118676db1dbvboxsync */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /*todo do I need to introduce a thread to fill the buffer in fltRecordcallback. So that
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * filling is in separate thread and the reading of that buffer is in separate thread
174f3dff60f96d89b320f9a322307118676db1dbvboxsync */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync void *pvSrc;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync RTCircBufAcquireReadBlock(pVRDEVoice->pRecordedVoiceBuf, cbToRead, &pvSrc, &cbToRead);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* How much to we get? */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync cSamplesToRead = cbToRead / sizeof(PDMAUDIOSAMPLE);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogFlowFunc(("AuderVRDE: There are %d samples (%d bytes) available\n", cSamplesToRead, cbToRead));
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* Break if nothing is used anymore. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync if (cSamplesToRead)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync {
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* Copy the data from our ring buffer to the mix buffer. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PPDMAUDIOSAMPLE psDst = pVRDEVoice->pHostVoiceIn.paSamples + pVRDEVoice->pHostVoiceIn.offSamplesWritten;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync memcpy(psDst, pvSrc, cbToRead);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync }
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* Release the read buffer, so it could be used for new data. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync RTCircBufReleaseReadBlock(pVRDEVoice->pRecordedVoiceBuf, cbToRead);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync if (!cSamplesToRead)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync break;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pVRDEVoice->pHostVoiceIn.offSamplesWritten = (pVRDEVoice->pHostVoiceIn.offSamplesWritten + cSamplesToRead)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync % pVRDEVoice->pHostVoiceIn.cSamples;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* How much have we reads so far. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync cSamplesRead += cSamplesToRead;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync }
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogFlowFunc(("Finished reading buffer with %zu samples (%zu bytes)\n",
174f3dff60f96d89b320f9a322307118676db1dbvboxsync cSamplesRead, cSamplesRead * sizeof(PDMAUDIOSAMPLE)));
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync *pcSamplesCaptured = cSamplesRead;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return VINF_SUCCESS;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync}
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic DECLCALLBACK(int) drvAudioVideoRecPlayOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHostVoiceOut,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync uint32_t *pcSamplesPlayed)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync{
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PDRVAUDIOVIDEOREC pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVIDEOREC, IHostAudioR3);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PVIDEORECAUDIOOUT pVRDEVoiceOut = (PVIDEORECAUDIOOUT)pHostVoiceOut;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /*
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * Just call the VRDP server with the data.
174f3dff60f96d89b320f9a322307118676db1dbvboxsync */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync int live = audio_pcm_hw_get_live_out(pHostVoiceOut);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync uint64_t now = PDMDrvHlpTMGetVirtualTime(pDrv->pDrvIns);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync uint64_t ticks = now - pVRDEVoiceOut->old_ticks;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync uint64_t ticks_per_second = PDMDrvHlpTMGetVirtualFreq(pDrv->pDrvIns);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync int cSamplesPlayed = (int)((2 * ticks * pHostVoiceOut->Props.uHz + ticks_per_second) / ticks_per_second / 2);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync if (cSamplesPlayed < 0)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync cSamplesPlayed = live;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pHostVoiceOut->Props.cBits = 128; /** @todo Make this configurable (or at least a define)? */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync VRDEAUDIOFORMAT format = VRDE_AUDIO_FMT_MAKE(pHostVoiceOut->Props.uHz,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pHostVoiceOut->Props.cChannels,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pHostVoiceOut->Props.cBits, /* bits per sample */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync !pHostVoiceOut->Props.fSigned);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogFlowFunc(("freq=%d, chan=%d, cBits = %d, fsigned = %d, cSamples=%d format=%d\n",
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pHostVoiceOut->Props.uHz, pHostVoiceOut->Props.cChannels,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pHostVoiceOut->Props.cBits, pHostVoiceOut->Props.fSigned,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pHostVoiceOut->cSamples, format));
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pVRDEVoiceOut->old_ticks = now;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync int cSamplesToSend = RT_MIN(live, cSamplesPlayed);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync if (pHostVoiceOut->cOffSamplesRead + cSamplesToSend > pHostVoiceOut->cSamples)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync {
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* send the samples till the end of pHostStereoSampleBuf */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pDrv->pConsoleVRDPServer->SendAudioSamples(&pHostVoiceOut->paSamples[pHostVoiceOut->cOffSamplesRead],
174f3dff60f96d89b320f9a322307118676db1dbvboxsync (pHostVoiceOut->cSamples - pHostVoiceOut->cOffSamplesRead), format);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /*pHostStereoSampleBuff already has the samples which exceeded its space. They have overwriten the old
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * played sampled starting from offset 0. So based on the number of samples that we had to play,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * read the number of samples from offset 0 .
174f3dff60f96d89b320f9a322307118676db1dbvboxsync */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pDrv->pConsoleVRDPServer->SendAudioSamples(&pHostVoiceOut->paSamples[0],
174f3dff60f96d89b320f9a322307118676db1dbvboxsync (cSamplesToSend - (pHostVoiceOut->cSamples -
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pHostVoiceOut->cOffSamplesRead)),
174f3dff60f96d89b320f9a322307118676db1dbvboxsync format);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync }
174f3dff60f96d89b320f9a322307118676db1dbvboxsync else
174f3dff60f96d89b320f9a322307118676db1dbvboxsync {
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pDrv->pConsoleVRDPServer->SendAudioSamples(&pHostVoiceOut->paSamples[pHostVoiceOut->cOffSamplesRead],
174f3dff60f96d89b320f9a322307118676db1dbvboxsync cSamplesToSend, format);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync }
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pHostVoiceOut->cOffSamplesRead = (pHostVoiceOut->cOffSamplesRead + cSamplesToSend) % pHostVoiceOut->cSamples;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync *pcSamplesPlayed = cSamplesToSend;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return VINF_SUCCESS;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync}
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic DECLCALLBACK(int) drvAudioVideoRecFiniIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN hw)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync{
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PDRVAUDIOVIDEOREC pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVIDEOREC, IHostAudioR3);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogFlowFuncEnter();
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pDrv->pConsoleVRDPServer->SendAudioInputEnd(NULL);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return VINF_SUCCESS;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync}
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic DECLCALLBACK(int) drvAudioVideoRecFiniOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHostVoiceOut)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync{
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PDRVAUDIOVIDEOREC pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVIDEOREC, IHostAudioR3);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogFlowFuncEnter();
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return VINF_SUCCESS;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync}
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic DECLCALLBACK(int) drvAudioVideoRecControlOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT hw,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PDMAUDIOSTREAMCMD enmStreamCmd)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync{
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PDRVAUDIOVIDEOREC pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVIDEOREC, IHostAudioR3);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogFlowFuncEnter();
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return VINF_SUCCESS;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync}
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic DECLCALLBACK(int) drvAudioVideoRecControlIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHostVoiceIn,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PDMAUDIOSTREAMCMD enmStreamCmd)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync{
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PDRVAUDIOVIDEOREC pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVIDEOREC, IHostAudioR3);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* Initialize VRDEVoice and return to VRDP server which returns this struct back to us
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * in the form void * pvContext
174f3dff60f96d89b320f9a322307118676db1dbvboxsync */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PVIDEORECAUDIOIN pVRDEVoice = (PVIDEORECAUDIOIN)pHostVoiceIn;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogFlowFunc(("enmStreamCmd=%ld\n", enmStreamCmd));
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* initialize only if not already done */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync if (enmStreamCmd == PDMAUDIOSTREAMCMD_ENABLE)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync {
174f3dff60f96d89b320f9a322307118676db1dbvboxsync //@todo if (!pVRDEVoice->fIsInit)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync // RTCircBufReset(pVRDEVoice->pRecordedVoiceBuf);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pVRDEVoice->fIsInit = 1;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pVRDEVoice->pHostVoiceIn = *pHostVoiceIn;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pVRDEVoice->cBytesPerFrame = 1;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pVRDEVoice->uFrequency = 0;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pVRDEVoice->rate = NULL;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pVRDEVoice->cbSamplesBufferAllocated = 0;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pVRDEVoice->pvRateBuffer = NULL;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pVRDEVoice->cbRateBufferAllocated = 0;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pVRDEVoice->pHostVoiceIn.cSamples = 2048;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* Initialize the hardware info section with the audio settings */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync ASMAtomicWriteU32(&pVRDEVoice->status, CA_STATUS_IN_INIT);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* Create the internal ring buffer. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync RTCircBufCreate(&pVRDEVoice->pRecordedVoiceBuf,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pVRDEVoice->pHostVoiceIn.cSamples * sizeof(PDMAUDIOSAMPLE));
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync if (!RT_VALID_PTR(pVRDEVoice->pRecordedVoiceBuf))
174f3dff60f96d89b320f9a322307118676db1dbvboxsync {
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogRel(("Failed to create internal ring buffer\n"));
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return VERR_NO_MEMORY;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync }
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync ASMAtomicWriteU32(&pVRDEVoice->status, CA_STATUS_INIT);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return pDrv->pConsoleVRDPServer->SendAudioInputBegin(NULL, pVRDEVoice, pHostVoiceIn->cSamples,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pHostVoiceIn->Props.uHz,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pHostVoiceIn->Props.cChannels, pHostVoiceIn->Props.cBits);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync }
174f3dff60f96d89b320f9a322307118676db1dbvboxsync else if (enmStreamCmd == PDMAUDIOSTREAMCMD_DISABLE)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync {
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pVRDEVoice->fIsInit = 0;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync ASMAtomicWriteU32(&pVRDEVoice->status, CA_STATUS_IN_UNINIT);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync RTCircBufDestroy(pVRDEVoice->pRecordedVoiceBuf);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pVRDEVoice->pRecordedVoiceBuf = NULL;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync ASMAtomicWriteU32(&pVRDEVoice->status, CA_STATUS_UNINIT);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pDrv->pConsoleVRDPServer->SendAudioInputEnd(NULL);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync }
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return VINF_SUCCESS;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync}
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic DECLCALLBACK(int) drvAudioVideoRecGetConf(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pAudioConf)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync{
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogFlowFunc(("pAudioConf=%p\n", pAudioConf));
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pAudioConf->cbStreamOut = sizeof(VIDEORECAUDIOOUT);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pAudioConf->cbStreamIn = sizeof(VIDEORECAUDIOIN);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pAudioConf->cMaxHstStrmsOut = 1;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pAudioConf->cMaxHstStrmsIn = 1;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return VINF_SUCCESS;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync}
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync/**
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * @interface_method_impl{PDMIBASE,pfnQueryInterface}
174f3dff60f96d89b320f9a322307118676db1dbvboxsync */
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic DECLCALLBACK(void *) drvAudioVideoRecQueryInterface(PPDMIBASE pInterface, const char *pszIID)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync{
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PDRVAUDIOVIDEOREC pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVIDEOREC);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudioR3);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return NULL;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync}
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncAudioVideoRec::AudioVideoRec(Console *pConsole)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync : mpDrv(NULL),
174f3dff60f96d89b320f9a322307118676db1dbvboxsync mParent(pConsole)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync{
174f3dff60f96d89b320f9a322307118676db1dbvboxsync}
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncAudioVideoRec::~AudioVideoRec(void)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync{
174f3dff60f96d89b320f9a322307118676db1dbvboxsync if (mpDrv)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync {
174f3dff60f96d89b320f9a322307118676db1dbvboxsync mpDrv->pAudioVideoRec = NULL;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync mpDrv = NULL;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync }
174f3dff60f96d89b320f9a322307118676db1dbvboxsync}
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncint AudioVideoRec::handleVideoRecSvrCmdAudioInputIntercept(bool fIntercept)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync{
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogFlowThisFunc(("fIntercept=%RTbool\n", fIntercept));
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return VINF_SUCCESS;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync}
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncint AudioVideoRec::handleVideoRecSvrCmdAudioInputEventBegin(void *pvContext, int iSampleHz, int cChannels,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync int cBits, bool fUnsigned)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync{
174f3dff60f96d89b320f9a322307118676db1dbvboxsync int bitIdx;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PVIDEORECAUDIOIN pVRDEVoice = (PVIDEORECAUDIOIN)pvContext;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogFlowFunc(("handleVRDPCmdInputEventBegin\n"));
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* Prepare a format convertion for the actually used format. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pVRDEVoice->cBytesPerFrame = ((cBits + 7) / 8) * cChannels;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync if (cBits == 16)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync {
174f3dff60f96d89b320f9a322307118676db1dbvboxsync bitIdx = 1;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync }
174f3dff60f96d89b320f9a322307118676db1dbvboxsync else if (cBits == 32)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync {
174f3dff60f96d89b320f9a322307118676db1dbvboxsync bitIdx = 2;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync }
174f3dff60f96d89b320f9a322307118676db1dbvboxsync else
174f3dff60f96d89b320f9a322307118676db1dbvboxsync {
174f3dff60f96d89b320f9a322307118676db1dbvboxsync bitIdx = 0;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync }
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync //PPDMIAUDIOCONNECTOR pPort = server->mConsole->getAudioVideoRec()->getDrvAudioPort();
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* Call DrvAudio interface to get the t_sample type conversion function */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /*mpDrv->pUpPort->pfnConvDevFmtToStSample(mpDrv->pUpPort,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync (cChannels == 2) ? 1 : 0,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync !fUnsigned, 0, bitIdx,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pVRDEVoice->convAudioDevFmtToStSampl);*/
174f3dff60f96d89b320f9a322307118676db1dbvboxsync if (pVRDEVoice->convAudioDevFmtToStSampl)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync {
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogFlowFunc(("Failed to get the conversion function \n"));
174f3dff60f96d89b320f9a322307118676db1dbvboxsync }
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogFlowFunc(("Required freq as requested by VRDP Server = %d\n", iSampleHz));
174f3dff60f96d89b320f9a322307118676db1dbvboxsync //if (iSampleHz && iSampleHz != pVRDEVoice->pHostVoiceIn.Props.uFrequency)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync {
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* @todo if the above condition is false then pVRDEVoice->uFrequency will remain 0 */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /*mpDrv->pUpPort->pfnPrepareAudioConversion(mpDrv->pUpPort, iSampleHz,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pVRDEVoice->pHostVoiceIn.Props.uFrequency,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync &pVRDEVoice->rate);*/
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pVRDEVoice->uFrequency = iSampleHz;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogFlowFunc(("pVRDEVoice assigned requested freq =%d\n", pVRDEVoice->uFrequency));
174f3dff60f96d89b320f9a322307118676db1dbvboxsync }
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return VINF_SUCCESS;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync}
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync/*
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * pvContext: pointer to VRDP voice returned by the VRDP server. The is same pointer that we initialized in
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * drvAudioVideoRecDisableEnableIn VOICE_ENABLE case.
174f3dff60f96d89b320f9a322307118676db1dbvboxsync */
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncint AudioVideoRec::handleVideoRecSvrCmdAudioInputEventData(void *pvContext, const void *pvData, uint32_t cbData)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync{
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PVIDEORECAUDIOIN pVRDEVoice = (PVIDEORECAUDIOIN)pvContext;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PPDMAUDIOSAMPLE pHostStereoSampleBuf; /* target sample buffer */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PPDMAUDIOSAMPLE pConvertedSampleBuf; /* samples adjusted for rate */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync uint32_t cSamples = cbData / pVRDEVoice->cBytesPerFrame; /* Count of samples */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync void * pTmpSampleBuf = NULL;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync uint32_t cConvertedSamples; /* samples adjusted for rate */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync uint32_t cbSamples; /* count of bytes occupied by samples */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync int rc = VINF_SUCCESS;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogFlowFunc(("handleVRDPCmdInputEventData cbData = %d, bytesperfram=%d\n",
174f3dff60f96d89b320f9a322307118676db1dbvboxsync cbData, pVRDEVoice->cBytesPerFrame));
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync vrdeReallocSampleBuf(pVRDEVoice, cSamples);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pHostStereoSampleBuf = (PPDMAUDIOSAMPLE)pVRDEVoice->pvSamplesBuffer;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pVRDEVoice->convAudioDevFmtToStSampl(pHostStereoSampleBuf, pvData, cSamples, &videorec_nominal_volume);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* count of rate adjusted samples */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pVRDEVoice->uFrequency = 22100; /* @todo handle this. How pVRDEVoice will get proper value */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync cConvertedSamples = (cSamples * pVRDEVoice->pHostVoiceIn.Props.uHz) / pVRDEVoice->uFrequency;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync vrdeReallocRateAdjSampleBuf(pVRDEVoice, cConvertedSamples);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pConvertedSampleBuf = (PPDMAUDIOSAMPLE)pVRDEVoice->pvRateBuffer;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync if (pConvertedSampleBuf)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync {
174f3dff60f96d89b320f9a322307118676db1dbvboxsync uint32_t cSampleSrc = cSamples;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync uint32_t cSampleDst = cConvertedSamples;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /*mpDrv->pUpPort->pfnDoRateConversion(mpDrv->pUpPort, pVRDEVoice->rate, pHostStereoSampleBuf,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pConvertedSampleBuf, &cSampleSrc, &cConvertedSamples);*/
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pTmpSampleBuf = pConvertedSampleBuf;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync cbSamples = cConvertedSamples * sizeof(PDMAUDIOSAMPLE);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync }
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync if (cbSamples)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync rc = vrdeRecordingCallback(pVRDEVoice, cbSamples, pTmpSampleBuf);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return rc;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync}
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync/*
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * pvContext: pointer to VRDP voice returned by the VRDP server. The is same pointer that we initialized in
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * drvAudioVideoRecDisableEnableIn VOICE_ENABLE case.
174f3dff60f96d89b320f9a322307118676db1dbvboxsync */
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncint AudioVideoRec::handleVideoRecSvrCmdAudioInputEventEnd(void *pvContext)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync{
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogFlowFuncEnter();
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PVIDEORECAUDIOIN pVRDEVoice = (PVIDEORECAUDIOIN)pvContext;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync AssertPtrReturn(pVRDEVoice, VERR_INVALID_POINTER);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* The caller will not use this context anymore. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync if (pVRDEVoice->rate)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync {
174f3dff60f96d89b320f9a322307118676db1dbvboxsync //mpDrv->pUpPort->pfnEndAudioConversion(mpDrv->pUpPort, pVRDEVoice->rate);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync }
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync if (pVRDEVoice->pvSamplesBuffer)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync {
174f3dff60f96d89b320f9a322307118676db1dbvboxsync RTMemFree(pVRDEVoice->pvSamplesBuffer);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pVRDEVoice->pvSamplesBuffer = NULL;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync }
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync if (pVRDEVoice->pvRateBuffer)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync {
174f3dff60f96d89b320f9a322307118676db1dbvboxsync RTMemFree(pVRDEVoice->pvRateBuffer);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pVRDEVoice->pvRateBuffer = NULL;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync }
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return VINF_SUCCESS;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync}
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync/**
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * Construct a VRDE audio driver instance.
174f3dff60f96d89b320f9a322307118676db1dbvboxsync *
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * @copydoc FNPDMDRVCONSTRUCT
174f3dff60f96d89b320f9a322307118676db1dbvboxsync */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync/* static */
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncDECLCALLBACK(int) AudioVideoRec::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync{
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PDRVAUDIOVIDEOREC pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVIDEOREC);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogRel(("Audio: Initializing VRDE driver\n"));
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogFlowFunc(("fFlags=0x%x\n", fFlags));
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* we save the address of AudioVideoRec in Object node in CFGM tree and address of VRDP server in
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * ObjectVRDPServer node. So presence of both is necessary.
174f3dff60f96d89b320f9a322307118676db1dbvboxsync */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync //if (!CFGMR3AreValuesValid(pCfg, "Object\0") || !CFGMR3AreValuesValid(pCfg, "ObjectVRDPServer\0"))
174f3dff60f96d89b320f9a322307118676db1dbvboxsync // return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync ("Configuration error: Not possible to attach anything to this driver!\n"),
174f3dff60f96d89b320f9a322307118676db1dbvboxsync VERR_PDM_DRVINS_NO_ATTACH);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /*
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * Init the static parts.
174f3dff60f96d89b320f9a322307118676db1dbvboxsync */
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync pThis->pDrvIns = pDrvIns;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* IBase */
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync pDrvIns->IBase.pfnQueryInterface = drvAudioVideoRecQueryInterface;
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync /* IHostAudioR3 */
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync PDMAUDIO_IHOSTAUDIOR3_CALLBACKS(drvAudioVideoRec);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* Get VRDPServer pointer. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync void *pvUser;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync int rc = CFGMR3QueryPtr(pCfg, "ObjectVRDPServer", &pvUser);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync if (RT_FAILURE(rc))
174f3dff60f96d89b320f9a322307118676db1dbvboxsync {
174f3dff60f96d89b320f9a322307118676db1dbvboxsync AssertMsgFailed(("Confguration error: No/bad \"ObjectVRDPServer\" value, rc=%Rrc\n", rc));
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return rc;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync }
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* CFGM tree saves the pointer to ConsoleVRDPServer in the Object node of AudioVideoRec. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pThis->pConsoleVRDPServer = (ConsoleVRDPServer *)pvUser;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pvUser = NULL;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync rc = CFGMR3QueryPtr(pCfg, "Object", &pvUser);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync if (RT_FAILURE(rc))
174f3dff60f96d89b320f9a322307118676db1dbvboxsync {
174f3dff60f96d89b320f9a322307118676db1dbvboxsync AssertMsgFailed(("Confguration error: No/bad \"Object\" value, rc=%Rrc\n", rc));
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return rc;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync }
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pThis->pAudioVideoRec = (AudioVideoRec *)pvUser;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pThis->pAudioVideoRec->mpDrv = pThis;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /*
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * Get the interface for the above driver (DrvAudio) to make mixer/conversion calls.
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * Described in CFGM tree.
174f3dff60f96d89b320f9a322307118676db1dbvboxsync */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pThis->pUpPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIAUDIOCONNECTOR);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync if (!pThis->pUpPort)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync {
174f3dff60f96d89b320f9a322307118676db1dbvboxsync AssertMsgFailed(("Configuration error: No upper interface specified!\n"));
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return VERR_PDM_MISSING_INTERFACE_ABOVE;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync }
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return VINF_SUCCESS;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync}
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync/* static */
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncDECLCALLBACK(void) AudioVideoRec::drvDestruct(PPDMDRVINS pDrvIns)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync{
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogFlowFuncEnter();
174f3dff60f96d89b320f9a322307118676db1dbvboxsync}
174f3dff60f96d89b320f9a322307118676db1dbvboxsync
174f3dff60f96d89b320f9a322307118676db1dbvboxsync/**
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * VRDE audio driver registration record.
174f3dff60f96d89b320f9a322307118676db1dbvboxsync */
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncconst PDMDRVREG AudioVideoRec::DrvReg =
174f3dff60f96d89b320f9a322307118676db1dbvboxsync{
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PDM_DRVREG_VERSION,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* szName */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync "AudioVideoRec",
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* szRCMod */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync "",
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* szR0Mod */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync "",
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* pszDescription */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync "Audio driver for video recording",
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* fFlags */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* fClass. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PDM_DRVREG_CLASS_AUDIO,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* cMaxInstances */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync ~0U,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* cbInstance */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync sizeof(DRVAUDIOVIDEOREC),
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* pfnConstruct */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync AudioVideoRec::drvConstruct,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* pfnDestruct */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync AudioVideoRec::drvDestruct,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* pfnRelocate */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync NULL,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* pfnIOCtl */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync NULL,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* pfnPowerOn */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync NULL,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* pfnReset */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync NULL,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* pfnSuspend */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync NULL,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* pfnResume */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync NULL,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* pfnAttach */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync NULL,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* pfnDetach */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync NULL,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* pfnPowerOff */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync NULL,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* pfnSoftReset */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync NULL,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* u32EndVersion */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PDM_DRVREG_VERSION
174f3dff60f96d89b320f9a322307118676db1dbvboxsync};
174f3dff60f96d89b320f9a322307118676db1dbvboxsync