VirtualBox

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

Last change on this file since 56295 was 55920, checked in by vboxsync, 10 years ago

PDM/Audio: AudioMixBuffer documentation, renaming.

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