VirtualBox

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

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

Audio: Decoupled backend sinks and sources from the maximum of concurrent streams a backend can handle. Also, added some more enumeration code to the ALSA, PulseAudio and OSS backends, which later also can be used for configuration change callbacks. Some function renaming.

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