VirtualBox

source: vbox/trunk/src/VBox/Devices/Audio/DrvHostAudioDebug.cpp@ 89220

Last change on this file since 89220 was 89213, checked in by vboxsync, 4 years ago

Audio: Added an fImmediate indicator to the pfnStreamDestroy methods so the backend knows whether it's okay to continue draining the stream or if it must be destroyed without delay. The latter is typically only for shutdown and driver plumbing. This helps quite a bit for HDA/CoreAudio/knoppix. bugref:9890

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.1 KB
Line 
1/* $Id: DrvHostAudioDebug.cpp 89213 2021-05-21 10:00:12Z vboxsync $ */
2/** @file
3 * Host audio driver - Debug - For dumping and injecting audio data from/to the device emulation.
4 */
5
6/*
7 * Copyright (C) 2016-2021 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_HOST_AUDIO
23#include <VBox/log.h>
24#include <VBox/vmm/pdmaudioifs.h>
25#include <VBox/vmm/pdmaudioinline.h>
26
27#include <iprt/uuid.h> /* For PDMIBASE_2_PDMDRV. */
28
29#include "AudioHlp.h"
30#include "AudioTest.h"
31#include "VBoxDD.h"
32
33
34/*********************************************************************************************************************************
35* Structures and Typedefs *
36*********************************************************************************************************************************/
37/**
38 * Debug host audio stream.
39 */
40typedef struct DEBUGAUDIOSTREAM
41{
42 /** Common part. */
43 PDMAUDIOBACKENDSTREAM Core;
44 /** The stream's acquired configuration. */
45 PDMAUDIOSTREAMCFG Cfg;
46 /** Audio file to dump output to or read input from. */
47 PAUDIOHLPFILE pFile;
48 union
49 {
50 AUDIOTESTTONE In;
51 };
52} DEBUGAUDIOSTREAM;
53/** Pointer to a debug host audio stream. */
54typedef DEBUGAUDIOSTREAM *PDEBUGAUDIOSTREAM;
55
56/**
57 * Debug audio driver instance data.
58 * @implements PDMIAUDIOCONNECTOR
59 */
60typedef struct DRVHOSTDEBUGAUDIO
61{
62 /** Pointer to the driver instance structure. */
63 PPDMDRVINS pDrvIns;
64 /** Pointer to host audio interface. */
65 PDMIHOSTAUDIO IHostAudio;
66} DRVHOSTDEBUGAUDIO;
67/** Pointer to a debug host audio driver. */
68typedef DRVHOSTDEBUGAUDIO *PDRVHOSTDEBUGAUDIO;
69
70
71/**
72 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetConfig}
73 */
74static DECLCALLBACK(int) drvHostDebugAudioHA_GetConfig(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pBackendCfg)
75{
76 RT_NOREF(pInterface);
77 AssertPtrReturn(pBackendCfg, VERR_INVALID_POINTER);
78
79 /*
80 * Fill in the config structure.
81 */
82 RTStrCopy(pBackendCfg->szName, sizeof(pBackendCfg->szName), "DebugAudio");
83 pBackendCfg->cbStream = sizeof(DEBUGAUDIOSTREAM);
84 pBackendCfg->fFlags = 0;
85 pBackendCfg->cMaxStreamsOut = 1; /* Output; writing to a file. */
86 pBackendCfg->cMaxStreamsIn = 1; /* Input; generates a sine wave. */
87
88 return VINF_SUCCESS;
89}
90
91
92/**
93 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetStatus}
94 */
95static DECLCALLBACK(PDMAUDIOBACKENDSTS) drvHostDebugAudioHA_GetStatus(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
96{
97 RT_NOREF(pInterface, enmDir);
98 return PDMAUDIOBACKENDSTS_RUNNING;
99}
100
101
102/**
103 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCreate}
104 */
105static DECLCALLBACK(int) drvHostDebugAudioHA_StreamCreate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
106 PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
107{
108 PDRVHOSTDEBUGAUDIO pDrv = RT_FROM_MEMBER(pInterface, DRVHOSTDEBUGAUDIO, IHostAudio);
109 PDEBUGAUDIOSTREAM pStreamDbg = (PDEBUGAUDIOSTREAM)pStream;
110 AssertPtrReturn(pStreamDbg, VERR_INVALID_POINTER);
111 AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
112 AssertPtrReturn(pCfgAcq, VERR_INVALID_POINTER);
113
114 PDMAudioStrmCfgCopy(&pStreamDbg->Cfg, pCfgAcq);
115
116 if (pCfgReq->enmDir == PDMAUDIODIR_IN)
117 AudioTestToneInitRandom(&pStreamDbg->In, &pStreamDbg->Cfg.Props);
118
119 int rc = AudioHlpFileCreateAndOpenEx(&pStreamDbg->pFile, AUDIOHLPFILETYPE_WAV, NULL /*use temp dir*/,
120 pCfgReq->enmDir == PDMAUDIODIR_IN ? "DebugAudioIn" : "DebugAudioOut",
121 pDrv->pDrvIns->iInstance, AUDIOHLPFILENAME_FLAGS_NONE, AUDIOHLPFILE_FLAGS_NONE,
122 &pCfgReq->Props, RTFILE_O_WRITE | RTFILE_O_DENY_WRITE | RTFILE_O_CREATE_REPLACE);
123 if (RT_FAILURE(rc))
124 LogRel(("DebugAudio: Failed to creating debug file for %s stream '%s' in the temp directory: %Rrc\n",
125 pCfgReq->enmDir == PDMAUDIODIR_IN ? "input" : "output", pCfgReq->szName, rc));
126
127 return rc;
128}
129
130
131/**
132 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDestroy}
133 */
134static DECLCALLBACK(int) drvHostDebugAudioHA_StreamDestroy(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
135 bool fImmediate)
136{
137 RT_NOREF(pInterface, fImmediate);
138 PDEBUGAUDIOSTREAM pStreamDbg = (PDEBUGAUDIOSTREAM)pStream;
139 AssertPtrReturn(pStreamDbg, VERR_INVALID_POINTER);
140
141 if (pStreamDbg->pFile)
142 {
143 AudioHlpFileDestroy(pStreamDbg->pFile);
144 pStreamDbg->pFile = NULL;
145 }
146
147 return VINF_SUCCESS;
148}
149
150
151/**
152 * @ interface_method_impl{PDMIHOSTAUDIO,pfnStreamEnable}
153 */
154static DECLCALLBACK(int) drvHostDebugAudioHA_StreamControlStub(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
155{
156 RT_NOREF(pInterface, pStream);
157 return VINF_SUCCESS;
158}
159
160
161/**
162 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamControl}
163 */
164static DECLCALLBACK(int) drvHostDebugAudioHA_StreamControl(PPDMIHOSTAUDIO pInterface,
165 PPDMAUDIOBACKENDSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd)
166{
167 /** @todo r=bird: I'd like to get rid of this pfnStreamControl method,
168 * replacing it with individual StreamXxxx methods. That would save us
169 * potentally huge switches and more easily see which drivers implement
170 * which operations (grep for pfnStreamXxxx). */
171 switch (enmStreamCmd)
172 {
173 case PDMAUDIOSTREAMCMD_ENABLE:
174 return drvHostDebugAudioHA_StreamControlStub(pInterface, pStream);
175 case PDMAUDIOSTREAMCMD_DISABLE:
176 return drvHostDebugAudioHA_StreamControlStub(pInterface, pStream);
177 case PDMAUDIOSTREAMCMD_PAUSE:
178 return drvHostDebugAudioHA_StreamControlStub(pInterface, pStream);
179 case PDMAUDIOSTREAMCMD_RESUME:
180 return drvHostDebugAudioHA_StreamControlStub(pInterface, pStream);
181 case PDMAUDIOSTREAMCMD_DRAIN:
182 return drvHostDebugAudioHA_StreamControlStub(pInterface, pStream);
183
184 case PDMAUDIOSTREAMCMD_END:
185 case PDMAUDIOSTREAMCMD_32BIT_HACK:
186 case PDMAUDIOSTREAMCMD_INVALID:
187 /* no default*/
188 break;
189 }
190 return VERR_NOT_SUPPORTED;
191}
192
193
194/**
195 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetReadable}
196 */
197static DECLCALLBACK(uint32_t) drvHostDebugAudioHA_StreamGetReadable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
198{
199 RT_NOREF(pInterface);
200 PDEBUGAUDIOSTREAM pStreamDbg = (PDEBUGAUDIOSTREAM)pStream;
201
202 return PDMAudioPropsMilliToBytes(&pStreamDbg->Cfg.Props, 10 /*ms*/);
203}
204
205
206/**
207 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetWritable}
208 */
209static DECLCALLBACK(uint32_t) drvHostDebugAudioHA_StreamGetWritable(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
210{
211 RT_NOREF(pInterface, pStream);
212 return UINT32_MAX;
213}
214
215
216/**
217 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetPending}
218 */
219static DECLCALLBACK(uint32_t) drvHostDebugAudioHA_StreamGetPending(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)
220{
221 RT_NOREF(pInterface, pStream);
222 return 0;
223}
224
225
226/**
227 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetState}
228 */
229static DECLCALLBACK(PDMHOSTAUDIOSTREAMSTATE) drvHostDebugAudioHA_StreamGetState(PPDMIHOSTAUDIO pInterface,
230 PPDMAUDIOBACKENDSTREAM pStream)
231{
232 RT_NOREF(pInterface);
233 AssertPtrReturn(pStream, PDMHOSTAUDIOSTREAMSTATE_INVALID);
234 return PDMHOSTAUDIOSTREAMSTATE_OKAY;
235}
236
237
238/**
239 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamPlay}
240 */
241static DECLCALLBACK(int) drvHostDebugAudioHA_StreamPlay(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
242 const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)
243{
244 RT_NOREF(pInterface);
245 PDEBUGAUDIOSTREAM pStreamDbg = (PDEBUGAUDIOSTREAM)pStream;
246
247 int rc = AudioHlpFileWrite(pStreamDbg->pFile, pvBuf, cbBuf, 0 /* fFlags */);
248 if (RT_SUCCESS(rc))
249 *pcbWritten = cbBuf;
250 else
251 LogRelMax(32, ("DebugAudio: Writing output failed with %Rrc\n", rc));
252 return rc;
253}
254
255
256/**
257 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCapture}
258 */
259static DECLCALLBACK(int) drvHostDebugAudioHA_StreamCapture(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream,
260 void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
261{
262 RT_NOREF(pInterface);
263 PDEBUGAUDIOSTREAM pStreamDbg = (PDEBUGAUDIOSTREAM)pStream;
264/** @todo rate limit this? */
265
266 uint32_t cbWritten;
267 int rc = AudioTestToneGenerate(&pStreamDbg->In, pvBuf, cbBuf, &cbWritten);
268 if (RT_SUCCESS(rc))
269 {
270 /*
271 * Write it.
272 */
273 rc = AudioHlpFileWrite(pStreamDbg->pFile, pvBuf, cbWritten, 0 /* fFlags */);
274 if (RT_SUCCESS(rc))
275 *pcbRead = cbWritten;
276 }
277
278 if (RT_FAILURE(rc))
279 LogRelMax(32, ("DebugAudio: Writing input failed with %Rrc\n", rc));
280
281 return rc;
282}
283
284
285/**
286 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
287 */
288static DECLCALLBACK(void *) drvHostDebugAudioQueryInterface(PPDMIBASE pInterface, const char *pszIID)
289{
290 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
291 PDRVHOSTDEBUGAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTDEBUGAUDIO);
292
293 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
294 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
295 return NULL;
296}
297
298
299/**
300 * Constructs a Null audio driver instance.
301 *
302 * @copydoc FNPDMDRVCONSTRUCT
303 */
304static DECLCALLBACK(int) drvHostDebugAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
305{
306 RT_NOREF(pCfg, fFlags);
307 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
308 PDRVHOSTDEBUGAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTDEBUGAUDIO);
309 LogRel(("Audio: Initializing DEBUG driver\n"));
310
311 /*
312 * Init the static parts.
313 */
314 pThis->pDrvIns = pDrvIns;
315 /* IBase */
316 pDrvIns->IBase.pfnQueryInterface = drvHostDebugAudioQueryInterface;
317 /* IHostAudio */
318 pThis->IHostAudio.pfnGetConfig = drvHostDebugAudioHA_GetConfig;
319 pThis->IHostAudio.pfnGetDevices = NULL;
320 pThis->IHostAudio.pfnGetStatus = drvHostDebugAudioHA_GetStatus;
321 pThis->IHostAudio.pfnDoOnWorkerThread = NULL;
322 pThis->IHostAudio.pfnStreamConfigHint = NULL;
323 pThis->IHostAudio.pfnStreamCreate = drvHostDebugAudioHA_StreamCreate;
324 pThis->IHostAudio.pfnStreamInitAsync = NULL;
325 pThis->IHostAudio.pfnStreamDestroy = drvHostDebugAudioHA_StreamDestroy;
326 pThis->IHostAudio.pfnStreamNotifyDeviceChanged = NULL;
327 pThis->IHostAudio.pfnStreamControl = drvHostDebugAudioHA_StreamControl;
328 pThis->IHostAudio.pfnStreamGetReadable = drvHostDebugAudioHA_StreamGetReadable;
329 pThis->IHostAudio.pfnStreamGetWritable = drvHostDebugAudioHA_StreamGetWritable;
330 pThis->IHostAudio.pfnStreamGetPending = drvHostDebugAudioHA_StreamGetPending;
331 pThis->IHostAudio.pfnStreamGetState = drvHostDebugAudioHA_StreamGetState;
332 pThis->IHostAudio.pfnStreamPlay = drvHostDebugAudioHA_StreamPlay;
333 pThis->IHostAudio.pfnStreamCapture = drvHostDebugAudioHA_StreamCapture;
334
335#ifdef VBOX_AUDIO_DEBUG_DUMP_PCM_DATA
336 RTFileDelete(VBOX_AUDIO_DEBUG_DUMP_PCM_DATA_PATH "AudioDebugOutput.pcm");
337#endif
338
339 return VINF_SUCCESS;
340}
341
342/**
343 * Char driver registration record.
344 */
345const PDMDRVREG g_DrvHostDebugAudio =
346{
347 /* u32Version */
348 PDM_DRVREG_VERSION,
349 /* szName */
350 "DebugAudio",
351 /* szRCMod */
352 "",
353 /* szR0Mod */
354 "",
355 /* pszDescription */
356 "Debug audio host driver",
357 /* fFlags */
358 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
359 /* fClass. */
360 PDM_DRVREG_CLASS_AUDIO,
361 /* cMaxInstances */
362 ~0U,
363 /* cbInstance */
364 sizeof(DRVHOSTDEBUGAUDIO),
365 /* pfnConstruct */
366 drvHostDebugAudioConstruct,
367 /* pfnDestruct */
368 NULL,
369 /* pfnRelocate */
370 NULL,
371 /* pfnIOCtl */
372 NULL,
373 /* pfnPowerOn */
374 NULL,
375 /* pfnReset */
376 NULL,
377 /* pfnSuspend */
378 NULL,
379 /* pfnResume */
380 NULL,
381 /* pfnAttach */
382 NULL,
383 /* pfnDetach */
384 NULL,
385 /* pfnPowerOff */
386 NULL,
387 /* pfnSoftReset */
388 NULL,
389 /* u32EndVersion */
390 PDM_DRVREG_VERSION
391};
392
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