VirtualBox

source: vbox/trunk/src/VBox/Devices/Audio/DrvHostValidationKit.cpp@ 73596

Last change on this file since 73596 was 73596, checked in by vboxsync, 6 years ago

Audio/DrvHostValidationKit: Build fix.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.0 KB
Line 
1/* $Id: DrvHostValidationKit.cpp 73596 2018-08-09 17:27:04Z vboxsync $ */
2/** @file
3 * ValidationKit audio driver - host backend for dumping and injecting audio data
4 * from/to the device emulation.
5 */
6
7/*
8 * Copyright (C) 2016-2018 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19#include <iprt/alloc.h>
20#include <iprt/uuid.h> /* For PDMIBASE_2_PDMDRV. */
21
22#define LOG_GROUP LOG_GROUP_DRV_HOST_AUDIO
23#include <VBox/log.h>
24#include <VBox/vmm/pdmaudioifs.h>
25
26#include "DrvAudio.h"
27#include "VBoxDD.h"
28
29
30/**
31 * Structure for keeping a VAKIT input/output stream.
32 */
33typedef struct VAKITAUDIOSTREAM
34{
35 /** The stream's acquired configuration. */
36 PPDMAUDIOSTREAMCFG pCfg;
37 /** Audio file to dump output to or read input from. */
38 PPDMAUDIOFILE pFile;
39 /** Text file to store timing of audio buffers submittions**/
40 RTFILE hFileTiming;
41 /** Timestamp of the first play or record request**/
42 uint64_t tsStarted;
43 /** Total number of samples played or recorded so far**/
44 uint32_t uSamplesSinceStarted;
45 union
46 {
47 struct
48 {
49 /** Timestamp of last captured samples. */
50 uint64_t tsLastCaptured;
51 } In;
52 struct
53 {
54 /** Timestamp of last played samples. */
55 uint64_t tsLastPlayed;
56 uint8_t *pu8PlayBuffer;
57 uint32_t cbPlayBuffer;
58 } Out;
59 };
60} VAKITAUDIOSTREAM, *PVAKITAUDIOSTREAM;
61
62/**
63 * VAKIT audio driver instance data.
64 * @implements PDMIAUDIOCONNECTOR
65 */
66typedef struct DRVHOSTVAKITAUDIO
67{
68 /** Pointer to the driver instance structure. */
69 PPDMDRVINS pDrvIns;
70 /** Pointer to host audio interface. */
71 PDMIHOSTAUDIO IHostAudio;
72} DRVHOSTVAKITAUDIO, *PDRVHOSTVAKITAUDIO;
73
74/*******************************************PDM_AUDIO_DRIVER******************************/
75
76
77/**
78 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetConfig}
79 */
80static DECLCALLBACK(int) drvHostVaKitAudioGetConfig(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pBackendCfg)
81{
82 RT_NOREF(pInterface);
83 AssertPtrReturn(pBackendCfg, VERR_INVALID_POINTER);
84
85 pBackendCfg->cbStreamOut = sizeof(VAKITAUDIOSTREAM);
86 pBackendCfg->cbStreamIn = sizeof(VAKITAUDIOSTREAM);
87
88 pBackendCfg->cMaxStreamsOut = 1; /* Output */
89 pBackendCfg->cMaxStreamsIn = 2; /* Line input + microphone input. */
90
91 return VINF_SUCCESS;
92}
93
94
95/**
96 * @interface_method_impl{PDMIHOSTAUDIO,pfnInit}
97 */
98static DECLCALLBACK(int) drvHostVaKitAudioInit(PPDMIHOSTAUDIO pInterface)
99{
100 RT_NOREF(pInterface);
101
102 LogFlowFuncLeaveRC(VINF_SUCCESS);
103 return VINF_SUCCESS;
104}
105
106
107/**
108 * @interface_method_impl{PDMIHOSTAUDIO,pfnShutdown}
109 */
110static DECLCALLBACK(void) drvHostVaKitAudioShutdown(PPDMIHOSTAUDIO pInterface)
111{
112 RT_NOREF(pInterface);
113}
114
115
116/**
117 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetStatus}
118 */
119static DECLCALLBACK(PDMAUDIOBACKENDSTS) drvHostVaKitAudioGetStatus(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
120{
121 RT_NOREF(enmDir);
122 AssertPtrReturn(pInterface, PDMAUDIOBACKENDSTS_UNKNOWN);
123
124 return PDMAUDIOBACKENDSTS_RUNNING;
125}
126
127
128static int debugCreateStreamIn(PDRVHOSTVAKITAUDIO pDrv, PVAKITAUDIOSTREAM pStreamDbg,
129 PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
130{
131 RT_NOREF(pDrv, pStreamDbg, pCfgReq, pCfgAcq);
132
133 return VINF_SUCCESS;
134}
135
136
137static int debugCreateStreamOut(PDRVHOSTVAKITAUDIO pDrv, PVAKITAUDIOSTREAM pStreamDbg,
138 PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
139{
140 RT_NOREF(pDrv, pCfgAcq);
141
142 int rc = VINF_SUCCESS;
143
144 pStreamDbg->tsStarted = 0;
145 pStreamDbg->uSamplesSinceStarted = 0;
146 pStreamDbg->Out.tsLastPlayed = 0;
147 pStreamDbg->Out.cbPlayBuffer = DrvAudioHlpFramesToBytes(pCfgReq->Backend.cfBufferSize, &pCfgReq->Props);
148 pStreamDbg->Out.pu8PlayBuffer = (uint8_t *)RTMemAlloc(pStreamDbg->Out.cbPlayBuffer);
149 if (!pStreamDbg->Out.pu8PlayBuffer)
150 rc = VERR_NO_MEMORY;
151
152 if (RT_SUCCESS(rc))
153 {
154 char szTemp[RTPATH_MAX];
155 rc = RTPathTemp(szTemp, sizeof(szTemp));
156
157 RTPathAppend(szTemp, sizeof(szTemp), "VBoxTestTmp\\VBoxAudioValKit");
158
159 if (RT_SUCCESS(rc))
160 {
161 char szFile[RTPATH_MAX + 1];
162
163 rc = DrvAudioHlpFileNameGet(szFile, RT_ELEMENTS(szFile), szTemp, "VaKit",
164 0 /* Instance */, PDMAUDIOFILETYPE_WAV, PDMAUDIOFILENAME_FLAG_NONE);
165 if (RT_SUCCESS(rc))
166 {
167 rc = DrvAudioHlpFileCreate(PDMAUDIOFILETYPE_WAV, szFile, PDMAUDIOFILE_FLAG_NONE, &pStreamDbg->pFile);
168 if (RT_SUCCESS(rc))
169 rc = DrvAudioHlpFileOpen(pStreamDbg->pFile, PDMAUDIOFILE_DEFAULT_OPEN_FLAGS, &pCfgReq->Props);
170 }
171
172 if (RT_FAILURE(rc))
173 {
174 LogRel(("VaKitAudio: Creating output file '%s' failed with %Rrc\n", szFile, rc));
175 }
176 else
177 {
178 size_t cch;
179 char szTimingInfo[128];
180 cch = RTStrPrintf(szTimingInfo, sizeof(szTimingInfo), "# %dHz %dch %dbit\n",
181 pCfgReq->Props.uHz, pCfgReq->Props.cChannels, pCfgReq->Props.cBytes * 8);
182
183 RTFileWrite(pStreamDbg->hFileTiming, szTimingInfo, cch, NULL);
184 }
185 }
186 else
187 LogRel(("VaKitAudio: Unable to retrieve temp dir: %Rrc\n", rc));
188 }
189
190 return rc;
191}
192
193
194/**
195 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCreate}
196 */
197static DECLCALLBACK(int) drvHostVaKitAudioStreamCreate(PPDMIHOSTAUDIO pInterface,
198 PPDMAUDIOBACKENDSTREAM pStream,
199 PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
200{
201 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
202 AssertPtrReturn(pStream, VERR_INVALID_POINTER);
203 AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
204 AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER);
205
206 PDRVHOSTVAKITAUDIO pDrv = RT_FROM_MEMBER(pInterface, DRVHOSTVAKITAUDIO, IHostAudio);
207 PVAKITAUDIOSTREAM pStreamDbg = (PVAKITAUDIOSTREAM)pStream;
208
209 int rc;
210 if (pCfgReq->enmDir == PDMAUDIODIR_IN)
211 rc = debugCreateStreamIn( pDrv, pStreamDbg, pCfgReq, pCfgAcq);
212 else
213 rc = debugCreateStreamOut(pDrv, pStreamDbg, pCfgReq, pCfgAcq);
214
215 if (RT_SUCCESS(rc))
216 {
217 pStreamDbg->pCfg = DrvAudioHlpStreamCfgDup(pCfgAcq);
218 if (!pStreamDbg->pCfg)
219 rc = VERR_NO_MEMORY;
220 }
221
222 return rc;
223}
224
225
226/**
227 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamPlay}
228 */
229static DECLCALLBACK(int) drvHostVaKitAudioStreamPlay(PPDMIHOSTAUDIO pInterface,
230 PPDMAUDIOBACKENDSTREAM pStream, const void *pvBuf, uint32_t cxBuf,
231 uint32_t *pcxWritten)
232{
233 PDRVHOSTVAKITAUDIO pDrv = RT_FROM_MEMBER(pInterface, DRVHOSTVAKITAUDIO, IHostAudio);
234 PVAKITAUDIOSTREAM pStreamDbg = (PVAKITAUDIOSTREAM)pStream;
235 RT_NOREF(pDrv);
236
237 uint64_t tsSinceStart;
238 size_t cch;
239 char szTimingInfo[128];
240
241 if (pStreamDbg->tsStarted == 0)
242 {
243 pStreamDbg->tsStarted = RTTimeNanoTS();
244 tsSinceStart = 0;
245 }
246 else
247 {
248 tsSinceStart = RTTimeNanoTS() - pStreamDbg->tsStarted;
249 }
250
251 // Microseconds are used everythere below
252 uint32_t sBuf = cxBuf >> pStreamDbg->pCfg->Props.cShift;
253 cch = RTStrPrintf(szTimingInfo, sizeof(szTimingInfo), "%d %d %d %d\n",
254 (uint32_t)(tsSinceStart / 1000), // Host time elapsed since Guest submitted the first buffer for playback
255 (uint32_t)(pStreamDbg->uSamplesSinceStarted * 1.0E6 / pStreamDbg->pCfg->Props.uHz), // how long all the samples submitted previously were played
256 (uint32_t)(sBuf * 1.0E6 / pStreamDbg->pCfg->Props.uHz), // how long a new uSamplesReady samples should\will be played
257 sBuf);
258 RTFileWrite(pStreamDbg->hFileTiming, szTimingInfo, cch, NULL);
259 pStreamDbg->uSamplesSinceStarted += sBuf;
260
261 /* Remember when samples were consumed. */
262 // pStreamDbg->Out.tsLastPlayed = PDMDrvHlpTMGetVirtualTime(pDrv->pDrvIns);;
263
264 int rc2 = DrvAudioHlpFileWrite(pStreamDbg->pFile, pvBuf, cxBuf, 0 /* fFlags */);
265 if (RT_FAILURE(rc2))
266 LogRel(("DebugAudio: Writing output failed with %Rrc\n", rc2));
267
268 *pcxWritten = cxBuf;
269
270 return VINF_SUCCESS;
271}
272
273
274/**
275 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCapture}
276 */
277static DECLCALLBACK(int) drvHostVaKitAudioStreamCapture(PPDMIHOSTAUDIO pInterface,
278 PPDMAUDIOBACKENDSTREAM pStream, void *pvBuf, uint32_t cxBuf,
279 uint32_t *pcxRead)
280{
281 RT_NOREF(pInterface, pStream, pvBuf, cxBuf);
282
283 /* Never capture anything. */
284 if (pcxRead)
285 *pcxRead = 0;
286
287 return VINF_SUCCESS;
288}
289
290
291static int debugDestroyStreamIn(PDRVHOSTVAKITAUDIO pDrv, PVAKITAUDIOSTREAM pStreamDbg)
292{
293 RT_NOREF(pDrv, pStreamDbg);
294 return VINF_SUCCESS;
295}
296
297
298static int debugDestroyStreamOut(PDRVHOSTVAKITAUDIO pDrv, PVAKITAUDIOSTREAM pStreamDbg)
299{
300 RT_NOREF(pDrv);
301
302 if (pStreamDbg->Out.pu8PlayBuffer)
303 {
304 RTMemFree(pStreamDbg->Out.pu8PlayBuffer);
305 pStreamDbg->Out.pu8PlayBuffer = NULL;
306 }
307
308 if (pStreamDbg->pFile)
309 {
310 size_t cbDataSize = DrvAudioHlpFileGetDataSize(pStreamDbg->pFile);
311 if (cbDataSize)
312 LogRel(("VaKitAudio: Created output file '%s' (%zu bytes)\n", pStreamDbg->pFile->szName, cbDataSize));
313
314 DrvAudioHlpFileDestroy(pStreamDbg->pFile);
315 pStreamDbg->pFile = NULL;
316 }
317
318 return VINF_SUCCESS;
319}
320
321
322static DECLCALLBACK(int) drvHostVaKitAudioStreamDestroy(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
323{
324 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
325
326 PDRVHOSTVAKITAUDIO pDrv = RT_FROM_MEMBER(pInterface, DRVHOSTVAKITAUDIO, IHostAudio);
327 PVAKITAUDIOSTREAM pStreamDbg = (PVAKITAUDIOSTREAM)pStream;
328
329 if (!pStreamDbg->pCfg) /* Not (yet) configured? Skip. */
330 return VINF_SUCCESS;
331
332 int rc;
333 if (pStreamDbg->pCfg->enmDir == PDMAUDIODIR_IN)
334 rc = debugDestroyStreamIn (pDrv, pStreamDbg);
335 else
336 rc = debugDestroyStreamOut(pDrv, pStreamDbg);
337
338 if (RT_SUCCESS(rc))
339 {
340 DrvAudioHlpStreamCfgFree(pStreamDbg->pCfg);
341 pStreamDbg->pCfg = NULL;
342 }
343
344 return rc;
345}
346
347static DECLCALLBACK(int) drvHostVaKitAudioStreamControl(PPDMIHOSTAUDIO pInterface,
348 PPDMAUDIOBACKENDSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd)
349{
350 RT_NOREF(enmStreamCmd);
351 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
352 AssertPtrReturn(pStream, VERR_INVALID_POINTER);
353
354 return VINF_SUCCESS;
355}
356
357/**
358 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetReadable}
359 */
360static DECLCALLBACK(uint32_t) drvHostVaKitAudioStreamGetReadable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
361{
362 RT_NOREF(pInterface, pStream);
363
364 return UINT32_MAX;
365}
366
367
368/**
369 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetWritable}
370 */
371static DECLCALLBACK(uint32_t) drvHostVaKitAudioStreamGetWritable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
372{
373 RT_NOREF(pInterface, pStream);
374
375 return UINT32_MAX;
376}
377
378static DECLCALLBACK(PDMAUDIOSTREAMSTS) drvHostVaKitAudioStreamGetStatus(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
379{
380 RT_NOREF(pInterface, pStream);
381
382 return (PDMAUDIOSTREAMSTS_FLAG_INITIALIZED | PDMAUDIOSTREAMSTS_FLAG_ENABLED);
383}
384
385static DECLCALLBACK(int) drvHostVaKitAudioStreamIterate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
386{
387 RT_NOREF(pInterface, pStream);
388 return VINF_SUCCESS;
389}
390
391
392/**
393 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
394 */
395static DECLCALLBACK(void *) drvHostVaKitAudioQueryInterface(PPDMIBASE pInterface, const char *pszIID)
396{
397 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
398 PDRVHOSTVAKITAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTVAKITAUDIO);
399
400 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
401 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
402 return NULL;
403}
404
405
406/**
407 * Constructs a VaKit audio driver instance.
408 *
409 * @copydoc FNPDMDRVCONSTRUCT
410 */
411static DECLCALLBACK(int) drvHostVaKitAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
412{
413 RT_NOREF(pCfg, fFlags);
414 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
415 PDRVHOSTVAKITAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTVAKITAUDIO);
416 LogRel(("Audio: Initializing VAKIT driver\n"));
417
418 /*
419 * Init the static parts.
420 */
421 pThis->pDrvIns = pDrvIns;
422 /* IBase */
423 pDrvIns->IBase.pfnQueryInterface = drvHostVaKitAudioQueryInterface;
424 /* IHostAudio */
425 PDMAUDIO_IHOSTAUDIO_CALLBACKS(drvHostVaKitAudio);
426
427 return VINF_SUCCESS;
428}
429
430/**
431 * Char driver registration record.
432 */
433const PDMDRVREG g_DrvHostValidationKitAudio =
434{
435 /* u32Version */
436 PDM_DRVREG_VERSION,
437 /* szName */
438 "ValidationKitAudio",
439 /* szRCMod */
440 "",
441 /* szR0Mod */
442 "",
443 /* pszDescription */
444 "ValidationKitAudio audio host driver",
445 /* fFlags */
446 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
447 /* fClass. */
448 PDM_DRVREG_CLASS_AUDIO,
449 /* cMaxInstances */
450 ~0U,
451 /* cbInstance */
452 sizeof(DRVHOSTVAKITAUDIO),
453 /* pfnConstruct */
454 drvHostVaKitAudioConstruct,
455 /* pfnDestruct */
456 NULL,
457 /* pfnRelocate */
458 NULL,
459 /* pfnIOCtl */
460 NULL,
461 /* pfnPowerOn */
462 NULL,
463 /* pfnReset */
464 NULL,
465 /* pfnSuspend */
466 NULL,
467 /* pfnResume */
468 NULL,
469 /* pfnAttach */
470 NULL,
471 /* pfnDetach */
472 NULL,
473 /* pfnPowerOff */
474 NULL,
475 /* pfnSoftReset */
476 NULL,
477 /* u32EndVersion */
478 PDM_DRVREG_VERSION
479};
480
Note: See TracBrowser for help on using the repository browser.

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