VirtualBox

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

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

DrvHostNullAudio.cpp: Cleanup.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.2 KB
Line 
1/* $Id: DrvHostNullAudio.cpp 58372 2015-10-22 10:48:08Z 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 = drvAudioHstOutSamplesLive(pHstStrmOut);
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, cSamplesPlayed << pHstStrmOut->Props.cShift, &csRead);
188 AudioMixBufFinish(&pHstStrmOut->MixBuf, csRead);
189
190 if (pcSamplesPlayed)
191 *pcSamplesPlayed = csRead;
192
193 return VINF_SUCCESS;
194}
195
196static DECLCALLBACK(int) drvHostNullAudioCaptureIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
197 uint32_t *pcSamplesCaptured)
198{
199 /* Never capture anything. */
200 if (pcSamplesCaptured)
201 *pcSamplesCaptured = 0;
202
203 return VINF_SUCCESS;
204}
205
206static DECLCALLBACK(int) drvHostNullAudioControlIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
207 PDMAUDIOSTREAMCMD enmStreamCmd)
208{
209 NOREF(pInterface);
210 NOREF(pHstStrmIn);
211 NOREF(enmStreamCmd);
212
213 return VINF_SUCCESS;
214}
215
216static DECLCALLBACK(int) drvHostNullAudioControlOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
217 PDMAUDIOSTREAMCMD enmStreamCmd)
218{
219 NOREF(pInterface);
220 NOREF(pHstStrmOut);
221 NOREF(enmStreamCmd);
222
223 return VINF_SUCCESS;
224}
225
226static DECLCALLBACK(int) drvHostNullAudioFiniIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn)
227{
228 return VINF_SUCCESS;
229}
230
231static DECLCALLBACK(int) drvHostNullAudioFiniOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut)
232{
233 PNULLAUDIOSTREAMOUT pNullStrmOut = (PNULLAUDIOSTREAMOUT)pHstStrmOut;
234 if ( pNullStrmOut
235 && pNullStrmOut->pu8PlayBuffer)
236 {
237 RTMemFree(pNullStrmOut->pu8PlayBuffer);
238 }
239 return VINF_SUCCESS;
240}
241
242/**
243 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
244 */
245static DECLCALLBACK(void *) drvHostNullAudioQueryInterface(PPDMIBASE pInterface, const char *pszIID)
246{
247 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
248 PDRVHOSTNULLAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTNULLAUDIO);
249
250 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
251 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
252 return NULL;
253}
254
255static DECLCALLBACK(void) drvHostNullAudioShutdown(PPDMIHOSTAUDIO pInterface)
256{
257 NOREF(pInterface);
258}
259
260/**
261 * Constructs a Null audio driver instance.
262 *
263 * @copydoc FNPDMDRVCONSTRUCT
264 */
265static DECLCALLBACK(int) drvHostNullAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
266{
267 AssertPtrReturn(pDrvIns, VERR_INVALID_POINTER);
268 /* pCfg is optional. */
269
270 PDRVHOSTNULLAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTNULLAUDIO);
271 LogRel(("Audio: Initializing NULL driver\n"));
272
273 /*
274 * Init the static parts.
275 */
276 pThis->pDrvIns = pDrvIns;
277 /* IBase */
278 pDrvIns->IBase.pfnQueryInterface = drvHostNullAudioQueryInterface;
279 /* IHostAudio */
280 PDMAUDIO_IHOSTAUDIO_CALLBACKS(drvHostNullAudio);
281
282 return VINF_SUCCESS;
283}
284
285/**
286 * Char driver registration record.
287 */
288const PDMDRVREG g_DrvHostNullAudio =
289{
290 /* u32Version */
291 PDM_DRVREG_VERSION,
292 /* szName */
293 "NullAudio",
294 /* szRCMod */
295 "",
296 /* szR0Mod */
297 "",
298 /* pszDescription */
299 "NULL audio host driver",
300 /* fFlags */
301 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
302 /* fClass. */
303 PDM_DRVREG_CLASS_AUDIO,
304 /* cMaxInstances */
305 ~0U,
306 /* cbInstance */
307 sizeof(DRVHOSTNULLAUDIO),
308 /* pfnConstruct */
309 drvHostNullAudioConstruct,
310 /* pfnDestruct */
311 NULL,
312 /* pfnRelocate */
313 NULL,
314 /* pfnIOCtl */
315 NULL,
316 /* pfnPowerOn */
317 NULL,
318 /* pfnReset */
319 NULL,
320 /* pfnSuspend */
321 NULL,
322 /* pfnResume */
323 NULL,
324 /* pfnAttach */
325 NULL,
326 /* pfnDetach */
327 NULL,
328 /* pfnPowerOff */
329 NULL,
330 /* pfnSoftReset */
331 NULL,
332 /* u32EndVersion */
333 PDM_DRVREG_VERSION
334};
335
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