VirtualBox

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

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

VideoRec: More infrastructure work on making the WebM writer as much as possible independent from the actual codec(s) being used. It also now has the ability to add tracks, making it more flexible in usage (e.g. if an additional audio track is required). Work in progress.

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