VirtualBox

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

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

VideoRec: Opus encoding header fixes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.1 KB
Line 
1/* $Id: DrvAudioVideoRec.cpp 65281 2017-01-13 13:21:12Z 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.215389.xyz. 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
27#include "Logging.h"
28
29#include "../../Devices/Audio/DrvAudio.h"
30#include "../../Devices/Audio/AudioMixBuffer.h"
31#include "EbmlWriter.h"
32
33#include <iprt/mem.h>
34#include <iprt/cdefs.h>
35
36#include <VBox/vmm/pdmaudioifs.h>
37#include <VBox/vmm/pdmdrv.h>
38#include <VBox/vmm/cfgm.h>
39#include <VBox/err.h>
40
41#ifdef VBOX_WITH_LIBOPUS
42# include <opus.h>
43#endif
44
45/*********************************************************************************************************************************
46* Structures and Typedefs *
47*********************************************************************************************************************************/
48
49/**
50 * Enumeration for audio/video recording driver recording mode.
51 */
52typedef enum AVRECMODE
53{
54 /** Unknown / invalid recording mode. */
55 AVRECMODE_UNKNOWN = 0,
56 /** Only record audio.
57 * This mode does not need to talk to the video recording driver,
58 * as this driver then simply creates an own WebM container. */
59 AVRECMODE_AUDIO = 1,
60 /** Records audio and video.
61 * Needs to work together with the video recording driver in
62 * order to get a full-featured WebM container. */
63 AVRECMODE_AUDIO_VIDEO = 2
64} AVRECMODE;
65
66/**
67 * Structure for keeping codec specific data.
68 */
69typedef struct AVRECCODEC
70{
71 union
72 {
73#ifdef VBOX_WITH_LIBOPUS
74 struct
75 {
76 /** Encoder we're going to use. */
77 OpusEncoder *pEnc;
78 } Opus;
79#endif /* VBOX_WITH_LIBOPUS */
80 };
81} AVRECCODEC, *PAVRECCODEC;
82
83/**
84 * Audio video recording output stream.
85 */
86typedef struct AVRECSTREAMOUT
87{
88 /** Note: Always must come first! */
89 PDMAUDIOSTREAM Stream;
90 /** The PCM properties of this stream. */
91 PDMAUDIOPCMPROPS Props;
92 uint64_t old_ticks;
93 uint64_t cSamplesSentPerSec;
94 /** Codec-specific data.
95 * As every stream can be different, one codec per stream is needed. */
96 AVRECCODEC Codec;
97 /** (Audio) frame buffer. */
98 uint8_t *pvFrameBuf;
99 size_t cbFrameBufSize;
100 size_t cbFrameBufUsed;
101 size_t offFrameBufRead;
102 size_t offFrameBufWrite;
103} AVRECSTREAMOUT, *PAVRECSTREAMOUT;
104
105/**
106 * Video recording audio driver instance data.
107 */
108typedef struct DRVAUDIOVIDEOREC
109{
110 /** Pointer to audio video recording object. */
111 AudioVideoRec *pAudioVideoRec;
112 /** Pointer to the driver instance structure. */
113 PPDMDRVINS pDrvIns;
114 /** Pointer to host audio interface. */
115 PDMIHOSTAUDIO IHostAudio;
116 /** Pointer to the DrvAudio port interface that is above us. */
117 PPDMIAUDIOCONNECTOR pDrvAudio;
118 /** Recording mode. */
119 AVRECMODE enmMode;
120 /** Pointer to WebM container to write recorded audio data to.
121 * See the AVRECMODE enumeration for more information. */
122 WebMWriter *pEBML;
123} DRVAUDIOVIDEOREC, *PDRVAUDIOVIDEOREC;
124
125/** Makes DRVAUDIOVIDEOREC out of PDMIHOSTAUDIO. */
126#define PDMIHOSTAUDIO_2_DRVAUDIOVIDEOREC(pInterface) \
127 ( (PDRVAUDIOVIDEOREC)((uintptr_t)pInterface - RT_OFFSETOF(DRVAUDIOVIDEOREC, IHostAudio)) )
128
129
130static int avRecCreateStreamOut(PPDMIHOSTAUDIO pInterface,
131 PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
132{
133 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
134 AssertPtrReturn(pStream, VERR_INVALID_POINTER);
135 AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
136 AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER);
137
138 PAVRECSTREAMOUT pStreamOut = (PAVRECSTREAMOUT)pStream;
139
140 int rc;
141
142#ifdef VBOX_WITH_LIBOPUS
143 rc = DrvAudioHlpStreamCfgToProps(pCfgReq, &pStreamOut->Props);
144 if (RT_SUCCESS(rc))
145 {
146 size_t cbFrameBuf = sizeof(uint8_t) * _8K; /** @todo Make this configurable */
147
148 pStreamOut->pvFrameBuf = (uint8_t *)RTMemAlloc(cbFrameBuf);
149 if (pStreamOut->pvFrameBuf)
150 {
151 pStreamOut->cbFrameBufSize = cbFrameBuf;
152 pStreamOut->cbFrameBufUsed = 0;
153 pStreamOut->offFrameBufRead = 0;
154 pStreamOut->offFrameBufWrite = 0;
155
156 OpusEncoder *pEnc = NULL;
157
158 int orc;
159 pEnc = opus_encoder_create(48000 /* Hz */, 2 /* Stereo */, OPUS_APPLICATION_AUDIO, &orc);
160 if (orc != OPUS_OK)
161 {
162 LogRel(("VideoRec: Audio codec failed to initialize: %s\n", opus_strerror(orc)));
163 return VERR_AUDIO_BACKEND_INIT_FAILED;
164 }
165
166 AssertPtr(pEnc);
167
168 #if 0
169 orc = opus_encoder_ctl(pEnc, OPUS_SET_BITRATE(DrvAudioHlpCalcBitrate()));
170 if (orc != OPUS_OK)
171 {
172 LogRel(("VideoRec: Audio codec failed to set bitrate: %s\n", opus_strerror(orc)));
173 rc = VERR_AUDIO_BACKEND_INIT_FAILED;
174 }
175 else
176 {
177 #endif
178 pStreamOut->Codec.Opus.pEnc = pEnc;
179
180 if (pCfgAcq)
181 pCfgAcq->cSampleBufferSize = _4K; /** @todo Make this configurable. */
182 // }
183 }
184 }
185#else
186 rc = VERR_NOT_SUPPORTED;
187#endif /* VBOX_WITH_LIBOPUS */
188
189 LogFlowFuncLeaveRC(rc);
190 return rc;
191}
192
193
194static int avRecControlStreamOut(PPDMIHOSTAUDIO pInterface,
195 PPDMAUDIOSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd)
196{
197 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
198 AssertPtrReturn(pStream, VERR_INVALID_POINTER);
199 RT_NOREF(enmStreamCmd);
200
201 PDRVAUDIOVIDEOREC pThis = PDMIHOSTAUDIO_2_DRVAUDIOVIDEOREC(pInterface);
202 RT_NOREF(pThis);
203
204 LogFlowFunc(("enmStreamCmd=%ld\n", enmStreamCmd));
205
206 AudioMixBufReset(&pStream->MixBuf);
207
208 return VINF_SUCCESS;
209}
210
211
212/**
213 * @interface_method_impl{PDMIHOSTAUDIO,pfnInit}
214 */
215static DECLCALLBACK(int) drvAudioVideoRecInit(PPDMIHOSTAUDIO pInterface)
216{
217 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
218
219 LogFlowFuncEnter();
220
221 PDRVAUDIOVIDEOREC pThis = PDMIHOSTAUDIO_2_DRVAUDIOVIDEOREC(pInterface);
222
223 pThis->enmMode = AVRECMODE_AUDIO; /** @todo Fix mode! */
224
225 int rc;
226
227 try
228 {
229 switch (pThis->enmMode)
230 {
231 case AVRECMODE_AUDIO:
232 {
233 pThis->pEBML = new WebMWriter();
234 rc = pThis->pEBML->Create("/tmp/acap.webm", RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE, /** @todo Fix path! */
235 WebMWriter::AudioCodec_Opus, WebMWriter::VideoCodec_None);
236 if (RT_SUCCESS(rc))
237 rc = pThis->pEBML->AddAudioTrack(44100, 2, 16);
238 break;
239 }
240
241 case AVRECMODE_AUDIO_VIDEO:
242 {
243 rc = VERR_NOT_SUPPORTED;
244 break;
245 }
246
247 default:
248 rc = VERR_NOT_SUPPORTED;
249 break;
250 }
251 }
252 catch (std::bad_alloc)
253 {
254 rc = VERR_NO_MEMORY;
255 }
256
257 if (RT_FAILURE(rc))
258 {
259 LogRel(("VideoRec: Audio recording driver failed to initialize, rc=%Rrc\n", rc));
260 }
261 else
262 LogRel2(("VideoRec: Audio recording driver initialized\n"));
263
264 return rc;
265}
266
267
268/**
269 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCapture}
270 */
271static DECLCALLBACK(int) drvAudioVideoRecStreamCapture(PPDMIHOSTAUDIO pInterface,
272 PPDMAUDIOSTREAM pStream, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
273{
274 RT_NOREF(pInterface, pStream, pvBuf, cbBuf);
275
276 if (pcbRead)
277 *pcbRead = 0;
278
279 return VINF_SUCCESS;
280}
281
282
283/**
284 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamPlay}
285 */
286static DECLCALLBACK(int) drvAudioVideoRecStreamPlay(PPDMIHOSTAUDIO pInterface,
287 PPDMAUDIOSTREAM pStream, const void *pvBuf, uint32_t cbBuf,
288 uint32_t *pcbWritten)
289{
290 RT_NOREF2(pvBuf, cbBuf);
291
292 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
293 AssertPtrReturn(pStream, VERR_INVALID_POINTER);
294 /* pcbWritten is optional. */
295
296 PDRVAUDIOVIDEOREC pThis = PDMIHOSTAUDIO_2_DRVAUDIOVIDEOREC(pInterface);
297 PAVRECSTREAMOUT pStreamOut = (PAVRECSTREAMOUT)pStream;
298
299 uint32_t cLive = AudioMixBufLive(&pStream->MixBuf);
300
301 uint64_t now = PDMDrvHlpTMGetVirtualTime(pThis->pDrvIns);
302 uint64_t ticks = now - pStreamOut->old_ticks;
303 uint64_t ticks_per_second = PDMDrvHlpTMGetVirtualFreq(pThis->pDrvIns);
304
305 /* Minimize the rounding error: samples = int((ticks * freq) / ticks_per_second + 0.5). */
306 uint32_t cSamplesPlayed = (int)((2 * ticks * pStreamOut->Props.uHz + ticks_per_second) / ticks_per_second / 2);
307
308 /* Don't play more than available. */
309 if (cSamplesPlayed > cLive)
310 cSamplesPlayed = cLive;
311
312 /* Remember when samples were consumed. */
313 pStreamOut->old_ticks = now;
314
315 int cSamplesToSend = cSamplesPlayed;
316
317 LogFlowFunc(("uFreq=%RU32, cChan=%RU8, cBits=%RU8, fSigned=%RTbool, cSamplesToSend=%RU32\n",
318 pStreamOut->Props.uHz, pStreamOut->Props.cChannels,
319 pStreamOut->Props.cBits, pStreamOut->Props.fSigned, cSamplesToSend));
320
321 uint32_t csRead = 0;
322
323 int rc;
324
325 /*
326 * Call the encoder with the data.
327 */
328#ifdef VBOX_WITH_LIBOPUS
329
330 /** @todo For now we ASSUME 25 FPS. */
331 uint16_t csFrameSize = /*pStreamOut->Props.uHz*/ 48000 / 25;
332 size_t cbFrameSize = AUDIOMIXBUF_S2B(&pStream->MixBuf, csFrameSize);
333
334 rc = AudioMixBufReadCirc(&pStream->MixBuf, (uint8_t *)&pStreamOut->pvFrameBuf[pStreamOut->offFrameBufWrite],
335 pStreamOut->cbFrameBufSize - pStreamOut->offFrameBufWrite, &csRead);
336 if (RT_SUCCESS(rc))
337 {
338 const uint32_t cbRead = AUDIOMIXBUF_S2B(&pStream->MixBuf, csRead);
339
340 pStreamOut->offFrameBufWrite =
341 (pStreamOut->offFrameBufWrite + cbRead) % pStreamOut->cbFrameBufSize;
342 Assert(pStreamOut->offFrameBufWrite <= pStreamOut->cbFrameBufSize);
343 pStreamOut->cbFrameBufUsed += cbRead;
344 Assert(pStreamOut->cbFrameBufUsed <= pStreamOut->cbFrameBufSize);
345
346 if (pStreamOut->cbFrameBufUsed >= cbFrameSize)
347 {
348 /* Opus always encodes PER FRAME, that is, 2.5, 5, 10, 20, 40 or 60 ms of audio data. */
349 uint8_t abDst[_4K];
350 size_t cbDst = sizeof(abDst);
351
352 /* Call the encoder to encode our input samples. */
353 opus_int32 cbWritten = opus_encode(pStreamOut->Codec.Opus.pEnc,
354 (opus_int16 *)&pStreamOut->pvFrameBuf[pStreamOut->offFrameBufRead],
355 csFrameSize, abDst, cbDst);
356 if (cbWritten > 0)
357 {
358 pStreamOut->offFrameBufRead = (pStreamOut->offFrameBufRead + cbWritten) % pStreamOut->cbFrameBufSize;
359 Assert(pStreamOut->cbFrameBufUsed >= cbFrameSize);
360 pStreamOut->cbFrameBufUsed -= cbFrameSize;
361
362 /* Call the WebM writer to actually write the encoded audio data. */
363 WebMWriter::BlockData_Opus blockData = { abDst, cbDst };
364 rc = pThis->pEBML->WriteBlock(WebMWriter::BlockType_Audio, &blockData, sizeof(blockData));
365 AssertRC(rc);
366 }
367 else if (cbWritten < 0)
368 AssertMsgFailed(("Encoding failed: %s\n", opus_strerror(cbWritten)));
369 }
370 }
371#else
372 rc = VERR_NOT_SUPPORTED;
373#endif /* VBOX_WITH_LIBOPUS */
374
375 if (csRead)
376 AudioMixBufFinish(&pStream->MixBuf, csRead);
377
378 /*
379 * Always report back all samples acquired, regardless of whether the
380 * encoder actually did process those.
381 */
382 if (pcbWritten)
383 *pcbWritten = csRead;
384
385 LogFlowFunc(("csRead=%RU32, rc=%Rrc\n", csRead, rc));
386 return rc;
387}
388
389
390static int avRecDestroyStreamOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
391{
392 PDRVAUDIOVIDEOREC pThis = PDMIHOSTAUDIO_2_DRVAUDIOVIDEOREC(pInterface);
393 RT_NOREF(pThis);
394 PAVRECSTREAMOUT pStreamOut = (PAVRECSTREAMOUT)pStream;
395
396 if (pStreamOut->pvFrameBuf)
397 {
398 Assert(pStreamOut->cbFrameBufSize);
399 RTMemFree(pStreamOut->pvFrameBuf);
400 pStreamOut->pvFrameBuf = NULL;
401 }
402
403#ifdef VBOX_WITH_LIBOPUS
404 if (pStreamOut->Codec.Opus.pEnc)
405 {
406 opus_encoder_destroy(pStreamOut->Codec.Opus.pEnc);
407 pStreamOut->Codec.Opus.pEnc = NULL;
408 }
409#endif
410
411 return VINF_SUCCESS;
412}
413
414
415/**
416 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetConfig}
417 */
418static DECLCALLBACK(int) drvAudioVideoRecGetConfig(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pBackendCfg)
419{
420 NOREF(pInterface);
421 AssertPtrReturn(pBackendCfg, VERR_INVALID_POINTER);
422
423 pBackendCfg->cbStreamOut = sizeof(AVRECSTREAMOUT);
424 pBackendCfg->cbStreamIn = 0;
425 pBackendCfg->cMaxStreamsIn = 0;
426 pBackendCfg->cMaxStreamsOut = UINT32_MAX;
427
428 return VINF_SUCCESS;
429}
430
431
432/**
433 * @interface_method_impl{PDMIHOSTAUDIO,pfnShutdown}
434 */
435static DECLCALLBACK(void) drvAudioVideoRecShutdown(PPDMIHOSTAUDIO pInterface)
436{
437 LogFlowFuncEnter();
438
439 PDRVAUDIOVIDEOREC pThis = PDMIHOSTAUDIO_2_DRVAUDIOVIDEOREC(pInterface);
440
441 int rc;
442
443 switch (pThis->enmMode)
444 {
445 case AVRECMODE_AUDIO:
446 {
447 if (pThis->pEBML)
448 {
449 pThis->pEBML->Close();
450
451 delete pThis->pEBML;
452 pThis->pEBML = NULL;
453 }
454 break;
455 }
456
457 case AVRECMODE_AUDIO_VIDEO:
458 {
459 break;
460 }
461
462 default:
463 rc = VERR_NOT_SUPPORTED;
464 break;
465 }
466
467 LogFlowFuncLeaveRC(rc);
468}
469
470
471/**
472 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetStatus}
473 */
474static DECLCALLBACK(PDMAUDIOBACKENDSTS) drvAudioVideoRecGetStatus(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
475{
476 RT_NOREF(enmDir);
477 AssertPtrReturn(pInterface, PDMAUDIOBACKENDSTS_UNKNOWN);
478
479 return PDMAUDIOBACKENDSTS_RUNNING;
480}
481
482
483/**
484 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCreate}
485 */
486static DECLCALLBACK(int) drvAudioVideoRecStreamCreate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream,
487 PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
488{
489 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
490 AssertPtrReturn(pStream, VERR_INVALID_POINTER);
491 AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
492 AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER);
493
494 if (pCfgReq->enmDir == PDMAUDIODIR_OUT)
495 return avRecCreateStreamOut(pInterface, pStream, pCfgReq, pCfgAcq);
496
497 return VERR_NOT_SUPPORTED;
498}
499
500
501/**
502 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDestroy}
503 */
504static DECLCALLBACK(int) drvAudioVideoRecStreamDestroy(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
505{
506 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
507 AssertPtrReturn(pStream, VERR_INVALID_POINTER);
508
509 if (pStream->enmDir == PDMAUDIODIR_OUT)
510 return avRecDestroyStreamOut(pInterface, pStream);
511
512 return VINF_SUCCESS;
513}
514
515
516/**
517 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamControl}
518 */
519static DECLCALLBACK(int) drvAudioVideoRecStreamControl(PPDMIHOSTAUDIO pInterface,
520 PPDMAUDIOSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd)
521{
522 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
523 AssertPtrReturn(pStream, VERR_INVALID_POINTER);
524
525 Assert(pStream->enmCtx == PDMAUDIOSTREAMCTX_HOST);
526
527 if (pStream->enmDir == PDMAUDIODIR_OUT)
528 return avRecControlStreamOut(pInterface, pStream, enmStreamCmd);
529
530 return VINF_SUCCESS;
531}
532
533
534/**
535 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetStatus}
536 */
537static DECLCALLBACK(PDMAUDIOSTRMSTS) drvAudioVideoRecStreamGetStatus(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
538{
539 NOREF(pInterface);
540 NOREF(pStream);
541
542 return ( PDMAUDIOSTRMSTS_FLAG_INITIALIZED | PDMAUDIOSTRMSTS_FLAG_ENABLED
543 | PDMAUDIOSTRMSTS_FLAG_DATA_READABLE | PDMAUDIOSTRMSTS_FLAG_DATA_WRITABLE);
544}
545
546
547/**
548 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamIterate}
549 */
550static DECLCALLBACK(int) drvAudioVideoRecStreamIterate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
551{
552 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
553 AssertPtrReturn(pStream, VERR_INVALID_POINTER);
554
555 LogFlowFuncEnter();
556
557 /* Nothing to do here for video recording. */
558 return VINF_SUCCESS;
559}
560
561
562/**
563 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
564 */
565static DECLCALLBACK(void *) drvAudioVideoRecQueryInterface(PPDMIBASE pInterface, const char *pszIID)
566{
567 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
568 PDRVAUDIOVIDEOREC pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVIDEOREC);
569
570 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
571 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
572 return NULL;
573}
574
575
576AudioVideoRec::AudioVideoRec(Console *pConsole)
577 : mpDrv(NULL),
578 mParent(pConsole)
579{
580}
581
582
583AudioVideoRec::~AudioVideoRec(void)
584{
585 if (mpDrv)
586 {
587 mpDrv->pAudioVideoRec = NULL;
588 mpDrv = NULL;
589 }
590}
591
592
593/**
594 * Construct a audio video recording driver instance.
595 *
596 * @copydoc FNPDMDRVCONSTRUCT
597 */
598/* static */
599DECLCALLBACK(int) AudioVideoRec::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
600{
601 RT_NOREF(fFlags);
602
603 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
604 PDRVAUDIOVIDEOREC pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVIDEOREC);
605
606 AssertPtrReturn(pDrvIns, VERR_INVALID_POINTER);
607 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
608
609 LogRel(("Audio: Initializing video recording audio driver\n"));
610 LogFlowFunc(("fFlags=0x%x\n", fFlags));
611
612 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
613 ("Configuration error: Not possible to attach anything to this driver!\n"),
614 VERR_PDM_DRVINS_NO_ATTACH);
615
616 /*
617 * Init the static parts.
618 */
619 pThis->pDrvIns = pDrvIns;
620 /* IBase */
621 pDrvIns->IBase.pfnQueryInterface = drvAudioVideoRecQueryInterface;
622 /* IHostAudio */
623 PDMAUDIO_IHOSTAUDIO_CALLBACKS(drvAudioVideoRec);
624
625 /*
626 * Get the AudioVideoRec object pointer.
627 */
628 void *pvUser = NULL;
629 int rc = CFGMR3QueryPtr(pCfg, "Object", &pvUser); /** @todo r=andy Get rid of this hack and use IHostAudio::SetCallback. */
630 AssertMsgRCReturn(rc, ("Confguration error: No/bad \"Object\" value, rc=%Rrc\n", rc), rc);
631
632 pThis->pAudioVideoRec = (AudioVideoRec *)pvUser;
633 pThis->pAudioVideoRec->mpDrv = pThis;
634
635 /*
636 * Get the interface for the above driver (DrvAudio) to make mixer/conversion calls.
637 * Described in CFGM tree.
638 */
639 pThis->pDrvAudio = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIAUDIOCONNECTOR);
640 AssertMsgReturn(pThis->pDrvAudio, ("Configuration error: No upper interface specified!\n"), VERR_PDM_MISSING_INTERFACE_ABOVE);
641
642 return VINF_SUCCESS;
643}
644
645
646/**
647 * @interface_method_impl{PDMDRVREG,pfnDestruct}
648 */
649/* static */
650DECLCALLBACK(void) AudioVideoRec::drvDestruct(PPDMDRVINS pDrvIns)
651{
652 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
653 PDRVAUDIOVIDEOREC pThis = PDMINS_2_DATA(pDrvIns, PDRVAUDIOVIDEOREC);
654 LogFlowFuncEnter();
655
656 /*
657 * If the AudioVideoRec object is still alive, we must clear it's reference to
658 * us since we'll be invalid when we return from this method.
659 */
660 if (pThis->pAudioVideoRec)
661 {
662 pThis->pAudioVideoRec->mpDrv = NULL;
663 pThis->pAudioVideoRec = NULL;
664 }
665}
666
667
668/**
669 * Video recording audio driver registration record.
670 */
671const PDMDRVREG AudioVideoRec::DrvReg =
672{
673 PDM_DRVREG_VERSION,
674 /* szName */
675 "AudioVideoRec",
676 /* szRCMod */
677 "",
678 /* szR0Mod */
679 "",
680 /* pszDescription */
681 "Audio driver for video recording",
682 /* fFlags */
683 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
684 /* fClass. */
685 PDM_DRVREG_CLASS_AUDIO,
686 /* cMaxInstances */
687 ~0U,
688 /* cbInstance */
689 sizeof(DRVAUDIOVIDEOREC),
690 /* pfnConstruct */
691 AudioVideoRec::drvConstruct,
692 /* pfnDestruct */
693 AudioVideoRec::drvDestruct,
694 /* pfnRelocate */
695 NULL,
696 /* pfnIOCtl */
697 NULL,
698 /* pfnPowerOn */
699 NULL,
700 /* pfnReset */
701 NULL,
702 /* pfnSuspend */
703 NULL,
704 /* pfnResume */
705 NULL,
706 /* pfnAttach */
707 NULL,
708 /* pfnDetach */
709 NULL,
710 /* pfnPowerOff */
711 NULL,
712 /* pfnSoftReset */
713 NULL,
714 /* u32EndVersion */
715 PDM_DRVREG_VERSION
716};
717
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