DrvAudioVideoRec.cpp revision 1705f7565ed8533058b8541d72d6c5d4453de00f
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * Video recording audio backend for Main.
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync * Copyright (C) 2014-2015 Oracle Corporation
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/* 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//@todo move t_sample as a PDM interface
174f3dff60f96d89b320f9a322307118676db1dbvboxsync//typedef struct { int mute; uint32_t r; uint32_t l; } volume_t;
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.
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic struct
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * Audio video recording driver instance data.
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * @extends PDMIAUDIOSNIFFERCONNECTOR
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /** Pointer to audio video recording object. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /** Pointer to the driver instance structure. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /** Pointer to the DrvAudio port interface that is above it. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsynctypedef struct PDMAUDIOHSTSTRMOUT PDMAUDIOHSTSTRMOUT;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* Audio and audio details for recording */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* Number of bytes per frame (bitsPerSample * channels) of the actual input format. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* Frequency of the actual audio format. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* If the actual format frequence differs from the requested format, this is not NULL. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* Temporary buffer for st_sample_t representation of the input audio data. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* buffer for bytes of samples (not rate converted) */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* Temporary buffer for frequency conversion. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* buffer for bytes rate converted samples */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* A ring buffer for transferring data to the playback thread */
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic DECLCALLBACK(int) drvAudioVideoRecInit(PPDMIHOSTAUDIO pInterface)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync/** @todo Replace this with drvAudioHlpPcmPropsFromCfg(). */
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic int drvAudioVideoRecPcmInitInfo(PDMPCMPROPS * pProps, PPDMAUDIOSTREAMCFG as)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync bool fSigned = false;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pProps->fSwapEndian = (as->enmEndianness != PDMAUDIOHOSTENDIANESS);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * Hard voice (playback)
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic int audio_pcm_hw_find_min_out (PPDMAUDIOHSTSTRMOUT hw, int *nb_livep)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync RTListForEach(&hw->lstGstStrmOut, pIter, PDMAUDIOGSTSTRMOUT, Node)
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic int audio_pcm_hw_get_live_out2 (PPDMAUDIOHSTSTRMOUT hw, int *nb_live)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogFlowFunc(("Error: live=%d hw->samples=%d\n", live, hw->cSamples));
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic int audio_pcm_hw_get_live_out (PPDMAUDIOHSTSTRMOUT hw)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogFlowFunc(("Error: live=%d hw->samples=%d\n", live, hw->cSamples));
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * Hard voice (capture)
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic int audio_pcm_hw_find_min_in (PPDMAUDIOHSTSTRMIN hw)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync RTListForEach(&hw->lstGstStreamsIn, pIter, PDMAUDIOGSTSTRMIN, Node)
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncint audio_pcm_hw_get_live_in (PPDMAUDIOHSTSTRMIN hw)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync int live = hw->cTotalSamplesCaptured - audio_pcm_hw_find_min_in (hw);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogFlowFunc(("Error: live=%d hw->samples=%d\n", live, hw->cSamples));
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return (d + incr);
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic int vrdeReallocSampleBuf(PVIDEORECAUDIOIN pVRDEVoice, uint32_t cSamples)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync uint32_t cbBuffer = cSamples * sizeof(PDMAUDIOSAMPLE);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync if (cbBuffer > pVRDEVoice->cbSamplesBufferAllocated)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /** @todo r=andy Why not using RTMemReAlloc? */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pVRDEVoice->pvSamplesBuffer = RTMemAlloc(cbBuffer);
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic int vrdeReallocRateAdjSampleBuf(PVIDEORECAUDIOIN pVRDEVoice, uint32_t cSamples)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync uint32_t cbBuffer = cSamples * sizeof(PDMAUDIOSAMPLE);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync/*******************************************************************************
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * AudioVideoRec input section
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 * @param cbSamples Size of pvSamples array in bytes.
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * @param pvSamples Points to an array of samples.
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * @return IPRT status code.
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic int vrdeRecordingCallback(PVIDEORECAUDIOIN pVRDEVoice, uint32_t cbSamples, const void *pvSamples)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* If nothing is pending return immediately. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* How much space is free in the ring buffer? */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync size_t csAvail = RTCircBufFree(pVRDEVoice->pRecordedVoiceBuf) / sizeof(PDMAUDIOSAMPLE); /* bytes -> samples */
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 /* Iterate as long as data is available. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* How much is left? */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync size_t cbToWrite = csToWrite * sizeof(PDMAUDIOSAMPLE);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* Try to acquire the necessary space from the ring buffer. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync RTCircBufAcquireWriteBlock(pVRDEVoice->pRecordedVoiceBuf, cbToWrite, &pcDst, &cbToWrite);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* How much do we get? */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* Copy the data from the audio buffer to the ring buffer in PVRDEVoice. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync memcpy(pcDst, (uint8_t *)pvSamples + (csWritten * sizeof(PDMAUDIOSAMPLE)), cbToWrite);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* Release the ring buffer, so the main thread could start reading this data. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync RTCircBufReleaseWriteBlock(pVRDEVoice->pRecordedVoiceBuf, cbToWrite);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogFlowFunc(("Finished writing buffer with %RU32 samples (%RU32 bytes)\n",
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic DECLCALLBACK(int) drvAudioVideoRecInitOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHostVoiceOut, PPDMAUDIOSTREAMCFG pCfg)
8a204879c937e7c55da35682a0e5d2e1df91c856vboxsync PDRVAUDIOVIDEOREC pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVIDEOREC, IHostAudio);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PVIDEORECAUDIOOUT pVRDEVoiceOut = (PVIDEORECAUDIOOUT)pHostVoiceOut;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pHostVoiceOut->cSamples = _4K; /* 4096 samples * 4 = 16K bytes total. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return drvAudioVideoRecPcmInitInfo(&pVRDEVoiceOut->pHostVoiceOut.Props, pCfg);
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic DECLCALLBACK(int) drvAudioVideoRecInitIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHostVoiceIn, PPDMAUDIOSTREAMCFG pCfg)
8a204879c937e7c55da35682a0e5d2e1df91c856vboxsync PDRVAUDIOVIDEOREC pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVIDEOREC, IHostAudio);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PVIDEORECAUDIOIN pVRDEVoice = (PVIDEORECAUDIOIN)pHostVoiceIn;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pHostVoiceIn->cSamples = _4K; /* 4096 samples * 4 = 16K bytes total. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return drvAudioVideoRecPcmInitInfo(&pVRDEVoice->pHostVoiceIn.Props, pCfg);
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic DECLCALLBACK(int) drvAudioVideoRecCaptureIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHostVoiceIn,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /** @todo Take care of the size of the buffer allocated to pHostVoiceIn. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PVIDEORECAUDIOIN pVRDEVoice = (PVIDEORECAUDIOIN)pHostVoiceIn;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* use this from DrvHostCoreAudio.c */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync if (ASMAtomicReadU32(&pVRDEVoice->status) != CA_STATUS_INIT)
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 /* 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 LogFlowFunc(("Start reading buffer with %d samples (%d bytes)\n", cSamplesRingBuffer,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* Iterate as long as data is available */
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 /* 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 /*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 RTCircBufAcquireReadBlock(pVRDEVoice->pRecordedVoiceBuf, cbToRead, &pvSrc, &cbToRead);
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 /* Break if nothing is used anymore. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* Copy the data from our ring buffer to the mix buffer. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PPDMAUDIOSAMPLE psDst = pVRDEVoice->pHostVoiceIn.paSamples + pVRDEVoice->pHostVoiceIn.offSamplesWritten;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* Release the read buffer, so it could be used for new data. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync RTCircBufReleaseReadBlock(pVRDEVoice->pRecordedVoiceBuf, cbToRead);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pVRDEVoice->pHostVoiceIn.offSamplesWritten = (pVRDEVoice->pHostVoiceIn.offSamplesWritten + cSamplesToRead)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* How much have we reads so far. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogFlowFunc(("Finished reading buffer with %zu samples (%zu bytes)\n",
174f3dff60f96d89b320f9a322307118676db1dbvboxsync cSamplesRead, cSamplesRead * sizeof(PDMAUDIOSAMPLE)));
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic DECLCALLBACK(int) drvAudioVideoRecPlayOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHostVoiceOut,
8a204879c937e7c55da35682a0e5d2e1df91c856vboxsync PDRVAUDIOVIDEOREC pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVIDEOREC, IHostAudio);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PVIDEORECAUDIOOUT pVRDEVoiceOut = (PVIDEORECAUDIOOUT)pHostVoiceOut;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * Just call the VRDP server with the data.
174f3dff60f96d89b320f9a322307118676db1dbvboxsync int live = audio_pcm_hw_get_live_out(pHostVoiceOut);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync uint64_t now = PDMDrvHlpTMGetVirtualTime(pDrv->pDrvIns);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync uint64_t ticks_per_second = PDMDrvHlpTMGetVirtualFreq(pDrv->pDrvIns);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync int cSamplesPlayed = (int)((2 * ticks * pHostVoiceOut->Props.uHz + ticks_per_second) / ticks_per_second / 2);
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 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 if (pHostVoiceOut->cOffSamplesRead + cSamplesToSend > pHostVoiceOut->cSamples)
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 pDrv->pConsoleVRDPServer->SendAudioSamples(&pHostVoiceOut->paSamples[0],
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pDrv->pConsoleVRDPServer->SendAudioSamples(&pHostVoiceOut->paSamples[pHostVoiceOut->cOffSamplesRead],
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pHostVoiceOut->cOffSamplesRead = (pHostVoiceOut->cOffSamplesRead + cSamplesToSend) % pHostVoiceOut->cSamples;
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic DECLCALLBACK(int) drvAudioVideoRecFiniIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN hw)
8a204879c937e7c55da35682a0e5d2e1df91c856vboxsync PDRVAUDIOVIDEOREC pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVIDEOREC, IHostAudio);
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic DECLCALLBACK(int) drvAudioVideoRecFiniOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHostVoiceOut)
8a204879c937e7c55da35682a0e5d2e1df91c856vboxsync PDRVAUDIOVIDEOREC pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVIDEOREC, IHostAudio);
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic DECLCALLBACK(int) drvAudioVideoRecControlOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT hw,
8a204879c937e7c55da35682a0e5d2e1df91c856vboxsync PDRVAUDIOVIDEOREC pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVIDEOREC, IHostAudio);
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic DECLCALLBACK(int) drvAudioVideoRecControlIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHostVoiceIn,
8a204879c937e7c55da35682a0e5d2e1df91c856vboxsync PDRVAUDIOVIDEOREC pDrv = RT_FROM_MEMBER(pInterface, DRVAUDIOVIDEOREC, IHostAudio);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* Initialize VRDEVoice and return to VRDP server which returns this struct back to us
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * in the form void * pvContext
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PVIDEORECAUDIOIN pVRDEVoice = (PVIDEORECAUDIOIN)pHostVoiceIn;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* initialize only if not already done */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync //@todo if (!pVRDEVoice->fIsInit)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync // RTCircBufReset(pVRDEVoice->pRecordedVoiceBuf);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* Initialize the hardware info section with the audio settings */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync ASMAtomicWriteU32(&pVRDEVoice->status, CA_STATUS_IN_INIT);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* Create the internal ring buffer. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pVRDEVoice->pHostVoiceIn.cSamples * sizeof(PDMAUDIOSAMPLE));
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogRel(("Failed to create internal ring buffer\n"));
174f3dff60f96d89b320f9a322307118676db1dbvboxsync ASMAtomicWriteU32(&pVRDEVoice->status, CA_STATUS_INIT);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync return pDrv->pConsoleVRDPServer->SendAudioInputBegin(NULL, pVRDEVoice, pHostVoiceIn->cSamples,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pHostVoiceIn->Props.cChannels, pHostVoiceIn->Props.cBits);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync else if (enmStreamCmd == PDMAUDIOSTREAMCMD_DISABLE)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync ASMAtomicWriteU32(&pVRDEVoice->status, CA_STATUS_IN_UNINIT);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync ASMAtomicWriteU32(&pVRDEVoice->status, CA_STATUS_UNINIT);
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic DECLCALLBACK(int) drvAudioVideoRecGetConf(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pAudioConf)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pAudioConf->cbStreamOut = sizeof(VIDEORECAUDIOOUT);
1705f7565ed8533058b8541d72d6c5d4453de00fvboxsyncstatic DECLCALLBACK(void) drvAudioVideoRecShutdown(PPDMIHOSTAUDIO pInterface)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * @interface_method_impl{PDMIBASE,pfnQueryInterface}
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncstatic DECLCALLBACK(void *) drvAudioVideoRecQueryInterface(PPDMIBASE pInterface, const char *pszIID)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PDRVAUDIOVIDEOREC pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVIDEOREC);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
8a204879c937e7c55da35682a0e5d2e1df91c856vboxsync PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncint AudioVideoRec::handleVideoRecSvrCmdAudioInputIntercept(bool fIntercept)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogFlowThisFunc(("fIntercept=%RTbool\n", fIntercept));
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncint AudioVideoRec::handleVideoRecSvrCmdAudioInputEventBegin(void *pvContext, int iSampleHz, int cChannels,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PVIDEORECAUDIOIN pVRDEVoice = (PVIDEORECAUDIOIN)pvContext;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* Prepare a format convertion for the actually used format. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pVRDEVoice->cBytesPerFrame = ((cBits + 7) / 8) * cChannels;
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 LogFlowFunc(("Failed to get the conversion function \n"));
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogFlowFunc(("Required freq as requested by VRDP Server = %d\n", iSampleHz));
174f3dff60f96d89b320f9a322307118676db1dbvboxsync //if (iSampleHz && iSampleHz != pVRDEVoice->pHostVoiceIn.Props.uFrequency)
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 LogFlowFunc(("pVRDEVoice assigned requested freq =%d\n", pVRDEVoice->uFrequency));
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * pvContext: pointer to VRDP voice returned by the VRDP server. The is same pointer that we initialized in
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * drvAudioVideoRecDisableEnableIn VOICE_ENABLE case.
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncint AudioVideoRec::handleVideoRecSvrCmdAudioInputEventData(void *pvContext, const void *pvData, uint32_t cbData)
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 uint32_t cConvertedSamples; /* samples adjusted for rate */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync uint32_t cbSamples; /* count of bytes occupied by samples */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync LogFlowFunc(("handleVRDPCmdInputEventData cbData = %d, bytesperfram=%d\n",
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pHostStereoSampleBuf = (PPDMAUDIOSAMPLE)pVRDEVoice->pvSamplesBuffer;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pVRDEVoice->convAudioDevFmtToStSampl(pHostStereoSampleBuf, pvData, cSamples, &videorec_nominal_volume);
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 pConvertedSampleBuf = (PPDMAUDIOSAMPLE)pVRDEVoice->pvRateBuffer;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /*mpDrv->pUpPort->pfnDoRateConversion(mpDrv->pUpPort, pVRDEVoice->rate, pHostStereoSampleBuf,
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pConvertedSampleBuf, &cSampleSrc, &cConvertedSamples);*/
174f3dff60f96d89b320f9a322307118676db1dbvboxsync cbSamples = cConvertedSamples * sizeof(PDMAUDIOSAMPLE);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync rc = vrdeRecordingCallback(pVRDEVoice, cbSamples, pTmpSampleBuf);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * pvContext: pointer to VRDP voice returned by the VRDP server. The is same pointer that we initialized in
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * drvAudioVideoRecDisableEnableIn VOICE_ENABLE case.
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncint AudioVideoRec::handleVideoRecSvrCmdAudioInputEventEnd(void *pvContext)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PVIDEORECAUDIOIN pVRDEVoice = (PVIDEORECAUDIOIN)pvContext;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* The caller will not use this context anymore. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync //mpDrv->pUpPort->pfnEndAudioConversion(mpDrv->pUpPort, pVRDEVoice->rate);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * Construct a VRDE audio driver instance.
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * @copydoc FNPDMDRVCONSTRUCT
174f3dff60f96d89b320f9a322307118676db1dbvboxsync/* static */
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncDECLCALLBACK(int) AudioVideoRec::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync PDRVAUDIOVIDEOREC pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVIDEOREC);
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 //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 * Init the static parts.
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* IBase */
e95cc69731ec79cf167e6167808e1c9b275ea007vboxsync pDrvIns->IBase.pfnQueryInterface = drvAudioVideoRecQueryInterface;
8a204879c937e7c55da35682a0e5d2e1df91c856vboxsync /* IHostAudio */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* Get VRDPServer pointer. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync int rc = CFGMR3QueryPtr(pCfg, "ObjectVRDPServer", &pvUser);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync AssertMsgFailed(("Confguration error: No/bad \"ObjectVRDPServer\" value, rc=%Rrc\n", rc));
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* CFGM tree saves the pointer to ConsoleVRDPServer in the Object node of AudioVideoRec. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pThis->pConsoleVRDPServer = (ConsoleVRDPServer *)pvUser;
174f3dff60f96d89b320f9a322307118676db1dbvboxsync AssertMsgFailed(("Confguration error: No/bad \"Object\" value, rc=%Rrc\n", rc));
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * Get the interface for the above driver (DrvAudio) to make mixer/conversion calls.
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * Described in CFGM tree.
174f3dff60f96d89b320f9a322307118676db1dbvboxsync pThis->pUpPort = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIAUDIOCONNECTOR);
174f3dff60f96d89b320f9a322307118676db1dbvboxsync AssertMsgFailed(("Configuration error: No upper interface specified!\n"));
174f3dff60f96d89b320f9a322307118676db1dbvboxsync/* static */
174f3dff60f96d89b320f9a322307118676db1dbvboxsyncDECLCALLBACK(void) AudioVideoRec::drvDestruct(PPDMDRVINS pDrvIns)
174f3dff60f96d89b320f9a322307118676db1dbvboxsync * VRDE audio driver registration record.
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* szName */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync "AudioVideoRec",
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* szRCMod */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* szR0Mod */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* pszDescription */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync "Audio driver for video recording",
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* fFlags */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* fClass. */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* cMaxInstances */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* cbInstance */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* pfnConstruct */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* pfnDestruct */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* pfnRelocate */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* pfnIOCtl */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* pfnPowerOn */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* pfnReset */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* pfnSuspend */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* pfnResume */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* pfnAttach */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* pfnDetach */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* pfnPowerOff */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* pfnSoftReset */
174f3dff60f96d89b320f9a322307118676db1dbvboxsync /* u32EndVersion */