VirtualBox

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

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

Audio: Removed PDMAUDIOSTRMSTS_FLAG_DATA_READABLE / PDMAUDIOSTRMSTS_FLAG_DATA_WRITABLE and added IHostAudio::pfnStreamGetReadable() and IHostAudio::pfnStreamGetWritable() instead.

Split up drvAudioStreamPlay() into drvAudioStreamPlayNonInterleaved() and drvAudioStreamPlayRaw() for handling different audio data layouts.

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