VirtualBox

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

Last change on this file since 59470 was 58983, checked in by vboxsync, 9 years ago

Audio: Added support for dynamically enabling/disabling host audio backends, more code for audio callback support (still disabled).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.3 KB
Line 
1/* $Id: DrvHostNullAudio.cpp 58983 2015-12-04 14:15:30Z 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-2015 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#define LOG_GROUP LOG_GROUP_DRV_HOST_AUDIO
44#include <VBox/log.h>
45#include "DrvAudio.h"
46#include "AudioMixBuffer.h"
47
48#include "VBoxDD.h"
49
50#include <iprt/alloc.h>
51#include <iprt/uuid.h> /* For PDMIBASE_2_PDMDRV. */
52#include <VBox/vmm/pdmaudioifs.h>
53
54typedef struct NULLAUDIOSTREAMOUT
55{
56 /** Note: Always must come first! */
57 PDMAUDIOHSTSTRMOUT streamOut;
58 uint64_t u64TicksLast;
59 uint64_t csPlayBuffer;
60 uint8_t *pu8PlayBuffer;
61} NULLAUDIOSTREAMOUT, *PNULLAUDIOSTREAMOUT;
62
63typedef struct NULLAUDIOSTREAMIN
64{
65 /** Note: Always must come first! */
66 PDMAUDIOHSTSTRMIN streamIn;
67} NULLAUDIOSTREAMIN, *PNULLAUDIOSTREAMIN;
68
69/**
70 * NULL audio driver instance data.
71 * @implements PDMIAUDIOCONNECTOR
72 */
73typedef struct DRVHOSTNULLAUDIO
74{
75 /** Pointer to the driver instance structure. */
76 PPDMDRVINS pDrvIns;
77 /** Pointer to host audio interface. */
78 PDMIHOSTAUDIO IHostAudio;
79} DRVHOSTNULLAUDIO, *PDRVHOSTNULLAUDIO;
80
81/*******************************************PDM_AUDIO_DRIVER******************************/
82
83
84static DECLCALLBACK(int) drvHostNullAudioGetConf(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pCfg)
85{
86 NOREF(pInterface);
87 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
88
89 pCfg->cbStreamOut = sizeof(NULLAUDIOSTREAMOUT);
90 pCfg->cbStreamIn = sizeof(NULLAUDIOSTREAMIN);
91
92 pCfg->cMaxHstStrmsOut = 1; /* Output */
93 pCfg->cMaxHstStrmsIn = 2; /* Line input + microphone input. */
94
95 return VINF_SUCCESS;
96}
97
98static DECLCALLBACK(int) drvHostNullAudioInit(PPDMIHOSTAUDIO pInterface)
99{
100 NOREF(pInterface);
101
102 return VINF_SUCCESS;
103}
104
105static DECLCALLBACK(int) drvHostNullAudioInitIn(PPDMIHOSTAUDIO pInterface,
106 PPDMAUDIOHSTSTRMIN pHstStrmIn, PPDMAUDIOSTREAMCFG pCfg,
107 PDMAUDIORECSOURCE enmRecSource,
108 uint32_t *pcSamples)
109{
110 NOREF(pInterface);
111 NOREF(enmRecSource);
112
113 /* Just adopt the wanted stream configuration. */
114 int rc = DrvAudioStreamCfgToProps(pCfg, &pHstStrmIn->Props);
115 if (RT_SUCCESS(rc))
116 {
117 if (pcSamples)
118 *pcSamples = _1K;
119 }
120
121 return VINF_SUCCESS;
122}
123
124static DECLCALLBACK(int) drvHostNullAudioInitOut(PPDMIHOSTAUDIO pInterface,
125 PPDMAUDIOHSTSTRMOUT pHstStrmOut, PPDMAUDIOSTREAMCFG pCfg,
126 uint32_t *pcSamples)
127{
128 NOREF(pInterface);
129
130 /* Just adopt the wanted stream configuration. */
131 int rc = DrvAudioStreamCfgToProps(pCfg, &pHstStrmOut->Props);
132 if (RT_SUCCESS(rc))
133 {
134 PNULLAUDIOSTREAMOUT pNullStrmOut = (PNULLAUDIOSTREAMOUT)pHstStrmOut;
135 pNullStrmOut->u64TicksLast = 0;
136 pNullStrmOut->csPlayBuffer = _1K;
137 pNullStrmOut->pu8PlayBuffer = (uint8_t *)RTMemAlloc(_1K << pHstStrmOut->Props.cShift);
138 if (pNullStrmOut->pu8PlayBuffer)
139 {
140 if (pcSamples)
141 *pcSamples = pNullStrmOut->csPlayBuffer;
142 }
143 else
144 {
145 rc = VERR_NO_MEMORY;
146 }
147 }
148
149 return rc;
150}
151
152static DECLCALLBACK(bool) drvHostNullAudioIsEnabled(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
153{
154 NOREF(pInterface);
155 NOREF(enmDir);
156 return true; /* Always all enabled. */
157}
158
159static DECLCALLBACK(int) drvHostNullAudioPlayOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
160 uint32_t *pcSamplesPlayed)
161{
162 PDRVHOSTNULLAUDIO pDrv = RT_FROM_MEMBER(pInterface, DRVHOSTNULLAUDIO, IHostAudio);
163 PNULLAUDIOSTREAMOUT pNullStrmOut = (PNULLAUDIOSTREAMOUT)pHstStrmOut;
164
165 /* Consume as many samples as would be played at the current frequency since last call. */
166 uint32_t csLive = AudioMixBufAvail(&pHstStrmOut->MixBuf);
167 uint64_t u64TicksNow = PDMDrvHlpTMGetVirtualTime(pDrv->pDrvIns);
168 uint64_t u64TicksElapsed = u64TicksNow - pNullStrmOut->u64TicksLast;
169 uint64_t u64TicksFreq = PDMDrvHlpTMGetVirtualFreq(pDrv->pDrvIns);
170
171 /* Remember when samples were consumed. */
172 pNullStrmOut->u64TicksLast = u64TicksNow;
173
174 /*
175 * Minimize the rounding error by adding 0.5: samples = int((u64TicksElapsed * samplesFreq) / u64TicksFreq + 0.5).
176 * If rounding is not taken into account then the playback rate will be consistently lower that expected.
177 */
178 uint64_t cSamplesPlayed = (2 * u64TicksElapsed * pHstStrmOut->Props.uHz + u64TicksFreq) / u64TicksFreq / 2;
179
180 /* Don't play more than available. */
181 if (cSamplesPlayed > csLive)
182 cSamplesPlayed = csLive;
183
184 cSamplesPlayed = RT_MIN(cSamplesPlayed, pNullStrmOut->csPlayBuffer);
185
186 uint32_t csRead = 0;
187 AudioMixBufReadCirc(&pHstStrmOut->MixBuf, pNullStrmOut->pu8PlayBuffer,
188 AUDIOMIXBUF_S2B(&pHstStrmOut->MixBuf, cSamplesPlayed), &csRead);
189 AudioMixBufFinish(&pHstStrmOut->MixBuf, csRead);
190
191 if (pcSamplesPlayed)
192 *pcSamplesPlayed = csRead;
193
194 return VINF_SUCCESS;
195}
196
197static DECLCALLBACK(int) drvHostNullAudioCaptureIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
198 uint32_t *pcSamplesCaptured)
199{
200 /* Never capture anything. */
201 if (pcSamplesCaptured)
202 *pcSamplesCaptured = 0;
203
204 return VINF_SUCCESS;
205}
206
207static DECLCALLBACK(int) drvHostNullAudioControlIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
208 PDMAUDIOSTREAMCMD enmStreamCmd)
209{
210 NOREF(pInterface);
211 NOREF(pHstStrmIn);
212 NOREF(enmStreamCmd);
213
214 return VINF_SUCCESS;
215}
216
217static DECLCALLBACK(int) drvHostNullAudioControlOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
218 PDMAUDIOSTREAMCMD enmStreamCmd)
219{
220 NOREF(pInterface);
221 NOREF(pHstStrmOut);
222 NOREF(enmStreamCmd);
223
224 return VINF_SUCCESS;
225}
226
227static DECLCALLBACK(int) drvHostNullAudioFiniIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn)
228{
229 return VINF_SUCCESS;
230}
231
232static DECLCALLBACK(int) drvHostNullAudioFiniOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut)
233{
234 PNULLAUDIOSTREAMOUT pNullStrmOut = (PNULLAUDIOSTREAMOUT)pHstStrmOut;
235 if ( pNullStrmOut
236 && pNullStrmOut->pu8PlayBuffer)
237 {
238 RTMemFree(pNullStrmOut->pu8PlayBuffer);
239 }
240 return VINF_SUCCESS;
241}
242
243/**
244 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
245 */
246static DECLCALLBACK(void *) drvHostNullAudioQueryInterface(PPDMIBASE pInterface, const char *pszIID)
247{
248 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
249 PDRVHOSTNULLAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTNULLAUDIO);
250
251 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
252 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
253 return NULL;
254}
255
256static DECLCALLBACK(void) drvHostNullAudioShutdown(PPDMIHOSTAUDIO pInterface)
257{
258 NOREF(pInterface);
259}
260
261/**
262 * Constructs a Null audio driver instance.
263 *
264 * @copydoc FNPDMDRVCONSTRUCT
265 */
266static DECLCALLBACK(int) drvHostNullAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
267{
268 AssertPtrReturn(pDrvIns, VERR_INVALID_POINTER);
269 /* pCfg is optional. */
270
271 PDRVHOSTNULLAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTNULLAUDIO);
272 LogRel(("Audio: Initializing NULL driver\n"));
273
274 /*
275 * Init the static parts.
276 */
277 pThis->pDrvIns = pDrvIns;
278 /* IBase */
279 pDrvIns->IBase.pfnQueryInterface = drvHostNullAudioQueryInterface;
280 /* IHostAudio */
281 PDMAUDIO_IHOSTAUDIO_CALLBACKS(drvHostNullAudio);
282
283 return VINF_SUCCESS;
284}
285
286/**
287 * Char driver registration record.
288 */
289const PDMDRVREG g_DrvHostNullAudio =
290{
291 /* u32Version */
292 PDM_DRVREG_VERSION,
293 /* szName */
294 "NullAudio",
295 /* szRCMod */
296 "",
297 /* szR0Mod */
298 "",
299 /* pszDescription */
300 "NULL audio host driver",
301 /* fFlags */
302 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
303 /* fClass. */
304 PDM_DRVREG_CLASS_AUDIO,
305 /* cMaxInstances */
306 ~0U,
307 /* cbInstance */
308 sizeof(DRVHOSTNULLAUDIO),
309 /* pfnConstruct */
310 drvHostNullAudioConstruct,
311 /* pfnDestruct */
312 NULL,
313 /* pfnRelocate */
314 NULL,
315 /* pfnIOCtl */
316 NULL,
317 /* pfnPowerOn */
318 NULL,
319 /* pfnReset */
320 NULL,
321 /* pfnSuspend */
322 NULL,
323 /* pfnResume */
324 NULL,
325 /* pfnAttach */
326 NULL,
327 /* pfnDetach */
328 NULL,
329 /* pfnPowerOff */
330 NULL,
331 /* pfnSoftReset */
332 NULL,
333 /* u32EndVersion */
334 PDM_DRVREG_VERSION
335};
336
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