VirtualBox

source: vbox/trunk/src/VBox/Devices/Audio/AudioMixBuffer.cpp@ 88037

Last change on this file since 88037 was 87936, checked in by vboxsync, 4 years ago

AudioMixBuffer: Combine the out-of-range checks in audioMixBufClipToXxxx. Mark it and it's counterpart as inline rather than callback. GCC 10 generates microscopically better code now. bugref:9890

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 70.0 KB
Line 
1/* $Id: AudioMixBuffer.cpp 87936 2021-03-03 13:14:44Z vboxsync $ */
2/** @file
3 * Audio mixing buffer for converting reading/writing audio data.
4 */
5
6/*
7 * Copyright (C) 2014-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17#define LOG_GROUP LOG_GROUP_AUDIO_MIXER_BUFFER
18#include <VBox/log.h>
19
20#if 0
21/*
22 * AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA enables dumping the raw PCM data
23 * to a file on the host. Be sure to adjust AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA_PATH
24 * to your needs before using this!
25 */
26# define AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA
27# ifdef RT_OS_WINDOWS
28# define AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA_PATH "c:\\temp\\"
29# else
30# define AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA_PATH "/tmp/"
31# endif
32/* Warning: Enabling this will generate *huge* logs! */
33//# define AUDIOMIXBUF_DEBUG_MACROS
34#endif
35
36#include <iprt/asm-math.h>
37#include <iprt/assert.h>
38#ifdef AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA
39# include <iprt/file.h>
40#endif
41#include <iprt/mem.h>
42#include <iprt/string.h> /* For RT_BZERO. */
43
44#ifdef VBOX_AUDIO_TESTCASE
45# define LOG_ENABLED
46# include <iprt/stream.h>
47#endif
48#include <VBox/err.h>
49
50#include "AudioMixBuffer.h"
51
52#ifndef VBOX_AUDIO_TESTCASE
53# ifdef DEBUG
54# define AUDMIXBUF_LOG(x) LogFlowFunc(x)
55# else
56# define AUDMIXBUF_LOG(x) do {} while (0)
57# endif
58#else /* VBOX_AUDIO_TESTCASE */
59# define AUDMIXBUF_LOG(x) RTPrintf x
60#endif
61
62#ifdef DEBUG
63DECLINLINE(void) audioMixBufDbgPrintInternal(PPDMAUDIOMIXBUF pMixBuf, const char *pszFunc);
64DECL_FORCE_INLINE(bool) audioMixBufDbgValidate(PPDMAUDIOMIXBUF pMixBuf);
65#endif
66
67/*
68 * Soft Volume Control
69 *
70 * The external code supplies an 8-bit volume (attenuation) value in the
71 * 0 .. 255 range. This represents 0 to -96dB attenuation where an input
72 * value of 0 corresponds to -96dB and 255 corresponds to 0dB (unchanged).
73 *
74 * Each step thus corresponds to 96 / 256 or 0.375dB. Every 6dB (16 steps)
75 * represents doubling the sample value.
76 *
77 * For internal use, the volume control needs to be converted to a 16-bit
78 * (sort of) exponential value between 1 and 65536. This is used with fixed
79 * point arithmetic such that 65536 means 1.0 and 1 means 1/65536.
80 *
81 * For actual volume calculation, 33.31 fixed point is used. Maximum (or
82 * unattenuated) volume is represented as 0x40000000; conveniently, this
83 * value fits into a uint32_t.
84 *
85 * To enable fast processing, the maximum volume must be a power of two
86 * and must not have a sign when converted to int32_t. While 0x80000000
87 * violates these constraints, 0x40000000 does not.
88 */
89
90
91/** Logarithmic/exponential volume conversion table. */
92static uint32_t const s_aVolumeConv[256] = {
93 1, 1, 1, 1, 1, 1, 1, 1, /* 7 */
94 1, 2, 2, 2, 2, 2, 2, 2, /* 15 */
95 2, 2, 2, 2, 2, 3, 3, 3, /* 23 */
96 3, 3, 3, 3, 4, 4, 4, 4, /* 31 */
97 4, 4, 5, 5, 5, 5, 5, 6, /* 39 */
98 6, 6, 6, 7, 7, 7, 8, 8, /* 47 */
99 8, 9, 9, 10, 10, 10, 11, 11, /* 55 */
100 12, 12, 13, 13, 14, 15, 15, 16, /* 63 */
101 17, 17, 18, 19, 20, 21, 22, 23, /* 71 */
102 24, 25, 26, 27, 28, 29, 31, 32, /* 79 */
103 33, 35, 36, 38, 40, 41, 43, 45, /* 87 */
104 47, 49, 52, 54, 56, 59, 61, 64, /* 95 */
105 67, 70, 73, 76, 79, 83, 87, 91, /* 103 */
106 95, 99, 103, 108, 112, 117, 123, 128, /* 111 */
107 134, 140, 146, 152, 159, 166, 173, 181, /* 119 */
108 189, 197, 206, 215, 225, 235, 245, 256, /* 127 */
109 267, 279, 292, 304, 318, 332, 347, 362, /* 135 */
110 378, 395, 412, 431, 450, 470, 490, 512, /* 143 */
111 535, 558, 583, 609, 636, 664, 693, 724, /* 151 */
112 756, 790, 825, 861, 899, 939, 981, 1024, /* 159 */
113 1069, 1117, 1166, 1218, 1272, 1328, 1387, 1448, /* 167 */
114 1512, 1579, 1649, 1722, 1798, 1878, 1961, 2048, /* 175 */
115 2139, 2233, 2332, 2435, 2543, 2656, 2774, 2896, /* 183 */
116 3025, 3158, 3298, 3444, 3597, 3756, 3922, 4096, /* 191 */
117 4277, 4467, 4664, 4871, 5087, 5312, 5547, 5793, /* 199 */
118 6049, 6317, 6597, 6889, 7194, 7512, 7845, 8192, /* 207 */
119 8555, 8933, 9329, 9742, 10173, 10624, 11094, 11585, /* 215 */
120 12098, 12634, 13193, 13777, 14387, 15024, 15689, 16384, /* 223 */
121 17109, 17867, 18658, 19484, 20347, 21247, 22188, 23170, /* 231 */
122 24196, 25268, 26386, 27554, 28774, 30048, 31379, 32768, /* 239 */
123 34219, 35734, 37316, 38968, 40693, 42495, 44376, 46341, /* 247 */
124 48393, 50535, 52773, 55109, 57549, 60097, 62757, 65536, /* 255 */
125};
126
127/* Bit shift for fixed point conversion. */
128#define AUDIOMIXBUF_VOL_SHIFT 30
129
130/* Internal representation of 0dB volume (1.0 in fixed point). */
131#define AUDIOMIXBUF_VOL_0DB (1 << AUDIOMIXBUF_VOL_SHIFT)
132
133AssertCompile(AUDIOMIXBUF_VOL_0DB <= 0x40000000); /* Must always hold. */
134AssertCompile(AUDIOMIXBUF_VOL_0DB == 0x40000000); /* For now -- when only attenuation is used. */
135
136
137/**
138 * Peeks for audio frames without any conversion done.
139 * This will get the raw frame data out of a mixing buffer.
140 *
141 * @return IPRT status code or VINF_AUDIO_MORE_DATA_AVAILABLE if more data is available to read.
142 *
143 * @param pMixBuf Mixing buffer to acquire audio frames from.
144 * @param cFramesToRead Number of audio frames to read.
145 * @param paFrameBuf Buffer where to store the returned audio frames.
146 * @param cFrameBuf Size (in frames) of the buffer to store audio frames into.
147 * @param pcFramesRead Returns number of read audio frames. Optional.
148 *
149 * @remark This function is not thread safe!
150 */
151int AudioMixBufPeek(PPDMAUDIOMIXBUF pMixBuf, uint32_t cFramesToRead,
152 PPDMAUDIOFRAME paFrameBuf, uint32_t cFrameBuf, uint32_t *pcFramesRead)
153{
154 AssertPtrReturn(pMixBuf, VERR_INVALID_POINTER);
155 AssertPtrReturn(paFrameBuf, VERR_INVALID_POINTER);
156 AssertReturn(cFrameBuf, VERR_INVALID_PARAMETER);
157 /* pcRead is optional. */
158
159 int rc;
160
161 if (!cFramesToRead)
162 {
163 if (pcFramesRead)
164 *pcFramesRead = 0;
165 return VINF_SUCCESS;
166 }
167
168 uint32_t cRead;
169 if (pMixBuf->offRead + cFramesToRead > pMixBuf->cFrames)
170 {
171 cRead = pMixBuf->cFrames - pMixBuf->offRead;
172 rc = VINF_AUDIO_MORE_DATA_AVAILABLE;
173 }
174 else
175 {
176 cRead = cFramesToRead;
177 rc = VINF_SUCCESS;
178 }
179
180 if (cRead > cFrameBuf)
181 {
182 cRead = cFrameBuf;
183 rc = VINF_AUDIO_MORE_DATA_AVAILABLE;
184 }
185
186 if (cRead)
187 {
188 memcpy(paFrameBuf, &pMixBuf->pFrames[pMixBuf->offRead], sizeof(PDMAUDIOFRAME) * cRead);
189
190 pMixBuf->offRead = (pMixBuf->offRead + cRead) % pMixBuf->cFrames;
191 Assert(pMixBuf->offRead <= pMixBuf->cFrames);
192 pMixBuf->cUsed -= RT_MIN(cRead, pMixBuf->cUsed);
193 }
194
195 if (pcFramesRead)
196 *pcFramesRead = cRead;
197
198 return rc;
199}
200
201/**
202 * Returns a mutable pointer to the mixing buffer's audio frame buffer for writing raw
203 * audio frames.
204 *
205 * @return IPRT status code. VINF_TRY_AGAIN for getting next pointer at beginning (circular).
206 * @param pMixBuf Mixing buffer to acquire audio frames from.
207 * @param cFrames Number of requested audio frames to write.
208 * @param ppvFrames Returns a mutable pointer to the buffer's audio frame data.
209 * @param pcFramesToWrite Number of available audio frames to write.
210 *
211 * @remark This function is not thread safe!
212 */
213int AudioMixBufPeekMutable(PPDMAUDIOMIXBUF pMixBuf, uint32_t cFrames,
214 PPDMAUDIOFRAME *ppvFrames, uint32_t *pcFramesToWrite)
215{
216 AssertPtrReturn(pMixBuf, VERR_INVALID_POINTER);
217 AssertPtrReturn(ppvFrames, VERR_INVALID_POINTER);
218 AssertPtrReturn(pcFramesToWrite, VERR_INVALID_POINTER);
219
220 int rc;
221
222 if (!cFrames)
223 {
224 *pcFramesToWrite = 0;
225 return VINF_SUCCESS;
226 }
227
228 uint32_t cFramesToWrite;
229 if (pMixBuf->offWrite + cFrames > pMixBuf->cFrames)
230 {
231 cFramesToWrite = pMixBuf->cFrames - pMixBuf->offWrite;
232 rc = VINF_TRY_AGAIN;
233 }
234 else
235 {
236 cFramesToWrite = cFrames;
237 rc = VINF_SUCCESS;
238 }
239
240 *ppvFrames = &pMixBuf->pFrames[pMixBuf->offWrite];
241 AssertPtr(ppvFrames);
242
243 pMixBuf->offWrite = (pMixBuf->offWrite + cFramesToWrite) % pMixBuf->cFrames;
244 Assert(pMixBuf->offWrite <= pMixBuf->cFrames);
245 pMixBuf->cUsed += RT_MIN(cFramesToWrite, pMixBuf->cUsed);
246
247 *pcFramesToWrite = cFramesToWrite;
248
249 return rc;
250}
251
252/**
253 * Clears the entire frame buffer.
254 *
255 * @param pMixBuf Mixing buffer to clear.
256 *
257 */
258void AudioMixBufClear(PPDMAUDIOMIXBUF pMixBuf)
259{
260 AssertPtrReturnVoid(pMixBuf);
261
262 if (pMixBuf->cFrames)
263 RT_BZERO(pMixBuf->pFrames, pMixBuf->cFrames * sizeof(PDMAUDIOFRAME));
264}
265
266/**
267 * Clears (zeroes) the buffer by a certain amount of (used) frames and
268 * keeps track to eventually assigned children buffers.
269 *
270 * @param pMixBuf Mixing buffer to clear.
271 * @param cFramesToClear Number of audio frames to clear.
272 */
273void AudioMixBufFinish(PPDMAUDIOMIXBUF pMixBuf, uint32_t cFramesToClear)
274{
275 AUDMIXBUF_LOG(("cFramesToClear=%RU32\n", cFramesToClear));
276 AUDMIXBUF_LOG(("%s: offRead=%RU32, cUsed=%RU32\n",
277 pMixBuf->pszName, pMixBuf->offRead, pMixBuf->cUsed));
278
279 AssertStmt(cFramesToClear <= pMixBuf->cFrames, cFramesToClear = pMixBuf->cFrames);
280
281 PPDMAUDIOMIXBUF pIter;
282 RTListForEach(&pMixBuf->lstChildren, pIter, PDMAUDIOMIXBUF, Node)
283 {
284 AUDMIXBUF_LOG(("\t%s: cMixed=%RU32 -> %RU32\n",
285 pIter->pszName, pIter->cMixed, pIter->cMixed - cFramesToClear));
286
287 pIter->cMixed -= RT_MIN(pIter->cMixed, cFramesToClear);
288 /* Note: Do not increment pIter->cUsed here, as this gets done when reading from that buffer using AudioMixBufReadXXX. */
289 }
290
291 uint32_t cClearOff;
292 uint32_t cClearLen;
293
294 /* Clear end of buffer (wrap around). */
295 if (cFramesToClear > pMixBuf->offRead)
296 {
297 cClearOff = pMixBuf->cFrames - (cFramesToClear - pMixBuf->offRead);
298 cClearLen = pMixBuf->cFrames - cClearOff;
299
300 AUDMIXBUF_LOG(("Clearing1: %RU32 - %RU32\n", cClearOff, cClearOff + cClearLen));
301
302 RT_BZERO(pMixBuf->pFrames + cClearOff, cClearLen * sizeof(PDMAUDIOFRAME));
303
304 Assert(cFramesToClear >= cClearLen);
305 cFramesToClear -= cClearLen;
306 }
307
308 /* Clear beginning of buffer. */
309 if ( cFramesToClear
310 && pMixBuf->offRead)
311 {
312 Assert(pMixBuf->offRead >= cFramesToClear);
313
314 cClearOff = pMixBuf->offRead - cFramesToClear;
315 cClearLen = cFramesToClear;
316
317 Assert(cClearOff + cClearLen <= pMixBuf->cFrames);
318
319 AUDMIXBUF_LOG(("Clearing2: %RU32 - %RU32\n", cClearOff, cClearOff + cClearLen));
320
321 RT_BZERO(pMixBuf->pFrames + cClearOff, cClearLen * sizeof(PDMAUDIOFRAME));
322 }
323}
324
325/**
326 * Destroys (uninitializes) a mixing buffer.
327 *
328 * @param pMixBuf Mixing buffer to destroy.
329 */
330void AudioMixBufDestroy(PPDMAUDIOMIXBUF pMixBuf)
331{
332 if (!pMixBuf)
333 return;
334
335 AudioMixBufUnlink(pMixBuf);
336
337 if (pMixBuf->pszName)
338 {
339 AUDMIXBUF_LOG(("%s\n", pMixBuf->pszName));
340
341 RTStrFree(pMixBuf->pszName);
342 pMixBuf->pszName = NULL;
343 }
344
345 if (pMixBuf->pRate)
346 {
347 RTMemFree(pMixBuf->pRate);
348 pMixBuf->pRate = NULL;
349 }
350
351 if (pMixBuf->pFrames)
352 {
353 Assert(pMixBuf->cFrames);
354
355 RTMemFree(pMixBuf->pFrames);
356 pMixBuf->pFrames = NULL;
357 }
358
359 pMixBuf->cFrames = 0;
360}
361
362/**
363 * Returns the size (in audio frames) of free audio buffer space.
364 *
365 * @return uint32_t Size (in audio frames) of free audio buffer space.
366 * @param pMixBuf Mixing buffer to return free size for.
367 */
368uint32_t AudioMixBufFree(PPDMAUDIOMIXBUF pMixBuf)
369{
370 AssertPtrReturn(pMixBuf, 0);
371
372 uint32_t cFrames, cFramesFree;
373 if (pMixBuf->pParent)
374 {
375 /*
376 * As a linked child buffer we want to know how many frames
377 * already have been consumed by the parent.
378 */
379 cFrames = pMixBuf->pParent->cFrames;
380
381 Assert(pMixBuf->cMixed <= cFrames);
382 cFramesFree = cFrames - pMixBuf->cMixed;
383 }
384 else /* As a parent. */
385 {
386 cFrames = pMixBuf->cFrames;
387 Assert(cFrames >= pMixBuf->cUsed);
388 cFramesFree = pMixBuf->cFrames - pMixBuf->cUsed;
389 }
390
391 AUDMIXBUF_LOG(("%s: %RU32 of %RU32\n", pMixBuf->pszName, cFramesFree, cFrames));
392 return cFramesFree;
393}
394
395/**
396 * Returns the size (in bytes) of free audio buffer space.
397 *
398 * @return uint32_t Size (in bytes) of free audio buffer space.
399 * @param pMixBuf Mixing buffer to return free size for.
400 */
401uint32_t AudioMixBufFreeBytes(PPDMAUDIOMIXBUF pMixBuf)
402{
403 return AUDIOMIXBUF_F2B(pMixBuf, AudioMixBufFree(pMixBuf));
404}
405
406/**
407 * Allocates the internal audio frame buffer.
408 *
409 * @return IPRT status code.
410 * @param pMixBuf Mixing buffer to allocate frame buffer for.
411 * @param cFrames Number of audio frames to allocate.
412 */
413static int audioMixBufAlloc(PPDMAUDIOMIXBUF pMixBuf, uint32_t cFrames)
414{
415 AssertPtrReturn(pMixBuf, VERR_INVALID_POINTER);
416 AssertReturn(cFrames, VERR_INVALID_PARAMETER);
417
418 AUDMIXBUF_LOG(("%s: cFrames=%RU32\n", pMixBuf->pszName, cFrames));
419
420 size_t cbFrames = cFrames * sizeof(PDMAUDIOFRAME);
421 pMixBuf->pFrames = (PPDMAUDIOFRAME)RTMemAllocZ(cbFrames);
422 if (pMixBuf->pFrames)
423 {
424 pMixBuf->cFrames = cFrames;
425 return VINF_SUCCESS;
426 }
427 return VERR_NO_MEMORY;
428}
429
430#ifdef AUDIOMIXBUF_DEBUG_MACROS
431# define AUDMIXBUF_MACRO_LOG(x) AUDMIXBUF_LOG(x)
432#elif defined(VBOX_AUDIO_TESTCASE_VERBOSE) /* Warning: VBOX_AUDIO_TESTCASE_VERBOSE will generate huge logs! */
433# define AUDMIXBUF_MACRO_LOG(x) RTPrintf x
434#else
435# define AUDMIXBUF_MACRO_LOG(x) do {} while (0)
436#endif
437
438/**
439 * Macro for generating the conversion routines from/to different formats.
440 * Be careful what to pass in/out, as most of the macros are optimized for speed and
441 * thus don't do any bounds checking!
442 *
443 * Note: Currently does not handle any endianness conversion yet!
444 */
445#define AUDMIXBUF_CONVERT(_aName, _aType, _aMin, _aMax, _aSigned, _aShift) \
446 /* Clips a specific output value to a single sample value. */ \
447 DECLINLINE(int64_t) audioMixBufClipFrom##_aName(_aType aVal) \
448 { \
449 /* left shifting of signed values is not defined, therefore the intermediate uint64_t cast */ \
450 if (_aSigned) \
451 return (int64_t) (((uint64_t) ((int64_t) aVal )) << (32 - _aShift)); \
452 return (int64_t) (((uint64_t) ((int64_t) aVal - ((_aMax >> 1) + 1))) << (32 - _aShift)); \
453 } \
454 \
455 /* Clips a single sample value to a specific output value. */ \
456 DECLINLINE(_aType) audioMixBufClipTo##_aName(int64_t iVal) \
457 { \
458 /*if (iVal >= 0x7fffffff) return _aMax; if (iVal < -INT64_C(0x80000000)) return _aMin;*/ \
459 if (!(((uint64_t)iVal + UINT64_C(0x80000000)) & UINT64_C(0xffffffff00000000))) \
460 { \
461 if (_aSigned) \
462 return (_aType) (iVal >> (32 - _aShift)); \
463 return (_aType) ((iVal >> (32 - _aShift)) + ((_aMax >> 1) + 1)); \
464 } \
465 return iVal >= 0 ? _aMax : _aMin; \
466 } \
467 \
468 DECLCALLBACK(uint32_t) audioMixBufConvFrom##_aName##Stereo(PPDMAUDIOFRAME paDst, const void *pvSrc, uint32_t cbSrc, \
469 PCPDMAUDMIXBUFCONVOPTS pOpts) \
470 { \
471 _aType const *pSrc = (_aType const *)pvSrc; \
472 uint32_t cFrames = RT_MIN(pOpts->cFrames, cbSrc / sizeof(_aType)); \
473 AUDMIXBUF_MACRO_LOG(("cFrames=%RU32, BpS=%zu, lVol=%RU32, rVol=%RU32\n", \
474 pOpts->cFrames, sizeof(_aType), pOpts->From.Volume.uLeft, pOpts->From.Volume.uRight)); \
475 for (uint32_t i = 0; i < cFrames; i++) \
476 { \
477 paDst->i64LSample = ASMMult2xS32RetS64((int32_t)audioMixBufClipFrom##_aName(*pSrc++), pOpts->From.Volume.uLeft ) >> AUDIOMIXBUF_VOL_SHIFT; \
478 paDst->i64RSample = ASMMult2xS32RetS64((int32_t)audioMixBufClipFrom##_aName(*pSrc++), pOpts->From.Volume.uRight) >> AUDIOMIXBUF_VOL_SHIFT; \
479 paDst++; \
480 } \
481 \
482 return cFrames; \
483 } \
484 \
485 DECLCALLBACK(uint32_t) audioMixBufConvFrom##_aName##Mono(PPDMAUDIOFRAME paDst, const void *pvSrc, uint32_t cbSrc, \
486 PCPDMAUDMIXBUFCONVOPTS pOpts) \
487 { \
488 _aType const *pSrc = (_aType const *)pvSrc; \
489 const uint32_t cFrames = RT_MIN(pOpts->cFrames, cbSrc / sizeof(_aType)); \
490 AUDMIXBUF_MACRO_LOG(("cFrames=%RU32, BpS=%zu, lVol=%RU32, rVol=%RU32\n", \
491 cFrames, sizeof(_aType), pOpts->From.Volume.uLeft, pOpts->From.Volume.uRight)); \
492 for (uint32_t i = 0; i < cFrames; i++) \
493 { \
494 paDst->i64LSample = ASMMult2xS32RetS64((int32_t)audioMixBufClipFrom##_aName(*pSrc), pOpts->From.Volume.uLeft) >> AUDIOMIXBUF_VOL_SHIFT; \
495 paDst->i64RSample = ASMMult2xS32RetS64((int32_t)audioMixBufClipFrom##_aName(*pSrc), pOpts->From.Volume.uRight) >> AUDIOMIXBUF_VOL_SHIFT; \
496 pSrc++; \
497 paDst++; \
498 } \
499 \
500 return cFrames; \
501 } \
502 \
503 DECLCALLBACK(void) audioMixBufConvTo##_aName##Stereo(void *pvDst, PCPDMAUDIOFRAME paSrc, PCPDMAUDMIXBUFCONVOPTS pOpts) \
504 { \
505 PCPDMAUDIOFRAME pSrc = paSrc; \
506 _aType *pDst = (_aType *)pvDst; \
507 uint32_t cFrames = pOpts->cFrames; \
508 while (cFrames--) \
509 { \
510 AUDMIXBUF_MACRO_LOG(("%p: l=%RI64, r=%RI64\n", pSrc, pSrc->i64LSample, pSrc->i64RSample)); \
511 pDst[0] = audioMixBufClipTo##_aName(pSrc->i64LSample); \
512 pDst[1] = audioMixBufClipTo##_aName(pSrc->i64RSample); \
513 AUDMIXBUF_MACRO_LOG(("\t-> l=%RI16, r=%RI16\n", pDst[0], pDst[1])); \
514 pDst += 2; \
515 pSrc++; \
516 } \
517 } \
518 \
519 DECLCALLBACK(void) audioMixBufConvTo##_aName##Mono(void *pvDst, PCPDMAUDIOFRAME paSrc, PCPDMAUDMIXBUFCONVOPTS pOpts) \
520 { \
521 PCPDMAUDIOFRAME pSrc = paSrc; \
522 _aType *pDst = (_aType *)pvDst; \
523 uint32_t cFrames = pOpts->cFrames; \
524 while (cFrames--) \
525 { \
526 *pDst++ = audioMixBufClipTo##_aName((pSrc->i64LSample + pSrc->i64RSample) / 2); \
527 pSrc++; \
528 } \
529 }
530
531/* audioMixBufConvXXXS8: 8 bit, signed. */
532AUDMIXBUF_CONVERT(S8 /* Name */, int8_t, INT8_MIN /* Min */, INT8_MAX /* Max */, true /* fSigned */, 8 /* cShift */)
533/* audioMixBufConvXXXU8: 8 bit, unsigned. */
534AUDMIXBUF_CONVERT(U8 /* Name */, uint8_t, 0 /* Min */, UINT8_MAX /* Max */, false /* fSigned */, 8 /* cShift */)
535/* audioMixBufConvXXXS16: 16 bit, signed. */
536AUDMIXBUF_CONVERT(S16 /* Name */, int16_t, INT16_MIN /* Min */, INT16_MAX /* Max */, true /* fSigned */, 16 /* cShift */)
537/* audioMixBufConvXXXU16: 16 bit, unsigned. */
538AUDMIXBUF_CONVERT(U16 /* Name */, uint16_t, 0 /* Min */, UINT16_MAX /* Max */, false /* fSigned */, 16 /* cShift */)
539/* audioMixBufConvXXXS32: 32 bit, signed. */
540AUDMIXBUF_CONVERT(S32 /* Name */, int32_t, INT32_MIN /* Min */, INT32_MAX /* Max */, true /* fSigned */, 32 /* cShift */)
541/* audioMixBufConvXXXU32: 32 bit, unsigned. */
542AUDMIXBUF_CONVERT(U32 /* Name */, uint32_t, 0 /* Min */, UINT32_MAX /* Max */, false /* fSigned */, 32 /* cShift */)
543
544#undef AUDMIXBUF_CONVERT
545
546#define AUDMIXBUF_MIXOP(_aName, _aOp) \
547 static void audioMixBufOp##_aName(PPDMAUDIOFRAME paDst, uint32_t cDstFrames, \
548 PPDMAUDIOFRAME paSrc, uint32_t cSrcFrames, \
549 PPDMAUDIOSTREAMRATE pRate, \
550 uint32_t *pcDstWritten, uint32_t *pcSrcRead) \
551 { \
552 AUDMIXBUF_MACRO_LOG(("cSrcFrames=%RU32, cDstFrames=%RU32\n", cSrcFrames, cDstFrames)); \
553 AUDMIXBUF_MACRO_LOG(("Rate: offSrc=%RU32, offDst=%RU32, uDstInc=%RU32\n", \
554 pRate->offSrc, \
555 (uint32_t)(pRate->offDst >> 32), (uint32_t)(pRate->uDstInc >> 32))); \
556 \
557 if (pRate->uDstInc == (UINT64_C(1) + UINT32_MAX)) /* No conversion needed? */ \
558 { \
559 uint32_t cFrames = RT_MIN(cSrcFrames, cDstFrames); \
560 AUDMIXBUF_MACRO_LOG(("cFrames=%RU32\n", cFrames)); \
561 for (uint32_t i = 0; i < cFrames; i++) \
562 { \
563 paDst[i].i64LSample _aOp paSrc[i].i64LSample; \
564 paDst[i].i64RSample _aOp paSrc[i].i64RSample; \
565 } \
566 \
567 if (pcDstWritten) \
568 *pcDstWritten = cFrames; \
569 if (pcSrcRead) \
570 *pcSrcRead = cFrames; \
571 return; \
572 } \
573 \
574 PPDMAUDIOFRAME paSrcStart = paSrc; \
575 PPDMAUDIOFRAME paSrcEnd = paSrc + cSrcFrames; \
576 PPDMAUDIOFRAME paDstStart = paDst; \
577 PPDMAUDIOFRAME paDstEnd = paDst + cDstFrames; \
578 PDMAUDIOFRAME frameCur = { 0 }; \
579 PDMAUDIOFRAME frameOut; \
580 PDMAUDIOFRAME frameLast = pRate->SrcFrameLast; \
581 \
582 while (paDst < paDstEnd) \
583 { \
584 Assert(paSrc <= paSrcEnd); \
585 Assert(paDst <= paDstEnd); \
586 if (paSrc >= paSrcEnd) \
587 break; \
588 \
589 while (pRate->offSrc <= (pRate->offDst >> 32)) \
590 { \
591 Assert(paSrc <= paSrcEnd); \
592 frameLast = *paSrc++; \
593 pRate->offSrc++; \
594 if (paSrc == paSrcEnd) \
595 break; \
596 } \
597 \
598 Assert(paSrc <= paSrcEnd); \
599 if (paSrc == paSrcEnd) \
600 break; \
601 \
602 frameCur = *paSrc; \
603 \
604 /* Interpolate. */ \
605 int64_t iDstOffInt = pRate->offDst & UINT32_MAX; \
606 \
607 frameOut.i64LSample = (frameLast.i64LSample * ((int64_t) (INT64_C(1) << 32) - iDstOffInt) + frameCur.i64LSample * iDstOffInt) >> 32; \
608 frameOut.i64RSample = (frameLast.i64RSample * ((int64_t) (INT64_C(1) << 32) - iDstOffInt) + frameCur.i64RSample * iDstOffInt) >> 32; \
609 \
610 paDst->i64LSample _aOp frameOut.i64LSample; \
611 paDst->i64RSample _aOp frameOut.i64RSample; \
612 \
613 AUDMIXBUF_MACRO_LOG(("\tiDstOffInt=%RI64, l=%RI64, r=%RI64 (cur l=%RI64, r=%RI64)\n", \
614 iDstOffInt, \
615 paDst->i64LSample >> 32, paDst->i64RSample >> 32, \
616 frameCur.i64LSample >> 32, frameCur.i64RSample >> 32)); \
617 \
618 paDst++; \
619 pRate->offDst += pRate->uDstInc; \
620 \
621 AUDMIXBUF_MACRO_LOG(("\t\tpRate->offDst=%RU32\n", pRate->offDst >> 32)); \
622 \
623 } \
624 \
625 AUDMIXBUF_MACRO_LOG(("%zu source frames -> %zu dest frames\n", paSrc - paSrcStart, paDst - paDstStart)); \
626 \
627 pRate->SrcFrameLast = frameLast; \
628 \
629 AUDMIXBUF_MACRO_LOG(("pRate->srcSampleLast l=%RI64, r=%RI64\n", \
630 pRate->SrcFrameLast.i64LSample, pRate->SrcFrameLast.i64RSample)); \
631 \
632 if (pcDstWritten) \
633 *pcDstWritten = paDst - paDstStart; \
634 if (pcSrcRead) \
635 *pcSrcRead = paSrc - paSrcStart; \
636 }
637
638/* audioMixBufOpAssign: Assigns values from source buffer to destination bufffer, overwriting the destination. */
639AUDMIXBUF_MIXOP(Assign /* Name */, = /* Operation */)
640#if 0 /* unused */
641/* audioMixBufOpBlend: Blends together the values from both, the source and the destination buffer. */
642AUDMIXBUF_MIXOP(Blend /* Name */, += /* Operation */)
643#endif
644
645#undef AUDMIXBUF_MIXOP
646#undef AUDMIXBUF_MACRO_LOG
647
648/** Dummy conversion used when the source is muted. */
649static DECLCALLBACK(uint32_t)
650audioMixBufConvFromSilence(PPDMAUDIOFRAME paDst, const void *pvSrc, uint32_t cbSrc, PCPDMAUDMIXBUFCONVOPTS pOpts)
651{
652 RT_NOREF(cbSrc, pvSrc);
653
654 /* Internally zero always corresponds to silence. */
655 RT_BZERO(paDst, pOpts->cFrames * sizeof(paDst[0]));
656 return pOpts->cFrames;
657}
658
659/**
660 * Looks up the matching conversion (macro) routine for converting
661 * audio frames from a source format.
662 *
663 ** @todo Speed up the lookup by binding it to the actual stream state.
664 *
665 * @return PAUDMIXBUF_FN_CONVFROM Function pointer to conversion macro if found, NULL if not supported.
666 * @param enmFmt Audio format to lookup conversion macro for.
667 */
668static PFNPDMAUDIOMIXBUFCONVFROM audioMixBufConvFromLookup(PDMAUDIOMIXBUFFMT enmFmt)
669{
670 if (AUDMIXBUF_FMT_SIGNED(enmFmt))
671 {
672 if (AUDMIXBUF_FMT_CHANNELS(enmFmt) == 2)
673 {
674 switch (AUDMIXBUF_FMT_BITS_PER_SAMPLE(enmFmt))
675 {
676 case 8: return audioMixBufConvFromS8Stereo;
677 case 16: return audioMixBufConvFromS16Stereo;
678 case 32: return audioMixBufConvFromS32Stereo;
679 default: return NULL;
680 }
681 }
682 else
683 {
684 switch (AUDMIXBUF_FMT_BITS_PER_SAMPLE(enmFmt))
685 {
686 case 8: return audioMixBufConvFromS8Mono;
687 case 16: return audioMixBufConvFromS16Mono;
688 case 32: return audioMixBufConvFromS32Mono;
689 default: return NULL;
690 }
691 }
692 }
693 else /* Unsigned */
694 {
695 if (AUDMIXBUF_FMT_CHANNELS(enmFmt) == 2)
696 {
697 switch (AUDMIXBUF_FMT_BITS_PER_SAMPLE(enmFmt))
698 {
699 case 8: return audioMixBufConvFromU8Stereo;
700 case 16: return audioMixBufConvFromU16Stereo;
701 case 32: return audioMixBufConvFromU32Stereo;
702 default: return NULL;
703 }
704 }
705 else
706 {
707 switch (AUDMIXBUF_FMT_BITS_PER_SAMPLE(enmFmt))
708 {
709 case 8: return audioMixBufConvFromU8Mono;
710 case 16: return audioMixBufConvFromU16Mono;
711 case 32: return audioMixBufConvFromU32Mono;
712 default: return NULL;
713 }
714 }
715 }
716 /* not reached */
717}
718
719/**
720 * Looks up the matching conversion (macro) routine for converting
721 * audio frames to a destination format.
722 *
723 ** @todo Speed up the lookup by binding it to the actual stream state.
724 *
725 * @return PAUDMIXBUF_FN_CONVTO Function pointer to conversion macro if found, NULL if not supported.
726 * @param enmFmt Audio format to lookup conversion macro for.
727 */
728static PFNPDMAUDIOMIXBUFCONVTO audioMixBufConvToLookup(PDMAUDIOMIXBUFFMT enmFmt)
729{
730 if (AUDMIXBUF_FMT_SIGNED(enmFmt))
731 {
732 if (AUDMIXBUF_FMT_CHANNELS(enmFmt) == 2)
733 {
734 switch (AUDMIXBUF_FMT_BITS_PER_SAMPLE(enmFmt))
735 {
736 case 8: return audioMixBufConvToS8Stereo;
737 case 16: return audioMixBufConvToS16Stereo;
738 case 32: return audioMixBufConvToS32Stereo;
739 default: return NULL;
740 }
741 }
742 else
743 {
744 switch (AUDMIXBUF_FMT_BITS_PER_SAMPLE(enmFmt))
745 {
746 case 8: return audioMixBufConvToS8Mono;
747 case 16: return audioMixBufConvToS16Mono;
748 case 32: return audioMixBufConvToS32Mono;
749 default: return NULL;
750 }
751 }
752 }
753 else /* Unsigned */
754 {
755 if (AUDMIXBUF_FMT_CHANNELS(enmFmt) == 2)
756 {
757 switch (AUDMIXBUF_FMT_BITS_PER_SAMPLE(enmFmt))
758 {
759 case 8: return audioMixBufConvToU8Stereo;
760 case 16: return audioMixBufConvToU16Stereo;
761 case 32: return audioMixBufConvToU32Stereo;
762 default: return NULL;
763 }
764 }
765 else
766 {
767 switch (AUDMIXBUF_FMT_BITS_PER_SAMPLE(enmFmt))
768 {
769 case 8: return audioMixBufConvToU8Mono;
770 case 16: return audioMixBufConvToU16Mono;
771 case 32: return audioMixBufConvToU32Mono;
772 default: return NULL;
773 }
774 }
775 }
776 /* not reached */
777}
778
779/**
780 * Converts a PDM audio volume to an internal mixing buffer volume.
781 *
782 * @returns IPRT status code.
783 * @param pVolDst Where to store the converted mixing buffer volume.
784 * @param pVolSrc Volume to convert.
785 */
786static int audioMixBufConvVol(PPDMAUDMIXBUFVOL pVolDst, PPDMAUDIOVOLUME pVolSrc)
787{
788 if (!pVolSrc->fMuted) /* Only change/convert the volume value if we're not muted. */
789 {
790 uint8_t uVolL = pVolSrc->uLeft & 0xFF;
791 uint8_t uVolR = pVolSrc->uRight & 0xFF;
792
793 /** @todo Ensure that the input is in the correct range/initialized! */
794 pVolDst->uLeft = s_aVolumeConv[uVolL] * (AUDIOMIXBUF_VOL_0DB >> 16);
795 pVolDst->uRight = s_aVolumeConv[uVolR] * (AUDIOMIXBUF_VOL_0DB >> 16);
796 }
797
798 pVolDst->fMuted = pVolSrc->fMuted;
799
800 return VINF_SUCCESS;
801}
802
803/**
804 * Initializes a mixing buffer.
805 *
806 * @return IPRT status code.
807 * @param pMixBuf Mixing buffer to initialize.
808 * @param pszName Name of mixing buffer for easier identification. Optional.
809 * @param pProps PCM audio properties to use for the mixing buffer.
810 * @param cFrames Maximum number of audio frames the mixing buffer can hold.
811 */
812int AudioMixBufInit(PPDMAUDIOMIXBUF pMixBuf, const char *pszName, PPDMAUDIOPCMPROPS pProps, uint32_t cFrames)
813{
814 AssertPtrReturn(pMixBuf, VERR_INVALID_POINTER);
815 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
816 AssertPtrReturn(pProps, VERR_INVALID_POINTER);
817
818 pMixBuf->pParent = NULL;
819
820 RTListInit(&pMixBuf->lstChildren);
821 pMixBuf->cChildren = 0;
822
823 pMixBuf->pFrames = NULL;
824 pMixBuf->cFrames = 0;
825
826 pMixBuf->offRead = 0;
827 pMixBuf->offWrite = 0;
828 pMixBuf->cMixed = 0;
829 pMixBuf->cUsed = 0;
830
831 /* Set initial volume to max. */
832 pMixBuf->Volume.fMuted = false;
833 pMixBuf->Volume.uLeft = AUDIOMIXBUF_VOL_0DB;
834 pMixBuf->Volume.uRight = AUDIOMIXBUF_VOL_0DB;
835
836 /* Prevent division by zero.
837 * Do a 1:1 conversion according to AUDIOMIXBUF_S2B_RATIO. */
838 pMixBuf->iFreqRatio = 1 << 20;
839
840 pMixBuf->pRate = NULL;
841
842 pMixBuf->uAudioFmt = AUDMIXBUF_AUDIO_FMT_MAKE(pProps->uHz,
843 pProps->cChannels,
844 pProps->cbSample * 8 /* Bit */,
845 pProps->fSigned);
846
847 pMixBuf->pfnConvFrom = audioMixBufConvFromLookup(pMixBuf->uAudioFmt);
848 pMixBuf->pfnConvTo = audioMixBufConvToLookup(pMixBuf->uAudioFmt);
849
850 pMixBuf->cShift = pProps->cShift;
851 pMixBuf->pszName = RTStrDup(pszName);
852 if (!pMixBuf->pszName)
853 return VERR_NO_MEMORY;
854
855 AUDMIXBUF_LOG(("%s: uHz=%RU32, cChan=%RU8, cBits=%RU8, fSigned=%RTbool\n",
856 pMixBuf->pszName,
857 AUDMIXBUF_FMT_SAMPLE_FREQ(pMixBuf->uAudioFmt),
858 AUDMIXBUF_FMT_CHANNELS(pMixBuf->uAudioFmt),
859 AUDMIXBUF_FMT_BITS_PER_SAMPLE(pMixBuf->uAudioFmt),
860 RT_BOOL(AUDMIXBUF_FMT_SIGNED(pMixBuf->uAudioFmt))));
861
862 return audioMixBufAlloc(pMixBuf, cFrames);
863}
864
865/**
866 * Returns @c true if there are any audio frames available for processing,
867 * @c false if not.
868 *
869 * @return bool @c true if there are any audio frames available for processing, @c false if not.
870 * @param pMixBuf Mixing buffer to return value for.
871 */
872bool AudioMixBufIsEmpty(PPDMAUDIOMIXBUF pMixBuf)
873{
874 AssertPtrReturn(pMixBuf, true);
875
876 if (pMixBuf->pParent)
877 return (pMixBuf->cMixed == 0);
878 return (pMixBuf->cUsed == 0);
879}
880
881/**
882 * Calculates the frequency (sample rate) ratio of mixing buffer A in relation to mixing buffer B.
883 *
884 * @returns Calculated frequency ratio.
885 * @param pMixBufA First mixing buffer.
886 * @param pMixBufB Second mixing buffer.
887 */
888static int64_t audioMixBufCalcFreqRatio(PPDMAUDIOMIXBUF pMixBufA, PPDMAUDIOMIXBUF pMixBufB)
889{
890 int64_t iRatio = ((int64_t)AUDMIXBUF_FMT_SAMPLE_FREQ(pMixBufA->uAudioFmt) << 32)
891 / AUDMIXBUF_FMT_SAMPLE_FREQ(pMixBufB->uAudioFmt);
892
893 if (iRatio == 0) /* Catch division by zero. */
894 iRatio = 1 << 20; /* Do a 1:1 conversion instead. */
895
896 return iRatio;
897}
898
899/**
900 * Links an audio mixing buffer to a parent mixing buffer. A parent mixing
901 * buffer can have multiple children mixing buffers [1:N], whereas a child only can
902 * have one parent mixing buffer [N:1].
903 *
904 * The mixing direction always goes from the child/children buffer(s) to the
905 * parent buffer.
906 *
907 * For guest audio output the host backend owns the parent mixing buffer, the
908 * device emulation owns the child/children.
909 *
910 * The audio format of each mixing buffer can vary; the internal mixing code
911 * then will automatically do the (needed) conversion.
912 *
913 * @return IPRT status code.
914 * @param pMixBuf Mixing buffer to link parent to.
915 * @param pParent Parent mixing buffer to use for linking.
916 *
917 * @remark Circular linking is not allowed.
918 */
919int AudioMixBufLinkTo(PPDMAUDIOMIXBUF pMixBuf, PPDMAUDIOMIXBUF pParent)
920{
921 AssertPtrReturn(pMixBuf, VERR_INVALID_POINTER);
922 AssertPtrReturn(pParent, VERR_INVALID_POINTER);
923
924 AssertMsgReturn(AUDMIXBUF_FMT_SAMPLE_FREQ(pParent->uAudioFmt),
925 ("Parent frame frequency (Hz) not set\n"), VERR_INVALID_PARAMETER);
926 AssertMsgReturn(AUDMIXBUF_FMT_SAMPLE_FREQ(pMixBuf->uAudioFmt),
927 ("Buffer sample frequency (Hz) not set\n"), VERR_INVALID_PARAMETER);
928 AssertMsgReturn(pMixBuf != pParent,
929 ("Circular linking not allowed\n"), VERR_INVALID_PARAMETER);
930
931 if (pMixBuf->pParent) /* Already linked? */
932 {
933 AUDMIXBUF_LOG(("%s: Already linked to parent '%s'\n",
934 pMixBuf->pszName, pMixBuf->pParent->pszName));
935 return VERR_ACCESS_DENIED;
936 }
937
938 RTListAppend(&pParent->lstChildren, &pMixBuf->Node);
939 pParent->cChildren++;
940
941 /* Set the parent. */
942 pMixBuf->pParent = pParent;
943
944 /* Calculate the frequency ratios. */
945 pMixBuf->iFreqRatio = audioMixBufCalcFreqRatio(pParent, pMixBuf);
946
947 int rc = VINF_SUCCESS;
948#if 0
949 uint32_t cFrames = (uint32_t)RT_MIN( ((uint64_t)pParent->cFrames << 32)
950 / pMixBuf->iFreqRatio, _64K /* 64K frames max. */);
951 if (!cFrames)
952 cFrames = pParent->cFrames;
953
954 int rc = VINF_SUCCESS;
955
956 if (cFrames != pMixBuf->cFrames)
957 {
958 AUDMIXBUF_LOG(("%s: Reallocating frames %RU32 -> %RU32\n",
959 pMixBuf->pszName, pMixBuf->cFrames, cFrames));
960
961 uint32_t cbSamples = cFrames * sizeof(PDMAUDIOSAMPLE);
962 Assert(cbSamples);
963 pMixBuf->pSamples = (PPDMAUDIOSAMPLE)RTMemRealloc(pMixBuf->pSamples, cbSamples);
964 if (!pMixBuf->pSamples)
965 rc = VERR_NO_MEMORY;
966
967 if (RT_SUCCESS(rc))
968 {
969 pMixBuf->cFrames = cFrames;
970
971 /* Make sure to zero the reallocated buffer so that it can be
972 * used properly when blending with another buffer later. */
973 RT_BZERO(pMixBuf->pSamples, cbSamples);
974 }
975 }
976#endif
977
978 if (RT_SUCCESS(rc))
979 {
980 if (!pMixBuf->pRate)
981 {
982 /* Create rate conversion. */
983 pMixBuf->pRate = (PPDMAUDIOSTREAMRATE)RTMemAllocZ(sizeof(PDMAUDIOSTREAMRATE));
984 if (!pMixBuf->pRate)
985 return VERR_NO_MEMORY;
986 }
987 else
988 RT_BZERO(pMixBuf->pRate, sizeof(PDMAUDIOSTREAMRATE));
989
990 pMixBuf->pRate->uDstInc = ((uint64_t)AUDMIXBUF_FMT_SAMPLE_FREQ(pMixBuf->uAudioFmt) << 32)
991 / AUDMIXBUF_FMT_SAMPLE_FREQ(pParent->uAudioFmt);
992
993 AUDMIXBUF_LOG(("uThisHz=%RU32, uParentHz=%RU32, iFreqRatio=0x%RX64 (%RI64), uRateInc=0x%RX64 (%RU64), cFrames=%RU32 (%RU32 parent)\n",
994 AUDMIXBUF_FMT_SAMPLE_FREQ(pMixBuf->uAudioFmt),
995 AUDMIXBUF_FMT_SAMPLE_FREQ(pParent->uAudioFmt),
996 pMixBuf->iFreqRatio, pMixBuf->iFreqRatio,
997 pMixBuf->pRate->uDstInc, pMixBuf->pRate->uDstInc,
998 pMixBuf->cFrames,
999 pParent->cFrames));
1000 AUDMIXBUF_LOG(("%s (%RU32Hz) -> %s (%RU32Hz)\n",
1001 pMixBuf->pszName, AUDMIXBUF_FMT_SAMPLE_FREQ(pMixBuf->uAudioFmt),
1002 pMixBuf->pParent->pszName, AUDMIXBUF_FMT_SAMPLE_FREQ(pParent->uAudioFmt)));
1003 }
1004
1005 return rc;
1006}
1007
1008/**
1009 * Returns number of available live frames, that is, frames that
1010 * have been written into the mixing buffer but not have been processed yet.
1011 *
1012 * For a parent buffer, this simply returns the currently used number of frames
1013 * in the buffer.
1014 *
1015 * For a child buffer, this returns the number of frames which have been mixed
1016 * to the parent and were not processed by the parent yet.
1017 *
1018 * @return uint32_t Number of live frames available.
1019 * @param pMixBuf Mixing buffer to return value for.
1020 */
1021uint32_t AudioMixBufLive(PPDMAUDIOMIXBUF pMixBuf)
1022{
1023 AssertPtrReturn(pMixBuf, 0);
1024
1025#ifdef RT_STRICT
1026 uint32_t cFrames;
1027#endif
1028 uint32_t cAvail;
1029 if (pMixBuf->pParent) /* Is this a child buffer? */
1030 {
1031#ifdef RT_STRICT
1032 /* Use the frame count from the parent, as
1033 * pMixBuf->cMixed specifies the frame count
1034 * in parent frames. */
1035 cFrames = pMixBuf->pParent->cFrames;
1036#endif
1037 cAvail = pMixBuf->cMixed;
1038 }
1039 else
1040 {
1041#ifdef RT_STRICT
1042 cFrames = pMixBuf->cFrames;
1043#endif
1044 cAvail = pMixBuf->cUsed;
1045 }
1046
1047 Assert(cAvail <= cFrames);
1048 return cAvail;
1049}
1050
1051/**
1052 * Mixes audio frames from a source mixing buffer to a destination mixing buffer.
1053 *
1054 * @return IPRT status code.
1055 * VERR_BUFFER_UNDERFLOW if the source did not have enough audio data.
1056 * VERR_BUFFER_OVERFLOW if the destination did not have enough space to store the converted source audio data.
1057 *
1058 * @param pDst Destination mixing buffer.
1059 * @param pSrc Source mixing buffer.
1060 * @param cSrcOff Offset of source audio frames to mix.
1061 * @param cSrcFrames Number of source audio frames to mix.
1062 * @param pcSrcMixed Number of source audio frames successfully mixed. Optional.
1063 */
1064static int audioMixBufMixTo(PPDMAUDIOMIXBUF pDst, PPDMAUDIOMIXBUF pSrc, uint32_t cSrcOff, uint32_t cSrcFrames,
1065 uint32_t *pcSrcMixed)
1066{
1067 AssertPtrReturn(pDst, VERR_INVALID_POINTER);
1068 AssertPtrReturn(pSrc, VERR_INVALID_POINTER);
1069 /* pcSrcMixed is optional. */
1070
1071 AssertMsgReturn(pDst == pSrc->pParent, ("Source buffer '%s' is not a child of destination '%s'\n",
1072 pSrc->pszName, pDst->pszName), VERR_INVALID_PARAMETER);
1073 uint32_t cReadTotal = 0;
1074 uint32_t cWrittenTotal = 0;
1075
1076 Assert(pSrc->cMixed <= pDst->cFrames);
1077
1078 Assert(pSrc->cUsed >= pDst->cMixed);
1079 Assert(pDst->cUsed <= pDst->cFrames);
1080
1081 uint32_t offSrcRead = cSrcOff;
1082
1083 uint32_t offDstWrite = pDst->offWrite;
1084 uint32_t cDstMixed = pSrc->cMixed;
1085
1086 uint32_t cSrcAvail = RT_MIN(cSrcFrames, pSrc->cUsed);
1087 uint32_t cDstAvail = pDst->cFrames - pDst->cUsed; /** @todo Use pDst->cMixed later? */
1088
1089 AUDMIXBUF_LOG(("%s (%RU32 available) -> %s (%RU32 available)\n",
1090 pSrc->pszName, cSrcAvail, pDst->pszName, cDstAvail));
1091#ifdef DEBUG
1092 audioMixBufDbgPrintInternal(pDst, __FUNCTION__);
1093#endif
1094
1095 if (!cSrcAvail)
1096 return VERR_BUFFER_UNDERFLOW;
1097
1098 if (!cDstAvail)
1099 return VERR_BUFFER_OVERFLOW;
1100
1101 uint32_t cSrcToRead = 0;
1102 uint32_t cSrcRead;
1103
1104 uint32_t cDstToWrite;
1105 uint32_t cDstWritten;
1106
1107 int rc = VINF_SUCCESS;
1108
1109 while (cSrcAvail && cDstAvail)
1110 {
1111 cSrcToRead = RT_MIN(cSrcAvail, pSrc->cFrames - offSrcRead);
1112 cDstToWrite = RT_MIN(cDstAvail, pDst->cFrames - offDstWrite);
1113
1114 AUDMIXBUF_LOG(("\tSource: %RU32 @ %RU32 -> reading %RU32\n", cSrcAvail, offSrcRead, cSrcToRead));
1115 AUDMIXBUF_LOG(("\tDest : %RU32 @ %RU32 -> writing %RU32\n", cDstAvail, offDstWrite, cDstToWrite));
1116
1117 if ( !cDstToWrite
1118 || !cSrcToRead)
1119 {
1120 break;
1121 }
1122
1123 cDstWritten = cSrcRead = 0;
1124
1125 Assert(offSrcRead < pSrc->cFrames);
1126 Assert(offSrcRead + cSrcToRead <= pSrc->cFrames);
1127
1128 Assert(offDstWrite < pDst->cFrames);
1129 Assert(offDstWrite + cDstToWrite <= pDst->cFrames);
1130
1131 audioMixBufOpAssign(pDst->pFrames + offDstWrite, cDstToWrite,
1132 pSrc->pFrames + offSrcRead, cSrcToRead,
1133 pSrc->pRate, &cDstWritten, &cSrcRead);
1134
1135 cReadTotal += cSrcRead;
1136 cWrittenTotal += cDstWritten;
1137
1138 offSrcRead = (offSrcRead + cSrcRead) % pSrc->cFrames;
1139 offDstWrite = (offDstWrite + cDstWritten) % pDst->cFrames;
1140
1141 cDstMixed += cDstWritten;
1142
1143 Assert(cSrcAvail >= cSrcRead);
1144 cSrcAvail -= cSrcRead;
1145
1146 Assert(cDstAvail >= cDstWritten);
1147 cDstAvail -= cDstWritten;
1148
1149 AUDMIXBUF_LOG(("\t%RU32 read (%RU32 left @ %RU32), %RU32 written (%RU32 left @ %RU32)\n",
1150 cSrcRead, cSrcAvail, offSrcRead,
1151 cDstWritten, cDstAvail, offDstWrite));
1152 }
1153
1154 pSrc->offRead = offSrcRead;
1155 Assert(pSrc->cUsed >= cReadTotal);
1156 pSrc->cUsed -= RT_MIN(pSrc->cUsed, cReadTotal);
1157
1158 /* Note: Always count in parent frames, as the rate can differ! */
1159 pSrc->cMixed = RT_MIN(cDstMixed, pDst->cFrames);
1160
1161 pDst->offWrite = offDstWrite;
1162 Assert(pDst->offWrite <= pDst->cFrames);
1163 Assert((pDst->cUsed + cWrittenTotal) <= pDst->cFrames);
1164 pDst->cUsed += cWrittenTotal;
1165
1166 /* If there are more used frames than fitting in the destination buffer,
1167 * adjust the values accordingly.
1168 *
1169 * This can happen if this routine has been called too often without
1170 * actually processing the destination buffer in between. */
1171 if (pDst->cUsed > pDst->cFrames)
1172 {
1173 LogFunc(("%s: Warning: Destination buffer used %RU32 / %RU32 frames\n", pDst->pszName, pDst->cUsed, pDst->cFrames));
1174 pDst->offWrite = 0;
1175 pDst->cUsed = pDst->cFrames;
1176
1177 rc = VERR_BUFFER_OVERFLOW;
1178 }
1179
1180#ifdef DEBUG
1181 audioMixBufDbgValidate(pSrc);
1182 audioMixBufDbgValidate(pDst);
1183
1184 Assert(pSrc->cMixed <= pDst->cFrames);
1185#endif
1186
1187#ifdef AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA
1188 uint32_t offRead = pDst->offRead;
1189
1190 uint32_t cLeft = cWrittenTotal;
1191 while (cLeft)
1192 {
1193 uint8_t auBuf[256];
1194 RT_ZERO(auBuf);
1195
1196 Assert(sizeof(auBuf) >= 4);
1197 Assert(sizeof(auBuf) % 4 == 0);
1198
1199 uint32_t cToRead = RT_MIN(AUDIOMIXBUF_B2F(pDst, sizeof(auBuf)), RT_MIN(cLeft, pDst->cFrames - offRead));
1200 Assert(cToRead <= pDst->cUsed);
1201
1202 PDMAUDMIXBUFCONVOPTS convOpts;
1203 RT_ZERO(convOpts);
1204 convOpts.cFrames = cToRead;
1205
1206 pDst->pfnConvTo(auBuf, pDst->pFrames + offRead, &convOpts);
1207
1208 RTFILE fh;
1209 int rc2 = RTFileOpen(&fh, AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA_PATH "mixbuf_mixto.pcm",
1210 RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
1211 if (RT_SUCCESS(rc2))
1212 {
1213 RTFileWrite(fh, auBuf, AUDIOMIXBUF_F2B(pDst, cToRead), NULL);
1214 RTFileClose(fh);
1215 }
1216
1217 offRead = (offRead + cToRead) % pDst->cFrames;
1218 cLeft -= cToRead;
1219 }
1220#endif /* AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA */
1221
1222#ifdef DEBUG
1223 audioMixBufDbgPrintInternal(pDst, __FUNCTION__);
1224#endif
1225
1226 if (pcSrcMixed)
1227 *pcSrcMixed = cReadTotal;
1228
1229 AUDMIXBUF_LOG(("cReadTotal=%RU32, cWrittenTotal=%RU32, cSrcMixed=%RU32, cDstUsed=%RU32, rc=%Rrc\n",
1230 cReadTotal, cWrittenTotal, pSrc->cMixed, pDst->cUsed, rc));
1231 return rc;
1232}
1233
1234/**
1235 * Mixes audio frames down to the parent mixing buffer, extended version.
1236 *
1237 * @return IPRT status code. See audioMixBufMixTo() for a more detailed explanation.
1238 * @param pMixBuf Source mixing buffer to mix to its parent.
1239 * @param cSrcOffset Offset (in frames) of source mixing buffer.
1240 * @param cSrcFrames Number of source audio frames to mix to its parent.
1241 * @param pcSrcMixed Number of source audio frames successfully mixed. Optional.
1242 */
1243int AudioMixBufMixToParentEx(PPDMAUDIOMIXBUF pMixBuf, uint32_t cSrcOffset, uint32_t cSrcFrames, uint32_t *pcSrcMixed)
1244{
1245 AssertMsgReturn(VALID_PTR(pMixBuf->pParent),
1246 ("Buffer is not linked to a parent buffer\n"),
1247 VERR_INVALID_PARAMETER);
1248
1249 return audioMixBufMixTo(pMixBuf->pParent, pMixBuf, cSrcOffset, cSrcFrames, pcSrcMixed);
1250}
1251
1252/**
1253 * Mixes audio frames down to the parent mixing buffer.
1254 *
1255 * @return IPRT status code. See audioMixBufMixTo() for a more detailed explanation.
1256 * @param pMixBuf Source mixing buffer to mix to its parent.
1257 * @param cSrcFrames Number of source audio frames to mix to its parent.
1258 * @param pcSrcMixed Number of source audio frames successfully mixed. Optional.
1259 */
1260int AudioMixBufMixToParent(PPDMAUDIOMIXBUF pMixBuf, uint32_t cSrcFrames, uint32_t *pcSrcMixed)
1261{
1262 return audioMixBufMixTo(pMixBuf->pParent, pMixBuf, pMixBuf->offRead, cSrcFrames, pcSrcMixed);
1263}
1264
1265#ifdef DEBUG
1266/**
1267 * Prints a single mixing buffer.
1268 * Internal helper function for debugging. Do not use directly.
1269 *
1270 * @return IPRT status code.
1271 * @param pMixBuf Mixing buffer to print.
1272 * @param pszFunc Function name to log this for.
1273 * @param fIsParent Whether this is a parent buffer or not.
1274 * @param uIdtLvl Indention level to use.
1275 */
1276DECL_FORCE_INLINE(void) audioMixBufDbgPrintSingle(PPDMAUDIOMIXBUF pMixBuf, const char *pszFunc, bool fIsParent, uint16_t uIdtLvl)
1277{
1278 Log(("%s: %*s[%s] %s: offRead=%RU32, offWrite=%RU32, cMixed=%RU32 -> %RU32/%RU32\n",
1279 pszFunc, uIdtLvl * 4, "", fIsParent ? "PARENT" : "CHILD",
1280 pMixBuf->pszName, pMixBuf->offRead, pMixBuf->offWrite, pMixBuf->cMixed, pMixBuf->cUsed, pMixBuf->cFrames));
1281}
1282
1283/**
1284 * Validates a single mixing buffer.
1285 *
1286 * @return @true if the buffer state is valid or @false if not.
1287 * @param pMixBuf Mixing buffer to validate.
1288 */
1289DECL_FORCE_INLINE(bool) audioMixBufDbgValidate(PPDMAUDIOMIXBUF pMixBuf)
1290{
1291 //const uint32_t offReadEnd = (pMixBuf->offRead + pMixBuf->cUsed) % pMixBuf->cFrames;
1292 //const uint32_t offWriteEnd = (pMixBuf->offWrite + (pMixBuf->cFrames - pMixBuf->cUsed)) % pMixBuf->cFrames;
1293
1294 bool fValid = true;
1295
1296 AssertStmt(pMixBuf->offRead <= pMixBuf->cFrames, fValid = false);
1297 AssertStmt(pMixBuf->offWrite <= pMixBuf->cFrames, fValid = false);
1298 AssertStmt(pMixBuf->cUsed <= pMixBuf->cFrames, fValid = false);
1299
1300 if (pMixBuf->offWrite > pMixBuf->offRead)
1301 {
1302 if (pMixBuf->offWrite - pMixBuf->offRead != pMixBuf->cUsed)
1303 fValid = false;
1304 }
1305 else if (pMixBuf->offWrite < pMixBuf->offRead)
1306 {
1307 if (pMixBuf->offWrite + pMixBuf->cFrames - pMixBuf->offRead != pMixBuf->cUsed)
1308 fValid = false;
1309 }
1310
1311 if (!fValid)
1312 {
1313 audioMixBufDbgPrintInternal(pMixBuf, __FUNCTION__);
1314 AssertFailed();
1315 }
1316
1317 return fValid;
1318}
1319
1320/**
1321 * Internal helper function for audioMixBufPrintChain().
1322 * Do not use directly.
1323 *
1324 * @return IPRT status code.
1325 * @param pMixBuf Mixing buffer to print.
1326 * @param pszFunc Function name to print the chain for.
1327 * @param uIdtLvl Indention level to use.
1328 * @param pcChildren Pointer to children counter.
1329 */
1330DECL_FORCE_INLINE(void) audioMixBufDbgPrintChainHelper(PPDMAUDIOMIXBUF pMixBuf, const char *pszFunc, uint16_t uIdtLvl,
1331 size_t *pcChildren)
1332{
1333 PPDMAUDIOMIXBUF pIter;
1334 RTListForEach(&pMixBuf->lstChildren, pIter, PDMAUDIOMIXBUF, Node)
1335 {
1336 audioMixBufDbgPrintSingle(pIter, pszFunc, false /* ifIsParent */, uIdtLvl + 1);
1337 *pcChildren++;
1338 }
1339}
1340
1341DECL_FORCE_INLINE(void) audioMixBufDbgPrintChainInternal(PPDMAUDIOMIXBUF pMixBuf, const char *pszFunc)
1342{
1343 PPDMAUDIOMIXBUF pParent = pMixBuf->pParent;
1344 while (pParent)
1345 {
1346 if (!pParent->pParent)
1347 break;
1348
1349 pParent = pParent->pParent;
1350 }
1351
1352 if (!pParent)
1353 pParent = pMixBuf;
1354
1355 audioMixBufDbgPrintSingle(pParent, pszFunc, true /* fIsParent */, 0 /* uIdtLvl */);
1356
1357 /* Recursively iterate children. */
1358 size_t cChildren = 0;
1359 audioMixBufDbgPrintChainHelper(pParent, pszFunc, 0 /* uIdtLvl */, &cChildren);
1360
1361 Log(("%s: Children: %zu\n", pszFunc, cChildren));
1362}
1363
1364/**
1365 * Prints statistics and status of the full chain of a mixing buffer to the logger,
1366 * starting from the top root mixing buffer.
1367 * For debug versions only.
1368 *
1369 * @return IPRT status code.
1370 * @param pMixBuf Mixing buffer to print.
1371 */
1372void AudioMixBufDbgPrintChain(PPDMAUDIOMIXBUF pMixBuf)
1373{
1374 audioMixBufDbgPrintChainInternal(pMixBuf, __FUNCTION__);
1375}
1376
1377DECL_FORCE_INLINE(void) audioMixBufDbgPrintInternal(PPDMAUDIOMIXBUF pMixBuf, const char *pszFunc)
1378{
1379 PPDMAUDIOMIXBUF pParent = pMixBuf;
1380 if (pMixBuf->pParent)
1381 pParent = pMixBuf->pParent;
1382
1383 audioMixBufDbgPrintSingle(pMixBuf, pszFunc, pParent == pMixBuf /* fIsParent */, 0 /* iIdtLevel */);
1384
1385 PPDMAUDIOMIXBUF pIter;
1386 RTListForEach(&pMixBuf->lstChildren, pIter, PDMAUDIOMIXBUF, Node)
1387 {
1388 if (pIter == pMixBuf)
1389 continue;
1390 audioMixBufDbgPrintSingle(pIter, pszFunc, false /* fIsParent */, 1 /* iIdtLevel */);
1391 }
1392}
1393
1394/**
1395 * Prints statistics and status of a mixing buffer to the logger.
1396 * For debug versions only.
1397 *
1398 * @return IPRT status code.
1399 * @param pMixBuf Mixing buffer to print.
1400 */
1401void AudioMixBufDbgPrint(PPDMAUDIOMIXBUF pMixBuf)
1402{
1403 audioMixBufDbgPrintInternal(pMixBuf, __FUNCTION__);
1404}
1405#endif /* DEBUG */
1406
1407/**
1408 * Returns the total number of audio frames used.
1409 *
1410 * @return uint32_t
1411 * @param pMixBuf
1412 */
1413uint32_t AudioMixBufUsed(PPDMAUDIOMIXBUF pMixBuf)
1414{
1415 AssertPtrReturn(pMixBuf, 0);
1416 return pMixBuf->cUsed;
1417}
1418
1419/**
1420 * Returns the total number of bytes used.
1421 *
1422 * @return uint32_t
1423 * @param pMixBuf
1424 */
1425uint32_t AudioMixBufUsedBytes(PPDMAUDIOMIXBUF pMixBuf)
1426{
1427 AssertPtrReturn(pMixBuf, 0);
1428 return AUDIOMIXBUF_F2B(pMixBuf, pMixBuf->cUsed);
1429}
1430
1431/**
1432 * Reads audio frames at a specific offset.
1433 *
1434 * @return IPRT status code.
1435 * @param pMixBuf Mixing buffer to read audio frames from.
1436 * @param offFrames Offset (in audio frames) to start reading from.
1437 * @param pvBuf Pointer to buffer to write output to.
1438 * @param cbBuf Size (in bytes) of buffer to write to.
1439 * @param pcbRead Size (in bytes) of data read. Optional.
1440 */
1441int AudioMixBufReadAt(PPDMAUDIOMIXBUF pMixBuf,
1442 uint32_t offFrames,
1443 void *pvBuf, uint32_t cbBuf,
1444 uint32_t *pcbRead)
1445{
1446 return AudioMixBufReadAtEx(pMixBuf, pMixBuf->uAudioFmt,
1447 offFrames, pvBuf, cbBuf, pcbRead);
1448}
1449
1450/**
1451 * Reads audio frames at a specific offset.
1452 * If the audio format of the mixing buffer and the requested audio format do
1453 * not match the output will be converted accordingly.
1454 *
1455 * @return IPRT status code.
1456 * @param pMixBuf Mixing buffer to read audio frames from.
1457 * @param enmFmt Audio format to use for output.
1458 * @param offFrames Offset (in audio frames) to start reading from.
1459 * @param pvBuf Pointer to buffer to write output to.
1460 * @param cbBuf Size (in bytes) of buffer to write to.
1461 * @param pcbRead Size (in bytes) of data read. Optional.
1462 */
1463int AudioMixBufReadAtEx(PPDMAUDIOMIXBUF pMixBuf, PDMAUDIOMIXBUFFMT enmFmt,
1464 uint32_t offFrames,
1465 void *pvBuf, uint32_t cbBuf,
1466 uint32_t *pcbRead)
1467{
1468 AssertPtrReturn(pMixBuf, VERR_INVALID_POINTER);
1469 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
1470 /* pcbRead is optional. */
1471
1472 uint32_t cDstFrames = pMixBuf->cFrames;
1473 uint32_t cLive = pMixBuf->cUsed;
1474
1475 uint32_t cDead = cDstFrames - cLive;
1476 uint32_t cToProcess = (uint32_t)AUDIOMIXBUF_F2F_RATIO(pMixBuf, cDead);
1477 cToProcess = RT_MIN(cToProcess, AUDIOMIXBUF_B2F(pMixBuf, cbBuf));
1478
1479 AUDMIXBUF_LOG(("%s: offFrames=%RU32, cLive=%RU32, cDead=%RU32, cToProcess=%RU32\n",
1480 pMixBuf->pszName, offFrames, cLive, cDead, cToProcess));
1481
1482 int rc;
1483 if (cToProcess)
1484 {
1485 PFNPDMAUDIOMIXBUFCONVTO pfnConvTo = NULL;
1486 if (pMixBuf->uAudioFmt != enmFmt)
1487 pfnConvTo = audioMixBufConvToLookup(enmFmt);
1488 else
1489 pfnConvTo = pMixBuf->pfnConvTo;
1490
1491 if (pfnConvTo)
1492 {
1493 PDMAUDMIXBUFCONVOPTS convOpts;
1494 RT_ZERO(convOpts);
1495 /* Note: No volume handling/conversion done in the conversion-to macros (yet). */
1496
1497 convOpts.cFrames = cToProcess;
1498
1499 pfnConvTo(pvBuf, pMixBuf->pFrames + offFrames, &convOpts);
1500
1501#ifdef DEBUG
1502 AudioMixBufDbgPrint(pMixBuf);
1503#endif
1504 rc = VINF_SUCCESS;
1505 }
1506 else
1507 {
1508 AssertFailed();
1509 rc = VERR_NOT_SUPPORTED;
1510 }
1511 }
1512 else
1513 rc = VINF_SUCCESS;
1514
1515 if (RT_SUCCESS(rc))
1516 {
1517 if (pcbRead)
1518 *pcbRead = AUDIOMIXBUF_F2B(pMixBuf, cToProcess);
1519 }
1520
1521 AUDMIXBUF_LOG(("cbRead=%RU32, rc=%Rrc\n", AUDIOMIXBUF_F2B(pMixBuf, cToProcess), rc));
1522 return rc;
1523}
1524
1525/**
1526 * Reads audio frames. The audio format of the mixing buffer will be used.
1527 *
1528 * @return IPRT status code.
1529 * @param pMixBuf Mixing buffer to read audio frames from.
1530 * @param pvBuf Pointer to buffer to write output to.
1531 * @param cbBuf Size (in bytes) of buffer to write to.
1532 * @param pcBlock Returns acquired block to read (in audio frames).
1533 */
1534int AudioMixBufAcquireReadBlock(PPDMAUDIOMIXBUF pMixBuf, void *pvBuf, uint32_t cbBuf, uint32_t *pcBlock)
1535{
1536 return AudioMixBufAcquireReadBlockEx(pMixBuf, pMixBuf->uAudioFmt, pvBuf, cbBuf, pcBlock);
1537}
1538
1539/**
1540 * Reads audio frames in a specific audio format.
1541 * If the audio format of the mixing buffer and the requested audio format do
1542 * not match the output will be converted accordingly.
1543 *
1544 * @return IPRT status code.
1545 * @param pMixBuf Mixing buffer to read audio frames from.
1546 * @param enmFmt Audio format to use for output.
1547 * @param pvBuf Pointer to buffer to write output to.
1548 * @param cbBuf Size (in bytes) of buffer to write to.
1549 * @param pcBlock Returns acquired block to read (in audio frames).
1550 */
1551int AudioMixBufAcquireReadBlockEx(PPDMAUDIOMIXBUF pMixBuf, PDMAUDIOMIXBUFFMT enmFmt, void *pvBuf, uint32_t cbBuf,
1552 uint32_t *pcBlock)
1553{
1554 AssertPtrReturn(pMixBuf, VERR_INVALID_POINTER);
1555 AssertReturn(cbBuf, VERR_INVALID_PARAMETER);
1556 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
1557 AssertPtrReturn(pcBlock, VERR_INVALID_POINTER);
1558
1559 /* Make sure that we at least have space for a full audio frame. */
1560 AssertReturn(AUDIOMIXBUF_B2F(pMixBuf, cbBuf), VERR_INVALID_PARAMETER);
1561
1562 uint32_t cToRead = RT_MIN(pMixBuf->cUsed, AUDIOMIXBUF_B2F(pMixBuf, cbBuf));
1563
1564 AUDMIXBUF_LOG(("%s: cbBuf=%RU32 (%RU32 frames), cToRead=%RU32, fmtSrc=0x%x, fmtDst=0x%x\n",
1565 pMixBuf->pszName, cbBuf, AUDIOMIXBUF_B2F(pMixBuf, cbBuf), cToRead, pMixBuf->uAudioFmt, enmFmt));
1566
1567 if (!cToRead)
1568 {
1569#ifdef DEBUG
1570 audioMixBufDbgPrintInternal(pMixBuf, __FUNCTION__);
1571#endif
1572 *pcBlock = 0;
1573 return VINF_SUCCESS;
1574 }
1575
1576 PFNPDMAUDIOMIXBUFCONVTO pfnConvTo = NULL;
1577 if (pMixBuf->uAudioFmt != enmFmt)
1578 pfnConvTo = audioMixBufConvToLookup(enmFmt);
1579 else
1580 pfnConvTo = pMixBuf->pfnConvTo;
1581
1582 if (!pfnConvTo) /* Audio format not supported. */
1583 {
1584 AssertFailed();
1585 return VERR_NOT_SUPPORTED;
1586 }
1587
1588 cToRead = RT_MIN(cToRead, pMixBuf->cFrames - pMixBuf->offRead);
1589 if (cToRead)
1590 {
1591 PDMAUDMIXBUFCONVOPTS convOpts;
1592 RT_ZERO(convOpts);
1593 convOpts.cFrames = cToRead;
1594
1595 AUDMIXBUF_LOG(("cToRead=%RU32\n", cToRead));
1596
1597 pfnConvTo(pvBuf, pMixBuf->pFrames + pMixBuf->offRead, &convOpts);
1598
1599#ifdef AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA
1600 RTFILE fh;
1601 int rc2 = RTFileOpen(&fh, AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA_PATH "mixbuf_readcirc.pcm",
1602 RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
1603 if (RT_SUCCESS(rc2))
1604 {
1605 RTFileWrite(fh, pvBuf, AUDIOMIXBUF_F2B(pMixBuf, cToRead), NULL);
1606 RTFileClose(fh);
1607 }
1608#endif
1609 }
1610
1611 *pcBlock = cToRead;
1612
1613#ifdef DEBUG
1614 audioMixBufDbgValidate(pMixBuf);
1615#endif
1616
1617 AUDMIXBUF_LOG(("cRead=%RU32 (%RU32 bytes)\n", cToRead, AUDIOMIXBUF_F2B(pMixBuf, cToRead)));
1618 return VINF_SUCCESS;
1619}
1620
1621/**
1622 * Releases a formerly acquired read block again.
1623 *
1624 * @param pMixBuf Mixing buffer to release acquired read block for.
1625 * @param cBlock Size of the block to release (in audio frames).
1626 */
1627void AudioMixBufReleaseReadBlock(PPDMAUDIOMIXBUF pMixBuf, uint32_t cBlock)
1628{
1629 AssertPtrReturnVoid(pMixBuf);
1630
1631 if (!cBlock)
1632 return;
1633
1634 pMixBuf->offRead = (pMixBuf->offRead + cBlock) % pMixBuf->cFrames;
1635 Assert(pMixBuf->cUsed >= cBlock);
1636 pMixBuf->cUsed -= RT_MIN(cBlock, pMixBuf->cUsed);
1637}
1638
1639/**
1640 * Returns the current read position of a mixing buffer.
1641 *
1642 * @returns IPRT status code.
1643 * @param pMixBuf Mixing buffer to return position for.
1644 */
1645uint32_t AudioMixBufReadPos(PPDMAUDIOMIXBUF pMixBuf)
1646{
1647 AssertPtrReturn(pMixBuf, 0);
1648
1649 return pMixBuf->offRead;
1650}
1651
1652/**
1653 * Resets a mixing buffer.
1654 *
1655 * @param pMixBuf Mixing buffer to reset.
1656 */
1657void AudioMixBufReset(PPDMAUDIOMIXBUF pMixBuf)
1658{
1659 AssertPtrReturnVoid(pMixBuf);
1660
1661 AUDMIXBUF_LOG(("%s\n", pMixBuf->pszName));
1662
1663 pMixBuf->offRead = 0;
1664 pMixBuf->offWrite = 0;
1665 pMixBuf->cMixed = 0;
1666 pMixBuf->cUsed = 0;
1667
1668 AudioMixBufClear(pMixBuf);
1669}
1670
1671/**
1672 * Sets the overall (master) volume.
1673 *
1674 * @param pMixBuf Mixing buffer to set volume for.
1675 * @param pVol Pointer to volume structure to set.
1676 */
1677void AudioMixBufSetVolume(PPDMAUDIOMIXBUF pMixBuf, PPDMAUDIOVOLUME pVol)
1678{
1679 AssertPtrReturnVoid(pMixBuf);
1680 AssertPtrReturnVoid(pVol);
1681
1682 LogFlowFunc(("%s: lVol=%RU8, rVol=%RU8, fMuted=%RTbool\n", pMixBuf->pszName, pVol->uLeft, pVol->uRight, pVol->fMuted));
1683
1684 int rc2 = audioMixBufConvVol(&pMixBuf->Volume /* Dest */, pVol /* Source */);
1685 AssertRC(rc2);
1686}
1687
1688/**
1689 * Returns the maximum amount of audio frames this buffer can hold.
1690 *
1691 * @return uint32_t Size (in audio frames) the mixing buffer can hold.
1692 * @param pMixBuf Mixing buffer to retrieve maximum for.
1693 */
1694uint32_t AudioMixBufSize(PPDMAUDIOMIXBUF pMixBuf)
1695{
1696 AssertPtrReturn(pMixBuf, 0);
1697 return pMixBuf->cFrames;
1698}
1699
1700/**
1701 * Returns the maximum amount of bytes this buffer can hold.
1702 *
1703 * @return uint32_t Size (in bytes) the mixing buffer can hold.
1704 * @param pMixBuf Mixing buffer to retrieve maximum for.
1705 */
1706uint32_t AudioMixBufSizeBytes(PPDMAUDIOMIXBUF pMixBuf)
1707{
1708 AssertPtrReturn(pMixBuf, 0);
1709 return AUDIOMIXBUF_F2B(pMixBuf, pMixBuf->cFrames);
1710}
1711
1712/**
1713 * Unlinks a mixing buffer from its parent, if any.
1714 *
1715 * @return IPRT status code.
1716 * @param pMixBuf Mixing buffer to unlink from parent.
1717 */
1718void AudioMixBufUnlink(PPDMAUDIOMIXBUF pMixBuf)
1719{
1720 if (!pMixBuf || !pMixBuf->pszName)
1721 return;
1722
1723 AUDMIXBUF_LOG(("%s\n", pMixBuf->pszName));
1724
1725 if (pMixBuf->pParent) /* IS this a children buffer? */
1726 {
1727 AUDMIXBUF_LOG(("%s: Unlinking from parent \"%s\"\n",
1728 pMixBuf->pszName, pMixBuf->pParent->pszName));
1729
1730 RTListNodeRemove(&pMixBuf->Node);
1731
1732 /* Decrease the paren't children count. */
1733 Assert(pMixBuf->pParent->cChildren);
1734 pMixBuf->pParent->cChildren--;
1735
1736 /* Make sure to reset the parent mixing buffer each time it gets linked
1737 * to a new child. */
1738 AudioMixBufReset(pMixBuf->pParent);
1739 pMixBuf->pParent = NULL;
1740 }
1741
1742 PPDMAUDIOMIXBUF pChild, pChildNext;
1743 RTListForEachSafe(&pMixBuf->lstChildren, pChild, pChildNext, PDMAUDIOMIXBUF, Node)
1744 {
1745 AUDMIXBUF_LOG(("\tUnlinking \"%s\"\n", pChild->pszName));
1746
1747 AudioMixBufReset(pChild);
1748
1749 Assert(pChild->pParent == pMixBuf);
1750 pChild->pParent = NULL;
1751
1752 RTListNodeRemove(&pChild->Node);
1753
1754 /* Decrease the children count. */
1755 Assert(pMixBuf->cChildren);
1756 pMixBuf->cChildren--;
1757 }
1758
1759 Assert(RTListIsEmpty(&pMixBuf->lstChildren));
1760 Assert(pMixBuf->cChildren == 0);
1761
1762 AudioMixBufReset(pMixBuf);
1763
1764 if (pMixBuf->pRate)
1765 {
1766 pMixBuf->pRate->offDst = pMixBuf->pRate->offSrc = 0;
1767 pMixBuf->pRate->uDstInc = 0;
1768 }
1769
1770 pMixBuf->iFreqRatio = 1; /* Prevent division by zero. */
1771}
1772
1773/**
1774 * Writes audio frames at a specific offset.
1775 * The sample format being written must match the format of the mixing buffer.
1776 *
1777 * @return IPRT status code.
1778 * @param pMixBuf Pointer to mixing buffer to write to.
1779 * @param offFrames Offset (in frames) starting to write at.
1780 * @param pvBuf Pointer to audio buffer to be written.
1781 * @param cbBuf Size (in bytes) of audio buffer.
1782 * @param pcWritten Returns number of audio frames written. Optional.
1783 */
1784int AudioMixBufWriteAt(PPDMAUDIOMIXBUF pMixBuf, uint32_t offFrames, const void *pvBuf, uint32_t cbBuf, uint32_t *pcWritten)
1785{
1786 return AudioMixBufWriteAtEx(pMixBuf, pMixBuf->uAudioFmt, offFrames, pvBuf, cbBuf, pcWritten);
1787}
1788
1789/**
1790 * Writes audio frames at a specific offset.
1791 *
1792 * Note that this operation also modifies the current read and write position
1793 * to \a offFrames + written frames on success.
1794 *
1795 * The audio sample format to be written can be different from the audio format
1796 * the mixing buffer operates on.
1797 *
1798 * @return IPRT status code.
1799 * @param pMixBuf Pointer to mixing buffer to write to.
1800 * @param enmFmt Audio format supplied in the buffer.
1801 * @param offFrames Offset (in frames) starting to write at.
1802 * @param pvBuf Pointer to audio buffer to be written.
1803 * @param cbBuf Size (in bytes) of audio buffer.
1804 * @param pcWritten Returns number of audio frames written. Optional.
1805 */
1806int AudioMixBufWriteAtEx(PPDMAUDIOMIXBUF pMixBuf, PDMAUDIOMIXBUFFMT enmFmt,
1807 uint32_t offFrames, const void *pvBuf, uint32_t cbBuf,
1808 uint32_t *pcWritten)
1809{
1810 AssertPtrReturn(pMixBuf, VERR_INVALID_POINTER);
1811 AssertReturn(cbBuf, VERR_INVALID_PARAMETER);
1812 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
1813 /* pcbWritten is optional. */
1814
1815 if (offFrames >= pMixBuf->cFrames)
1816 {
1817 if (pcWritten)
1818 *pcWritten = 0;
1819 return VERR_BUFFER_OVERFLOW;
1820 }
1821
1822 /*
1823 * Adjust cToWrite so we don't overflow our buffers.
1824 */
1825 uint32_t cToWrite = RT_MIN(AUDIOMIXBUF_B2F(pMixBuf, cbBuf), pMixBuf->cFrames - offFrames);
1826
1827#ifdef AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA
1828 /*
1829 * Now that we know how much we'll be converting we can log it.
1830 */
1831 RTFILE hFile;
1832 int rc2 = RTFileOpen(&hFile, AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA_PATH "mixbuf_writeat.pcm",
1833 RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
1834 if (RT_SUCCESS(rc2))
1835 {
1836 RTFileWrite(hFile, pvBuf, AUDIOMIXBUF_F2B(pMixBuf, cToWrite), NULL);
1837 RTFileClose(hFile);
1838 }
1839#endif
1840
1841 /*
1842 * Pick the conversion function and do the conversion.
1843 */
1844 PFNPDMAUDIOMIXBUFCONVFROM pfnConvFrom = NULL;
1845 if (!pMixBuf->Volume.fMuted)
1846 {
1847 if (pMixBuf->uAudioFmt != enmFmt)
1848 pfnConvFrom = audioMixBufConvFromLookup(enmFmt);
1849 else
1850 pfnConvFrom = pMixBuf->pfnConvFrom;
1851 }
1852 else
1853 pfnConvFrom = &audioMixBufConvFromSilence;
1854
1855 int rc = VINF_SUCCESS;
1856
1857 uint32_t cWritten;
1858 if ( pfnConvFrom
1859 && cToWrite)
1860 {
1861 PDMAUDMIXBUFCONVOPTS convOpts;
1862
1863 convOpts.cFrames = cToWrite;
1864 convOpts.From.Volume.fMuted = pMixBuf->Volume.fMuted;
1865 convOpts.From.Volume.uLeft = pMixBuf->Volume.uLeft;
1866 convOpts.From.Volume.uRight = pMixBuf->Volume.uRight;
1867
1868 cWritten = pfnConvFrom(pMixBuf->pFrames + offFrames, pvBuf, AUDIOMIXBUF_F2B(pMixBuf, cToWrite), &convOpts);
1869 }
1870 else
1871 {
1872 cWritten = 0;
1873 if (!pfnConvFrom)
1874 {
1875 AssertFailed();
1876 rc = VERR_NOT_SUPPORTED;
1877 }
1878 }
1879
1880 AUDMIXBUF_LOG(("%s: offFrames=%RU32, cbBuf=%RU32, cToWrite=%RU32 (%zu bytes), cWritten=%RU32 (%zu bytes), rc=%Rrc\n",
1881 pMixBuf->pszName, offFrames, cbBuf,
1882 cToWrite, AUDIOMIXBUF_F2B(pMixBuf, cToWrite),
1883 cWritten, AUDIOMIXBUF_F2B(pMixBuf, cWritten), rc));
1884
1885 if (RT_SUCCESS(rc))
1886 {
1887 pMixBuf->offRead = offFrames % pMixBuf->cFrames;
1888 pMixBuf->offWrite = (offFrames + cWritten) % pMixBuf->cFrames;
1889 pMixBuf->cUsed = cWritten;
1890 pMixBuf->cMixed = 0;
1891
1892#ifdef DEBUG
1893 audioMixBufDbgValidate(pMixBuf);
1894#endif
1895 if (pcWritten)
1896 *pcWritten = cWritten;
1897 }
1898 else
1899 AUDMIXBUF_LOG(("%s: Failed with %Rrc\n", pMixBuf->pszName, rc));
1900
1901 return rc;
1902}
1903
1904/**
1905 * Writes audio frames.
1906 *
1907 * The sample format being written must match the format of the mixing buffer.
1908 *
1909 * @return IPRT status code, or VERR_BUFFER_OVERFLOW if frames which not have
1910 * been processed yet have been overwritten (due to cyclic buffer).
1911 * @param pMixBuf Pointer to mixing buffer to write to.
1912 * @param pvBuf Pointer to audio buffer to be written.
1913 * @param cbBuf Size (in bytes) of audio buffer.
1914 * @param pcWritten Returns number of audio frames written. Optional.
1915 */
1916int AudioMixBufWriteCirc(PPDMAUDIOMIXBUF pMixBuf,
1917 const void *pvBuf, uint32_t cbBuf,
1918 uint32_t *pcWritten)
1919{
1920 return AudioMixBufWriteCircEx(pMixBuf, pMixBuf->uAudioFmt, pvBuf, cbBuf, pcWritten);
1921}
1922
1923/**
1924 * Writes audio frames of a specific format.
1925 * This function might write less data at once than requested.
1926 *
1927 * @return IPRT status code, or VERR_BUFFER_OVERFLOW no space is available for writing anymore.
1928 * @param pMixBuf Pointer to mixing buffer to write to.
1929 * @param enmFmt Audio format supplied in the buffer.
1930 * @param pvBuf Pointer to audio buffer to be written.
1931 * @param cbBuf Size (in bytes) of audio buffer.
1932 * @param pcWritten Returns number of audio frames written. Optional.
1933 */
1934int AudioMixBufWriteCircEx(PPDMAUDIOMIXBUF pMixBuf, PDMAUDIOMIXBUFFMT enmFmt,
1935 const void *pvBuf, uint32_t cbBuf, uint32_t *pcWritten)
1936{
1937 AssertPtrReturn(pMixBuf, VERR_INVALID_POINTER);
1938 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
1939 /* pcbWritten is optional. */
1940
1941 if (!cbBuf)
1942 {
1943 if (pcWritten)
1944 *pcWritten = 0;
1945 return VINF_SUCCESS;
1946 }
1947
1948 /* Make sure that we at least write a full audio frame. */
1949 AssertReturn(AUDIOMIXBUF_B2F(pMixBuf, cbBuf), VERR_INVALID_PARAMETER);
1950
1951 Assert(pMixBuf->cFrames);
1952 AssertPtr(pMixBuf->pFrames);
1953
1954 PFNPDMAUDIOMIXBUFCONVFROM pfnConvFrom = NULL;
1955 if (!pMixBuf->Volume.fMuted)
1956 {
1957 if (pMixBuf->uAudioFmt != enmFmt)
1958 pfnConvFrom = audioMixBufConvFromLookup(enmFmt);
1959 else
1960 pfnConvFrom = pMixBuf->pfnConvFrom;
1961 }
1962 else
1963 pfnConvFrom = &audioMixBufConvFromSilence;
1964
1965 if (!pfnConvFrom)
1966 {
1967 AssertFailed();
1968 return VERR_NOT_SUPPORTED;
1969 }
1970
1971 int rc = VINF_SUCCESS;
1972
1973 uint32_t cWritten = 0;
1974
1975 uint32_t cFree = pMixBuf->cFrames - pMixBuf->cUsed;
1976 if (cFree)
1977 {
1978 if ((pMixBuf->cFrames - pMixBuf->offWrite) == 0)
1979 pMixBuf->offWrite = 0;
1980
1981 uint32_t cToWrite = RT_MIN(AUDIOMIXBUF_B2F(pMixBuf, cbBuf), RT_MIN(pMixBuf->cFrames - pMixBuf->offWrite, cFree));
1982 Assert(cToWrite);
1983
1984 PDMAUDMIXBUFCONVOPTS convOpts;
1985 RT_ZERO(convOpts);
1986
1987 convOpts.From.Volume.fMuted = pMixBuf->Volume.fMuted;
1988 convOpts.From.Volume.uLeft = pMixBuf->Volume.uLeft;
1989 convOpts.From.Volume.uRight = pMixBuf->Volume.uRight;
1990
1991 convOpts.cFrames = cToWrite;
1992
1993 cWritten = pfnConvFrom(pMixBuf->pFrames + pMixBuf->offWrite,
1994 pvBuf, AUDIOMIXBUF_F2B(pMixBuf, cToWrite), &convOpts);
1995 Assert(cWritten == cToWrite);
1996
1997#ifdef AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA
1998 RTFILE fh;
1999 RTFileOpen(&fh, AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA_PATH "mixbuf_writecirc_ex.pcm",
2000 RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
2001 RTFileWrite(fh, pvBuf, AUDIOMIXBUF_F2B(pMixBuf, cToWrite), NULL);
2002 RTFileClose(fh);
2003#endif
2004 pMixBuf->cUsed += cWritten;
2005 Assert(pMixBuf->cUsed <= pMixBuf->cFrames);
2006
2007 pMixBuf->offWrite = (pMixBuf->offWrite + cWritten) % pMixBuf->cFrames;
2008 Assert(pMixBuf->offWrite <= pMixBuf->cFrames);
2009 }
2010 else
2011 rc = VERR_BUFFER_OVERFLOW;
2012
2013#ifdef DEBUG
2014 audioMixBufDbgPrintInternal(pMixBuf, __FUNCTION__);
2015 audioMixBufDbgValidate(pMixBuf);
2016#endif
2017
2018 if (pcWritten)
2019 *pcWritten = cWritten;
2020
2021 AUDMIXBUF_LOG(("%s: enmFmt=0x%x, cbBuf=%RU32 (%RU32 frames), cWritten=%RU32, rc=%Rrc\n",
2022 pMixBuf->pszName, enmFmt, cbBuf, AUDIOMIXBUF_B2F(pMixBuf, cbBuf), cWritten, rc));
2023 return rc;
2024}
2025
2026/**
2027 * Returns the current write position of a mixing buffer.
2028 *
2029 * @returns IPRT status code.
2030 * @param pMixBuf Mixing buffer to return position for.
2031 */
2032uint32_t AudioMixBufWritePos(PPDMAUDIOMIXBUF pMixBuf)
2033{
2034 AssertPtrReturn(pMixBuf, 0);
2035
2036 return pMixBuf->offWrite;
2037}
2038
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