VirtualBox

source: vbox/trunk/src/VBox/Devices/Audio_old/AudioMixBuffer.cpp@ 61497

Last change on this file since 61497 was 61413, checked in by vboxsync, 9 years ago

Audio: Use the old audio code for now when doing a release. Set VBOX_WITH_AUDIO_STABLE to an empty value to enable the new audio code (default for non-release builds for now).

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