- Timestamp:
- Jan 5, 2017 5:26:48 PM (8 years ago)
- Location:
- trunk/src/VBox/Main
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/Makefile.kmk
r65049 r65162 5 5 6 6 # 7 # Copyright (C) 2004-201 6Oracle Corporation7 # Copyright (C) 2004-2017 Oracle Corporation 8 8 # 9 9 # This file is part of VirtualBox Open Source Edition (OSE), as … … 288 288 $(if $(VBOX_WITH_AUDIO_DEBUG),VBOX_WITH_AUDIO_DEBUG,) \ 289 289 $(if $(VBOX_WITH_AUDIO_VALIDATIONKIT),VBOX_WITH_AUDIO_VALIDATIONKIT,) \ 290 $(if $(VBOX_WITH_AUDIO_VIDEOREC),VBOX_WITH_AUDIO_VIDEOREC,) \ 290 291 $(if $(VBOX_WITH_VRDE_AUDIO),VBOX_WITH_VRDE_AUDIO,) \ 291 292 $(if $(VBOX_WITH_E1000),VBOX_WITH_E1000,) \ … … 669 670 $(if $(VBOX_WITH_AUDIO_DEBUG),VBOX_WITH_AUDIO_DEBUG,) \ 670 671 $(if $(VBOX_WITH_AUDIO_VALIDATIONKIT),VBOX_WITH_AUDIO_VALIDATIONKIT,) \ 672 $(if $(VBOX_WITH_AUDIO_VIDEOREC),VBOX_WITH_AUDIO_VIDEOREC,) \ 671 673 $(if $(VBOX_WITH_VRDE_AUDIO),VBOX_WITH_VRDE_AUDIO,) \ 672 674 $(if $(VBOX_WITH_E1000),VBOX_WITH_E1000,) \ … … 812 814 ../Devices/Audio/AudioMixBuffer.cpp \ 813 815 ../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,) 815 818 816 819 VBoxC_SOURCES.win = \ -
trunk/src/VBox/Main/include/ConsoleImpl.h
r65088 r65162 5 5 6 6 /* 7 * Copyright (C) 2005-201 6Oracle Corporation7 * Copyright (C) 2005-2017 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 37 37 class EmulatedUSB; 38 38 class AudioVRDE; 39 #ifdef VBOX_WITH_AUDIO_VIDEOREC 40 class AudioVideoRec; 41 #endif 39 42 class Nvram; 40 43 #ifdef VBOX_WITH_USB_CARDREADER … … 132 135 Display *i_getDisplay() const { return mDisplay; } 133 136 MachineDebugger *i_getMachineDebugger() const { return mDebugger; } 137 #ifdef VBOX_WITH_VRDE_AUDIO 134 138 AudioVRDE *i_getAudioVRDE() const { return mAudioVRDE; } 139 #endif 140 #ifdef VBOX_WITH_AUDIO_VIDEOREC 141 AudioVideoRec *getAudioVideoRec() const { return mAudioVideoRec; } 142 #endif 135 143 136 144 const ComPtr<IMachine> &i_machine() const { return mMachine; } … … 847 855 bool mfVRDEChangeInProcess; 848 856 bool mfVRDEChangePending; 849 850 857 const ComObjPtr<Guest> mGuest; 851 858 const ComObjPtr<Keyboard> mKeyboard; … … 909 916 VMMDev * m_pVMMDev; 910 917 AudioVRDE * const mAudioVRDE; 918 #ifdef VBOX_WITH_AUDIO_VIDEOREC 919 /** The video recording audio backend. */ 920 AudioVideoRec * const mAudioVideoRec; 921 #endif 911 922 Nvram * const mNvram; 912 923 #ifdef VBOX_WITH_USB_CARDREADER -
trunk/src/VBox/Main/include/DrvAudioVideoRec.h
r62485 r65162 41 41 public: 42 42 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 50 43 static DECLCALLBACK(int) drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags); 51 44 static DECLCALLBACK(void) drvDestruct(PPDMDRVINS pDrvIns); -
trunk/src/VBox/Main/src-client/ConsoleImpl.cpp
r65120 r65162 5 5 6 6 /* 7 * Copyright (C) 2005-201 6Oracle Corporation7 * Copyright (C) 2005-2017 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 59 59 # include "DrvAudioVRDE.h" 60 60 #endif 61 #ifdef VBOX_WITH_AUDIO_VIDEOREC 62 # include "DrvAudioVideoRec.h" 63 #endif 61 64 #include "Nvram.h" 62 65 #ifdef VBOX_WITH_USB_CARDREADER … … 392 395 , m_pVMMDev(NULL) 393 396 , mAudioVRDE(NULL) 397 #ifdef VBOX_WITH_AUDIO_VIDEOREC 398 , mAudioVideoRec(NULL) 399 #endif 394 400 , mNvram(NULL) 395 401 #ifdef VBOX_WITH_USB_CARDREADER … … 575 581 AssertReturn(mAudioVRDE, E_FAIL); 576 582 #endif 583 #ifdef VBOX_WITH_AUDIO_VIDEOREC 584 unconst(mAudioVideoRec) = new AudioVideoRec(this); 585 AssertReturn(mAudioVideoRec, E_FAIL); 586 #endif 577 587 FirmwareType_T enmFirmwareType; 578 588 mMachine->COMGETTER(FirmwareType)(&enmFirmwareType); … … 716 726 delete mAudioVRDE; 717 727 unconst(mAudioVRDE) = NULL; 728 } 729 #endif 730 731 #ifdef VBOX_WITH_AUDIO_VIDEOREC 732 if (mAudioVideoRec) 733 { 734 delete mAudioVideoRec; 735 unconst(mAudioVideoRec) = NULL; 718 736 } 719 737 #endif -
trunk/src/VBox/Main/src-client/ConsoleImpl2.cpp
r65120 r65162 10 10 11 11 /* 12 * Copyright (C) 2006-201 6Oracle Corporation12 * Copyright (C) 2006-2017 Oracle Corporation 13 13 * 14 14 * This file is part of VirtualBox Open Source Edition (OSE), as … … 2951 2951 #endif /* VBOX_WITH_VRDE_AUDIO */ 2952 2952 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 2953 2970 #ifdef VBOX_WITH_AUDIO_DEBUG 2954 2971 /* … … 3975 3992 } 3976 3993 } 3977 3994 3978 3995 /* 3979 3996 * 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 5 5 6 6 /* 7 * Copyright (C) 201 4-2016Oracle Corporation7 * Copyright (C) 2016-2017 Oracle Corporation 8 8 * 9 9 * This file is part of VirtualBox Open Source Edition (OSE), as … … 15 15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. 16 16 */ 17 18 19 /********************************************************************************************************************************* 20 * Header Files * 21 *********************************************************************************************************************************/ 22 #define LOG_GROUP LOG_GROUP_DRV_AUDIO 23 #include <VBox/log.h> 17 24 #include "DrvAudioVideoRec.h" 18 25 #include "ConsoleImpl.h" … … 21 28 #include "Logging.h" 22 29 30 #include "../../Devices/Audio/DrvAudio.h" 31 #include "../../Devices/Audio/AudioMixBuffer.h" 32 23 33 #include <iprt/mem.h> 24 34 #include <iprt/cdefs.h> … … 27 37 #include <VBox/vmm/pdmaudioifs.h> 28 38 #include <VBox/vmm/pdmdrv.h> 29 #include <VBox/RemoteDesktop/VRDE.h>30 39 #include <VBox/vmm/cfgm.h> 31 40 #include <VBox/err.h> 32 41 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. 76 48 */ 77 49 typedef struct DRVAUDIOVIDEOREC 78 50 { 79 51 /** Pointer to audio video recording object. */ 80 AudioVideoRec *pAudioVideoRec; 81 PPDMDRVINS pDrvIns; 52 AudioVideoRec *pAudioVideoRec; 82 53 /** 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; 87 61 } 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 63 typedef 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 78 static 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 100 static 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 */ 124 121 static DECLCALLBACK(int) drvAudioVideoRecInit(PPDMIHOSTAUDIO pInterface) 125 122 { 123 RT_NOREF(pInterface); 126 124 LogFlowFuncEnter(); 127 125 … … 129 127 } 130 128 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 */ 133 static 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 */ 148 static 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) 140 193 { 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) 191 197 { 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; 194 202 } 195 203 } 196 204 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 219 static 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 231 static 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 */ 243 static 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 */ 260 static DECLCALLBACK(void) drvAudioVideoRecShutdown(PPDMIHOSTAUDIO pInterface) 261 { 262 RT_NOREF(pInterface); 263 } 264 265 266 /** 267 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetStatus} 268 */ 269 static 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 */ 281 static 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 */ 299 static 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); 210 307 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); 375 309 376 310 return rc; 377 311 } 378 312 379 static DECLCALLBACK(int) drvAudioVideoRecInitOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHostVoiceOut, PPDMAUDIOSTREAMCFG pCfg) 380 { 313 314 /** 315 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamControl} 316 */ 317 static 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 */ 335 static 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 */ 348 static DECLCALLBACK(int) drvAudioVideoRecStreamIterate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream) 349 { 350 AssertPtrReturn(pInterface, VERR_INVALID_POINTER); 351 AssertPtrReturn(pStream, VERR_INVALID_POINTER); 352 381 353 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 638 359 639 360 /** … … 643 364 { 644 365 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface); 645 PDRVAUDIOVIDEOREC pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVIDEOREC); 366 PDRVAUDIOVIDEOREC pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVIDEOREC); 367 646 368 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase); 647 369 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio); … … 649 371 } 650 372 373 651 374 AudioVideoRec::AudioVideoRec(Console *pConsole) 652 375 : mpDrv(NULL), … … 654 377 { 655 378 } 379 656 380 657 381 AudioVideoRec::~AudioVideoRec(void) … … 664 388 } 665 389 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. 794 393 * 795 394 * @copydoc FNPDMDRVCONSTRUCT … … 798 397 DECLCALLBACK(int) AudioVideoRec::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags) 799 398 { 399 RT_NOREF(fFlags); 400 401 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns); 800 402 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")); 802 408 LogFlowFunc(("fFlags=0x%x\n", fFlags)); 803 409 804 /* we save the address of AudioVideoRec in Object node in CFGM tree and address of VRDP server in805 * 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;809 410 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER, 810 411 ("Configuration error: Not possible to attach anything to this driver!\n"), … … 820 421 PDMAUDIO_IHOSTAUDIO_CALLBACKS(drvAudioVideoRec); 821 422 822 /* Get VRDPServer pointer. */ 423 /* 424 * Get the ConsoleVRDPServer object pointer. 425 */ 823 426 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); 830 429 831 430 /* CFGM tree saves the pointer to ConsoleVRDPServer in the Object node of AudioVideoRec. */ 832 431 pThis->pConsoleVRDPServer = (ConsoleVRDPServer *)pvUser; 833 432 433 /* 434 * Get the AudioVideoRec object pointer. 435 */ 834 436 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); 841 439 842 440 pThis->pAudioVideoRec = (AudioVideoRec *)pvUser; … … 847 445 * Described in CFGM tree. 848 446 */ 849 pThis->p UpPort= 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 */ 859 457 /* static */ 860 458 DECLCALLBACK(void) AudioVideoRec::drvDestruct(PPDMDRVINS pDrvIns) 861 459 { 460 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns); 461 PDRVAUDIOVIDEOREC pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVIDEOREC); 862 462 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. 867 478 */ 868 479 const PDMDRVREG AudioVideoRec::DrvReg =
Note:
See TracChangeset
for help on using the changeset viewer.