VirtualBox

Changeset 65162 in vbox for trunk/src


Ignore:
Timestamp:
Jan 5, 2017 5:26:48 PM (8 years ago)
Author:
vboxsync
Message:

Audio/Main: Some (ground) work for audio support for video recording.

Location:
trunk/src/VBox/Main
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/Makefile.kmk

    r65049 r65162  
    55
    66#
    7 # Copyright (C) 2004-2016 Oracle Corporation
     7# Copyright (C) 2004-2017 Oracle Corporation
    88#
    99# This file is part of VirtualBox Open Source Edition (OSE), as
     
    288288        $(if $(VBOX_WITH_AUDIO_DEBUG),VBOX_WITH_AUDIO_DEBUG,) \
    289289        $(if $(VBOX_WITH_AUDIO_VALIDATIONKIT),VBOX_WITH_AUDIO_VALIDATIONKIT,) \
     290    $(if $(VBOX_WITH_AUDIO_VIDEOREC),VBOX_WITH_AUDIO_VIDEOREC,) \
    290291        $(if $(VBOX_WITH_VRDE_AUDIO),VBOX_WITH_VRDE_AUDIO,) \
    291292        $(if $(VBOX_WITH_E1000),VBOX_WITH_E1000,) \
     
    669670        $(if $(VBOX_WITH_AUDIO_DEBUG),VBOX_WITH_AUDIO_DEBUG,) \
    670671        $(if $(VBOX_WITH_AUDIO_VALIDATIONKIT),VBOX_WITH_AUDIO_VALIDATIONKIT,) \
     672    $(if $(VBOX_WITH_AUDIO_VIDEOREC),VBOX_WITH_AUDIO_VIDEOREC,) \
    671673        $(if $(VBOX_WITH_VRDE_AUDIO),VBOX_WITH_VRDE_AUDIO,) \
    672674        $(if $(VBOX_WITH_E1000),VBOX_WITH_E1000,) \
     
    812814        ../Devices/Audio/AudioMixBuffer.cpp \
    813815        ../Devices/Audio/DrvAudioCommon.cpp \
    814         $(if $(VBOX_WITH_VRDE_AUDIO),src-client/DrvAudioVRDE$(VBOX_AUDIO_FILE_SUFFIX).cpp,)
     816        $(if $(VBOX_WITH_VRDE_AUDIO),src-client/DrvAudioVRDE.cpp,) \
     817        $(if $(VBOX_WITH_AUDIO_VIDEOREC),src-client/DrvAudioVideoRec.cpp,)
    815818
    816819VBoxC_SOURCES.win = \
  • trunk/src/VBox/Main/include/ConsoleImpl.h

    r65088 r65162  
    55
    66/*
    7  * Copyright (C) 2005-2016 Oracle Corporation
     7 * Copyright (C) 2005-2017 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    3737class EmulatedUSB;
    3838class AudioVRDE;
     39#ifdef VBOX_WITH_AUDIO_VIDEOREC
     40class AudioVideoRec;
     41#endif
    3942class Nvram;
    4043#ifdef VBOX_WITH_USB_CARDREADER
     
    132135    Display *i_getDisplay() const { return mDisplay; }
    133136    MachineDebugger *i_getMachineDebugger() const { return mDebugger; }
     137#ifdef VBOX_WITH_VRDE_AUDIO
    134138    AudioVRDE *i_getAudioVRDE() const { return mAudioVRDE; }
     139#endif
     140#ifdef VBOX_WITH_AUDIO_VIDEOREC
     141    AudioVideoRec *getAudioVideoRec() const { return mAudioVideoRec; }
     142#endif
    135143
    136144    const ComPtr<IMachine> &i_machine() const { return mMachine; }
     
    847855    bool mfVRDEChangeInProcess;
    848856    bool mfVRDEChangePending;
    849 
    850857    const ComObjPtr<Guest> mGuest;
    851858    const ComObjPtr<Keyboard> mKeyboard;
     
    909916    VMMDev *                    m_pVMMDev;
    910917    AudioVRDE * const           mAudioVRDE;
     918#ifdef VBOX_WITH_AUDIO_VIDEOREC
     919    /** The video recording audio backend. */
     920    AudioVideoRec * const       mAudioVideoRec;
     921#endif
    911922    Nvram   * const             mNvram;
    912923#ifdef VBOX_WITH_USB_CARDREADER
  • trunk/src/VBox/Main/include/DrvAudioVideoRec.h

    r62485 r65162  
    4141public:
    4242
    43     int handleVideoRecSvrCmdAudioInputIntercept(bool fIntercept);
    44     int handleVideoRecSvrCmdAudioInputEventBegin(void *pvContext, int iSampleHz, int cChannels, int cBits, bool fUnsigned);
    45     int handleVideoRecSvrCmdAudioInputEventData(void *pvContext, const void *pvData, uint32_t cbData);
    46     int handleVideoRecSvrCmdAudioInputEventEnd(void *pvContext);
    47 
    48 public:
    49 
    5043    static DECLCALLBACK(int) drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags);
    5144    static DECLCALLBACK(void) drvDestruct(PPDMDRVINS pDrvIns);
  • trunk/src/VBox/Main/src-client/ConsoleImpl.cpp

    r65120 r65162  
    55
    66/*
    7  * Copyright (C) 2005-2016 Oracle Corporation
     7 * Copyright (C) 2005-2017 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    5959# include "DrvAudioVRDE.h"
    6060#endif
     61#ifdef VBOX_WITH_AUDIO_VIDEOREC
     62# include "DrvAudioVideoRec.h"
     63#endif
    6164#include "Nvram.h"
    6265#ifdef VBOX_WITH_USB_CARDREADER
     
    392395    , m_pVMMDev(NULL)
    393396    , mAudioVRDE(NULL)
     397#ifdef VBOX_WITH_AUDIO_VIDEOREC
     398    , mAudioVideoRec(NULL)
     399#endif
    394400    , mNvram(NULL)
    395401#ifdef VBOX_WITH_USB_CARDREADER
     
    575581        AssertReturn(mAudioVRDE, E_FAIL);
    576582#endif
     583#ifdef VBOX_WITH_AUDIO_VIDEOREC
     584        unconst(mAudioVideoRec) = new AudioVideoRec(this);
     585        AssertReturn(mAudioVideoRec, E_FAIL);
     586#endif
    577587        FirmwareType_T enmFirmwareType;
    578588        mMachine->COMGETTER(FirmwareType)(&enmFirmwareType);
     
    716726        delete mAudioVRDE;
    717727        unconst(mAudioVRDE) = NULL;
     728    }
     729#endif
     730
     731#ifdef VBOX_WITH_AUDIO_VIDEOREC
     732    if (mAudioVideoRec)
     733    {
     734        delete mAudioVideoRec;
     735        unconst(mAudioVideoRec) = NULL;
    718736    }
    719737#endif
  • trunk/src/VBox/Main/src-client/ConsoleImpl2.cpp

    r65120 r65162  
    1010
    1111/*
    12  * Copyright (C) 2006-2016 Oracle Corporation
     12 * Copyright (C) 2006-2017 Oracle Corporation
    1313 *
    1414 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    29512951#endif /* VBOX_WITH_VRDE_AUDIO */
    29522952
     2953#ifdef VBOX_WITH_AUDIO_VIDEOREC
     2954            /*
     2955             * The video recording audio backend driver.
     2956             * Currently being used with VPX video recording only.
     2957             */
     2958            CFGMR3InsertNodeF(pInst, &pLunL1, "LUN#%RU8", u8AudioLUN++);
     2959            InsertConfigString(pLunL1, "Driver", "AUDIO");
     2960
     2961            InsertConfigNode(pLunL1, "AttachedDriver", &pLunL1);
     2962            InsertConfigString(pLunL1, "Driver", "AudioVideoRec");
     2963
     2964            InsertConfigNode(pLunL1, "Config", &pCfg);
     2965            InsertConfigString(pCfg, "AudioDriver", "AudioVideoRec");
     2966            InsertConfigString(pCfg, "StreamName", bstr);
     2967            InsertConfigInteger(pCfg, "Object", (uintptr_t)mAudioVideoRec);
     2968#endif /* VBOX_WITH_AUDIO_VIDEOREC */
     2969
    29532970#ifdef VBOX_WITH_AUDIO_DEBUG
    29542971            /*
     
    39753992            }
    39763993        }
    3977        
     3994
    39783995        /*
    39793996         * 2.6.18 bug: Check if the host I/O cache is disabled and the host is running
  • trunk/src/VBox/Main/src-client/DrvAudioVideoRec.cpp

    r64766 r65162  
    55
    66/*
    7  * Copyright (C) 2014-2016 Oracle Corporation
     7 * Copyright (C) 2016-2017 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    1515 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
    1616 */
     17
     18
     19/*********************************************************************************************************************************
     20*   Header Files                                                                                                                 *
     21*********************************************************************************************************************************/
     22#define LOG_GROUP LOG_GROUP_DRV_AUDIO
     23#include <VBox/log.h>
    1724#include "DrvAudioVideoRec.h"
    1825#include "ConsoleImpl.h"
     
    2128#include "Logging.h"
    2229
     30#include "../../Devices/Audio/DrvAudio.h"
     31#include "../../Devices/Audio/AudioMixBuffer.h"
     32
    2333#include <iprt/mem.h>
    2434#include <iprt/cdefs.h>
     
    2737#include <VBox/vmm/pdmaudioifs.h>
    2838#include <VBox/vmm/pdmdrv.h>
    29 #include <VBox/RemoteDesktop/VRDE.h>
    3039#include <VBox/vmm/cfgm.h>
    3140#include <VBox/err.h>
    3241
    33 #ifdef LOG_GROUP
    34  #undef LOG_GROUP
    35 #endif
    36 #define LOG_GROUP LOG_GROUP_DEV_AUDIO
    37 #include <VBox/log.h>
    38 
    39 /* Initialization status indicator used for the recreation of the AudioUnits. */
    40 #define CA_STATUS_UNINIT    UINT32_C(0) /* The device is uninitialized */
    41 #define CA_STATUS_IN_INIT   UINT32_C(1) /* The device is currently initializing */
    42 #define CA_STATUS_INIT      UINT32_C(2) /* The device is initialized */
    43 #define CA_STATUS_IN_UNINIT UINT32_C(3) /* The device is currently uninitializing */
    44 
    45 /// @todo move t_sample as a PDM interface
    46 //typedef struct { int mute;  uint32_t r; uint32_t l; } volume_t;
    47 
    48 #define INT_MAX         0x7fffffff
    49 volume_t videorec_nominal_volume = {
    50     0,
    51     INT_MAX,
    52     INT_MAX
    53 };
    54 
    55 /* The desired buffer length in milliseconds. Will be the target total stream
    56  * latency on newer version of pulse. Apparent latency can be less (or more.)
    57  * In case its need to be used. Currently its not used.
    58  */
    59 #if 0
    60 static struct
    61 {
    62     int         buffer_msecs_out;
    63     int         buffer_msecs_in;
    64 } confAudioVideoRec
    65 =
    66 {
    67     INIT_FIELD (.buffer_msecs_out = ) 100,
    68     INIT_FIELD (.buffer_msecs_in  = ) 100,
    69 };
    70 #endif
    71 
    72 /**
    73  * Audio video recording driver instance data.
    74  *
    75  * @extends PDMIAUDIOSNIFFERCONNECTOR
     42
     43/*********************************************************************************************************************************
     44*   Structures and Typedefs                                                                                                      *
     45*********************************************************************************************************************************/
     46/**
     47 * Video recording audio driver instance data.
    7648 */
    7749typedef struct DRVAUDIOVIDEOREC
    7850{
    7951    /** Pointer to audio video recording object. */
    80     AudioVideoRec      *pAudioVideoRec;
    81     PPDMDRVINS          pDrvIns;
     52    AudioVideoRec       *pAudioVideoRec;
    8253    /** Pointer to the driver instance structure. */
    83     PDMIHOSTAUDIO       IHostAudio;
    84     ConsoleVRDPServer *pConsoleVRDPServer;
    85     /** Pointer to the DrvAudio port interface that is above it. */
    86     PPDMIAUDIOCONNECTOR       pUpPort;
     54    PPDMDRVINS           pDrvIns;
     55    /** Pointer to host audio interface. */
     56    PDMIHOSTAUDIO        IHostAudio;
     57    /** Pointer to the VRDP's console object. */
     58    ConsoleVRDPServer   *pConsoleVRDPServer;
     59    /** Pointer to the DrvAudio port interface that is above us. */
     60    PPDMIAUDIOCONNECTOR  pDrvAudio;
    8761} DRVAUDIOVIDEOREC, *PDRVAUDIOVIDEOREC;
    88 typedef struct PDMAUDIOHSTSTRMOUT PDMAUDIOHSTSTRMOUT;
    89 typedef PDMAUDIOHSTSTRMOUT *PPDMAUDIOHSTSTRMOUT;
    90 
    91 typedef struct VIDEORECAUDIOIN
    92 {
    93     /* Audio and audio details for recording */
    94     PDMAUDIOHSTSTRMIN   pHostVoiceIn;
    95     void * pvUserCtx;
    96     /* Number of bytes per frame (bitsPerSample * channels) of the actual input format. */
    97     uint32_t cBytesPerFrame;
    98     /* Frequency of the actual audio format. */
    99     uint32_t uFrequency;
    100     /* If the actual format frequence differs from the requested format, this is not NULL. */
    101     void *rate;
    102     /* Temporary buffer for st_sample_t representation of the input audio data. */
    103     void *pvSamplesBuffer;
    104     /* buffer for bytes of samples (not rate converted) */
    105     uint32_t cbSamplesBufferAllocated;
    106     /* Temporary buffer for frequency conversion. */
    107     void *pvRateBuffer;
    108     /* buffer for bytes rate converted samples */
    109     uint32_t cbRateBufferAllocated;
    110     /* A ring buffer for transferring data to the playback thread */
    111     PRTCIRCBUF pRecordedVoiceBuf;
    112     t_sample * convAudioDevFmtToStSampl;
    113     uint32_t fIsInit;
    114     uint32_t status;
    115 } VIDEORECAUDIOIN, *PVIDEORECAUDIOIN;
    116 
    117 typedef struct VIDEORECAUDIOOUT
    118 {
    119     PDMAUDIOHSTSTRMOUT pHostVoiceOut;
    120     uint64_t old_ticks;
    121     uint64_t cSamplesSentPerSec;
    122 } VIDEORECAUDIOOUT, *PVIDEORECAUDIOOUT;
    123 
     62
     63typedef struct AVRECSTREAMOUT
     64{
     65    /** Note: Always must come first! */
     66    PDMAUDIOSTREAM       Stream;
     67    /** The PCM properties of this stream. */
     68    PDMAUDIOPCMPROPS     Props;
     69    uint64_t             old_ticks;
     70    uint64_t             cSamplesSentPerSec;
     71} AVRECSTREAMOUT, *PAVRECSTREAMOUT;
     72
     73/** Makes DRVAUDIOVIDEOREC out of PDMIHOSTAUDIO. */
     74#define PDMIHOSTAUDIO_2_DRVAUDIOVIDEOREC(pInterface) \
     75    ( (PDRVAUDIOVIDEOREC)((uintptr_t)pInterface - RT_OFFSETOF(DRVAUDIOVIDEOREC, IHostAudio)) )
     76
     77
     78static int avRecCreateStreamOut(PPDMIHOSTAUDIO pInterface,
     79                                PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
     80{
     81    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
     82    AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
     83    AssertPtrReturn(pCfgReq,    VERR_INVALID_POINTER);
     84    AssertPtrReturn(pCfgAcq,    VERR_INVALID_POINTER);
     85
     86    PAVRECSTREAMOUT pStreamOut = (PAVRECSTREAMOUT)pStream;
     87
     88    int rc = DrvAudioHlpStreamCfgToProps(pCfgReq, &pStreamOut->Props);
     89    if (RT_SUCCESS(rc))
     90    {
     91        if (pCfgAcq)
     92            pCfgAcq->cSampleBufferSize = _4K; /** @todo Make this configurable. */
     93    }
     94
     95    LogFlowFuncLeaveRC(VINF_SUCCESS);
     96    return VINF_SUCCESS;
     97}
     98
     99
     100static int avRecControlStreamOut(PPDMIHOSTAUDIO pInterface,
     101                                 PPDMAUDIOSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd)
     102{
     103    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
     104    AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
     105    RT_NOREF(enmStreamCmd);
     106
     107    PDRVAUDIOVIDEOREC pThis = PDMIHOSTAUDIO_2_DRVAUDIOVIDEOREC(pInterface);
     108    RT_NOREF(pThis);
     109
     110    LogFlowFunc(("enmStreamCmd=%ld\n", enmStreamCmd));
     111
     112    AudioMixBufReset(&pStream->MixBuf);
     113
     114    return VINF_SUCCESS;
     115}
     116
     117
     118/**
     119 * @interface_method_impl{PDMIHOSTAUDIO,pfnInit}
     120 */
    124121static DECLCALLBACK(int) drvAudioVideoRecInit(PPDMIHOSTAUDIO pInterface)
    125122{
     123    RT_NOREF(pInterface);
    126124    LogFlowFuncEnter();
    127125
     
    129127}
    130128
    131 /** @todo Replace this with drvAudioHlpPcmPropsFromCfg(). */
    132 static int drvAudioVideoRecPcmInitInfo(PDMAUDIOPCMPROPS * pProps, PPDMAUDIOSTREAMCFG as)
    133 {
    134     int rc = VINF_SUCCESS;
    135 
    136     uint8_t cBits = 8, cShift = 0;
    137     bool fSigned = false;
    138 
    139     switch (as->enmFormat)
     129
     130/**
     131 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCapture}
     132 */
     133static DECLCALLBACK(int) drvAudioVideoRecStreamCapture(PPDMIHOSTAUDIO pInterface,
     134                                                       PPDMAUDIOSTREAM pStream, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
     135{
     136    RT_NOREF(pInterface, pStream, pvBuf, cbBuf);
     137
     138    if (pcbRead)
     139        *pcbRead = 0;
     140
     141    return VINF_SUCCESS;
     142}
     143
     144
     145/**
     146 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamPlay}
     147 */
     148static DECLCALLBACK(int) drvAudioVideoRecStreamPlay(PPDMIHOSTAUDIO pInterface,
     149                                                    PPDMAUDIOSTREAM pStream, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)
     150{
     151    RT_NOREF2(pvBuf, cbBuf);
     152
     153    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
     154    AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
     155    /* pcbWritten is optional. */
     156
     157    PDRVAUDIOVIDEOREC pThis      = PDMIHOSTAUDIO_2_DRVAUDIOVIDEOREC(pInterface);
     158    PAVRECSTREAMOUT   pStreamOut = (PAVRECSTREAMOUT)pStream;
     159
     160    uint32_t cLive = AudioMixBufLive(&pStream->MixBuf);
     161
     162    uint64_t now = PDMDrvHlpTMGetVirtualTime(pThis->pDrvIns);
     163    uint64_t ticks = now  - pStreamOut->old_ticks;
     164    uint64_t ticks_per_second = PDMDrvHlpTMGetVirtualFreq(pThis->pDrvIns);
     165
     166    /* Minimize the rounding error: samples = int((ticks * freq) / ticks_per_second + 0.5). */
     167    uint32_t cSamplesPlayed = (int)((2 * ticks * pStreamOut->Props.uHz + ticks_per_second) / ticks_per_second / 2);
     168
     169    /* Don't play more than available. */
     170    if (cSamplesPlayed > cLive)
     171        cSamplesPlayed = cLive;
     172
     173    /* Remember when samples were consumed. */
     174    pStreamOut->old_ticks = now;
     175
     176    int cSamplesToSend = cSamplesPlayed;
     177
     178    LogFlowFunc(("uFreq=%RU32, cChan=%RU8, cBits=%RU8, fSigned=%RTbool, cSamplesToSend=%RU32\n",
     179                 pStreamOut->Props.uHz,   pStreamOut->Props.cChannels,
     180                 pStreamOut->Props.cBits, pStreamOut->Props.fSigned, cSamplesToSend));
     181
     182    /*
     183     * Call the VRDP server with the data.
     184     */
     185    uint32_t cReadTotal = 0;
     186
     187    PPDMAUDIOSAMPLE pSamples;
     188    uint32_t cRead;
     189    int rc = AudioMixBufAcquire(&pStream->MixBuf, cSamplesToSend,
     190                                &pSamples, &cRead);
     191    if (   RT_SUCCESS(rc)
     192        && cRead)
    140193    {
    141         case PDMAUDIOFMT_S8:
    142             fSigned = 1;
    143         case PDMAUDIOFMT_U8:
    144             break;
    145 
    146         case PDMAUDIOFMT_S16:
    147             fSigned = 1;
    148         case PDMAUDIOFMT_U16:
    149             cBits = 16;
    150             cShift = 1;
    151             break;
    152 
    153         case PDMAUDIOFMT_S32:
    154             fSigned = 1;
    155         case PDMAUDIOFMT_U32:
    156             cBits = 32;
    157             cShift = 2;
    158             break;
    159 
    160         default:
    161             rc = VERR_NOT_SUPPORTED;
    162             break;
    163     }
    164 
    165     pProps->uHz = as->uHz;
    166     pProps->cBits = cBits;
    167     pProps->fSigned = fSigned;
    168     pProps->cChannels = as->cChannels;
    169     pProps->cShift = (as->cChannels == 2) + cShift;
    170     pProps->uAlign = (1 << pProps->cShift) - 1;
    171     pProps->cbBitrate = (pProps->cBits * pProps->uHz * pProps->cChannels) / 8;
    172     pProps->fSwapEndian = (as->enmEndianness != PDMAUDIOHOSTENDIANESS);
    173 
    174     return rc;
    175 }
    176 
    177 /*
    178  * Hard voice (playback)
    179  */
    180 static int audio_pcm_hw_find_min_out (PPDMAUDIOHSTSTRMOUT hw, int *nb_livep)
    181 {
    182     PPDMAUDIOGSTSTRMOUT sw;
    183     int m = INT_MAX;
    184     int nb_live = 0;
    185 
    186     PPDMAUDIOGSTSTRMOUT pIter;
    187     RTListForEach(&hw->lstGstStrmOut, pIter, PDMAUDIOGSTSTRMOUT, Node)
    188     {
    189         sw = pIter;
    190         if (sw->State.fActive || !sw->State.fEmpty)
     194        cReadTotal = cRead;
     195
     196        if (rc == VINF_TRY_AGAIN)
    191197        {
    192             m = RT_MIN (m, sw->cTotalSamplesWritten);
    193             nb_live += 1;
     198            rc = AudioMixBufAcquire(&pStream->MixBuf, cSamplesToSend - cRead,
     199                                    &pSamples, &cRead);
     200
     201            cReadTotal += cRead;
    194202        }
    195203    }
    196204
    197     *nb_livep = nb_live;
    198     return m;
    199 }
    200 
    201 static int audio_pcm_hw_get_live_out2 (PPDMAUDIOHSTSTRMOUT hw, int *nb_live)
    202 {
    203     int smin;
    204 
    205     smin = audio_pcm_hw_find_min_out (hw, nb_live);
    206 
    207     if (!*nb_live) {
    208         return 0;
    209     }
     205    AudioMixBufFinish(&pStream->MixBuf, cSamplesToSend);
     206
     207    /*
     208     * Always report back all samples acquired, regardless of whether the
     209     * VRDP server actually did process those.
     210     */
     211    if (pcbWritten)
     212        *pcbWritten = cReadTotal;
     213
     214    LogFlowFunc(("cReadTotal=%RU32, rc=%Rrc\n", cReadTotal, rc));
     215    return rc;
     216}
     217
     218
     219static int avRecDestroyStreamIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
     220{
     221    RT_NOREF(pStream);
     222    PDRVAUDIOVIDEOREC pThis = PDMIHOSTAUDIO_2_DRVAUDIOVIDEOREC(pInterface);
     223
     224    if (pThis->pConsoleVRDPServer)
     225        pThis->pConsoleVRDPServer->SendAudioInputEnd(NULL);
     226
     227    return VINF_SUCCESS;
     228}
     229
     230
     231static int avRecDestroyStreamOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
     232{
     233    RT_NOREF(pInterface);
     234    RT_NOREF(pStream);
     235
     236    return VINF_SUCCESS;
     237}
     238
     239
     240/**
     241 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetConfig}
     242 */
     243static DECLCALLBACK(int) drvAudioVideoRecGetConfig(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pBackendCfg)
     244{
     245    NOREF(pInterface);
     246    AssertPtrReturn(pBackendCfg, VERR_INVALID_POINTER);
     247
     248    pBackendCfg->cbStreamOut    = sizeof(AVRECSTREAMOUT);
     249    pBackendCfg->cbStreamIn     = 0;
     250    pBackendCfg->cMaxStreamsIn  = 0;
     251    pBackendCfg->cMaxStreamsOut = UINT32_MAX;
     252
     253    return VINF_SUCCESS;
     254}
     255
     256
     257/**
     258 * @interface_method_impl{PDMIHOSTAUDIO,pfnShutdown}
     259 */
     260static DECLCALLBACK(void) drvAudioVideoRecShutdown(PPDMIHOSTAUDIO pInterface)
     261{
     262    RT_NOREF(pInterface);
     263}
     264
     265
     266/**
     267 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetStatus}
     268 */
     269static DECLCALLBACK(PDMAUDIOBACKENDSTS) drvAudioVideoRecGetStatus(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
     270{
     271    RT_NOREF(enmDir);
     272    AssertPtrReturn(pInterface, PDMAUDIOBACKENDSTS_UNKNOWN);
     273
     274    return PDMAUDIOBACKENDSTS_RUNNING;
     275}
     276
     277
     278/**
     279 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCreate}
     280 */
     281static DECLCALLBACK(int) drvAudioVideoRecStreamCreate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream,
     282                                                      PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
     283{
     284    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
     285    AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
     286    AssertPtrReturn(pCfgReq,    VERR_INVALID_POINTER);
     287    AssertPtrReturn(pCfgAcq,    VERR_INVALID_POINTER);
     288
     289    if (pCfgReq->enmDir == PDMAUDIODIR_OUT)
     290        return avRecCreateStreamOut(pInterface, pStream, pCfgReq, pCfgAcq);
     291
     292    return VERR_NOT_SUPPORTED;
     293}
     294
     295
     296/**
     297 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDestroy}
     298 */
     299static DECLCALLBACK(int) drvAudioVideoRecStreamDestroy(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
     300{
     301    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
     302    AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
     303
     304    int rc;
     305    if (pStream->enmDir == PDMAUDIODIR_IN)
     306        rc = avRecDestroyStreamIn(pInterface,  pStream);
    210307    else
    211     {
    212         int live = smin;
    213 
    214         if (live < 0 || live > hw->cSampleBufferSize)
    215         {
    216             LogFlowFunc(("Error: live=%d hw->samples=%d\n", live, hw->cSampleBufferSize));
    217             return 0;
    218         }
    219         return live;
    220     }
    221 }
    222 
    223 
    224 static int audio_pcm_hw_get_live_out (PPDMAUDIOHSTSTRMOUT hw)
    225 {
    226     int nb_live;
    227     int live;
    228 
    229     live = audio_pcm_hw_get_live_out2 (hw, &nb_live);
    230     if (live < 0 || live > hw->cSampleBufferSize)
    231     {
    232         LogFlowFunc(("Error: live=%d hw->samples=%d\n", live, hw->cSampleBufferSize));
    233         return 0;
    234     }
    235     return live;
    236 }
    237 
    238 /*
    239  * Hard voice (capture)
    240  */
    241 static int audio_pcm_hw_find_min_in (PPDMAUDIOHSTSTRMIN hw)
    242 {
    243     int m = hw->cTotalSamplesCaptured;
    244 
    245     PPDMAUDIOGSTSTRMIN pIter;
    246     RTListForEach(&hw->lstGstStreamsIn, pIter, PDMAUDIOGSTSTRMIN, Node)
    247     {
    248         if (pIter->State.fActive)
    249         {
    250             m = RT_MIN (m, pIter->cTotalHostSamplesRead);
    251         }
    252     }
    253     return m;
    254 }
    255 
    256 int audio_pcm_hw_get_live_in (PPDMAUDIOHSTSTRMIN hw)
    257 {
    258     int live = hw->cTotalSamplesCaptured - audio_pcm_hw_find_min_in (hw);
    259     if (live < 0 || live > hw->cSampleBufferSize)
    260     {
    261         LogFlowFunc(("Error: live=%d hw->samples=%d\n", live, hw->cSampleBufferSize));
    262         return 0;
    263     }
    264     return live;
    265 }
    266 
    267 static inline void *advance (void *p, int incr)
    268 {
    269     uint8_t *d = (uint8_t*)p;
    270     return (d + incr);
    271 }
    272 
    273 static int vrdeReallocSampleBuf(PVIDEORECAUDIOIN pVRDEVoice, uint32_t cSamples)
    274 {
    275     uint32_t cbBuffer = cSamples * sizeof(PDMAUDIOSAMPLE);
    276     if (cbBuffer > pVRDEVoice->cbSamplesBufferAllocated)
    277     {
    278         /** @todo r=andy Why not using RTMemReAlloc? */
    279         if (pVRDEVoice->pvSamplesBuffer)
    280         {
    281             RTMemFree(pVRDEVoice->pvSamplesBuffer);
    282             pVRDEVoice->pvSamplesBuffer = NULL;
    283         }
    284         pVRDEVoice->pvSamplesBuffer = RTMemAlloc(cbBuffer);
    285         if (pVRDEVoice->pvSamplesBuffer)
    286             pVRDEVoice->cbSamplesBufferAllocated = cbBuffer;
    287         else
    288             pVRDEVoice->cbSamplesBufferAllocated = 0;
    289     }
    290 
    291     return VINF_SUCCESS;
    292 }
    293 
    294 static int vrdeReallocRateAdjSampleBuf(PVIDEORECAUDIOIN pVRDEVoice, uint32_t cSamples)
    295 {
    296     uint32_t cbBuffer = cSamples * sizeof(PDMAUDIOSAMPLE);
    297     if (cbBuffer > pVRDEVoice->cbRateBufferAllocated)
    298     {
    299         RTMemFree(pVRDEVoice->pvRateBuffer);
    300         pVRDEVoice->pvRateBuffer = RTMemAlloc(cbBuffer);
    301         if (pVRDEVoice->pvRateBuffer)
    302             pVRDEVoice->cbRateBufferAllocated = cbBuffer;
    303         else
    304             pVRDEVoice->cbRateBufferAllocated = 0;
    305     }
    306 
    307     return VINF_SUCCESS;
    308 }
    309 
    310 /*******************************************************************************
    311  *
    312  * AudioVideoRec input section
    313  *
    314  ******************************************************************************/
    315 
    316 /*
    317  * Callback to feed audio input buffer. Samples format is be the same as
    318  * in the voice. The caller prepares st_sample_t.
    319  *
    320  * @param cbSamples Size of pvSamples array in bytes.
    321  * @param pvSamples Points to an array of samples.
    322  *
    323  * @return IPRT status code.
    324  */
    325 static int vrdeRecordingCallback(PVIDEORECAUDIOIN pVRDEVoice, uint32_t cbSamples, const void *pvSamples)
    326 {
    327     int rc = VINF_SUCCESS;
    328     size_t csWritten = 0;
    329 
    330     Assert((cbSamples % sizeof(PDMAUDIOSAMPLE)) == 0);
    331 
    332     if (!pVRDEVoice->fIsInit)
    333         return VINF_SUCCESS;
    334 
    335     /* If nothing is pending return immediately. */
    336     if (cbSamples == 0)
    337         return VINF_SUCCESS;
    338 
    339     /* How much space is free in the ring buffer? */
    340     size_t csAvail = RTCircBufFree(pVRDEVoice->pRecordedVoiceBuf) / sizeof(PDMAUDIOSAMPLE); /* bytes -> samples */
    341 
    342     /* How much space is used in the audio buffer. Use the smaller size of the too. */
    343     csAvail = RT_MIN(csAvail, cbSamples / sizeof(PDMAUDIOSAMPLE));
    344 
    345     /* Iterate as long as data is available. */
    346     while (csWritten < csAvail)
    347     {
    348         /* How much is left? */
    349         size_t csToWrite = csAvail - csWritten;
    350         size_t cbToWrite = csToWrite * sizeof(PDMAUDIOSAMPLE);
    351 
    352         /* Try to acquire the necessary space from the ring buffer. */
    353         void *pcDst;
    354         RTCircBufAcquireWriteBlock(pVRDEVoice->pRecordedVoiceBuf, cbToWrite, &pcDst, &cbToWrite);
    355 
    356         /* How much do we get? */
    357         csToWrite = cbToWrite / sizeof(PDMAUDIOSAMPLE);
    358 
    359         /* Copy the data from the audio buffer to the ring buffer in PVRDEVoice. */
    360         if (csToWrite)
    361         {
    362             memcpy(pcDst, (uint8_t *)pvSamples + (csWritten * sizeof(PDMAUDIOSAMPLE)), cbToWrite);
    363             csWritten += csToWrite;
    364         }
    365 
    366         /* Release the ring buffer, so the main thread could start reading this data. */
    367         RTCircBufReleaseWriteBlock(pVRDEVoice->pRecordedVoiceBuf, cbToWrite);
    368 
    369         if (RT_UNLIKELY(csToWrite == 0))
    370             break;
    371     }
    372 
    373     LogFlowFunc(("Finished writing buffer with %RU32 samples (%RU32 bytes)\n",
    374                  csWritten, csWritten * sizeof(PDMAUDIOSAMPLE)));
     308        rc = avRecDestroyStreamOut(pInterface, pStream);
    375309
    376310    return rc;
    377311}
    378312
    379 static DECLCALLBACK(int) drvAudioVideoRecInitOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHostVoiceOut, PPDMAUDIOSTREAMCFG pCfg)
    380 {
     313
     314/**
     315 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamControl}
     316 */
     317static DECLCALLBACK(int) drvAudioVideoRecStreamControl(PPDMIHOSTAUDIO pInterface,
     318                                                       PPDMAUDIOSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd)
     319{
     320    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
     321    AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
     322
     323    Assert(pStream->enmCtx == PDMAUDIOSTREAMCTX_HOST);
     324
     325    if (pStream->enmDir == PDMAUDIODIR_OUT)
     326        return avRecControlStreamOut(pInterface,  pStream, enmStreamCmd);
     327
     328    return VINF_SUCCESS;
     329}
     330
     331
     332/**
     333 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetStatus}
     334 */
     335static DECLCALLBACK(PDMAUDIOSTRMSTS) drvAudioVideoRecStreamGetStatus(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
     336{
     337    NOREF(pInterface);
     338    NOREF(pStream);
     339
     340    return (  PDMAUDIOSTRMSTS_FLAG_INITIALIZED | PDMAUDIOSTRMSTS_FLAG_ENABLED
     341            | PDMAUDIOSTRMSTS_FLAG_DATA_READABLE | PDMAUDIOSTRMSTS_FLAG_DATA_WRITABLE);
     342}
     343
     344
     345/**
     346 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamIterate}
     347 */
     348static DECLCALLBACK(int) drvAudioVideoRecStreamIterate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
     349{
     350    AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
     351    AssertPtrReturn(pStream,    VERR_INVALID_POINTER);
     352
    381353    LogFlowFuncEnter();
    382     PDRVAUDIOVIDEOREC pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVIDEOREC, IHostAudio);
    383 
    384     PVIDEORECAUDIOOUT pVRDEVoiceOut = (PVIDEORECAUDIOOUT)pHostVoiceOut;
    385     pHostVoiceOut->cSampleBufferSize = _4K; /* 4096 samples * 4 = 16K bytes total. */
    386 
    387     return drvAudioVideoRecPcmInitInfo(&pVRDEVoiceOut->pHostVoiceOut.Props, pCfg);
    388 }
    389 
    390 static DECLCALLBACK(int) drvAudioVideoRecInitIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHostVoiceIn, PPDMAUDIOSTREAMCFG pCfg)
    391 {
    392     LogFlowFuncEnter();
    393     PDRVAUDIOVIDEOREC pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVIDEOREC, IHostAudio);
    394 
    395     PVIDEORECAUDIOIN pVRDEVoice = (PVIDEORECAUDIOIN)pHostVoiceIn;
    396     pHostVoiceIn->cSampleBufferSize = _4K; /* 4096 samples * 4 = 16K bytes total. */
    397 
    398     return drvAudioVideoRecPcmInitInfo(&pVRDEVoice->pHostVoiceIn.Props, pCfg);
    399 }
    400 
    401 static DECLCALLBACK(int) drvAudioVideoRecCaptureIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHostVoiceIn,
    402                                                    uint32_t *pcSamplesCaptured)
    403 {
    404     /** @todo Take care of the size of the buffer allocated to pHostVoiceIn. */
    405     PVIDEORECAUDIOIN pVRDEVoice = (PVIDEORECAUDIOIN)pHostVoiceIn;
    406 
    407     /* use this from DrvHostCoreAudio.c */
    408     if (ASMAtomicReadU32(&pVRDEVoice->status) != CA_STATUS_INIT)
    409     {
    410         LogFlowFunc(("VRDE voice not initialized\n"));
    411 
    412         *pcSamplesCaptured = 0;
    413         return VERR_GENERAL_FAILURE; /** @todo Fudge! */
    414     }
    415 
    416     /* how much space is used in the ring buffer in pRecordedVocieBuf with pAudioVideoRec . Bytes-> samples*/
    417     size_t cSamplesRingBuffer = RTCircBufUsed(pVRDEVoice->pRecordedVoiceBuf) / sizeof(PDMAUDIOSAMPLE);
    418 
    419     /* How much space is available in the mix buffer. Use the smaller size of the too. */
    420     cSamplesRingBuffer = RT_MIN(cSamplesRingBuffer, (uint32_t)(pVRDEVoice->pHostVoiceIn.cSampleBufferSize -
    421                                 audio_pcm_hw_get_live_in (&pVRDEVoice->pHostVoiceIn)));
    422 
    423     LogFlowFunc(("Start reading buffer with %d samples (%d bytes)\n", cSamplesRingBuffer,
    424                  cSamplesRingBuffer * sizeof(PDMAUDIOSAMPLE)));
    425 
    426     /* Iterate as long as data is available */
    427     size_t cSamplesRead = 0;
    428     while (cSamplesRead < cSamplesRingBuffer)
    429     {
    430         /* How much is left? Split request at the end of our samples buffer. */
    431         size_t cSamplesToRead = RT_MIN(cSamplesRingBuffer - cSamplesRead,
    432                                        (uint32_t)(pVRDEVoice->pHostVoiceIn.cSampleBufferSize - pVRDEVoice->pHostVoiceIn.offSamplesWritten));
    433         size_t cbToRead = cSamplesToRead * sizeof(PDMAUDIOSAMPLE);
    434         LogFlowFunc(("Try reading %zu samples (%zu bytes)\n", cSamplesToRead, cbToRead));
    435 
    436         /* Try to acquire the necessary block from the ring buffer. Remeber in fltRecrodCallback we
    437          * we are filling this buffer with the audio data available from VRDP. Here we are reading it
    438          */
    439         /** @todo do I need to introduce a thread to fill the buffer in fltRecordcallback. So that
    440          * filling is in separate thread and the reading of that buffer is in separate thread
    441          */
    442         void *pvSrc;
    443         RTCircBufAcquireReadBlock(pVRDEVoice->pRecordedVoiceBuf, cbToRead, &pvSrc, &cbToRead);
    444 
    445         /* How much to we get? */
    446         cSamplesToRead = cbToRead / sizeof(PDMAUDIOSAMPLE);
    447         LogFlowFunc(("AuderVRDE: There are %d samples (%d bytes) available\n", cSamplesToRead, cbToRead));
    448 
    449         /* Break if nothing is used anymore. */
    450         if (cSamplesToRead)
    451         {
    452             /* Copy the data from our ring buffer to the mix buffer. */
    453             PPDMAUDIOSAMPLE psDst = pVRDEVoice->pHostVoiceIn.paSamples + pVRDEVoice->pHostVoiceIn.offSamplesWritten;
    454             memcpy(psDst, pvSrc, cbToRead);
    455         }
    456 
    457         /* Release the read buffer, so it could be used for new data. */
    458         RTCircBufReleaseReadBlock(pVRDEVoice->pRecordedVoiceBuf, cbToRead);
    459 
    460         if (!cSamplesToRead)
    461             break;
    462 
    463         pVRDEVoice->pHostVoiceIn.offSamplesWritten = (pVRDEVoice->pHostVoiceIn.offSamplesWritten + cSamplesToRead)
    464                                               % pVRDEVoice->pHostVoiceIn.cSampleBufferSize;
    465 
    466         /* How much have we reads so far. */
    467         cSamplesRead += cSamplesToRead;
    468     }
    469 
    470     LogFlowFunc(("Finished reading buffer with %zu samples (%zu bytes)\n",
    471                  cSamplesRead, cSamplesRead * sizeof(PDMAUDIOSAMPLE)));
    472 
    473     *pcSamplesCaptured = cSamplesRead;
    474     return VINF_SUCCESS;
    475 }
    476 
    477 static DECLCALLBACK(int) drvAudioVideoRecPlayOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHostVoiceOut,
    478                                                  uint32_t *pcSamplesPlayed)
    479 {
    480     PDRVAUDIOVIDEOREC pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVIDEOREC, IHostAudio);
    481     PVIDEORECAUDIOOUT pVRDEVoiceOut = (PVIDEORECAUDIOOUT)pHostVoiceOut;
    482 
    483     /*
    484      * Just call the VRDP server with the data.
    485      */
    486     int live = audio_pcm_hw_get_live_out(pHostVoiceOut);
    487     uint64_t now = PDMDrvHlpTMGetVirtualTime(pDrv->pDrvIns);
    488     uint64_t ticks = now  - pVRDEVoiceOut->old_ticks;
    489     uint64_t ticks_per_second = PDMDrvHlpTMGetVirtualFreq(pDrv->pDrvIns);
    490 
    491     int cSamplesPlayed = (int)((2 * ticks * pHostVoiceOut->Props.uHz + ticks_per_second) / ticks_per_second / 2);
    492     if (cSamplesPlayed < 0)
    493         cSamplesPlayed = live;
    494 
    495     pHostVoiceOut->Props.cBits = 128; /** @todo Make this configurable (or at least a define)? */
    496     VRDEAUDIOFORMAT format = VRDE_AUDIO_FMT_MAKE(pHostVoiceOut->Props.uHz,
    497                                                  pHostVoiceOut->Props.cChannels,
    498                                                  pHostVoiceOut->Props.cBits, /* bits per sample */
    499                                                  !pHostVoiceOut->Props.fSigned);
    500 
    501     LogFlowFunc(("freq=%d, chan=%d, cBits = %d, fsigned = %d, cSamples=%d format=%d\n",
    502                  pHostVoiceOut->Props.uHz, pHostVoiceOut->Props.cChannels,
    503                  pHostVoiceOut->Props.cBits, pHostVoiceOut->Props.fSigned,
    504                  pHostVoiceOut->cSampleBufferSize, format));
    505 
    506     pVRDEVoiceOut->old_ticks = now;
    507     int cSamplesToSend = RT_MIN(live, cSamplesPlayed);
    508 
    509     if (pHostVoiceOut->cOffSamplesRead + cSamplesToSend > pHostVoiceOut->cSampleBufferSize)
    510     {
    511         /* send the samples till the end of pHostStereoSampleBuf */
    512         pDrv->pConsoleVRDPServer->SendAudioSamples(&pHostVoiceOut->paSamples[pHostVoiceOut->cOffSamplesRead],
    513                                                    (pHostVoiceOut->cSampleBufferSize - pHostVoiceOut->cOffSamplesRead), format);
    514         /*pHostStereoSampleBuff already has the samples which exceeded its space. They have overwriten the old
    515          * played sampled starting from offset 0. So based on the number of samples that we had to play,
    516          * read the number of samples from offset 0 .
    517          */
    518         pDrv->pConsoleVRDPServer->SendAudioSamples(&pHostVoiceOut->paSamples[0],
    519                                                    (cSamplesToSend - (pHostVoiceOut->cSampleBufferSize -
    520                                                                       pHostVoiceOut->cOffSamplesRead)),
    521                                                    format);
    522     }
    523     else
    524     {
    525         pDrv->pConsoleVRDPServer->SendAudioSamples(&pHostVoiceOut->paSamples[pHostVoiceOut->cOffSamplesRead],
    526                                                    cSamplesToSend, format);
    527     }
    528 
    529     pHostVoiceOut->cOffSamplesRead = (pHostVoiceOut->cOffSamplesRead + cSamplesToSend) % pHostVoiceOut->cSampleBufferSize;
    530 
    531     *pcSamplesPlayed = cSamplesToSend;
    532     return VINF_SUCCESS;
    533 }
    534 
    535 static DECLCALLBACK(int) drvAudioVideoRecFiniIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN hw)
    536 {
    537     PDRVAUDIOVIDEOREC pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVIDEOREC, IHostAudio);
    538     LogFlowFuncEnter();
    539     pDrv->pConsoleVRDPServer->SendAudioInputEnd(NULL);
    540 
    541     return VINF_SUCCESS;
    542 }
    543 
    544 static DECLCALLBACK(int) drvAudioVideoRecFiniOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHostVoiceOut)
    545 {
    546     PDRVAUDIOVIDEOREC pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVIDEOREC, IHostAudio);
    547     LogFlowFuncEnter();
    548 
    549     return VINF_SUCCESS;
    550 }
    551 
    552 static DECLCALLBACK(int) drvAudioVideoRecControlOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT hw,
    553                                                     PDMAUDIOSTREAMCMD enmStreamCmd)
    554 {
    555     PDRVAUDIOVIDEOREC pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVIDEOREC, IHostAudio);
    556     LogFlowFuncEnter();
    557 
    558     return VINF_SUCCESS;
    559 }
    560 
    561 static DECLCALLBACK(int) drvAudioVideoRecControlIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHostVoiceIn,
    562                                                    PDMAUDIOSTREAMCMD enmStreamCmd)
    563 {
    564     PDRVAUDIOVIDEOREC pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVIDEOREC, IHostAudio);
    565 
    566     /* Initialize  VRDEVoice and return to VRDP server which returns this struct back to us
    567      * in the form void * pvContext
    568      */
    569     PVIDEORECAUDIOIN pVRDEVoice = (PVIDEORECAUDIOIN)pHostVoiceIn;
    570     LogFlowFunc(("enmStreamCmd=%ld\n", enmStreamCmd));
    571 
    572     /* initialize only if not already done */
    573     if (enmStreamCmd == PDMAUDIOSTREAMCMD_ENABLE)
    574     {
    575         /// @todo if (!pVRDEVoice->fIsInit)
    576         //    RTCircBufReset(pVRDEVoice->pRecordedVoiceBuf);
    577         pVRDEVoice->fIsInit = 1;
    578         pVRDEVoice->pHostVoiceIn = *pHostVoiceIn;
    579         pVRDEVoice->cBytesPerFrame = 1;
    580         pVRDEVoice->uFrequency = 0;
    581         pVRDEVoice->rate = NULL;
    582         pVRDEVoice->cbSamplesBufferAllocated = 0;
    583         pVRDEVoice->pvRateBuffer = NULL;
    584         pVRDEVoice->cbRateBufferAllocated = 0;
    585 
    586         pVRDEVoice->pHostVoiceIn.cSampleBufferSize = 2048;
    587         /* Initialize the hardware info section with the audio settings */
    588 
    589         ASMAtomicWriteU32(&pVRDEVoice->status, CA_STATUS_IN_INIT);
    590 
    591         /* Create the internal ring buffer. */
    592         RTCircBufCreate(&pVRDEVoice->pRecordedVoiceBuf,
    593                         pVRDEVoice->pHostVoiceIn.cSampleBufferSize * sizeof(PDMAUDIOSAMPLE));
    594 
    595         if (!RT_VALID_PTR(pVRDEVoice->pRecordedVoiceBuf))
    596         {
    597             LogRel(("Failed to create internal ring buffer\n"));
    598             return  VERR_NO_MEMORY;
    599         }
    600 
    601         ASMAtomicWriteU32(&pVRDEVoice->status, CA_STATUS_INIT);
    602         return pDrv->pConsoleVRDPServer->SendAudioInputBegin(NULL, pVRDEVoice, pHostVoiceIn->cSampleBufferSize,
    603                                                              pHostVoiceIn->Props.uHz,
    604                                                              pHostVoiceIn->Props.cChannels, pHostVoiceIn->Props.cBits);
    605     }
    606     else if (enmStreamCmd == PDMAUDIOSTREAMCMD_DISABLE)
    607     {
    608         pVRDEVoice->fIsInit = 0;
    609         ASMAtomicWriteU32(&pVRDEVoice->status, CA_STATUS_IN_UNINIT);
    610         RTCircBufDestroy(pVRDEVoice->pRecordedVoiceBuf);
    611         pVRDEVoice->pRecordedVoiceBuf = NULL;
    612         ASMAtomicWriteU32(&pVRDEVoice->status, CA_STATUS_UNINIT);
    613         pDrv->pConsoleVRDPServer->SendAudioInputEnd(NULL);
    614     }
    615 
    616     return VINF_SUCCESS;
    617 }
    618 
    619 static DECLCALLBACK(int) drvAudioVideoRecGetConf(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pCfg)
    620 {
    621     NOREF(pInterface);
    622     AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
    623 
    624     pCfg->cbStreamIn     = sizeof(VIDEORECAUDIOIN);
    625     pCfg->cbStreamOut    = sizeof(VIDEORECAUDIOOUT);
    626     pCfg->cMaxStreamsIn  = UINT32_MAx;
    627     pCfg->cMaxStreamsOut = UINT32_MAX;
    628     pCfg->cSources       = 1;
    629     pCfg->cSinks         = 1;
    630 
    631     return VINF_SUCCESS;
    632 }
    633 
    634 static DECLCALLBACK(void) drvAudioVideoRecShutdown(PPDMIHOSTAUDIO pInterface)
    635 {
    636     NOREF(pInterface);
    637 }
     354
     355    /* Nothing to do here for video recording. */
     356    return VINF_SUCCESS;
     357}
     358
    638359
    639360/**
     
    643364{
    644365    PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
    645     PDRVAUDIOVIDEOREC  pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVIDEOREC);
     366    PDRVAUDIOVIDEOREC pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVIDEOREC);
     367
    646368    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
    647369    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
     
    649371}
    650372
     373
    651374AudioVideoRec::AudioVideoRec(Console *pConsole)
    652375    : mpDrv(NULL),
     
    654377{
    655378}
     379
    656380
    657381AudioVideoRec::~AudioVideoRec(void)
     
    664388}
    665389
    666 int AudioVideoRec::handleVideoRecSvrCmdAudioInputIntercept(bool fIntercept)
    667 {
    668     LogFlowThisFunc(("fIntercept=%RTbool\n", fIntercept));
    669     return VINF_SUCCESS;
    670 }
    671 
    672 int AudioVideoRec::handleVideoRecSvrCmdAudioInputEventBegin(void *pvContext, int iSampleHz, int cChannels,
    673                                                             int cBits, bool fUnsigned)
    674 {
    675     int bitIdx;
    676     PVIDEORECAUDIOIN pVRDEVoice = (PVIDEORECAUDIOIN)pvContext;
    677     LogFlowFunc(("handleVRDPCmdInputEventBegin\n"));
    678     /* Prepare a format convertion for the actually used format. */
    679     pVRDEVoice->cBytesPerFrame = ((cBits + 7) / 8) * cChannels;
    680     if (cBits == 16)
    681     {
    682         bitIdx = 1;
    683     }
    684     else if (cBits == 32)
    685     {
    686         bitIdx = 2;
    687     }
    688     else
    689     {
    690         bitIdx = 0;
    691     }
    692 
    693     //PPDMIAUDIOCONNECTOR pPort = server->mConsole->getAudioVideoRec()->getDrvAudioPort();
    694     /* Call DrvAudio interface to get the t_sample type conversion function */
    695     /*mpDrv->pUpPort->pfnConvDevFmtToStSample(mpDrv->pUpPort,
    696                                             (cChannels == 2) ? 1 : 0,
    697                                             !fUnsigned, 0, bitIdx,
    698                                             pVRDEVoice->convAudioDevFmtToStSampl);*/
    699     if (pVRDEVoice->convAudioDevFmtToStSampl)
    700     {
    701         LogFlowFunc(("Failed to get the conversion function \n"));
    702     }
    703     LogFlowFunc(("Required freq as requested by VRDP Server = %d\n", iSampleHz));
    704     //if (iSampleHz && iSampleHz != pVRDEVoice->pHostVoiceIn.Props.uFrequency)
    705     {
    706         /** @todo if the above condition is false then pVRDEVoice->uFrequency will remain 0 */
    707         /*mpDrv->pUpPort->pfnPrepareAudioConversion(mpDrv->pUpPort, iSampleHz,
    708                                                   pVRDEVoice->pHostVoiceIn.Props.uFrequency,
    709                                                   &pVRDEVoice->rate);*/
    710         pVRDEVoice->uFrequency = iSampleHz;
    711         LogFlowFunc(("pVRDEVoice assigned requested freq =%d\n", pVRDEVoice->uFrequency));
    712     }
    713     return VINF_SUCCESS;
    714 }
    715 
    716 /*
    717  * pvContext: pointer to VRDP voice returned by the VRDP server. The is same pointer that we initialized in
    718  *            drvAudioVideoRecDisableEnableIn VOICE_ENABLE case.
    719  */
    720 int AudioVideoRec::handleVideoRecSvrCmdAudioInputEventData(void *pvContext, const void *pvData, uint32_t cbData)
    721 {
    722     PVIDEORECAUDIOIN pVRDEVoice = (PVIDEORECAUDIOIN)pvContext;
    723     PPDMAUDIOSAMPLE pHostStereoSampleBuf; /* target sample buffer */
    724     PPDMAUDIOSAMPLE pConvertedSampleBuf; /* samples adjusted for rate */
    725     uint32_t cSamples = cbData / pVRDEVoice->cBytesPerFrame; /* Count of samples */
    726     void * pTmpSampleBuf = NULL;
    727     uint32_t cConvertedSamples; /* samples adjusted for rate */
    728     uint32_t cbSamples = 0; /* count of bytes occupied by samples */
    729     int rc = VINF_SUCCESS;
    730 
    731     LogFlowFunc(("handleVRDPCmdInputEventData cbData = %d, bytesperfram=%d\n",
    732               cbData, pVRDEVoice->cBytesPerFrame));
    733 
    734     vrdeReallocSampleBuf(pVRDEVoice, cSamples);
    735     pHostStereoSampleBuf = (PPDMAUDIOSAMPLE)pVRDEVoice->pvSamplesBuffer;
    736     pVRDEVoice->convAudioDevFmtToStSampl(pHostStereoSampleBuf, pvData, cSamples, &videorec_nominal_volume);
    737 
    738     /* count of rate adjusted samples */
    739     pVRDEVoice->uFrequency = 22100; /** @todo handle this. How pVRDEVoice will get proper value */
    740     cConvertedSamples = (cSamples * pVRDEVoice->pHostVoiceIn.Props.uHz) / pVRDEVoice->uFrequency;
    741     vrdeReallocRateAdjSampleBuf(pVRDEVoice, cConvertedSamples);
    742 
    743     pConvertedSampleBuf = (PPDMAUDIOSAMPLE)pVRDEVoice->pvRateBuffer;
    744     if (pConvertedSampleBuf)
    745     {
    746         uint32_t cSampleSrc = cSamples;
    747         uint32_t cSampleDst = cConvertedSamples;
    748         /*mpDrv->pUpPort->pfnDoRateConversion(mpDrv->pUpPort, pVRDEVoice->rate, pHostStereoSampleBuf,
    749                                             pConvertedSampleBuf, &cSampleSrc, &cConvertedSamples);*/
    750         pTmpSampleBuf = pConvertedSampleBuf;
    751         cbSamples =  cConvertedSamples * sizeof(PDMAUDIOSAMPLE);
    752     }
    753 
    754     if (cbSamples)
    755         rc = vrdeRecordingCallback(pVRDEVoice, cbSamples, pTmpSampleBuf);
    756 
    757     return rc;
    758 }
    759 
    760 /*
    761  * pvContext: pointer to VRDP voice returned by the VRDP server. The is same pointer that we initialized in
    762  *            drvAudioVideoRecDisableEnableIn VOICE_ENABLE case.
    763  */
    764 int AudioVideoRec::handleVideoRecSvrCmdAudioInputEventEnd(void *pvContext)
    765 {
    766     LogFlowFuncEnter();
    767 
    768     PVIDEORECAUDIOIN pVRDEVoice = (PVIDEORECAUDIOIN)pvContext;
    769     AssertPtrReturn(pVRDEVoice, VERR_INVALID_POINTER);
    770 
    771     /* The caller will not use this context anymore. */
    772     if (pVRDEVoice->rate)
    773     {
    774         //mpDrv->pUpPort->pfnEndAudioConversion(mpDrv->pUpPort, pVRDEVoice->rate);
    775     }
    776 
    777     if (pVRDEVoice->pvSamplesBuffer)
    778     {
    779         RTMemFree(pVRDEVoice->pvSamplesBuffer);
    780         pVRDEVoice->pvSamplesBuffer = NULL;
    781     }
    782 
    783     if (pVRDEVoice->pvRateBuffer)
    784     {
    785         RTMemFree(pVRDEVoice->pvRateBuffer);
    786         pVRDEVoice->pvRateBuffer = NULL;
    787     }
    788 
    789     return VINF_SUCCESS;
    790 }
    791 
    792 /**
    793  * Construct a VRDE audio driver instance.
     390
     391/**
     392 * Construct a audio video recording driver instance.
    794393 *
    795394 * @copydoc FNPDMDRVCONSTRUCT
     
    798397DECLCALLBACK(int) AudioVideoRec::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
    799398{
     399    RT_NOREF(fFlags);
     400
     401    PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
    800402    PDRVAUDIOVIDEOREC pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVIDEOREC);
    801     LogRel(("Audio: Initializing VRDE driver\n"));
     403
     404    AssertPtrReturn(pDrvIns, VERR_INVALID_POINTER);
     405    AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
     406
     407    LogRel(("Audio: Initializing video recording driver\n"));
    802408    LogFlowFunc(("fFlags=0x%x\n", fFlags));
    803409
    804     /* we save the address of AudioVideoRec in Object node in CFGM tree and address of VRDP server in
    805      * ObjectVRDPServer node. So presence of both is necessary.
    806      */
    807     //if (!CFGMR3AreValuesValid(pCfg, "Object\0") || !CFGMR3AreValuesValid(pCfg, "ObjectVRDPServer\0"))
    808     //   return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
    809410    AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
    810411                    ("Configuration error: Not possible to attach anything to this driver!\n"),
     
    820421    PDMAUDIO_IHOSTAUDIO_CALLBACKS(drvAudioVideoRec);
    821422
    822     /* Get VRDPServer pointer. */
     423    /*
     424     * Get the ConsoleVRDPServer object pointer.
     425     */
    823426    void *pvUser;
    824     int rc = CFGMR3QueryPtr(pCfg, "ObjectVRDPServer", &pvUser);
    825     if (RT_FAILURE(rc))
    826     {
    827         AssertMsgFailed(("Confguration error: No/bad \"ObjectVRDPServer\" value, rc=%Rrc\n", rc));
    828         return rc;
    829     }
     427    int rc = CFGMR3QueryPtr(pCfg, "ObjectVRDPServer", &pvUser); /** @todo r=andy Get rid of this hack and use IHostAudio::SetCallback. */
     428    AssertMsgRCReturn(rc, ("Confguration error: No/bad \"ObjectVRDPServer\" value, rc=%Rrc\n", rc), rc);
    830429
    831430    /* CFGM tree saves the pointer to ConsoleVRDPServer in the Object node of AudioVideoRec. */
    832431    pThis->pConsoleVRDPServer = (ConsoleVRDPServer *)pvUser;
    833432
     433    /*
     434     * Get the AudioVideoRec object pointer.
     435     */
    834436    pvUser = NULL;
    835     rc = CFGMR3QueryPtr(pCfg, "Object", &pvUser);
    836     if (RT_FAILURE(rc))
    837     {
    838         AssertMsgFailed(("Confguration error: No/bad \"Object\" value, rc=%Rrc\n", rc));
    839         return rc;
    840     }
     437    rc = CFGMR3QueryPtr(pCfg, "Object", &pvUser); /** @todo r=andy Get rid of this hack and use IHostAudio::SetCallback. */
     438    AssertMsgRCReturn(rc, ("Confguration error: No/bad \"Object\" value, rc=%Rrc\n", rc), rc);
    841439
    842440    pThis->pAudioVideoRec = (AudioVideoRec *)pvUser;
     
    847445     * Described in CFGM tree.
    848446     */
    849     pThis->pUpPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIAUDIOCONNECTOR);
    850     if (!pThis->pUpPort)
    851     {
    852         AssertMsgFailed(("Configuration error: No upper interface specified!\n"));
    853         return VERR_PDM_MISSING_INTERFACE_ABOVE;
    854     }
    855 
    856     return VINF_SUCCESS;
    857 }
    858 
     447    pThis->pDrvAudio = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIAUDIOCONNECTOR);
     448    AssertMsgReturn(pThis->pDrvAudio, ("Configuration error: No upper interface specified!\n"), VERR_PDM_MISSING_INTERFACE_ABOVE);
     449
     450    return VINF_SUCCESS;
     451}
     452
     453
     454/**
     455 * @interface_method_impl{PDMDRVREG,pfnDestruct}
     456 */
    859457/* static */
    860458DECLCALLBACK(void) AudioVideoRec::drvDestruct(PPDMDRVINS pDrvIns)
    861459{
     460    PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
     461    PDRVAUDIOVIDEOREC pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVIDEOREC);
    862462    LogFlowFuncEnter();
    863 }
    864 
    865 /**
    866  * VRDE audio driver registration record.
     463
     464    /*
     465     * If the AudioVideoRec object is still alive, we must clear it's reference to
     466     * us since we'll be invalid when we return from this method.
     467     */
     468    if (pThis->pAudioVideoRec)
     469    {
     470        pThis->pAudioVideoRec->mpDrv = NULL;
     471        pThis->pAudioVideoRec = NULL;
     472    }
     473}
     474
     475
     476/**
     477 * Video recording audio driver registration record.
    867478 */
    868479const PDMDRVREG AudioVideoRec::DrvReg =
Note: See TracChangeset for help on using the changeset viewer.

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