VirtualBox

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

Last change on this file since 67815 was 67742, checked in by vboxsync, 7 years ago

AudioMixBuffer: comment

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