VirtualBox

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

Last change on this file since 61126 was 61091, checked in by vboxsync, 9 years ago

Audio/AudioMixBuffer: Cache pfnConvTo/pfnConvFrom function pointer for default format.

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