VirtualBox

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

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