VirtualBox

source: vbox/trunk/src/VBox/Devices/Audio/DrvHostNullAudio.cpp@ 63360

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

Audio: Added more defines / documentation for the host interfaces to keep the maintenance effort to a minimum in the future, misc. cleanup.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.2 KB
Line 
1/* $Id: DrvHostNullAudio.cpp 63360 2016-08-12 13:58:38Z vboxsync $ */
2/** @file
3 * NULL audio driver -- also acts as a fallback if no
4 * other backend is available.
5 */
6
7/*
8 * Copyright (C) 2006-2016 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 * This code is based on: noaudio.c QEMU based code.
20 *
21 * QEMU Timer based audio emulation
22 *
23 * Copyright (c) 2004-2005 Vassili Karpov (malc)
24 *
25 * Permission is hereby granted, free of charge, to any person obtaining a copy
26 * of this software and associated documentation files (the "Software"), to deal
27 * in the Software without restriction, including without limitation the rights
28 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
29 * copies of the Software, and to permit persons to whom the Software is
30 * furnished to do so, subject to the following conditions:
31 *
32 * The above copyright notice and this permission notice shall be included in
33 * all copies or substantial portions of the Software.
34 *
35 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
36 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
37 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
38 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
39 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
40 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
41 * THE SOFTWARE.
42 */
43
44/*********************************************************************************************************************************
45* Header Files *
46*********************************************************************************************************************************/
47#include <iprt/mem.h>
48#include <iprt/uuid.h> /* For PDMIBASE_2_PDMDRV. */
49
50#define LOG_GROUP LOG_GROUP_DRV_HOST_AUDIO
51#include <VBox/log.h>
52#include <VBox/vmm/pdmaudioifs.h>
53
54#include "DrvAudio.h"
55#include "AudioMixBuffer.h"
56#include "VBoxDD.h"
57
58
59/*********************************************************************************************************************************
60* Structures and Typedefs *
61*********************************************************************************************************************************/
62typedef struct NULLAUDIOSTREAMOUT
63{
64 PDMAUDIOSTREAM Stream;
65 uint64_t u64TicksLast;
66 uint64_t cMaxSamplesInPlayBuffer;
67 uint8_t *pbPlayBuffer;
68} NULLAUDIOSTREAMOUT;
69typedef NULLAUDIOSTREAMOUT *PNULLAUDIOSTREAMOUT;
70
71typedef struct NULLAUDIOSTREAMIN
72{
73 /** @note Always must come first! */
74 PDMAUDIOSTREAM Stream;
75} NULLAUDIOSTREAMIN;
76typedef NULLAUDIOSTREAMIN *PNULLAUDIOSTREAMIN;
77
78/**
79 * NULL audio driver instance data.
80 * @implements PDMIAUDIOCONNECTOR
81 */
82typedef struct DRVHOSTNULLAUDIO
83{
84 /** Pointer to the driver instance structure. */
85 PPDMDRVINS pDrvIns;
86 /** Pointer to host audio interface. */
87 PDMIHOSTAUDIO IHostAudio;
88} DRVHOSTNULLAUDIO, *PDRVHOSTNULLAUDIO;
89
90
91
92/**
93 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetConfig}
94 */
95PDMAUDIO_IHOSTAUDIO_EMIT_GETCONFIG(drvHostNullAudio)
96{
97 NOREF(pInterface);
98 AssertPtrReturn(pBackendCfg, VERR_INVALID_POINTER);
99
100 pBackendCfg->cbStreamOut = sizeof(NULLAUDIOSTREAMOUT);
101 pBackendCfg->cbStreamIn = sizeof(NULLAUDIOSTREAMIN);
102
103 /* The NULL backend has exactly one input source and one output sink. */
104 pBackendCfg->cSources = 1;
105 pBackendCfg->cSinks = 1;
106
107 pBackendCfg->cMaxStreamsOut = 1; /* Output */
108 pBackendCfg->cMaxStreamsIn = 2; /* Line input + microphone input. */
109
110 return VINF_SUCCESS;
111}
112
113
114/**
115 * @interface_method_impl{PDMIHOSTAUDIO,pfnInit}
116 */
117PDMAUDIO_IHOSTAUDIO_EMIT_INIT(drvHostNullAudio)
118{
119 NOREF(pInterface);
120
121 LogFlowFuncLeaveRC(VINF_SUCCESS);
122 return VINF_SUCCESS;
123}
124
125
126/**
127 * @interface_method_impl{PDMIHOSTAUDIO,pfnShutdown}
128 */
129PDMAUDIO_IHOSTAUDIO_EMIT_SHUTDOWN(drvHostNullAudio)
130{
131 RT_NOREF(pInterface);
132}
133
134
135/**
136 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetStatus}
137 */
138PDMAUDIO_IHOSTAUDIO_EMIT_GETSTATUS(drvHostNullAudio)
139{
140 RT_NOREF(enmDir);
141 AssertPtrReturn(pInterface, PDMAUDIOBACKENDSTS_UNKNOWN);
142
143 return PDMAUDIOBACKENDSTS_RUNNING;
144}
145
146
147/**
148 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamPlay}
149 */
150PDMAUDIO_IHOSTAUDIO_EMIT_STREAMPLAY(drvHostNullAudio)
151{
152 PDRVHOSTNULLAUDIO pDrv = RT_FROM_MEMBER(pInterface, DRVHOSTNULLAUDIO, IHostAudio);
153 PNULLAUDIOSTREAMOUT pNullStream = RT_FROM_MEMBER(pStream, NULLAUDIOSTREAMOUT, Stream);
154
155 /* Consume as many samples as would be played at the current frequency since last call. */
156 uint32_t cLive = AudioMixBufLive(&pStream->MixBuf);
157
158 uint64_t u64TicksNow = PDMDrvHlpTMGetVirtualTime(pDrv->pDrvIns);
159 uint64_t u64TicksElapsed = u64TicksNow - pNullStream->u64TicksLast;
160 uint64_t u64TicksFreq = PDMDrvHlpTMGetVirtualFreq(pDrv->pDrvIns);
161
162 /* Remember when samples were consumed. */
163 pNullStream->u64TicksLast = u64TicksNow;
164
165 /*
166 * Minimize the rounding error by adding 0.5: samples = int((u64TicksElapsed * samplesFreq) / u64TicksFreq + 0.5).
167 * If rounding is not taken into account then the playback rate will be consistently lower that expected.
168 */
169 uint64_t cSamplesPlayed = (2 * u64TicksElapsed * pStream->Props.uHz + u64TicksFreq) / u64TicksFreq / 2;
170
171 /* Don't play more than available. */
172 if (cSamplesPlayed > cLive)
173 cSamplesPlayed = cLive;
174
175 cSamplesPlayed = RT_MIN(cSamplesPlayed, pNullStream->cMaxSamplesInPlayBuffer);
176
177 uint32_t cSamplesToRead = 0;
178 AudioMixBufReadCirc(&pStream->MixBuf, pNullStream->pbPlayBuffer,
179 AUDIOMIXBUF_S2B(&pStream->MixBuf, cSamplesPlayed), &cSamplesToRead);
180 AudioMixBufFinish(&pStream->MixBuf, cSamplesToRead);
181
182 if (pcbWritten)
183 *pcbWritten = cSamplesToRead;
184
185 return VINF_SUCCESS;
186}
187
188
189/**
190 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCapture}
191 */
192PDMAUDIO_IHOSTAUDIO_EMIT_STREAMCAPTURE(drvHostNullAudio)
193{
194 RT_NOREF(pInterface, pStream);
195
196 /* Never capture anything. */
197 if (pcbRead)
198 *pcbRead = 0;
199
200 return VINF_SUCCESS;
201}
202
203
204static int nullCreateStreamIn(PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
205{
206 /* Just adopt the wanted stream configuration. */
207 int rc = DrvAudioHlpStreamCfgToProps(pCfgReq, &pStream->Props);
208 if (RT_SUCCESS(rc))
209 {
210 if (pCfgAcq)
211 pCfgAcq->cSamples = _1K;
212 }
213
214 LogFlowFuncLeaveRC(rc);
215 return rc;
216}
217
218
219static int nullCreateStreamOut(PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
220{
221 /* Just adopt the wanted stream configuration. */
222 int rc = DrvAudioHlpStreamCfgToProps(pCfgReq, &pStream->Props);
223 if (RT_SUCCESS(rc))
224 {
225 PNULLAUDIOSTREAMOUT pNullStream = RT_FROM_MEMBER(pStream, NULLAUDIOSTREAMOUT, Stream);
226
227 pNullStream->u64TicksLast = 0;
228 pNullStream->cMaxSamplesInPlayBuffer = _1K;
229
230 pNullStream->pbPlayBuffer = (uint8_t *)RTMemAlloc(_1K << pStream->Props.cShift);
231 if (pNullStream->pbPlayBuffer)
232 {
233 if (pCfgAcq)
234 pCfgAcq->cSamples = pNullStream->cMaxSamplesInPlayBuffer;
235 }
236 else
237 rc = VERR_NO_MEMORY;
238 }
239
240 LogFlowFuncLeaveRC(rc);
241 return rc;
242}
243
244
245/**
246 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCreate}
247 */
248PDMAUDIO_IHOSTAUDIO_EMIT_STREAMCREATE(drvHostNullAudio)
249{
250 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
251 AssertPtrReturn(pStream, VERR_INVALID_POINTER);
252 AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
253
254 int rc;
255 if (pCfgReq->enmDir == PDMAUDIODIR_IN)
256 rc = nullCreateStreamIn( pStream, pCfgReq, pCfgAcq);
257 else
258 rc = nullCreateStreamOut(pStream, pCfgReq, pCfgAcq);
259
260 LogFlowFunc(("%s: rc=%Rrc\n", pStream->szName, rc));
261 return rc;
262}
263
264
265static int nullDestroyStreamIn(void)
266{
267 LogFlowFuncLeaveRC(VINF_SUCCESS);
268 return VINF_SUCCESS;
269}
270
271
272static int nullDestroyStreamOut(PPDMAUDIOSTREAM pStream)
273{
274 PNULLAUDIOSTREAMOUT pNullStream = RT_FROM_MEMBER(pStream, NULLAUDIOSTREAMOUT, Stream);
275 if ( pNullStream
276 && pNullStream->pbPlayBuffer)
277 {
278 RTMemFree(pNullStream->pbPlayBuffer);
279 pNullStream->pbPlayBuffer = NULL;
280 }
281
282 LogFlowFuncLeaveRC(VINF_SUCCESS);
283 return VINF_SUCCESS;
284}
285
286
287/**
288 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDestroy}
289 */
290PDMAUDIO_IHOSTAUDIO_EMIT_STREAMDESTROY(drvHostNullAudio)
291{
292 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
293 AssertPtrReturn(pStream, VERR_INVALID_POINTER);
294
295 int rc;
296 if (pStream->enmDir == PDMAUDIODIR_IN)
297 rc = nullDestroyStreamIn();
298 else
299 rc = nullDestroyStreamOut(pStream);
300
301 return rc;
302}
303
304
305/**
306 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamControl}
307 */
308PDMAUDIO_IHOSTAUDIO_EMIT_STREAMCONTROL(drvHostNullAudio)
309{
310 RT_NOREF(enmStreamCmd);
311 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
312 AssertPtrReturn(pStream, VERR_INVALID_POINTER);
313
314 Assert(pStream->enmCtx == PDMAUDIOSTREAMCTX_HOST);
315
316 return VINF_SUCCESS;
317}
318
319
320/**
321 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetStatus}
322 */
323PDMAUDIO_IHOSTAUDIO_EMIT_STREAMGETSTATUS(drvHostNullAudio)
324{
325 RT_NOREF(pInterface, pStream);
326 return PDMAUDIOSTRMSTS_FLAG_INITIALIZED | PDMAUDIOSTRMSTS_FLAG_ENABLED
327 | PDMAUDIOSTRMSTS_FLAG_DATA_READABLE | PDMAUDIOSTRMSTS_FLAG_DATA_WRITABLE;
328}
329
330
331/**
332 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamIterate}
333 */
334PDMAUDIO_IHOSTAUDIO_EMIT_STREAMITERATE(drvHostNullAudio)
335{
336 NOREF(pInterface);
337 NOREF(pStream);
338
339 return VINF_SUCCESS;
340}
341
342
343/**
344 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
345 */
346static DECLCALLBACK(void *) drvHostNullAudioQueryInterface(PPDMIBASE pInterface, const char *pszIID)
347{
348 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
349 PDRVHOSTNULLAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTNULLAUDIO);
350
351 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
352 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
353 return NULL;
354}
355
356
357/**
358 * Constructs a Null audio driver instance.
359 *
360 * @copydoc FNPDMDRVCONSTRUCT
361 */
362static DECLCALLBACK(int) drvHostNullAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
363{
364 RT_NOREF(pCfg, fFlags);
365 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
366 AssertPtrReturn(pDrvIns, VERR_INVALID_POINTER);
367 /* pCfg is optional. */
368
369 PDRVHOSTNULLAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTNULLAUDIO);
370 LogRel(("Audio: Initializing NULL driver\n"));
371
372 /*
373 * Init the static parts.
374 */
375 pThis->pDrvIns = pDrvIns;
376 /* IBase */
377 pDrvIns->IBase.pfnQueryInterface = drvHostNullAudioQueryInterface;
378 /* IHostAudio */
379 PDMAUDIO_IHOSTAUDIO_CALLBACKS(drvHostNullAudio);
380
381 return VINF_SUCCESS;
382}
383
384
385/**
386 * Char driver registration record.
387 */
388const PDMDRVREG g_DrvHostNullAudio =
389{
390 /* u32Version */
391 PDM_DRVREG_VERSION,
392 /* szName */
393 "NullAudio",
394 /* szRCMod */
395 "",
396 /* szR0Mod */
397 "",
398 /* pszDescription */
399 "NULL audio host driver",
400 /* fFlags */
401 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
402 /* fClass. */
403 PDM_DRVREG_CLASS_AUDIO,
404 /* cMaxInstances */
405 ~0U,
406 /* cbInstance */
407 sizeof(DRVHOSTNULLAUDIO),
408 /* pfnConstruct */
409 drvHostNullAudioConstruct,
410 /* pfnDestruct */
411 NULL,
412 /* pfnRelocate */
413 NULL,
414 /* pfnIOCtl */
415 NULL,
416 /* pfnPowerOn */
417 NULL,
418 /* pfnReset */
419 NULL,
420 /* pfnSuspend */
421 NULL,
422 /* pfnResume */
423 NULL,
424 /* pfnAttach */
425 NULL,
426 /* pfnDetach */
427 NULL,
428 /* pfnPowerOff */
429 NULL,
430 /* pfnSoftReset */
431 NULL,
432 /* u32EndVersion */
433 PDM_DRVREG_VERSION
434};
435
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