VirtualBox

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

Last change on this file since 88391 was 88356, checked in by vboxsync, 4 years ago

Audio: Trimmed down PDMAUDIOSTREAM a lot by moving non-essential stuff into an wrapper structure in DrvAudio. This allows for the mixing buffers and other stuff to move (back?) into AudioMixBuffer.h. Also started specifying away to skip the mixing in DrvAudio as only DevSB16 really needs this (goal is to reduce number of copies and bufferings). bugref:9890

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

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