VirtualBox

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

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

Devices/Audio: doxygen fixes (s/@true/false / @c true/false/)

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