VirtualBox

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

Last change on this file since 61362 was 61352, checked in by vboxsync, 9 years ago

AudioMixBuffer,tstAudioMixBuffer,pdmaudioifs.h: Fixed buffer overflow in AudioMixBufWriteAtEx during testcase run due to incomplete checking. Fixed some coding convesion issues. Made the debug build of the testcsae always use the electric fence heap.

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

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