VirtualBox

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

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

Warnings (are errors).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.2 KB
Line 
1/* $Id: DrvHostNullAudio.cpp 63363 2016-08-12 14:30:13Z 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 */
95PDMAUDIO_IHOSTAUDIO_EMIT_GETCONFIG(drvHostNullAudio)
96{
97 NOREF(pInterface);
98 AssertPtrReturn(pBackendCfg, VERR_INVALID_POINTER);
99
100 pBackendCfg->cbStreamOut = sizeof(NULLAUDIOSTREAMOUT);
101 pBackendCfg->cbStreamIn = sizeof(NULLAUDIOSTREAMIN);
102
103 /* The NULL backend has exactly one input source and one output sink. */
104 pBackendCfg->cSources = 1;
105 pBackendCfg->cSinks = 1;
106
107 pBackendCfg->cMaxStreamsOut = 1; /* Output */
108 pBackendCfg->cMaxStreamsIn = 2; /* Line input + microphone input. */
109
110 return VINF_SUCCESS;
111}
112
113
114/**
115 * @interface_method_impl{PDMIHOSTAUDIO,pfnInit}
116 */
117PDMAUDIO_IHOSTAUDIO_EMIT_INIT(drvHostNullAudio)
118{
119 NOREF(pInterface);
120
121 LogFlowFuncLeaveRC(VINF_SUCCESS);
122 return VINF_SUCCESS;
123}
124
125
126/**
127 * @interface_method_impl{PDMIHOSTAUDIO,pfnShutdown}
128 */
129PDMAUDIO_IHOSTAUDIO_EMIT_SHUTDOWN(drvHostNullAudio)
130{
131 RT_NOREF(pInterface);
132}
133
134
135/**
136 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetStatus}
137 */
138PDMAUDIO_IHOSTAUDIO_EMIT_GETSTATUS(drvHostNullAudio)
139{
140 RT_NOREF(enmDir);
141 AssertPtrReturn(pInterface, PDMAUDIOBACKENDSTS_UNKNOWN);
142
143 return PDMAUDIOBACKENDSTS_RUNNING;
144}
145
146
147/**
148 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamPlay}
149 */
150PDMAUDIO_IHOSTAUDIO_EMIT_STREAMPLAY(drvHostNullAudio)
151{
152 RT_NOREF2(pvBuf, cbBuf);
153
154 PDRVHOSTNULLAUDIO pDrv = RT_FROM_MEMBER(pInterface, DRVHOSTNULLAUDIO, IHostAudio);
155 PNULLAUDIOSTREAMOUT pNullStream = RT_FROM_MEMBER(pStream, NULLAUDIOSTREAMOUT, Stream);
156
157 /* Consume as many samples as would be played at the current frequency since last call. */
158 uint32_t cLive = AudioMixBufLive(&pStream->MixBuf);
159
160 uint64_t u64TicksNow = PDMDrvHlpTMGetVirtualTime(pDrv->pDrvIns);
161 uint64_t u64TicksElapsed = u64TicksNow - pNullStream->u64TicksLast;
162 uint64_t u64TicksFreq = PDMDrvHlpTMGetVirtualFreq(pDrv->pDrvIns);
163
164 /* Remember when samples were consumed. */
165 pNullStream->u64TicksLast = u64TicksNow;
166
167 /*
168 * Minimize the rounding error by adding 0.5: samples = int((u64TicksElapsed * samplesFreq) / u64TicksFreq + 0.5).
169 * If rounding is not taken into account then the playback rate will be consistently lower that expected.
170 */
171 uint64_t cSamplesPlayed = (2 * u64TicksElapsed * pStream->Props.uHz + u64TicksFreq) / u64TicksFreq / 2;
172
173 /* Don't play more than available. */
174 if (cSamplesPlayed > cLive)
175 cSamplesPlayed = cLive;
176
177 cSamplesPlayed = RT_MIN(cSamplesPlayed, pNullStream->cMaxSamplesInPlayBuffer);
178
179 uint32_t cSamplesToRead = 0;
180 AudioMixBufReadCirc(&pStream->MixBuf, pNullStream->pbPlayBuffer,
181 AUDIOMIXBUF_S2B(&pStream->MixBuf, cSamplesPlayed), &cSamplesToRead);
182 AudioMixBufFinish(&pStream->MixBuf, cSamplesToRead);
183
184 if (pcbWritten)
185 *pcbWritten = cSamplesToRead;
186
187 return VINF_SUCCESS;
188}
189
190
191/**
192 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCapture}
193 */
194PDMAUDIO_IHOSTAUDIO_EMIT_STREAMCAPTURE(drvHostNullAudio)
195{
196 RT_NOREF4(pInterface, pStream, pvBuf, cbBuf);
197
198 /* Never capture anything. */
199 if (pcbRead)
200 *pcbRead = 0;
201
202 return VINF_SUCCESS;
203}
204
205
206static int nullCreateStreamIn(PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
207{
208 /* Just adopt the wanted stream configuration. */
209 int rc = DrvAudioHlpStreamCfgToProps(pCfgReq, &pStream->Props);
210 if (RT_SUCCESS(rc))
211 {
212 if (pCfgAcq)
213 pCfgAcq->cSamples = _1K;
214 }
215
216 LogFlowFuncLeaveRC(rc);
217 return rc;
218}
219
220
221static int nullCreateStreamOut(PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)
222{
223 /* Just adopt the wanted stream configuration. */
224 int rc = DrvAudioHlpStreamCfgToProps(pCfgReq, &pStream->Props);
225 if (RT_SUCCESS(rc))
226 {
227 PNULLAUDIOSTREAMOUT pNullStream = RT_FROM_MEMBER(pStream, NULLAUDIOSTREAMOUT, Stream);
228
229 pNullStream->u64TicksLast = 0;
230 pNullStream->cMaxSamplesInPlayBuffer = _1K;
231
232 pNullStream->pbPlayBuffer = (uint8_t *)RTMemAlloc(_1K << pStream->Props.cShift);
233 if (pNullStream->pbPlayBuffer)
234 {
235 if (pCfgAcq)
236 pCfgAcq->cSamples = pNullStream->cMaxSamplesInPlayBuffer;
237 }
238 else
239 rc = VERR_NO_MEMORY;
240 }
241
242 LogFlowFuncLeaveRC(rc);
243 return rc;
244}
245
246
247/**
248 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCreate}
249 */
250PDMAUDIO_IHOSTAUDIO_EMIT_STREAMCREATE(drvHostNullAudio)
251{
252 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
253 AssertPtrReturn(pStream, VERR_INVALID_POINTER);
254 AssertPtrReturn(pCfgReq, VERR_INVALID_POINTER);
255
256 int rc;
257 if (pCfgReq->enmDir == PDMAUDIODIR_IN)
258 rc = nullCreateStreamIn( pStream, pCfgReq, pCfgAcq);
259 else
260 rc = nullCreateStreamOut(pStream, pCfgReq, pCfgAcq);
261
262 LogFlowFunc(("%s: rc=%Rrc\n", pStream->szName, rc));
263 return rc;
264}
265
266
267static int nullDestroyStreamIn(void)
268{
269 LogFlowFuncLeaveRC(VINF_SUCCESS);
270 return VINF_SUCCESS;
271}
272
273
274static int nullDestroyStreamOut(PPDMAUDIOSTREAM pStream)
275{
276 PNULLAUDIOSTREAMOUT pNullStream = RT_FROM_MEMBER(pStream, NULLAUDIOSTREAMOUT, Stream);
277 if ( pNullStream
278 && pNullStream->pbPlayBuffer)
279 {
280 RTMemFree(pNullStream->pbPlayBuffer);
281 pNullStream->pbPlayBuffer = NULL;
282 }
283
284 LogFlowFuncLeaveRC(VINF_SUCCESS);
285 return VINF_SUCCESS;
286}
287
288
289/**
290 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDestroy}
291 */
292PDMAUDIO_IHOSTAUDIO_EMIT_STREAMDESTROY(drvHostNullAudio)
293{
294 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
295 AssertPtrReturn(pStream, VERR_INVALID_POINTER);
296
297 int rc;
298 if (pStream->enmDir == PDMAUDIODIR_IN)
299 rc = nullDestroyStreamIn();
300 else
301 rc = nullDestroyStreamOut(pStream);
302
303 return rc;
304}
305
306
307/**
308 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamControl}
309 */
310PDMAUDIO_IHOSTAUDIO_EMIT_STREAMCONTROL(drvHostNullAudio)
311{
312 RT_NOREF(enmStreamCmd);
313 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
314 AssertPtrReturn(pStream, VERR_INVALID_POINTER);
315
316 Assert(pStream->enmCtx == PDMAUDIOSTREAMCTX_HOST);
317
318 return VINF_SUCCESS;
319}
320
321
322/**
323 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetStatus}
324 */
325PDMAUDIO_IHOSTAUDIO_EMIT_STREAMGETSTATUS(drvHostNullAudio)
326{
327 RT_NOREF(pInterface, pStream);
328 return PDMAUDIOSTRMSTS_FLAG_INITIALIZED | PDMAUDIOSTRMSTS_FLAG_ENABLED
329 | PDMAUDIOSTRMSTS_FLAG_DATA_READABLE | PDMAUDIOSTRMSTS_FLAG_DATA_WRITABLE;
330}
331
332
333/**
334 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamIterate}
335 */
336PDMAUDIO_IHOSTAUDIO_EMIT_STREAMITERATE(drvHostNullAudio)
337{
338 NOREF(pInterface);
339 NOREF(pStream);
340
341 return VINF_SUCCESS;
342}
343
344
345/**
346 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
347 */
348static DECLCALLBACK(void *) drvHostNullAudioQueryInterface(PPDMIBASE pInterface, const char *pszIID)
349{
350 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
351 PDRVHOSTNULLAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTNULLAUDIO);
352
353 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
354 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
355 return NULL;
356}
357
358
359/**
360 * Constructs a Null audio driver instance.
361 *
362 * @copydoc FNPDMDRVCONSTRUCT
363 */
364static DECLCALLBACK(int) drvHostNullAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
365{
366 RT_NOREF(pCfg, fFlags);
367 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
368 AssertPtrReturn(pDrvIns, VERR_INVALID_POINTER);
369 /* pCfg is optional. */
370
371 PDRVHOSTNULLAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTNULLAUDIO);
372 LogRel(("Audio: Initializing NULL driver\n"));
373
374 /*
375 * Init the static parts.
376 */
377 pThis->pDrvIns = pDrvIns;
378 /* IBase */
379 pDrvIns->IBase.pfnQueryInterface = drvHostNullAudioQueryInterface;
380 /* IHostAudio */
381 PDMAUDIO_IHOSTAUDIO_CALLBACKS(drvHostNullAudio);
382
383 return VINF_SUCCESS;
384}
385
386
387/**
388 * Char driver registration record.
389 */
390const PDMDRVREG g_DrvHostNullAudio =
391{
392 /* u32Version */
393 PDM_DRVREG_VERSION,
394 /* szName */
395 "NullAudio",
396 /* szRCMod */
397 "",
398 /* szR0Mod */
399 "",
400 /* pszDescription */
401 "NULL audio host driver",
402 /* fFlags */
403 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
404 /* fClass. */
405 PDM_DRVREG_CLASS_AUDIO,
406 /* cMaxInstances */
407 ~0U,
408 /* cbInstance */
409 sizeof(DRVHOSTNULLAUDIO),
410 /* pfnConstruct */
411 drvHostNullAudioConstruct,
412 /* pfnDestruct */
413 NULL,
414 /* pfnRelocate */
415 NULL,
416 /* pfnIOCtl */
417 NULL,
418 /* pfnPowerOn */
419 NULL,
420 /* pfnReset */
421 NULL,
422 /* pfnSuspend */
423 NULL,
424 /* pfnResume */
425 NULL,
426 /* pfnAttach */
427 NULL,
428 /* pfnDetach */
429 NULL,
430 /* pfnPowerOff */
431 NULL,
432 /* pfnSoftReset */
433 NULL,
434 /* u32EndVersion */
435 PDM_DRVREG_VERSION
436};
437
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