VirtualBox

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

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

Audio: Bugfixes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.2 KB
Line 
1/* $Id: DrvAudioCommon.cpp 61177 2016-05-24 18:12:08Z 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
63
64/**
65 * Retrieves the matching PDMAUDIOFMT for given bits + signing flag.
66 *
67 * @return IPRT status code.
68 * @return PDMAUDIOFMT Resulting audio format or PDMAUDIOFMT_INVALID if invalid.
69 * @param cBits Bits to retrieve audio format for.
70 * @param fSigned Signed flag for bits to retrieve audio format for.
71 */
72PDMAUDIOFMT DrvAudioAudFmtBitsToAudFmt(uint8_t cBits, bool fSigned)
73{
74 if (fSigned)
75 {
76 switch (cBits)
77 {
78 case 8: return PDMAUDIOFMT_S8;
79 case 16: return PDMAUDIOFMT_S16;
80 case 32: return PDMAUDIOFMT_S32;
81 default: break;
82 }
83 }
84 else
85 {
86 switch (cBits)
87 {
88 case 8: return PDMAUDIOFMT_U8;
89 case 16: return PDMAUDIOFMT_U16;
90 case 32: return PDMAUDIOFMT_U32;
91 default: break;
92 }
93 }
94
95 AssertMsgFailed(("Bogus audio bits %RU8\n", cBits));
96 return PDMAUDIOFMT_INVALID;
97}
98
99/**
100 * Clears a sample buffer by the given amount of audio samples.
101 *
102 * @return IPRT status code.
103 * @param pPCMProps PCM properties to use for the buffer to clear.
104 * @param pvBuf Buffer to clear.
105 * @param cbBuf Size (in bytes) of the buffer.
106 * @param cSamples Number of audio samples to clear in the buffer.
107 */
108void DrvAudioHlpClearBuf(PPDMPCMPROPS pPCMProps, void *pvBuf, size_t cbBuf, uint32_t cSamples)
109{
110 AssertPtrReturnVoid(pPCMProps);
111 AssertPtrReturnVoid(pvBuf);
112
113 if (!cbBuf || !cSamples)
114 return;
115
116 Log2Func(("pPCMInfo=%p, pvBuf=%p, cSamples=%RU32, fSigned=%RTbool, cBits=%RU8, cShift=%RU8\n",
117 pPCMProps, pvBuf, cSamples, pPCMProps->fSigned, pPCMProps->cBits, pPCMProps->cShift));
118
119 if (pPCMProps->fSigned)
120 {
121 memset(pvBuf, 0, cSamples << pPCMProps->cShift);
122 }
123 else
124 {
125 switch (pPCMProps->cBits)
126 {
127 case 8:
128 {
129 memset(pvBuf, 0x80, cSamples << pPCMProps->cShift);
130 break;
131 }
132
133 case 16:
134 {
135 uint16_t *p = (uint16_t *)pvBuf;
136 int shift = pPCMProps->cChannels - 1;
137 short s = INT16_MAX;
138
139 if (pPCMProps->fSwapEndian)
140 s = RT_BSWAP_U16(s);
141
142 for (unsigned i = 0; i < cSamples << shift; i++)
143 p[i] = s;
144
145 break;
146 }
147
148 case 32:
149 {
150 uint32_t *p = (uint32_t *)pvBuf;
151 int shift = pPCMProps->cChannels - 1;
152 int32_t s = INT32_MAX;
153
154 if (pPCMProps->fSwapEndian)
155 s = RT_BSWAP_U32(s);
156
157 for (unsigned i = 0; i < cSamples << shift; i++)
158 p[i] = s;
159
160 break;
161 }
162
163 default:
164 {
165 AssertMsgFailed(("Invalid bits: %RU8\n", pPCMProps->cBits));
166 break;
167 }
168 }
169 }
170}
171
172const char *DrvAudioHlpRecSrcToStr(PDMAUDIORECSOURCE enmRecSrc)
173{
174 switch (enmRecSrc)
175 {
176 case PDMAUDIORECSOURCE_UNKNOWN: return "Unknown";
177 case PDMAUDIORECSOURCE_MIC: return "Microphone In";
178 case PDMAUDIORECSOURCE_CD: return "CD";
179 case PDMAUDIORECSOURCE_VIDEO: return "Video";
180 case PDMAUDIORECSOURCE_AUX: return "AUX";
181 case PDMAUDIORECSOURCE_LINE: return "Line In";
182 case PDMAUDIORECSOURCE_PHONE: return "Phone";
183 default:
184 break;
185 }
186
187 AssertMsgFailed(("Invalid recording source %ld\n", enmRecSrc));
188 return "Unknown";
189}
190
191/**
192 * Returns wether the given audio format has signed bits or not.
193 *
194 * @return IPRT status code.
195 * @return bool @true for signed bits, @false for unsigned.
196 * @param enmFmt Audio format to retrieve value for.
197 */
198bool DrvAudioHlpAudFmtIsSigned(PDMAUDIOFMT enmFmt)
199{
200 switch (enmFmt)
201 {
202 case PDMAUDIOFMT_S8:
203 case PDMAUDIOFMT_S16:
204 case PDMAUDIOFMT_S32:
205 return true;
206
207 case PDMAUDIOFMT_U8:
208 case PDMAUDIOFMT_U16:
209 case PDMAUDIOFMT_U32:
210 return false;
211
212 default:
213 break;
214 }
215
216 AssertMsgFailed(("Bogus audio format %ld\n", enmFmt));
217 return false;
218}
219
220/**
221 * Returns the bits of a given audio format.
222 *
223 * @return IPRT status code.
224 * @return uint8_t Bits of audio format.
225 * @param enmFmt Audio format to retrieve value for.
226 */
227uint8_t DrvAudioHlpAudFmtToBits(PDMAUDIOFMT enmFmt)
228{
229 switch (enmFmt)
230 {
231 case PDMAUDIOFMT_S8:
232 case PDMAUDIOFMT_U8:
233 return 8;
234
235 case PDMAUDIOFMT_U16:
236 case PDMAUDIOFMT_S16:
237 return 16;
238
239 case PDMAUDIOFMT_U32:
240 case PDMAUDIOFMT_S32:
241 return 32;
242
243 default:
244 break;
245 }
246
247 AssertMsgFailed(("Bogus audio format %ld\n", enmFmt));
248 return 0;
249}
250
251const char *DrvAudioHlpAudFmtToStr(PDMAUDIOFMT enmFmt)
252{
253 switch (enmFmt)
254 {
255 case PDMAUDIOFMT_U8:
256 return "U8";
257
258 case PDMAUDIOFMT_U16:
259 return "U16";
260
261 case PDMAUDIOFMT_U32:
262 return "U32";
263
264 case PDMAUDIOFMT_S8:
265 return "S8";
266
267 case PDMAUDIOFMT_S16:
268 return "S16";
269
270 case PDMAUDIOFMT_S32:
271 return "S32";
272
273 default:
274 break;
275 }
276
277 AssertMsgFailed(("Bogus audio format %ld\n", enmFmt));
278 return "Invalid";
279}
280
281PDMAUDIOFMT DrvAudioHlpStrToAudFmt(const char *pszFmt)
282{
283 AssertPtrReturn(pszFmt, PDMAUDIOFMT_INVALID);
284
285 if (!RTStrICmp(pszFmt, "u8"))
286 return PDMAUDIOFMT_U8;
287 else if (!RTStrICmp(pszFmt, "u16"))
288 return PDMAUDIOFMT_U16;
289 else if (!RTStrICmp(pszFmt, "u32"))
290 return PDMAUDIOFMT_U32;
291 else if (!RTStrICmp(pszFmt, "s8"))
292 return PDMAUDIOFMT_S8;
293 else if (!RTStrICmp(pszFmt, "s16"))
294 return PDMAUDIOFMT_S16;
295 else if (!RTStrICmp(pszFmt, "s32"))
296 return PDMAUDIOFMT_S32;
297
298 AssertMsgFailed(("Invalid audio format \"%s\"\n", pszFmt));
299 return PDMAUDIOFMT_INVALID;
300}
301
302bool DrvAudioHlpPCMPropsAreEqual(PPDMPCMPROPS pProps, PPDMAUDIOSTREAMCFG pCfg)
303{
304 AssertPtrReturn(pProps, false);
305 AssertPtrReturn(pCfg, false);
306
307 int cBits = 8;
308 bool fSigned = false;
309
310 switch (pCfg->enmFormat)
311 {
312 case PDMAUDIOFMT_S8:
313 fSigned = true;
314 case PDMAUDIOFMT_U8:
315 break;
316
317 case PDMAUDIOFMT_S16:
318 fSigned = true;
319 case PDMAUDIOFMT_U16:
320 cBits = 16;
321 break;
322
323 case PDMAUDIOFMT_S32:
324 fSigned = true;
325 case PDMAUDIOFMT_U32:
326 cBits = 32;
327 break;
328
329 default:
330 AssertMsgFailed(("Unknown format %ld\n", pCfg->enmFormat));
331 break;
332 }
333
334 bool fEqual = pProps->uHz == pCfg->uHz
335 && pProps->cChannels == pCfg->cChannels
336 && pProps->fSigned == fSigned
337 && pProps->cBits == cBits
338 && pProps->fSwapEndian == !(pCfg->enmEndianness == PDMAUDIOHOSTENDIANNESS);
339 return fEqual;
340}
341
342bool DrvAudioHlpPCMPropsAreEqual(PPDMPCMPROPS pProps1, PPDMPCMPROPS pProps2)
343{
344 AssertPtrReturn(pProps1, false);
345 AssertPtrReturn(pProps2, false);
346
347 return pProps1->uHz == pProps2->uHz
348 && pProps1->cChannels == pProps2->cChannels
349 && pProps1->fSigned == pProps2->fSigned
350 && pProps1->cBits == pProps2->cBits
351 && pProps1->fSwapEndian == pProps2->fSwapEndian;
352}
353
354/**
355 * Converts PCM properties to a audio stream configuration.
356 *
357 * @return IPRT status code.
358 * @param pPCMProps Pointer to PCM properties to convert.
359 * @param pCfg Pointer to audio stream configuration to store result into.
360 */
361int DrvAudioHlpPCMPropsToStreamCfg(PPDMPCMPROPS pPCMProps, PPDMAUDIOSTREAMCFG pCfg)
362{
363 AssertPtrReturn(pPCMProps, VERR_INVALID_POINTER);
364 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
365
366 pCfg->uHz = pPCMProps->uHz;
367 pCfg->cChannels = pPCMProps->cChannels;
368 pCfg->enmFormat = DrvAudioAudFmtBitsToAudFmt(pPCMProps->cBits, pPCMProps->fSigned);
369
370 /** @todo We assume little endian is the default for now. */
371 pCfg->enmEndianness = pPCMProps->fSwapEndian == false ? PDMAUDIOENDIANNESS_LITTLE : PDMAUDIOENDIANNESS_BIG;
372 return VINF_SUCCESS;
373}
374
375bool DrvAudioHlpStreamCfgIsValid(PPDMAUDIOSTREAMCFG pCfg)
376{
377 bool fValid = ( pCfg->cChannels == 1
378 || pCfg->cChannels == 2); /* Either stereo (2) or mono (1), per stream. */
379
380 fValid |= ( pCfg->enmEndianness == PDMAUDIOENDIANNESS_LITTLE
381 || pCfg->enmEndianness == PDMAUDIOENDIANNESS_BIG);
382
383 fValid |= ( pCfg->enmDir == PDMAUDIODIR_IN
384 || pCfg->enmDir == PDMAUDIODIR_OUT);
385
386 if (fValid)
387 {
388 switch (pCfg->enmFormat)
389 {
390 case PDMAUDIOFMT_S8:
391 case PDMAUDIOFMT_U8:
392 case PDMAUDIOFMT_S16:
393 case PDMAUDIOFMT_U16:
394 case PDMAUDIOFMT_S32:
395 case PDMAUDIOFMT_U32:
396 break;
397 default:
398 fValid = false;
399 break;
400 }
401 }
402
403 /** @todo Check for defined frequencies supported. */
404 fValid |= pCfg->uHz > 0;
405
406 return fValid;
407}
408
409/**
410 * Converts an audio stream configuration to matching PCM properties.
411 *
412 * @return IPRT status code.
413 * @param pCfg Audio stream configuration to convert.
414 * @param pProps PCM properties to save result to.
415 */
416int DrvAudioHlpStreamCfgToProps(PPDMAUDIOSTREAMCFG pCfg, PPDMPCMPROPS pProps)
417{
418 AssertPtrReturn(pCfg, VERR_INVALID_POINTER);
419 AssertPtrReturn(pProps, VERR_INVALID_POINTER);
420
421 int rc = VINF_SUCCESS;
422
423 int cBits = 8, cShift = 0;
424 bool fSigned = false;
425
426 switch (pCfg->enmFormat)
427 {
428 case PDMAUDIOFMT_S8:
429 fSigned = true;
430 case PDMAUDIOFMT_U8:
431 break;
432
433 case PDMAUDIOFMT_S16:
434 fSigned = true;
435 case PDMAUDIOFMT_U16:
436 cBits = 16;
437 cShift = 1;
438 break;
439
440 case PDMAUDIOFMT_S32:
441 fSigned = true;
442 case PDMAUDIOFMT_U32:
443 cBits = 32;
444 cShift = 2;
445 break;
446
447 default:
448 AssertMsgFailed(("Unknown format %ld\n", pCfg->enmFormat));
449 rc = VERR_NOT_SUPPORTED;
450 break;
451 }
452
453 if (RT_SUCCESS(rc))
454 {
455 pProps->uHz = pCfg->uHz;
456 pProps->cBits = cBits;
457 pProps->fSigned = fSigned;
458 pProps->cChannels = pCfg->cChannels;
459 pProps->cShift = (pCfg->cChannels == 2) + cShift;
460 pProps->uAlign = (1 << pProps->cShift) - 1;
461 pProps->cbPerSec = pProps->uHz << pProps->cShift;
462 pProps->fSwapEndian = pCfg->enmEndianness != PDMAUDIOHOSTENDIANNESS;
463 }
464
465 return rc;
466}
467
468void DrvAudioHlpStreamCfgPrint(PPDMAUDIOSTREAMCFG pCfg)
469{
470 AssertPtrReturnVoid(pCfg);
471
472 LogFlowFunc(("uHz=%RU32, cChannels=%RU8, enmFormat=", pCfg->uHz, pCfg->cChannels));
473
474 switch (pCfg->enmFormat)
475 {
476 case PDMAUDIOFMT_S8:
477 LogFlow(("S8"));
478 break;
479 case PDMAUDIOFMT_U8:
480 LogFlow(("U8"));
481 break;
482 case PDMAUDIOFMT_S16:
483 LogFlow(("S16"));
484 break;
485 case PDMAUDIOFMT_U16:
486 LogFlow(("U16"));
487 break;
488 case PDMAUDIOFMT_S32:
489 LogFlow(("S32"));
490 break;
491 case PDMAUDIOFMT_U32:
492 LogFlow(("U32"));
493 break;
494 default:
495 LogFlow(("invalid(%d)", pCfg->enmFormat));
496 break;
497 }
498
499 LogFlow((", endianness="));
500 switch (pCfg->enmEndianness)
501 {
502 case PDMAUDIOENDIANNESS_LITTLE:
503 LogFlow(("little\n"));
504 break;
505 case PDMAUDIOENDIANNESS_BIG:
506 LogFlow(("big\n"));
507 break;
508 default:
509 LogFlow(("invalid\n"));
510 break;
511 }
512}
513
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