VirtualBox

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

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

build fix

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.8 KB
Line 
1/* $Id: DrvHostNullAudio.cpp 62970 2016-08-04 10:22:57Z 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 */
95static DECLCALLBACK(int) drvHostNullAudioGetConfig(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pCfg)
96{
97 NOREF(pInterface);
98 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
99
100 pCfg->cbStreamOut = sizeof(NULLAUDIOSTREAMOUT);
101 pCfg->cbStreamIn = sizeof(NULLAUDIOSTREAMIN);
102
103 /* The NULL backend has exactly one input source and one output sink. */
104 pCfg->cSources = 1;
105 pCfg->cSinks = 1;
106
107 pCfg->cMaxStreamsOut = 1; /* Output */
108 pCfg->cMaxStreamsIn = 2; /* Line input + microphone input. */
109
110 return VINF_SUCCESS;
111}
112
113
114/**
115 * @interface_method_impl{PDMIHOSTAUDIO,pfnInit}
116 */
117static DECLCALLBACK(int) drvHostNullAudioInit(PPDMIHOSTAUDIO pInterface)
118{
119 NOREF(pInterface);
120
121 LogFlowFuncLeaveRC(VINF_SUCCESS);
122 return VINF_SUCCESS;
123}
124
125
126/**
127 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamPlay}
128 */
129static DECLCALLBACK(int) drvHostNullAudioStreamPlay(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream, uint32_t *pcSamplesPlayed)
130{
131 PDRVHOSTNULLAUDIO pDrv = RT_FROM_MEMBER(pInterface, DRVHOSTNULLAUDIO, IHostAudio);
132 PNULLAUDIOSTREAMOUT pNullStream = RT_FROM_MEMBER(pStream, NULLAUDIOSTREAMOUT, Stream);
133
134 /* Consume as many samples as would be played at the current frequency since last call. */
135 uint32_t cLive = AudioMixBufLive(&pStream->MixBuf);
136
137 uint64_t u64TicksNow = PDMDrvHlpTMGetVirtualTime(pDrv->pDrvIns);
138 uint64_t u64TicksElapsed = u64TicksNow - pNullStream->u64TicksLast;
139 uint64_t u64TicksFreq = PDMDrvHlpTMGetVirtualFreq(pDrv->pDrvIns);
140
141 /* Remember when samples were consumed. */
142 pNullStream->u64TicksLast = u64TicksNow;
143
144 /*
145 * Minimize the rounding error by adding 0.5: samples = int((u64TicksElapsed * samplesFreq) / u64TicksFreq + 0.5).
146 * If rounding is not taken into account then the playback rate will be consistently lower that expected.
147 */
148 uint64_t cSamplesPlayed = (2 * u64TicksElapsed * pStream->Props.uHz + u64TicksFreq) / u64TicksFreq / 2;
149
150 /* Don't play more than available. */
151 if (cSamplesPlayed > cLive)
152 cSamplesPlayed = cLive;
153
154 cSamplesPlayed = RT_MIN(cSamplesPlayed, pNullStream->cMaxSamplesInPlayBuffer);
155
156 uint32_t cSamplesToRead = 0;
157 AudioMixBufReadCirc(&pStream->MixBuf, pNullStream->pbPlayBuffer,
158 AUDIOMIXBUF_S2B(&pStream->MixBuf, cSamplesPlayed), &cSamplesToRead);
159 AudioMixBufFinish(&pStream->MixBuf, cSamplesToRead);
160
161 if (pcSamplesPlayed)
162 *pcSamplesPlayed = cSamplesToRead;
163
164 return VINF_SUCCESS;
165}
166
167
168/**
169 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCapture}
170 */
171static DECLCALLBACK(int)
172drvHostNullAudioStreamCapture(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream, uint32_t *pcSamplesCaptured)
173{
174 RT_NOREF(pInterface, pStream);
175
176 /* Never capture anything. */
177 if (pcSamplesCaptured)
178 *pcSamplesCaptured = 0;
179
180 return VINF_SUCCESS;
181}
182
183
184/**
185 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetStatus}
186 */
187static DECLCALLBACK(PDMAUDIOBACKENDSTS) drvHostNullAudioGetStatus(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
188{
189 RT_NOREF(enmDir);
190 AssertPtrReturn(pInterface, PDMAUDIOBACKENDSTS_UNKNOWN);
191
192 return PDMAUDIOBACKENDSTS_RUNNING;
193}
194
195
196static int nullCreateStreamIn(PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfg, uint32_t *pcSamples)
197{
198 /* Just adopt the wanted stream configuration. */
199 int rc = DrvAudioHlpStreamCfgToProps(pCfg, &pStream->Props);
200 if (RT_SUCCESS(rc))
201 {
202 if (pcSamples)
203 *pcSamples = _1K;
204 }
205
206 LogFlowFuncLeaveRC(rc);
207 return rc;
208}
209
210
211static int nullCreateStreamOut(PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfg, uint32_t *pcSamples)
212{
213 /* Just adopt the wanted stream configuration. */
214 int rc = DrvAudioHlpStreamCfgToProps(pCfg, &pStream->Props);
215 if (RT_SUCCESS(rc))
216 {
217 PNULLAUDIOSTREAMOUT pNullStream = RT_FROM_MEMBER(pStream, NULLAUDIOSTREAMOUT, Stream);
218 pNullStream->u64TicksLast = 0;
219 pNullStream->cMaxSamplesInPlayBuffer = _1K;
220 pNullStream->pbPlayBuffer = (uint8_t *)RTMemAlloc(_1K << pStream->Props.cShift);
221 if (pNullStream->pbPlayBuffer)
222 {
223 if (pcSamples)
224 *pcSamples = pNullStream->cMaxSamplesInPlayBuffer;
225 }
226 else
227 rc = VERR_NO_MEMORY;
228 }
229
230 LogFlowFuncLeaveRC(rc);
231 return rc;
232}
233
234
235/**
236 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCreate}
237 */
238static DECLCALLBACK(int)
239drvHostNullAudioStreamCreate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfg, uint32_t *pcSamples)
240{
241 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
242 AssertPtrReturn(pStream, VERR_INVALID_POINTER);
243 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
244
245 int rc;
246 if (pCfg->enmDir == PDMAUDIODIR_IN)
247 rc = nullCreateStreamIn( pStream, pCfg, pcSamples);
248 else
249 rc = nullCreateStreamOut(pStream, pCfg, pcSamples);
250
251 LogFlowFunc(("%s: rc=%Rrc\n", pStream->szName, rc));
252 return rc;
253}
254
255
256static int nullDestroyStreamIn(void)
257{
258 LogFlowFuncLeaveRC(VINF_SUCCESS);
259 return VINF_SUCCESS;
260}
261
262
263static int nullDestroyStreamOut(PPDMAUDIOSTREAM pStream)
264{
265 PNULLAUDIOSTREAMOUT pNullStream = RT_FROM_MEMBER(pStream, NULLAUDIOSTREAMOUT, Stream);
266 if ( pNullStream
267 && pNullStream->pbPlayBuffer)
268 {
269 RTMemFree(pNullStream->pbPlayBuffer);
270 pNullStream->pbPlayBuffer = NULL;
271 }
272
273 LogFlowFuncLeaveRC(VINF_SUCCESS);
274 return VINF_SUCCESS;
275}
276
277
278/**
279 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDestroy}
280 */
281static DECLCALLBACK(int) drvHostNullAudioStreamDestroy(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
282{
283 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
284 AssertPtrReturn(pStream, VERR_INVALID_POINTER);
285
286 int rc;
287 if (pStream->enmDir == PDMAUDIODIR_IN)
288 rc = nullDestroyStreamIn();
289 else
290 rc = nullDestroyStreamOut(pStream);
291
292 return rc;
293}
294
295
296/**
297 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamControl}
298 */
299static DECLCALLBACK(int)
300drvHostNullAudioStreamControl(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd)
301{
302 RT_NOREF(enmStreamCmd);
303 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
304 AssertPtrReturn(pStream, VERR_INVALID_POINTER);
305
306 Assert(pStream->enmCtx == PDMAUDIOSTREAMCTX_HOST);
307
308 return VINF_SUCCESS;
309}
310
311
312/**
313 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetStatus}
314 */
315static DECLCALLBACK(PDMAUDIOSTRMSTS) drvHostNullAudioStreamGetStatus(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
316{
317 RT_NOREF(pInterface, pStream);
318 return PDMAUDIOSTRMSTS_FLAG_INITIALIZED | PDMAUDIOSTRMSTS_FLAG_ENABLED
319 | PDMAUDIOSTRMSTS_FLAG_DATA_READABLE | PDMAUDIOSTRMSTS_FLAG_DATA_WRITABLE;
320}
321
322
323/**
324 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamIterate}
325 */
326static DECLCALLBACK(int) drvHostNullAudioStreamIterate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
327{
328 NOREF(pInterface);
329 NOREF(pStream);
330
331 return VINF_SUCCESS;
332}
333
334
335/**
336 * @interface_method_impl{PDMIHOSTAUDIO,pfnShutdown}
337 */
338static DECLCALLBACK(void) drvHostNullAudioShutdown(PPDMIHOSTAUDIO pInterface)
339{
340 RT_NOREF(pInterface);
341}
342
343
344/**
345 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
346 */
347static DECLCALLBACK(void *) drvHostNullAudioQueryInterface(PPDMIBASE pInterface, const char *pszIID)
348{
349 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
350 PDRVHOSTNULLAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTNULLAUDIO);
351
352 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
353 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
354 return NULL;
355}
356
357
358/**
359 * Constructs a Null audio driver instance.
360 *
361 * @copydoc FNPDMDRVCONSTRUCT
362 */
363static DECLCALLBACK(int) drvHostNullAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
364{
365 RT_NOREF(pCfg, fFlags);
366 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
367 AssertPtrReturn(pDrvIns, VERR_INVALID_POINTER);
368 /* pCfg is optional. */
369
370 PDRVHOSTNULLAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTNULLAUDIO);
371 LogRel(("Audio: Initializing NULL driver\n"));
372
373 /*
374 * Init the static parts.
375 */
376 pThis->pDrvIns = pDrvIns;
377 /* IBase */
378 pDrvIns->IBase.pfnQueryInterface = drvHostNullAudioQueryInterface;
379 /* IHostAudio */
380 PDMAUDIO_IHOSTAUDIO_CALLBACKS(drvHostNullAudio);
381
382 return VINF_SUCCESS;
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