VirtualBox

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

Last change on this file since 61177 was 61157, checked in by vboxsync, 9 years ago

Audio:

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

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