VirtualBox

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

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

Devices/Audio: actually consume samples in DrvHostNullAudio

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.1 KB
Line 
1/* $Id: DrvHostNullAudio.cpp 57827 2015-09-18 12:53:31Z 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 hw;
58 uint64_t u64TicksLast;
59 uint64_t csPlayBuffer;
60 uint8_t *pu8PlayBuffer;
61} NULLAUDIOSTREAMOUT;
62
63typedef struct NULLAUDIOSTREAMIN
64{
65 /** Note: Always must come first! */
66 PDMAUDIOHSTSTRMIN hw;
67} NULLAUDIOSTREAMIN;
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 NULLAUDIOSTREAMOUT *pNullStrmOut = (NULLAUDIOSTREAMOUT *)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 NULLAUDIOSTREAMOUT *pNullStrmOut = (NULLAUDIOSTREAMOUT *)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 /* Minimize the rounding error by adding 0.5: samples = int((u64TicksElapsed * samplesFreq) / u64TicksFreq + 0.5).
175 * If rounding is not taken into account then the playback rate will be consistently lower that expected.
176 */
177 uint64_t cSamplesPlayed = (2 * u64TicksElapsed * pHstStrmOut->Props.uHz + u64TicksFreq) / u64TicksFreq / 2;
178
179 /* Don't play more than available. */
180 if (cSamplesPlayed > csLive)
181 cSamplesPlayed = csLive;
182
183 cSamplesPlayed = RT_MIN(cSamplesPlayed, pNullStrmOut->csPlayBuffer);
184
185 uint32_t csRead = 0;
186 AudioMixBufReadCirc(&pHstStrmOut->MixBuf, pNullStrmOut->pu8PlayBuffer, cSamplesPlayed << pHstStrmOut->Props.cShift, &csRead);
187 AudioMixBufFinish(&pHstStrmOut->MixBuf, csRead);
188
189 if (pcSamplesPlayed)
190 *pcSamplesPlayed = csRead;
191
192 return VINF_SUCCESS;
193}
194
195static DECLCALLBACK(int) drvHostNullAudioCaptureIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
196 uint32_t *pcSamplesCaptured)
197{
198 /* Never capture anything. */
199 if (pcSamplesCaptured)
200 *pcSamplesCaptured = 0;
201
202 return VINF_SUCCESS;
203}
204
205static DECLCALLBACK(int) drvHostNullAudioControlIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn,
206 PDMAUDIOSTREAMCMD enmStreamCmd)
207{
208 NOREF(pInterface);
209 NOREF(pHstStrmIn);
210 NOREF(enmStreamCmd);
211
212 return VINF_SUCCESS;
213}
214
215static DECLCALLBACK(int) drvHostNullAudioControlOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut,
216 PDMAUDIOSTREAMCMD enmStreamCmd)
217{
218 NOREF(pInterface);
219 NOREF(pHstStrmOut);
220 NOREF(enmStreamCmd);
221
222 return VINF_SUCCESS;
223}
224
225static DECLCALLBACK(int) drvHostNullAudioFiniIn(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMIN pHstStrmIn)
226{
227 return VINF_SUCCESS;
228}
229
230static DECLCALLBACK(int) drvHostNullAudioFiniOut(PPDMIHOSTAUDIO pInterface, PPDMAUDIOHSTSTRMOUT pHstStrmOut)
231{
232 NULLAUDIOSTREAMOUT *pNullStrmOut = (NULLAUDIOSTREAMOUT *)pHstStrmOut;
233 RTMemFree(pNullStrmOut->pu8PlayBuffer);
234 return VINF_SUCCESS;
235}
236
237/**
238 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
239 */
240static DECLCALLBACK(void *) drvHostNullAudioQueryInterface(PPDMIBASE pInterface, const char *pszIID)
241{
242 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
243 PDRVHOSTNULLAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTNULLAUDIO);
244
245 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
246 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
247 return NULL;
248}
249
250static DECLCALLBACK(void) drvHostNullAudioShutdown(PPDMIHOSTAUDIO pInterface)
251{
252 NOREF(pInterface);
253}
254
255/**
256 * Constructs a Null audio driver instance.
257 *
258 * @copydoc FNPDMDRVCONSTRUCT
259 */
260static DECLCALLBACK(int) drvHostNullAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
261{
262 AssertPtrReturn(pDrvIns, VERR_INVALID_POINTER);
263 /* pCfg is optional. */
264
265 PDRVHOSTNULLAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTNULLAUDIO);
266 LogRel(("Audio: Initializing NULL driver\n"));
267
268 /*
269 * Init the static parts.
270 */
271 pThis->pDrvIns = pDrvIns;
272 /* IBase */
273 pDrvIns->IBase.pfnQueryInterface = drvHostNullAudioQueryInterface;
274 /* IHostAudio */
275 PDMAUDIO_IHOSTAUDIO_CALLBACKS(drvHostNullAudio);
276
277 return VINF_SUCCESS;
278}
279
280/**
281 * Char driver registration record.
282 */
283const PDMDRVREG g_DrvHostNullAudio =
284{
285 /* u32Version */
286 PDM_DRVREG_VERSION,
287 /* szName */
288 "NullAudio",
289 /* szRCMod */
290 "",
291 /* szR0Mod */
292 "",
293 /* pszDescription */
294 "NULL audio host driver",
295 /* fFlags */
296 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
297 /* fClass. */
298 PDM_DRVREG_CLASS_AUDIO,
299 /* cMaxInstances */
300 ~0U,
301 /* cbInstance */
302 sizeof(DRVHOSTNULLAUDIO),
303 /* pfnConstruct */
304 drvHostNullAudioConstruct,
305 /* pfnDestruct */
306 NULL,
307 /* pfnRelocate */
308 NULL,
309 /* pfnIOCtl */
310 NULL,
311 /* pfnPowerOn */
312 NULL,
313 /* pfnReset */
314 NULL,
315 /* pfnSuspend */
316 NULL,
317 /* pfnResume */
318 NULL,
319 /* pfnAttach */
320 NULL,
321 /* pfnDetach */
322 NULL,
323 /* pfnPowerOff */
324 NULL,
325 /* pfnSoftReset */
326 NULL,
327 /* u32EndVersion */
328 PDM_DRVREG_VERSION
329};
330
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