VirtualBox

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

最後變更 在這個檔案從62966是 62966,由 vboxsync 提交於 9 年 前

Devices: warnings

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 12.7 KB
 
1/* $Id: DrvHostNullAudio.cpp 62966 2016-08-04 10:15:55Z 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.alldomusa.eu.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 csPlayBuffer;
67 uint8_t *pu8PlayBuffer;
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->csPlayBuffer);
155
156 uint32_t csRead = 0;
157 AudioMixBufReadCirc(&pStream->MixBuf, pNullStream->pu8PlayBuffer, AUDIOMIXBUF_S2B(&pStream->MixBuf, cSamplesPlayed), &csRead);
158 AudioMixBufFinish(&pStream->MixBuf, csRead);
159
160 if (pcSamplesPlayed)
161 *pcSamplesPlayed = csRead;
162
163 return VINF_SUCCESS;
164}
165
166
167/**
168 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCapture}
169 */
170static DECLCALLBACK(int)
171drvHostNullAudioStreamCapture(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream, uint32_t *pcSamplesCaptured)
172{
173 RT_NOREF(pInterface, pStream);
174
175 /* Never capture anything. */
176 if (pcSamplesCaptured)
177 *pcSamplesCaptured = 0;
178
179 return VINF_SUCCESS;
180}
181
182
183/**
184 * @interface_method_impl{PDMIHOSTAUDIO,pfnGetStatus}
185 */
186static DECLCALLBACK(PDMAUDIOBACKENDSTS) drvHostNullAudioGetStatus(PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)
187{
188 RT_NOREF(enmDir);
189 AssertPtrReturn(pInterface, PDMAUDIOBACKENDSTS_UNKNOWN);
190
191 return PDMAUDIOBACKENDSTS_RUNNING;
192}
193
194
195static int nullCreateStreamIn(PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfg, uint32_t *pcSamples)
196{
197 /* Just adopt the wanted stream configuration. */
198 int rc = DrvAudioHlpStreamCfgToProps(pCfg, &pStream->Props);
199 if (RT_SUCCESS(rc))
200 {
201 if (pcSamples)
202 *pcSamples = _1K;
203 }
204
205 LogFlowFuncLeaveRC(rc);
206 return rc;
207}
208
209
210static int nullCreateStreamOut(PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfg, uint32_t *pcSamples)
211{
212 /* Just adopt the wanted stream configuration. */
213 int rc = DrvAudioHlpStreamCfgToProps(pCfg, &pStream->Props);
214 if (RT_SUCCESS(rc))
215 {
216 PNULLAUDIOSTREAMOUT pNullStream = RT_FROM_MEMBER(pStream, NULLAUDIOSTREAMOUT, Stream);
217 pNullStream->u64TicksLast = 0;
218 pNullStream->csPlayBuffer = _1K;
219 pNullStream->pu8PlayBuffer = (uint8_t *)RTMemAlloc(_1K << pStream->Props.cShift);
220 if (pNullStream->pu8PlayBuffer)
221 {
222 if (pcSamples)
223 *pcSamples = pNullStream->csPlayBuffer;
224 }
225 else
226 rc = VERR_NO_MEMORY;
227 }
228
229 LogFlowFuncLeaveRC(rc);
230 return rc;
231}
232
233
234/**
235 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamCreate}
236 */
237static DECLCALLBACK(int)
238drvHostNullAudioStreamCreate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream, PPDMAUDIOSTREAMCFG pCfg, uint32_t *pcSamples)
239{
240 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
241 AssertPtrReturn(pStream, VERR_INVALID_POINTER);
242 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
243
244 int rc;
245 if (pCfg->enmDir == PDMAUDIODIR_IN)
246 rc = nullCreateStreamIn( pStream, pCfg, pcSamples);
247 else
248 rc = nullCreateStreamOut(pStream, pCfg, pcSamples);
249
250 LogFlowFunc(("%s: rc=%Rrc\n", pStream->szName, rc));
251 return rc;
252}
253
254
255static int nullDestroyStreamIn(void)
256{
257 LogFlowFuncLeaveRC(VINF_SUCCESS);
258 return VINF_SUCCESS;
259}
260
261
262static int nullDestroyStreamOut(PPDMAUDIOSTREAM pStream)
263{
264 PNULLAUDIOSTREAMOUT pNullStream = RT_FROM_MEMBER(pStream, NULLAUDIOSTREAMOUT, Stream);
265 if ( pNullStream
266 && pNullStream->pu8PlayBuffer)
267 {
268 RTMemFree(pNullStream->pu8PlayBuffer);
269 pNullStream->pu8PlayBuffer = NULL;
270 }
271
272 LogFlowFuncLeaveRC(VINF_SUCCESS);
273 return VINF_SUCCESS;
274}
275
276
277/**
278 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamDestroy}
279 */
280static DECLCALLBACK(int) drvHostNullAudioStreamDestroy(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
281{
282 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
283 AssertPtrReturn(pStream, VERR_INVALID_POINTER);
284
285 int rc;
286 if (pStream->enmDir == PDMAUDIODIR_IN)
287 rc = nullDestroyStreamIn();
288 else
289 rc = nullDestroyStreamOut(pStream);
290
291 return rc;
292}
293
294
295/**
296 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamControl}
297 */
298static DECLCALLBACK(int)
299drvHostNullAudioStreamControl(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream, PDMAUDIOSTREAMCMD enmStreamCmd)
300{
301 RT_NOREF(enmStreamCmd);
302 AssertPtrReturn(pInterface, VERR_INVALID_POINTER);
303 AssertPtrReturn(pStream, VERR_INVALID_POINTER);
304
305 Assert(pStream->enmCtx == PDMAUDIOSTREAMCTX_HOST);
306
307 return VINF_SUCCESS;
308}
309
310
311/**
312 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamGetStatus}
313 */
314static DECLCALLBACK(PDMAUDIOSTRMSTS) drvHostNullAudioStreamGetStatus(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
315{
316 RT_NOREF(pInterface, pStream);
317 return PDMAUDIOSTRMSTS_FLAG_INITIALIZED | PDMAUDIOSTRMSTS_FLAG_ENABLED
318 | PDMAUDIOSTRMSTS_FLAG_DATA_READABLE | PDMAUDIOSTRMSTS_FLAG_DATA_WRITABLE;
319}
320
321
322/**
323 * @interface_method_impl{PDMIHOSTAUDIO,pfnStreamIterate}
324 */
325static DECLCALLBACK(int) drvHostNullAudioStreamIterate(PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAM pStream)
326{
327 NOREF(pInterface);
328 NOREF(pStream);
329
330 return VINF_SUCCESS;
331}
332
333
334/**
335 * @interface_method_impl{PDMIHOSTAUDIO,pfnShutdown}
336 */
337static DECLCALLBACK(void) drvHostNullAudioShutdown(PPDMIHOSTAUDIO pInterface)
338{
339 RT_NOREF(pInterface);
340}
341
342
343/**
344 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
345 */
346static DECLCALLBACK(void *) drvHostNullAudioQueryInterface(PPDMIBASE pInterface, const char *pszIID)
347{
348 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
349 PDRVHOSTNULLAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTNULLAUDIO);
350
351 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
352 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIHOSTAUDIO, &pThis->IHostAudio);
353 return NULL;
354}
355
356
357/**
358 * Constructs a Null audio driver instance.
359 *
360 * @copydoc FNPDMDRVCONSTRUCT
361 */
362static DECLCALLBACK(int) drvHostNullAudioConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
363{
364 RT_NOREF(pCfg, fFlags);
365 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
366 AssertPtrReturn(pDrvIns, VERR_INVALID_POINTER);
367 /* pCfg is optional. */
368
369 PDRVHOSTNULLAUDIO pThis = PDMINS_2_DATA(pDrvIns, PDRVHOSTNULLAUDIO);
370 LogRel(("Audio: Initializing NULL driver\n"));
371
372 /*
373 * Init the static parts.
374 */
375 pThis->pDrvIns = pDrvIns;
376 /* IBase */
377 pDrvIns->IBase.pfnQueryInterface = drvHostNullAudioQueryInterface;
378 /* IHostAudio */
379 PDMAUDIO_IHOSTAUDIO_CALLBACKS(drvHostNullAudio);
380
381 return VINF_SUCCESS;
382}
383
384/**
385 * Char driver registration record.
386 */
387const PDMDRVREG g_DrvHostNullAudio =
388{
389 /* u32Version */
390 PDM_DRVREG_VERSION,
391 /* szName */
392 "NullAudio",
393 /* szRCMod */
394 "",
395 /* szR0Mod */
396 "",
397 /* pszDescription */
398 "NULL audio host driver",
399 /* fFlags */
400 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
401 /* fClass. */
402 PDM_DRVREG_CLASS_AUDIO,
403 /* cMaxInstances */
404 ~0U,
405 /* cbInstance */
406 sizeof(DRVHOSTNULLAUDIO),
407 /* pfnConstruct */
408 drvHostNullAudioConstruct,
409 /* pfnDestruct */
410 NULL,
411 /* pfnRelocate */
412 NULL,
413 /* pfnIOCtl */
414 NULL,
415 /* pfnPowerOn */
416 NULL,
417 /* pfnReset */
418 NULL,
419 /* pfnSuspend */
420 NULL,
421 /* pfnResume */
422 NULL,
423 /* pfnAttach */
424 NULL,
425 /* pfnDetach */
426 NULL,
427 /* pfnPowerOff */
428 NULL,
429 /* pfnSoftReset */
430 NULL,
431 /* u32EndVersion */
432 PDM_DRVREG_VERSION
433};
434
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette