VirtualBox

source: vbox/trunk/src/VBox/Devices/Audio/DrvHostDebugAudio.cpp@ 86009

Last change on this file since 86009 was 82968, checked in by vboxsync, 5 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.9 KB
Line 
1/* $Id: DrvHostDebugAudio.cpp 82968 2020-02-04 10:35:17Z vboxsync $ */
2/** @file
3 * Debug audio driver.
4 *
5 * Host backend for dumping and injecting audio data from/to the device emulation.
6 */
7
8/*
9 * Copyright (C) 2016-2020 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 */
19
20#include <iprt/alloc.h>
21#include <iprt/uuid.h> /* For PDMIBASE_2_PDMDRV. */
22
23#define LOG_GROUP LOG_GROUP_DRV_HOST_AUDIO
24#include <VBox/log.h>
25#include <VBox/vmm/pdmaudioifs.h>
26
27#include "DrvAudio.h"
28#include "VBoxDD.h"
29
30
31/**
32 * Structure for keeping a debug input/output stream.
33 */
34typedef struct DEBUGAUDIOSTREAM
35{
36 /** The stream's acquired configuration. */
37 PPDMAUDIOSTREAMCFG pCfg;
38 /** Audio file to dump output to or read input from. */
39 PPDMAUDIOFILE pFile;
40 union
41 {
42 struct
43 {
44 /** Timestamp of last captured samples. */
45 uint64_t tsLastCaptured;
46 } In;
47 };
48} DEBUGAUDIOSTREAM, *PDEBUGAUDIOSTREAM;
49
50/**
51 * Debug audio driver instance data.
52 * @implements PDMIAUDIOCONNECTOR
53 */
54typedef struct DRVHOSTDEBUGAUDIO
55{
56 /** Pointer to the driver instance structure. */
57 PPDMDRVINS pDrvIns;
58 /** Pointer to host audio interface. */
59 PDMIHOSTAUDIO IHostAudio;
60} DRVHOSTDEBUGAUDIO, *PDRVHOSTDEBUGAUDIO;
61
62/*******************************************PDM_AUDIO_DRIVER******************************/
63
64
65/**
66 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetConfig}
67 */
68static DECLCALLBACK(int) drvHostDebugAudioHA_GetConfig(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pBackendCfg)
69{
70 RT_NOREF(pInterface);
71 AssertPtrReturn(pBackendCfg, VERR_INVALID_POINTER);
72
73 RTStrPrintf2(pBackendCfg->szName, sizeof(pBackendCfg->szName), "DebugAudio");
74
75 pBackendCfg->cbStreamOut = sizeof(DEBUGAUDIOSTREAM);
76 pBackendCfg->cbStreamIn = sizeof(DEBUGAUDIOSTREAM);
77
78 pBackendCfg->cMaxStreamsOut = 1; /* Output; writing to a file. */
79 pBackendCfg->cMaxStreamsIn = 0; /** @todo Right now we don't support any input (capturing, injecting from a file). */
80
81 return VINF_SUCCESS;
82}
83
84
85/**
86 * @interface_method_impl{PDMIHOSTAUDIO,pfnInit}
87 */
88static DECLCALLBACK(int) drvHostDebugAudioHA_Init(PPDMIHOSTAUDIO pInterface)
89{
90 RT_NOREF(pInterface);
91
92 LogFlowFuncLeaveRC(VINF_SUCCESS);
93 return VINF_SUCCESS;
94}
95
96
97/**
98 * @interface_method_impl{PDMIHOSTAUDIO,pfnShutdown}
99 */
100static DECLCALLBACK(void) drvHostDebugAudioHA_Shutdown(PPDMIHOSTAUDIO pInterface)
101{
102 RT_NOREF(pInterface);
103}
104
105
106/**
107 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetStatus}
108 */
109static DECLCALLBACK(PDMAUDIOBACKENDSTS) drvHostDebugAudioHA_GetStatus(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
110{
111 RT_NOREF(enmDir);
112 AssertPtrReturn(pInterface, PDMAUDIOBACKENDSTS_UNKNOWN);
113
114 return PDMAUDIOBACKENDSTS_RUNNING;
115}
116
117
118static int debugCreateStreamIn(PDRVHOSTDEBUGAUDIO pDrv, PDEBUGAUDIOSTREAM pStreamDbg,
119 PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
120{
121 RT_NOREF(pDrv, pStreamDbg, pCfgReq, pCfgAcq);
122
123 return VINF_SUCCESS;
124}
125
126
127static int debugCreateStreamOut(PDRVHOSTDEBUGAUDIO pDrv, PDEBUGAUDIOSTREAM pStreamDbg,
128 PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
129{
130 RT_NOREF(pDrv, pCfgAcq);
131
132 char szTemp[RTPATH_MAX];
133 int rc = RTPathTemp(szTemp, sizeof(szTemp));
134 if (RT_SUCCESS(rc))
135 {
136 char szFile[RTPATH_MAX];
137 rc = DrvAudioHlpFileNameGet(szFile, RT_ELEMENTS(szFile), szTemp, "DebugAudioOut",
138 pDrv->pDrvIns->iInstance, PDMAUDIOFILETYPE_WAV, PDMAUDIOFILENAME_FLAGS_NONE);
139 if (RT_SUCCESS(rc))
140 {
141 rc = DrvAudioHlpFileCreate(PDMAUDIOFILETYPE_WAV, szFile, PDMAUDIOFILE_FLAGS_NONE, &pStreamDbg->pFile);
142 if (RT_SUCCESS(rc))
143 {
144 rc = DrvAudioHlpFileOpen(pStreamDbg->pFile, RTFILE_O_WRITE | RTFILE_O_DENY_WRITE | RTFILE_O_CREATE_REPLACE,
145 &pCfgReq->Props);
146 }
147
148 if (RT_FAILURE(rc))
149 LogRel(("DebugAudio: Creating output file '%s' failed with %Rrc\n", szFile, rc));
150 }
151 else
152 LogRel(("DebugAudio: Unable to build file name for temp dir '%s': %Rrc\n", szTemp, rc));
153 }
154 else
155 LogRel(("DebugAudio: Unable to retrieve temp dir: %Rrc\n", rc));
156
157 return rc;
158}
159
160
161/**
162 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCreate}
163 */
164static DECLCALLBACK(int) drvHostDebugAudioHA_StreamCreate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
165 PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
166{
167 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
168 AssertPtrReturn(pStream, VERR_INVALID_POINTER);
169 AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
170 AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER);
171
172 PDRVHOSTDEBUGAUDIO pDrv = RT_FROM_MEMBER(pInterface, DRVHOSTDEBUGAUDIO, IHostAudio);
173 PDEBUGAUDIOSTREAM pStreamDbg = (PDEBUGAUDIOSTREAM)pStream;
174
175 int rc;
176 if (pCfgReq->enmDir == PDMAUDIODIR_IN)
177 rc = debugCreateStreamIn( pDrv, pStreamDbg, pCfgReq, pCfgAcq);
178 else
179 rc = debugCreateStreamOut(pDrv, pStreamDbg, pCfgReq, pCfgAcq);
180
181 if (RT_SUCCESS(rc))
182 {
183 pStreamDbg->pCfg = DrvAudioHlpStreamCfgDup(pCfgAcq);
184 if (!pStreamDbg->pCfg)
185 rc = VERR_NO_MEMORY;
186 }
187
188 return rc;
189}
190
191
192/**
193 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamPlay}
194 */
195static DECLCALLBACK(int) drvHostDebugAudioHA_StreamPlay(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
196 const void *pvBuf, uint32_t uBufSize, uint32_t *puWritten)
197{
198 RT_NOREF(pInterface);
199 PDEBUGAUDIOSTREAM pStreamDbg = (PDEBUGAUDIOSTREAM)pStream;
200
201 int rc = DrvAudioHlpFileWrite(pStreamDbg->pFile, pvBuf, uBufSize, 0 /* fFlags */);
202 if (RT_FAILURE(rc))
203 {
204 LogRel(("DebugAudio: Writing output failed with %Rrc\n", rc));
205 return rc;
206 }
207
208 if (puWritten)
209 *puWritten = uBufSize;
210
211 return VINF_SUCCESS;
212}
213
214
215/**
216 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCapture}
217 */
218static DECLCALLBACK(int) drvHostDebugAudioHA_StreamCapture(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
219 void *pvBuf, uint32_t uBufSize, uint32_t *puRead)
220{
221 RT_NOREF(pInterface, pStream, pvBuf, uBufSize);
222
223 /* Never capture anything. */
224 if (puRead)
225 *puRead = 0;
226
227 return VINF_SUCCESS;
228}
229
230
231static int debugDestroyStreamIn(PDRVHOSTDEBUGAUDIO pDrv, PDEBUGAUDIOSTREAM pStreamDbg)
232{
233 RT_NOREF(pDrv, pStreamDbg);
234 return VINF_SUCCESS;
235}
236
237
238static int debugDestroyStreamOut(PDRVHOSTDEBUGAUDIO pDrv, PDEBUGAUDIOSTREAM pStreamDbg)
239{
240 RT_NOREF(pDrv);
241
242 DrvAudioHlpFileDestroy(pStreamDbg->pFile);
243
244 return VINF_SUCCESS;
245}
246
247
248/**
249 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDestroy}
250 */
251static DECLCALLBACK(int) drvHostDebugAudioHA_StreamDestroy(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
252{
253 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
254
255 PDRVHOSTDEBUGAUDIO pDrv = RT_FROM_MEMBER(pInterface, DRVHOSTDEBUGAUDIO, IHostAudio);
256 PDEBUGAUDIOSTREAM pStreamDbg = (PDEBUGAUDIOSTREAM)pStream;
257
258 if (!pStreamDbg->pCfg) /* Not (yet) configured? Skip. */
259 return VINF_SUCCESS;
260
261 int rc;
262 if (pStreamDbg->pCfg->enmDir == PDMAUDIODIR_IN)
263 rc = debugDestroyStreamIn (pDrv, pStreamDbg);
264 else
265 rc = debugDestroyStreamOut(pDrv, pStreamDbg);
266
267 if (RT_SUCCESS(rc))
268 {
269 DrvAudioHlpStreamCfgFree(pStreamDbg->pCfg);
270 pStreamDbg->pCfg = NULL;
271 }
272
273 return rc;
274}
275
276
277/**
278 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamControl}
279 */
280static DECLCALLBACK(int) drvHostDebugAudioHA_StreamControl(PPDMIHOSTAUDIO pInterface,
281 PPDMAUDIOBACKENDSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd)
282{
283 RT_NOREF(enmStreamCmd);
284 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
285 AssertPtrReturn(pStream, VERR_INVALID_POINTER);
286
287 return VINF_SUCCESS;
288}
289
290
291/**
292 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetReadable}
293 */
294static DECLCALLBACK(uint32_t) drvHostDebugAudioHA_StreamGetReadable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
295{
296 RT_NOREF(pInterface, pStream);
297
298 return 0; /* Never capture anything. */
299}
300
301
302/**
303 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetWritable}
304 */
305static DECLCALLBACK(uint32_t) drvHostDebugAudioHA_StreamGetWritable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
306{
307 RT_NOREF(pInterface, pStream);
308
309 return UINT32_MAX;
310}
311
312
313/**
314 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetWritable}
315 */
316static DECLCALLBACK(PDMAUDIOSTREAMSTS) drvHostDebugAudioHA_StreamGetStatus(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
317{
318 RT_NOREF(pInterface, pStream);
319
320 return PDMAUDIOSTREAMSTS_FLAGS_INITIALIZED | PDMAUDIOSTREAMSTS_FLAGS_ENABLED;
321}
322
323
324/**
325 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamIterate}
326 */
327static DECLCALLBACK(int) drvHostDebugAudioHA_StreamIterate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
328{
329 RT_NOREF(pInterface, pStream);
330 return VINF_SUCCESS;
331}
332
333
334/**
335 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
336 */
337static DECLCALLBACK(void *) drvHostDebugAudioQueryInterface(PPDMIBASE pInterface, const char *pszIID)
338{
339 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
340 PDRVHOSTDEBUGAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTDEBUGAUDIO);
341
342 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
343 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
344 return NULL;
345}
346
347
348/**
349 * Constructs a Null audio driver instance.
350 *
351 * @copydoc FNPDMDRVCONSTRUCT
352 */
353static DECLCALLBACK(int) drvHostDebugAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
354{
355 RT_NOREF(pCfg, fFlags);
356 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
357 PDRVHOSTDEBUGAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTDEBUGAUDIO);
358 LogRel(("Audio: Initializing DEBUG driver\n"));
359
360 /*
361 * Init the static parts.
362 */
363 pThis->pDrvIns = pDrvIns;
364 /* IBase */
365 pDrvIns->IBase.pfnQueryInterface = drvHostDebugAudioQueryInterface;
366 /* IHostAudio */
367 pThis->IHostAudio.pfnInit = drvHostDebugAudioHA_Init;
368 pThis->IHostAudio.pfnShutdown = drvHostDebugAudioHA_Shutdown;
369 pThis->IHostAudio.pfnGetConfig = drvHostDebugAudioHA_GetConfig;
370 pThis->IHostAudio.pfnGetStatus = drvHostDebugAudioHA_GetStatus;
371 pThis->IHostAudio.pfnStreamCreate = drvHostDebugAudioHA_StreamCreate;
372 pThis->IHostAudio.pfnStreamDestroy = drvHostDebugAudioHA_StreamDestroy;
373 pThis->IHostAudio.pfnStreamControl = drvHostDebugAudioHA_StreamControl;
374 pThis->IHostAudio.pfnStreamGetReadable = drvHostDebugAudioHA_StreamGetReadable;
375 pThis->IHostAudio.pfnStreamGetWritable = drvHostDebugAudioHA_StreamGetWritable;
376 pThis->IHostAudio.pfnStreamGetStatus = drvHostDebugAudioHA_StreamGetStatus;
377 pThis->IHostAudio.pfnStreamIterate = drvHostDebugAudioHA_StreamIterate;
378 pThis->IHostAudio.pfnStreamPlay = drvHostDebugAudioHA_StreamPlay;
379 pThis->IHostAudio.pfnStreamCapture = drvHostDebugAudioHA_StreamCapture;
380 pThis->IHostAudio.pfnSetCallback = NULL;
381 pThis->IHostAudio.pfnGetDevices = NULL;
382 pThis->IHostAudio.pfnStreamGetPending = NULL;
383 pThis->IHostAudio.pfnStreamPlayBegin = NULL;
384 pThis->IHostAudio.pfnStreamPlayEnd = NULL;
385 pThis->IHostAudio.pfnStreamCaptureBegin = NULL;
386 pThis->IHostAudio.pfnStreamCaptureEnd = NULL;
387
388#ifdef VBOX_AUDIO_DEBUG_DUMP_PCM_DATA
389 RTFileDelete(VBOX_AUDIO_DEBUG_DUMP_PCM_DATA_PATH "AudioDebugOutput.pcm");
390#endif
391
392 return VINF_SUCCESS;
393}
394
395/**
396 * Char driver registration record.
397 */
398const PDMDRVREG g_DrvHostDebugAudio =
399{
400 /* u32Version */
401 PDM_DRVREG_VERSION,
402 /* szName */
403 "DebugAudio",
404 /* szRCMod */
405 "",
406 /* szR0Mod */
407 "",
408 /* pszDescription */
409 "Debug audio host driver",
410 /* fFlags */
411 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
412 /* fClass. */
413 PDM_DRVREG_CLASS_AUDIO,
414 /* cMaxInstances */
415 ~0U,
416 /* cbInstance */
417 sizeof(DRVHOSTDEBUGAUDIO),
418 /* pfnConstruct */
419 drvHostDebugAudioConstruct,
420 /* pfnDestruct */
421 NULL,
422 /* pfnRelocate */
423 NULL,
424 /* pfnIOCtl */
425 NULL,
426 /* pfnPowerOn */
427 NULL,
428 /* pfnReset */
429 NULL,
430 /* pfnSuspend */
431 NULL,
432 /* pfnResume */
433 NULL,
434 /* pfnAttach */
435 NULL,
436 /* pfnDetach */
437 NULL,
438 /* pfnPowerOff */
439 NULL,
440 /* pfnSoftReset */
441 NULL,
442 /* u32EndVersion */
443 PDM_DRVREG_VERSION
444};
445
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