VirtualBox

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

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

VideoRec: Update.

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