VirtualBox

source: vbox/trunk/src/VBox/Devices/Audio_old/DrvAudioCommon.cpp@ 62518

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

(C) 2016

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.8 KB
Line 
1/* $Id: DrvAudioCommon.cpp 62518 2016-07-22 19:14:29Z 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-2016 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#define LOG_GROUP LOG_GROUP_DRV_AUDIO
45#include <VBox/log.h>
46#include <iprt/asm-math.h>
47#include <iprt/assert.h>
48#include <iprt/uuid.h>
49#include <iprt/string.h>
50#include <iprt/alloc.h>
51
52#include <VBox/vmm/pdmdev.h>
53#include <VBox/vmm/pdm.h>
54#include <VBox/err.h>
55#include <VBox/vmm/mm.h>
56
57#include <ctype.h>
58#include <stdlib.h>
59
60#include "DrvAudio.h"
61#include "AudioMixBuffer.h"
62
63bool drvAudioPCMPropsAreEqual(PPDMPCMPROPS pProps, PPDMAUDIOSTREAMCFG pCfg);
64
65const char *drvAudioRecSourceToString(PDMAUDIORECSOURCE enmRecSource)
66{
67 switch (enmRecSource)
68 {
69 case PDMAUDIORECSOURCE_MIC: return "Microphone In";
70 case PDMAUDIORECSOURCE_CD: return "CD";
71 case PDMAUDIORECSOURCE_VIDEO: return "Video";
72 case PDMAUDIORECSOURCE_AUX: return "AUX";
73 case PDMAUDIORECSOURCE_LINE_IN: return "Line In";
74 case PDMAUDIORECSOURCE_PHONE: return "Phone";
75 default:
76 break;
77 }
78
79 AssertMsgFailed(("Bogus recording source %ld\n", enmRecSource));
80 return "Unknown";
81}
82
83const char *drvAudioHlpFormatToString(PDMAUDIOFMT enmFormat)
84{
85 switch (enmFormat)
86 {
87 case AUD_FMT_U8:
88 return "U8";
89
90 case AUD_FMT_U16:
91 return "U16";
92
93 case AUD_FMT_U32:
94 return "U32";
95
96 case AUD_FMT_S8:
97 return "S8";
98
99 case AUD_FMT_S16:
100 return "S16";
101
102 case AUD_FMT_S32:
103 return "S32";
104
105 default:
106 break;
107 }
108
109 AssertMsgFailed(("Bogus audio format %ld\n", enmFormat));
110 return "Invalid";
111}
112
113PDMAUDIOFMT drvAudioHlpStringToFormat(const char *pszFormat)
114{
115 if (!RTStrICmp(pszFormat, "u8"))
116 return AUD_FMT_U8;
117 else if (!RTStrICmp(pszFormat, "u16"))
118 return AUD_FMT_U16;
119 else if (!RTStrICmp(pszFormat, "u32"))
120 return AUD_FMT_U32;
121 else if (!RTStrICmp(pszFormat, "s8"))
122 return AUD_FMT_S8;
123 else if (!RTStrICmp(pszFormat, "s16"))
124 return AUD_FMT_S16;
125 else if (!RTStrICmp(pszFormat, "s32"))
126 return AUD_FMT_S32;
127
128 AssertMsgFailed(("Bogus audio format \"%s\"\n", pszFormat));
129 return AUD_FMT_INVALID;
130}
131
132/*********************************** In Stream Functions **********************************************/
133
134void drvAudioGstInFreeRes(PPDMAUDIOGSTSTRMIN pGstStrmIn)
135{
136 AssertPtrReturnVoid(pGstStrmIn);
137
138 if (pGstStrmIn->State.pszName)
139 {
140 RTStrFree(pGstStrmIn->State.pszName);
141 pGstStrmIn->State.pszName = NULL;
142 }
143
144 AudioMixBufDestroy(&pGstStrmIn->MixBuf);
145}
146
147void drvAudioHstInFreeRes(PPDMAUDIOHSTSTRMIN pHstStrmIn)
148{
149 AssertPtrReturnVoid(pHstStrmIn);
150 AudioMixBufDestroy(&pHstStrmIn->MixBuf);
151}
152
153void drvAudioGstOutFreeRes(PPDMAUDIOGSTSTRMOUT pGstStrmOut)
154{
155 if (!pGstStrmOut)
156 return;
157
158 if (pGstStrmOut->State.pszName)
159 {
160 RTStrFree(pGstStrmOut->State.pszName);
161 pGstStrmOut->State.pszName = NULL;
162 }
163
164 AudioMixBufDestroy(&pGstStrmOut->MixBuf);
165}
166
167#if 0
168
169/**
170 * Finds the minimum number of not yet captured samples of all
171 * attached guest input streams for a certain host input stream.
172 *
173 * @return uint32_t Minimum number of not yet captured samples.
174 * UINT32_MAX if none found.
175 * @param pHstStrmIn Host input stream to check for.
176 */
177inline uint32_t drvAudioHstInFindMinCaptured(PPDMAUDIOHSTSTRMIN pHstStrmIn)
178{
179 AssertPtrReturn(pHstStrmIn, 0);
180 uint32_t cMinSamples = UINT32_MAX;
181
182 PPDMAUDIOGSTSTRMIN pGstStrmIn;
183 RTListForEach(&pHstStrmIn->lstGstStrmIn, pGstStrmIn, PDMAUDIOGSTSTRMIN, Node)
184 {
185 if (pGstStrmIn->State.fActive)
186 cMinSamples = RT_MIN(cMinSamples, audioMixBufMixed(&pGstStrmIn->MixBuf));
187 }
188
189#ifdef DEBUG_andy
190 LogFlowFunc(("cMinSamples=%RU32\n", cMinSamples));
191#endif
192 return cMinSamples;
193}
194
195uint32_t drvAudioHstInGetFree(PPDMAUDIOHSTSTRMIN pHstStrmIn)
196{
197 AssertPtrReturn(pHstStrmIn, 0);
198
199 return audioMixBufSize(&pHstStrmIn->MixBuf) - drvAudioHstInGetLive(pHstStrmIn);
200}
201
202uint32_t drvAudioHstInGetLive(PPDMAUDIOHSTSTRMIN pHstStrmIn)
203{
204 AssertPtrReturn(pHstStrmIn, 0);
205
206 uint32_t cMinSamplesCaptured = drvAudioHstInFindMinCaptured(pHstStrmIn);
207 uint32_t cSamplesCaptured = audioMixBufMixed(&pHstStrmIn->MixBuf);
208
209 Assert(cSamplesCaptured >= cMinSamplesCaptured);
210 uint32_t cSamplesLive = cSamplesCaptured - cMinSamplesCaptured;
211 Assert(cSamplesLive <= audioMixBufSize(&pHstStrmIn->MixBuf));
212
213#ifdef DEBUG_andy
214 LogFlowFunc(("cSamplesLive=%RU32\n", cSamplesLive));
215#endif
216 return cSamplesLive;
217}
218#endif
219
220void drvAudioHstOutFreeRes(PPDMAUDIOHSTSTRMOUT pHstStrmOut)
221{
222 AssertPtrReturnVoid(pHstStrmOut);
223 AudioMixBufDestroy(&pHstStrmOut->MixBuf);
224}
225
226#if 0
227/**
228 * Returns the number of live sample data (in bytes) of a certain
229 * guest input stream.
230 *
231 * @return uint32_t Live sample data (in bytes), 0 if none.
232 * @param pGstStrmIn Guest input stream to check for.
233 */
234uint32_t drvAudioGstInGetLiveBytes(PPDMAUDIOGSTSTRMIN pGstStrmIn)
235{
236 AssertPtrReturn(pGstStrmIn, 0);
237 AssertPtrReturn(pGstStrmIn->pHstStrmIn, 0);
238
239 Assert(pGstStrmIn->pHstStrmIn->cTotalSamplesCaptured >= pGstStrmIn->cTotalHostSamplesRead);
240 uint32_t cSamplesLive = pGstStrmIn->pHstStrmIn->cTotalSamplesCaptured - pGstStrmIn->cTotalHostSamplesRead;
241 if (!cSamplesLive)
242 return 0;
243 Assert(cSamplesLive <= pGstStrmIn->pHstStrmIn->cSamples);
244
245 /** @todo Document / refactor this! */
246 return (((int64_t) cSamplesLive << 32) / pGstStrmIn->State.uFreqRatio) << pGstStrmIn->Props.cShift;
247}
248
249
250/**
251 * Returns the total number of unused sample data (in bytes) of a certain
252 * guest output stream.
253 *
254 * @return uint32_t Number of unused sample data (in bytes), 0 if all used up.
255 * @param pGstStrmOut Guest output stream to check for.
256 */
257uint32_t drvAudioGstOutGetFreeBytes(PPDMAUDIOGSTSTRMOUT pGstStrmOut)
258{
259 AssertPtrReturn(pGstStrmOut, 0);
260
261 Assert(pGstStrmOut->cTotalSamplesWritten <= pGstStrmOut->pHstStrmOut->cSamples);
262 uint32_t cSamplesFree = pGstStrmOut->pHstStrmOut->cSamples
263 - pGstStrmOut->cTotalSamplesWritten;
264 if (!cSamplesFree)
265 return 0;
266
267 /** @todo Document / refactor this! */
268 return (((int64_t) cSamplesFree << 32) / pGstStrmOut->State.uFreqRatio) << pGstStrmOut->Props.cShift;
269}
270#endif
271
272bool drvAudioPCMPropsAreEqual(PPDMPCMPROPS pProps, PPDMAUDIOSTREAMCFG pCfg)
273{
274 int cBits = 8;
275 bool fSigned = false;
276
277 switch (pCfg->enmFormat)
278 {
279 case AUD_FMT_S8:
280 fSigned = true;
281 case AUD_FMT_U8:
282 break;
283
284 case AUD_FMT_S16:
285 fSigned = true;
286 case AUD_FMT_U16:
287 cBits = 16;
288 break;
289
290 case AUD_FMT_S32:
291 fSigned = true;
292 case AUD_FMT_U32:
293 cBits = 32;
294 break;
295
296 default:
297 AssertMsgFailed(("Unknown format %ld\n", pCfg->enmFormat));
298 break;
299 }
300
301 bool fEqual = pProps->uHz == pCfg->uHz
302 && pProps->cChannels == pCfg->cChannels
303 && pProps->fSigned == fSigned
304 && pProps->cBits == cBits
305 && pProps->fSwapEndian == !(pCfg->enmEndianness == PDMAUDIOHOSTENDIANNESS);
306
307 LogFlowFunc(("fEqual=%RTbool\n", fEqual));
308 return fEqual;
309}
310
311/**
312 * Converts an audio stream configuration to matching PCM properties.
313 *
314 * @return IPRT status code.
315 * @param pCfg Audio stream configuration to convert.
316 * @param pProps PCM properties to save result to.
317 */
318int DrvAudioStreamCfgToProps(PPDMAUDIOSTREAMCFG pCfg, PPDMPCMPROPS pProps)
319{
320 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
321 AssertPtrReturn(pProps, VERR_INVALID_POINTER);
322
323 int rc = VINF_SUCCESS;
324
325 int cBits = 8, cShift = 0;
326 bool fSigned = false;
327
328 switch (pCfg->enmFormat)
329 {
330 case AUD_FMT_S8:
331 fSigned = true;
332 case AUD_FMT_U8:
333 break;
334
335 case AUD_FMT_S16:
336 fSigned = true;
337 case AUD_FMT_U16:
338 cBits = 16;
339 cShift = 1;
340 break;
341
342 case AUD_FMT_S32:
343 fSigned = true;
344 case AUD_FMT_U32:
345 cBits = 32;
346 cShift = 2;
347 break;
348
349 default:
350 AssertMsgFailed(("Unknown format %ld\n", pCfg->enmFormat));
351 rc = VERR_NOT_SUPPORTED;
352 break;
353 }
354
355 if (RT_SUCCESS(rc))
356 {
357 pProps->uHz = pCfg->uHz;
358 pProps->cBits = cBits;
359 pProps->fSigned = fSigned;
360 pProps->cChannels = pCfg->cChannels;
361 pProps->cShift = (pCfg->cChannels == 2) + cShift;
362 pProps->uAlign = (1 << pProps->cShift) - 1;
363 pProps->cbPerSec = pProps->uHz << pProps->cShift;
364 pProps->fSwapEndian = pCfg->enmEndianness != PDMAUDIOHOSTENDIANNESS;
365 }
366
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 PDMAUDIOENDIANNESS_LITTLE:
404 LogFlow(("little\n"));
405 break;
406 case PDMAUDIOENDIANNESS_BIG:
407 LogFlow(("big\n"));
408 break;
409 default:
410 LogFlow(("invalid\n"));
411 break;
412 }
413}
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