VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/DrvAudioVideoRec.cpp@ 65172

Last change on this file since 65172 was 65170, checked in by vboxsync, 8 years ago

VideoRec: Removed not needed code.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.6 KB
Line 
1/* $Id: DrvAudioVideoRec.cpp 65170 2017-01-06 09:55:26Z vboxsync $ */
2/** @file
3 * Video recording audio backend for Main.
4 */
5
6/*
7 * Copyright (C) 2016-2017 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_DRV_AUDIO
23#include <VBox/log.h>
24#include "DrvAudioVideoRec.h"
25#include "ConsoleImpl.h"
26#include "ConsoleVRDPServer.h"
27
28#include "Logging.h"
29
30#include "../../Devices/Audio/DrvAudio.h"
31#include "../../Devices/Audio/AudioMixBuffer.h"
32
33#include <iprt/mem.h>
34#include <iprt/cdefs.h>
35#include <iprt/circbuf.h>
36
37#include <VBox/vmm/pdmaudioifs.h>
38#include <VBox/vmm/pdmdrv.h>
39#include <VBox/vmm/cfgm.h>
40#include <VBox/err.h>
41
42
43/*********************************************************************************************************************************
44* Structures and Typedefs *
45*********************************************************************************************************************************/
46/**
47 * Video recording audio driver instance data.
48 */
49typedef struct DRVAUDIOVIDEOREC
50{
51 /** Pointer to audio video recording object. */
52 AudioVideoRec *pAudioVideoRec;
53 /** Pointer to the driver instance structure. */
54 PPDMDRVINS pDrvIns;
55 /** Pointer to host audio interface. */
56 PDMIHOSTAUDIO IHostAudio;
57 /** Pointer to the DrvAudio port interface that is above us. */
58 PPDMIAUDIOCONNECTOR pDrvAudio;
59} DRVAUDIOVIDEOREC, *PDRVAUDIOVIDEOREC;
60
61typedef struct AVRECSTREAMOUT
62{
63 /** Note: Always must come first! */
64 PDMAUDIOSTREAM Stream;
65 /** The PCM properties of this stream. */
66 PDMAUDIOPCMPROPS Props;
67 uint64_t old_ticks;
68 uint64_t cSamplesSentPerSec;
69} AVRECSTREAMOUT, *PAVRECSTREAMOUT;
70
71/** Makes DRVAUDIOVIDEOREC out of PDMIHOSTAUDIO. */
72#define PDMIHOSTAUDIO_2_DRVAUDIOVIDEOREC(pInterface) \
73 ( (PDRVAUDIOVIDEOREC)((uintptr_t)pInterface - RT_OFFSETOF(DRVAUDIOVIDEOREC, IHostAudio)) )
74
75
76static int avRecCreateStreamOut(PPDMIHOSTAUDIO pInterface,
77 PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
78{
79 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
80 AssertPtrReturn(pStream, VERR_INVALID_POINTER);
81 AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
82 AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER);
83
84 PAVRECSTREAMOUT pStreamOut = (PAVRECSTREAMOUT)pStream;
85
86 int rc = DrvAudioHlpStreamCfgToProps(pCfgReq, &pStreamOut->Props);
87 if (RT_SUCCESS(rc))
88 {
89 if (pCfgAcq)
90 pCfgAcq->cSampleBufferSize = _4K; /** @todo Make this configurable. */
91 }
92
93 LogFlowFuncLeaveRC(VINF_SUCCESS);
94 return VINF_SUCCESS;
95}
96
97
98static int avRecControlStreamOut(PPDMIHOSTAUDIO pInterface,
99 PPDMAUDIOSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd)
100{
101 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
102 AssertPtrReturn(pStream, VERR_INVALID_POINTER);
103 RT_NOREF(enmStreamCmd);
104
105 PDRVAUDIOVIDEOREC pThis = PDMIHOSTAUDIO_2_DRVAUDIOVIDEOREC(pInterface);
106 RT_NOREF(pThis);
107
108 LogFlowFunc(("enmStreamCmd=%ld\n", enmStreamCmd));
109
110 AudioMixBufReset(&pStream->MixBuf);
111
112 return VINF_SUCCESS;
113}
114
115
116/**
117 * @interface_method_impl{PDMIHOSTAUDIO,pfnInit}
118 */
119static DECLCALLBACK(int) drvAudioVideoRecInit(PPDMIHOSTAUDIO pInterface)
120{
121 RT_NOREF(pInterface);
122 LogFlowFuncEnter();
123
124 return VINF_SUCCESS;
125}
126
127
128/**
129 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCapture}
130 */
131static DECLCALLBACK(int) drvAudioVideoRecStreamCapture(PPDMIHOSTAUDIO pInterface,
132 PPDMAUDIOSTREAM pStream, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
133{
134 RT_NOREF(pInterface, pStream, pvBuf, cbBuf);
135
136 if (pcbRead)
137 *pcbRead = 0;
138
139 return VINF_SUCCESS;
140}
141
142
143/**
144 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamPlay}
145 */
146static DECLCALLBACK(int) drvAudioVideoRecStreamPlay(PPDMIHOSTAUDIO pInterface,
147 PPDMAUDIOSTREAM pStream, const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)
148{
149 RT_NOREF2(pvBuf, cbBuf);
150
151 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
152 AssertPtrReturn(pStream, VERR_INVALID_POINTER);
153 /* pcbWritten is optional. */
154
155 PDRVAUDIOVIDEOREC pThis = PDMIHOSTAUDIO_2_DRVAUDIOVIDEOREC(pInterface);
156 PAVRECSTREAMOUT pStreamOut = (PAVRECSTREAMOUT)pStream;
157
158 uint32_t cLive = AudioMixBufLive(&pStream->MixBuf);
159
160 uint64_t now = PDMDrvHlpTMGetVirtualTime(pThis->pDrvIns);
161 uint64_t ticks = now - pStreamOut->old_ticks;
162 uint64_t ticks_per_second = PDMDrvHlpTMGetVirtualFreq(pThis->pDrvIns);
163
164 /* Minimize the rounding error: samples = int((ticks * freq) / ticks_per_second + 0.5). */
165 uint32_t cSamplesPlayed = (int)((2 * ticks * pStreamOut->Props.uHz + ticks_per_second) / ticks_per_second / 2);
166
167 /* Don't play more than available. */
168 if (cSamplesPlayed > cLive)
169 cSamplesPlayed = cLive;
170
171 /* Remember when samples were consumed. */
172 pStreamOut->old_ticks = now;
173
174 int cSamplesToSend = cSamplesPlayed;
175
176 LogFlowFunc(("uFreq=%RU32, cChan=%RU8, cBits=%RU8, fSigned=%RTbool, cSamplesToSend=%RU32\n",
177 pStreamOut->Props.uHz, pStreamOut->Props.cChannels,
178 pStreamOut->Props.cBits, pStreamOut->Props.fSigned, cSamplesToSend));
179
180 /*
181 * Call the VRDP server with the data.
182 */
183 uint32_t cReadTotal = 0;
184
185 PPDMAUDIOSAMPLE pSamples;
186 uint32_t cRead;
187 int rc = AudioMixBufAcquire(&pStream->MixBuf, cSamplesToSend,
188 &pSamples, &cRead);
189 if ( RT_SUCCESS(rc)
190 && cRead)
191 {
192 cReadTotal = cRead;
193
194 if (rc == VINF_TRY_AGAIN)
195 {
196 rc = AudioMixBufAcquire(&pStream->MixBuf, cSamplesToSend - cRead,
197 &pSamples, &cRead);
198
199 cReadTotal += cRead;
200 }
201 }
202
203 AudioMixBufFinish(&pStream->MixBuf, cSamplesToSend);
204
205 /*
206 * Always report back all samples acquired, regardless of whether the
207 * VRDP server actually did process those.
208 */
209 if (pcbWritten)
210 *pcbWritten = cReadTotal;
211
212 LogFlowFunc(("cReadTotal=%RU32, rc=%Rrc\n", cReadTotal, rc));
213 return rc;
214}
215
216
217static int avRecDestroyStreamIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
218{
219 RT_NOREF(pInterface, pStream);
220
221 return VINF_SUCCESS;
222}
223
224
225static int avRecDestroyStreamOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
226{
227 RT_NOREF(pInterface);
228 RT_NOREF(pStream);
229
230 return VINF_SUCCESS;
231}
232
233
234/**
235 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetConfig}
236 */
237static DECLCALLBACK(int) drvAudioVideoRecGetConfig(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pBackendCfg)
238{
239 NOREF(pInterface);
240 AssertPtrReturn(pBackendCfg, VERR_INVALID_POINTER);
241
242 pBackendCfg->cbStreamOut = sizeof(AVRECSTREAMOUT);
243 pBackendCfg->cbStreamIn = 0;
244 pBackendCfg->cMaxStreamsIn = 0;
245 pBackendCfg->cMaxStreamsOut = UINT32_MAX;
246
247 return VINF_SUCCESS;
248}
249
250
251/**
252 * @interface_method_impl{PDMIHOSTAUDIO,pfnShutdown}
253 */
254static DECLCALLBACK(void) drvAudioVideoRecShutdown(PPDMIHOSTAUDIO pInterface)
255{
256 RT_NOREF(pInterface);
257}
258
259
260/**
261 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetStatus}
262 */
263static DECLCALLBACK(PDMAUDIOBACKENDSTS) drvAudioVideoRecGetStatus(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
264{
265 RT_NOREF(enmDir);
266 AssertPtrReturn(pInterface, PDMAUDIOBACKENDSTS_UNKNOWN);
267
268 return PDMAUDIOBACKENDSTS_RUNNING;
269}
270
271
272/**
273 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCreate}
274 */
275static DECLCALLBACK(int) drvAudioVideoRecStreamCreate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream,
276 PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
277{
278 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
279 AssertPtrReturn(pStream, VERR_INVALID_POINTER);
280 AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
281 AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER);
282
283 if (pCfgReq->enmDir == PDMAUDIODIR_OUT)
284 return avRecCreateStreamOut(pInterface, pStream, pCfgReq, pCfgAcq);
285
286 return VERR_NOT_SUPPORTED;
287}
288
289
290/**
291 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDestroy}
292 */
293static DECLCALLBACK(int) drvAudioVideoRecStreamDestroy(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
294{
295 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
296 AssertPtrReturn(pStream, VERR_INVALID_POINTER);
297
298 int rc;
299 if (pStream->enmDir == PDMAUDIODIR_IN)
300 rc = avRecDestroyStreamIn(pInterface, pStream);
301 else
302 rc = avRecDestroyStreamOut(pInterface, pStream);
303
304 return rc;
305}
306
307
308/**
309 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamControl}
310 */
311static DECLCALLBACK(int) drvAudioVideoRecStreamControl(PPDMIHOSTAUDIO pInterface,
312 PPDMAUDIOSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd)
313{
314 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
315 AssertPtrReturn(pStream, VERR_INVALID_POINTER);
316
317 Assert(pStream->enmCtx == PDMAUDIOSTREAMCTX_HOST);
318
319 if (pStream->enmDir == PDMAUDIODIR_OUT)
320 return avRecControlStreamOut(pInterface, pStream, enmStreamCmd);
321
322 return VINF_SUCCESS;
323}
324
325
326/**
327 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetStatus}
328 */
329static DECLCALLBACK(PDMAUDIOSTRMSTS) drvAudioVideoRecStreamGetStatus(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
330{
331 NOREF(pInterface);
332 NOREF(pStream);
333
334 return ( PDMAUDIOSTRMSTS_FLAG_INITIALIZED | PDMAUDIOSTRMSTS_FLAG_ENABLED
335 | PDMAUDIOSTRMSTS_FLAG_DATA_READABLE | PDMAUDIOSTRMSTS_FLAG_DATA_WRITABLE);
336}
337
338
339/**
340 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamIterate}
341 */
342static DECLCALLBACK(int) drvAudioVideoRecStreamIterate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
343{
344 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
345 AssertPtrReturn(pStream, VERR_INVALID_POINTER);
346
347 LogFlowFuncEnter();
348
349 /* Nothing to do here for video recording. */
350 return VINF_SUCCESS;
351}
352
353
354/**
355 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
356 */
357static DECLCALLBACK(void *) drvAudioVideoRecQueryInterface(PPDMIBASE pInterface, const char *pszIID)
358{
359 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
360 PDRVAUDIOVIDEOREC pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVIDEOREC);
361
362 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
363 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
364 return NULL;
365}
366
367
368AudioVideoRec::AudioVideoRec(Console *pConsole)
369 : mpDrv(NULL),
370 mParent(pConsole)
371{
372}
373
374
375AudioVideoRec::~AudioVideoRec(void)
376{
377 if (mpDrv)
378 {
379 mpDrv->pAudioVideoRec = NULL;
380 mpDrv = NULL;
381 }
382}
383
384
385/**
386 * Construct a audio video recording driver instance.
387 *
388 * @copydoc FNPDMDRVCONSTRUCT
389 */
390/* static */
391DECLCALLBACK(int) AudioVideoRec::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
392{
393 RT_NOREF(fFlags);
394
395 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
396 PDRVAUDIOVIDEOREC pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVIDEOREC);
397
398 AssertPtrReturn(pDrvIns, VERR_INVALID_POINTER);
399 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
400
401 LogRel(("Audio: Initializing video recording driver\n"));
402 LogFlowFunc(("fFlags=0x%x\n", fFlags));
403
404 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
405 ("Configuration error: Not possible to attach anything to this driver!\n"),
406 VERR_PDM_DRVINS_NO_ATTACH);
407
408 /*
409 * Init the static parts.
410 */
411 pThis->pDrvIns = pDrvIns;
412 /* IBase */
413 pDrvIns->IBase.pfnQueryInterface = drvAudioVideoRecQueryInterface;
414 /* IHostAudio */
415 PDMAUDIO_IHOSTAUDIO_CALLBACKS(drvAudioVideoRec);
416
417 /*
418 * Get the AudioVideoRec object pointer.
419 */
420 void *pvUser = NULL;
421 int rc = CFGMR3QueryPtr(pCfg, "Object", &pvUser); /** @todo r=andy Get rid of this hack and use IHostAudio::SetCallback. */
422 AssertMsgRCReturn(rc, ("Confguration error: No/bad \"Object\" value, rc=%Rrc\n", rc), rc);
423
424 pThis->pAudioVideoRec = (AudioVideoRec *)pvUser;
425 pThis->pAudioVideoRec->mpDrv = pThis;
426
427 /*
428 * Get the interface for the above driver (DrvAudio) to make mixer/conversion calls.
429 * Described in CFGM tree.
430 */
431 pThis->pDrvAudio = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIAUDIOCONNECTOR);
432 AssertMsgReturn(pThis->pDrvAudio, ("Configuration error: No upper interface specified!\n"), VERR_PDM_MISSING_INTERFACE_ABOVE);
433
434 return VINF_SUCCESS;
435}
436
437
438/**
439 * @interface_method_impl{PDMDRVREG,pfnDestruct}
440 */
441/* static */
442DECLCALLBACK(void) AudioVideoRec::drvDestruct(PPDMDRVINS pDrvIns)
443{
444 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
445 PDRVAUDIOVIDEOREC pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVIDEOREC);
446 LogFlowFuncEnter();
447
448 /*
449 * If the AudioVideoRec object is still alive, we must clear it's reference to
450 * us since we'll be invalid when we return from this method.
451 */
452 if (pThis->pAudioVideoRec)
453 {
454 pThis->pAudioVideoRec->mpDrv = NULL;
455 pThis->pAudioVideoRec = NULL;
456 }
457}
458
459
460/**
461 * Video recording audio driver registration record.
462 */
463const PDMDRVREG AudioVideoRec::DrvReg =
464{
465 PDM_DRVREG_VERSION,
466 /* szName */
467 "AudioVideoRec",
468 /* szRCMod */
469 "",
470 /* szR0Mod */
471 "",
472 /* pszDescription */
473 "Audio driver for video recording",
474 /* fFlags */
475 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
476 /* fClass. */
477 PDM_DRVREG_CLASS_AUDIO,
478 /* cMaxInstances */
479 ~0U,
480 /* cbInstance */
481 sizeof(DRVAUDIOVIDEOREC),
482 /* pfnConstruct */
483 AudioVideoRec::drvConstruct,
484 /* pfnDestruct */
485 AudioVideoRec::drvDestruct,
486 /* pfnRelocate */
487 NULL,
488 /* pfnIOCtl */
489 NULL,
490 /* pfnPowerOn */
491 NULL,
492 /* pfnReset */
493 NULL,
494 /* pfnSuspend */
495 NULL,
496 /* pfnResume */
497 NULL,
498 /* pfnAttach */
499 NULL,
500 /* pfnDetach */
501 NULL,
502 /* pfnPowerOff */
503 NULL,
504 /* pfnSoftReset */
505 NULL,
506 /* u32EndVersion */
507 PDM_DRVREG_VERSION
508};
509
Note: See TracBrowser for help on using the repository browser.

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