VirtualBox

source: vbox/trunk/src/VBox/Devices/Audio/DrvAudioCommon.cpp@ 55043

Last change on this file since 55043 was 54973, checked in by vboxsync, 10 years ago

Logging.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.9 KB
Line 
1/* $Id: DrvAudioCommon.cpp 54973 2015-03-26 19:08:48Z vboxsync $ */
2/** @file
3 * Intermedia audio driver, common routines. These are also used
4 * in the drivers which are bound to Main, e.g. the VRDE or the
5 * video audio recording drivers.
6 */
7
8/*
9 * Copyright (C) 2006-2014 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 * --------------------------------------------------------------------
19 *
20 * This code is based on: audio_template.h from QEMU AUDIO subsystem.
21 *
22 * QEMU Audio subsystem header
23 *
24 * Copyright (c) 2005 Vassili Karpov (malc)
25 *
26 * Permission is hereby granted, free of charge, to any person obtaining a copy
27 * of this software and associated documentation files (the "Software"), to deal
28 * in the Software without restriction, including without limitation the rights
29 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
30 * copies of the Software, and to permit persons to whom the Software is
31 * furnished to do so, subject to the following conditions:
32 *
33 * The above copyright notice and this permission notice shall be included in
34 * all copies or substantial portions of the Software.
35 *
36 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
37 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
38 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
39 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
40 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
41 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
42 * THE SOFTWARE.
43 */
44
45#include <iprt/asm-math.h>
46#include <iprt/assert.h>
47#include <iprt/uuid.h>
48#include <iprt/string.h>
49#include <iprt/alloc.h>
50
51#include <VBox/vmm/pdmdev.h>
52#include <VBox/vmm/pdm.h>
53#include <VBox/err.h>
54#include <VBox/vmm/mm.h>
55
56#ifdef LOG_GROUP
57# undef LOG_GROUP
58#endif
59#define LOG_GROUP LOG_GROUP_DEV_AUDIO
60#include <VBox/log.h>
61
62#include <ctype.h>
63#include <stdlib.h>
64
65#include "DrvAudio.h"
66#include "AudioMixBuffer.h"
67
68bool drvAudioPCMPropsAreEqual(PPDMPCMPROPS pProps, PPDMAUDIOSTREAMCFG pCfg);
69
70const char *drvAudioRecSourceToString(PDMAUDIORECSOURCE enmRecSource)
71{
72 switch (enmRecSource)
73 {
74 case PDMAUDIORECSOURCE_MIC: return "Microphone In";
75 case PDMAUDIORECSOURCE_CD: return "CD";
76 case PDMAUDIORECSOURCE_VIDEO: return "Video";
77 case PDMAUDIORECSOURCE_AUX: return "AUX";
78 case PDMAUDIORECSOURCE_LINE_IN: return "Line In";
79 case PDMAUDIORECSOURCE_PHONE: return "Phone";
80 default:
81 break;
82 }
83
84 AssertMsgFailed(("Bogus recording source %ld\n", enmRecSource));
85 return "Unknown";
86}
87
88const char *drvAudioHlpFormatToString(PDMAUDIOFMT enmFormat)
89{
90 switch (enmFormat)
91 {
92 case AUD_FMT_U8:
93 return "U8";
94
95 case AUD_FMT_U16:
96 return "U16";
97
98 case AUD_FMT_U32:
99 return "U32";
100
101 case AUD_FMT_S8:
102 return "S8";
103
104 case AUD_FMT_S16:
105 return "S16";
106
107 case AUD_FMT_S32:
108 return "S32";
109
110 default:
111 break;
112 }
113
114 AssertMsgFailed(("Bogus audio format %ld\n", enmFormat));
115 return "Invalid";
116}
117
118PDMAUDIOFMT drvAudioHlpStringToFormat(const char *pszFormat)
119{
120 if (!RTStrICmp(pszFormat, "u8"))
121 return AUD_FMT_U8;
122 else if (!RTStrICmp(pszFormat, "u16"))
123 return AUD_FMT_U16;
124 else if (!RTStrICmp(pszFormat, "u32"))
125 return AUD_FMT_U32;
126 else if (!RTStrICmp(pszFormat, "s8"))
127 return AUD_FMT_S8;
128 else if (!RTStrICmp(pszFormat, "s16"))
129 return AUD_FMT_S16;
130 else if (!RTStrICmp(pszFormat, "s32"))
131 return AUD_FMT_S32;
132
133 AssertMsgFailed(("Bogus audio format \"%s\"\n", pszFormat));
134 return AUD_FMT_INVALID;
135}
136
137/*********************************** In Stream Functions **********************************************/
138
139void drvAudioGstInFreeRes(PPDMAUDIOGSTSTRMIN pGstStrmIn)
140{
141 AssertPtrReturnVoid(pGstStrmIn);
142
143 if (pGstStrmIn->State.pszName)
144 {
145 RTStrFree(pGstStrmIn->State.pszName);
146 pGstStrmIn->State.pszName = NULL;
147 }
148
149 audioMixBufDestroy(&pGstStrmIn->MixBuf);
150}
151
152void drvAudioHstInFreeRes(PPDMAUDIOHSTSTRMIN pHstStrmIn)
153{
154 AssertPtrReturnVoid(pHstStrmIn);
155 audioMixBufDestroy(&pHstStrmIn->MixBuf);
156}
157
158void drvAudioGstOutFreeRes(PPDMAUDIOGSTSTRMOUT pGstStrmOut)
159{
160 if (!pGstStrmOut)
161 return;
162
163 if (pGstStrmOut->State.pszName)
164 {
165 RTStrFree(pGstStrmOut->State.pszName);
166 pGstStrmOut->State.pszName = NULL;
167 }
168
169 audioMixBufDestroy(&pGstStrmOut->MixBuf);
170}
171
172#if 0
173
174/**
175 * Finds the minimum number of not yet captured samples of all
176 * attached guest input streams for a certain host input stream.
177 *
178 * @return uint32_t Minimum number of not yet captured samples.
179 * UINT32_MAX if none found.
180 * @param pHstStrmIn Host input stream to check for.
181 */
182inline uint32_t drvAudioHstInFindMinCaptured(PPDMAUDIOHSTSTRMIN pHstStrmIn)
183{
184 AssertPtrReturn(pHstStrmIn, 0);
185 uint32_t cMinSamples = UINT32_MAX;
186
187 PPDMAUDIOGSTSTRMIN pGstStrmIn;
188 RTListForEach(&pHstStrmIn->lstGstStrmIn, pGstStrmIn, PDMAUDIOGSTSTRMIN, Node)
189 {
190 if (pGstStrmIn->State.fActive)
191 cMinSamples = RT_MIN(cMinSamples, audioMixBufMixed(&pGstStrmIn->MixBuf));
192 }
193
194#ifdef DEBUG_andy
195 LogFlowFunc(("cMinSamples=%RU32\n", cMinSamples));
196#endif
197 return cMinSamples;
198}
199
200uint32_t drvAudioHstInGetFree(PPDMAUDIOHSTSTRMIN pHstStrmIn)
201{
202 AssertPtrReturn(pHstStrmIn, 0);
203
204 return audioMixBufSize(&pHstStrmIn->MixBuf) - drvAudioHstInGetLive(pHstStrmIn);
205}
206
207uint32_t drvAudioHstInGetLive(PPDMAUDIOHSTSTRMIN pHstStrmIn)
208{
209 AssertPtrReturn(pHstStrmIn, 0);
210
211 uint32_t cMinSamplesCaptured = drvAudioHstInFindMinCaptured(pHstStrmIn);
212 uint32_t cSamplesCaptured = audioMixBufMixed(&pHstStrmIn->MixBuf);
213
214 Assert(cSamplesCaptured >= cMinSamplesCaptured);
215 uint32_t cSamplesLive = cSamplesCaptured - cMinSamplesCaptured;
216 Assert(cSamplesLive <= audioMixBufSize(&pHstStrmIn->MixBuf));
217
218#ifdef DEBUG_andy
219 LogFlowFunc(("cSamplesLive=%RU32\n", cSamplesLive));
220#endif
221 return cSamplesLive;
222}
223#endif
224
225void drvAudioHstOutFreeRes(PPDMAUDIOHSTSTRMOUT pHstStrmOut)
226{
227 AssertPtrReturnVoid(pHstStrmOut);
228 audioMixBufDestroy(&pHstStrmOut->MixBuf);
229}
230
231#if 0
232/**
233 * Returns the number of live sample data (in bytes) of a certain
234 * guest input stream.
235 *
236 * @return uint32_t Live sample data (in bytes), 0 if none.
237 * @param pGstStrmIn Guest input stream to check for.
238 */
239uint32_t drvAudioGstInGetLiveBytes(PPDMAUDIOGSTSTRMIN pGstStrmIn)
240{
241 AssertPtrReturn(pGstStrmIn, 0);
242 AssertPtrReturn(pGstStrmIn->pHstStrmIn, 0);
243
244 Assert(pGstStrmIn->pHstStrmIn->cTotalSamplesCaptured >= pGstStrmIn->cTotalHostSamplesRead);
245 uint32_t cSamplesLive = pGstStrmIn->pHstStrmIn->cTotalSamplesCaptured - pGstStrmIn->cTotalHostSamplesRead;
246 if (!cSamplesLive)
247 return 0;
248 Assert(cSamplesLive <= pGstStrmIn->pHstStrmIn->cSamples);
249
250 /** @todo Document / refactor this! */
251 return (((int64_t) cSamplesLive << 32) / pGstStrmIn->State.uFreqRatio) << pGstStrmIn->Props.cShift;
252}
253
254
255/**
256 * Returns the total number of unused sample data (in bytes) of a certain
257 * guest output stream.
258 *
259 * @return uint32_t Number of unused sample data (in bytes), 0 if all used up.
260 * @param pGstStrmOut Guest output stream to check for.
261 */
262uint32_t drvAudioGstOutGetFreeBytes(PPDMAUDIOGSTSTRMOUT pGstStrmOut)
263{
264 AssertPtrReturn(pGstStrmOut, 0);
265
266 Assert(pGstStrmOut->cTotalSamplesWritten <= pGstStrmOut->pHstStrmOut->cSamples);
267 uint32_t cSamplesFree = pGstStrmOut->pHstStrmOut->cSamples
268 - pGstStrmOut->cTotalSamplesWritten;
269 if (!cSamplesFree)
270 return 0;
271
272 /** @todo Document / refactor this! */
273 return (((int64_t) cSamplesFree << 32) / pGstStrmOut->State.uFreqRatio) << pGstStrmOut->Props.cShift;
274}
275#endif
276
277bool drvAudioPCMPropsAreEqual(PPDMPCMPROPS pProps, PPDMAUDIOSTREAMCFG pCfg)
278{
279 int cBits = 8;
280 bool fSigned = false;
281
282 switch (pCfg->enmFormat)
283 {
284 case AUD_FMT_S8:
285 fSigned = true;
286 case AUD_FMT_U8:
287 break;
288
289 case AUD_FMT_S16:
290 fSigned = true;
291 case AUD_FMT_U16:
292 cBits = 16;
293 break;
294
295 case AUD_FMT_S32:
296 fSigned = true;
297 case AUD_FMT_U32:
298 cBits = 32;
299 break;
300
301 default:
302 AssertMsgFailed(("Unknown format %ld\n", pCfg->enmFormat));
303 break;
304 }
305
306 bool fEqual = pProps->uHz == pCfg->uHz
307 && pProps->cChannels == pCfg->cChannels
308 && pProps->fSigned == fSigned
309 && pProps->cBits == cBits
310 && pProps->fSwapEndian == !(pCfg->enmEndianness == PDMAUDIOHOSTENDIANESS);
311
312 LogFlowFunc(("fEqual=%RTbool\n", fEqual));
313 return fEqual;
314}
315
316int drvAudioStreamCfgToProps(PPDMAUDIOSTREAMCFG pCfg, PPDMPCMPROPS pProps)
317{
318 int rc = VINF_SUCCESS;
319
320 int cBits = 8, cShift = 0;
321 bool fSigned = false;
322
323 switch (pCfg->enmFormat)
324 {
325 case AUD_FMT_S8:
326 fSigned = true;
327 case AUD_FMT_U8:
328 break;
329
330 case AUD_FMT_S16:
331 fSigned = true;
332 case AUD_FMT_U16:
333 cBits = 16;
334 cShift = 1;
335 break;
336
337 case AUD_FMT_S32:
338 fSigned = true;
339 case AUD_FMT_U32:
340 cBits = 32;
341 cShift = 2;
342 break;
343
344 default:
345 AssertMsgFailed(("Unknown format %ld\n", pCfg->enmFormat));
346 rc = VERR_NOT_SUPPORTED;
347 break;
348 }
349
350 if (RT_SUCCESS(rc))
351 {
352 pProps->uHz = pCfg->uHz;
353 pProps->cBits = cBits;
354 pProps->fSigned = fSigned;
355 pProps->cChannels = pCfg->cChannels;
356 pProps->cShift = (pCfg->cChannels == 2) + cShift;
357 pProps->uAlign = (1 << pProps->cShift) - 1;
358 pProps->cbPerSec = pProps->uHz << pProps->cShift;
359 pProps->fSwapEndian = pCfg->enmEndianness != PDMAUDIOHOSTENDIANESS;
360 }
361
362#ifdef DEBUG
363 drvAudioStreamCfgPrint(pCfg);
364#endif
365
366 LogFlowFunc(("rc=%Rrc\n", rc));
367 return rc;
368}
369
370void drvAudioStreamCfgPrint(PPDMAUDIOSTREAMCFG pCfg)
371{
372 LogFlowFunc(("uHz=%RU32, cChannels=%RU8, enmFormat=",
373 pCfg->uHz, pCfg->cChannels));
374
375 switch (pCfg->enmFormat)
376 {
377 case AUD_FMT_S8:
378 LogFlow(("S8"));
379 break;
380 case AUD_FMT_U8:
381 LogFlow(("U8"));
382 break;
383 case AUD_FMT_S16:
384 LogFlow(("S16"));
385 break;
386 case AUD_FMT_U16:
387 LogFlow(("U16"));
388 break;
389 case AUD_FMT_S32:
390 LogFlow(("S32"));
391 break;
392 case AUD_FMT_U32:
393 LogFlow(("U32"));
394 break;
395 default:
396 LogFlow(("invalid(%d)", pCfg->enmFormat));
397 break;
398 }
399
400 LogFlow((", endianness="));
401 switch (pCfg->enmEndianness)
402 {
403 case PDMAUDIOENDIANESS_LITTLE:
404 LogFlow(("little\n"));
405 break;
406 case PDMAUDIOENDIANESS_BIG:
407 LogFlow(("big\n"));
408 break;
409 default:
410 LogFlow(("invalid\n"));
411 break;
412 }
413}
414
415/**
416 * Returns the minimum number of live samples already written to all associated
417 * guest output streams of a specific host output stream.
418 *
419 * @return uint32_t Minimum number of total live samples already written to all
420 * associated guest output streams, UINT32_MAX if none found.
421 * @param pHstStrmOut Host output stream to search in.
422 * @param pcStreamsLive Returns the number of live guest streams associated to
423 * this host output stream. Optional.
424 */
425static uint32_t drvAudioHstOutMinSamplesMixed(PPDMAUDIOHSTSTRMOUT pHstStrmOut, uint32_t *pcStreamsLive)
426{
427 AssertPtrReturn(pHstStrmOut, 0);
428 /* pcStreamsLive is optional. */
429
430 uint32_t cStreamsLive = 0;
431 uint32_t cMinSamplesMixed = UINT32_MAX;
432 uint32_t cSamples;
433
434 PPDMAUDIOGSTSTRMOUT pGstStrmOut;
435 RTListForEach(&pHstStrmOut->lstGstStrmOut, pGstStrmOut, PDMAUDIOGSTSTRMOUT, Node)
436 {
437 if ( pGstStrmOut->State.fActive
438 || !pGstStrmOut->State.fEmpty)
439 {
440 cSamples = audioMixBufMixed(&pGstStrmOut->MixBuf);
441 cMinSamplesMixed = RT_MIN(cMinSamplesMixed, cSamples);
442
443 cStreamsLive++;
444 }
445 }
446
447 if (pcStreamsLive)
448 *pcStreamsLive = cStreamsLive;
449
450 return cMinSamplesMixed;
451}
452
453/**
454 * Finds the number of live (guest) samples of a specific host output stream.
455 *
456 * @return uint32_t Minimum number of live host output samples processed
457 * by all connected guest output streams.
458 * @param pHstStrmOut Host output stream to search in.
459 * @param pcStreamsLive Number of associated guest live streams. Optional.
460 */
461uint32_t drvAudioHstOutSamplesLive(PPDMAUDIOHSTSTRMOUT pHstStrmOut, uint32_t *pcStreamsLive)
462{
463 AssertPtrReturn(pHstStrmOut, 0);
464 /* pcStreamsLive is optional. */
465
466 uint32_t cStreamsLive;
467 uint32_t cSamplesMin = drvAudioHstOutMinSamplesMixed(pHstStrmOut, &cStreamsLive);
468
469 if (pcStreamsLive)
470 *pcStreamsLive = cStreamsLive;
471
472 if (cStreamsLive) /* Any live streams at all? */
473 {
474 if ( cSamplesMin == UINT32_MAX
475 || cSamplesMin > audioMixBufSize(&pHstStrmOut->MixBuf))
476 {
477 LogFlowFunc(("Error: cSamplesMin=%RU32\n", cSamplesMin));
478 return 0;
479 }
480
481 return cSamplesMin;
482 }
483
484 return 0;
485}
486
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