VirtualBox

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

Last change on this file since 88913 was 88889, checked in by vboxsync, 4 years ago

AudioMixBuffer: Fixed bug in AudioMixBufPeekResampling where we'd poentially overflow the output buffer. bugref:9890

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 92.9 KB
Line 
1/* $Id: AudioMixBuffer.cpp 88889 2021-05-06 00:47:10Z vboxsync $ */
2/** @file
3 * Audio mixing buffer for converting reading/writing audio data.
4 */
5
6/*
7 * Copyright (C) 2014-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17#define LOG_GROUP LOG_GROUP_AUDIO_MIXER_BUFFER
18#include <VBox/log.h>
19
20#if 0
21/*
22 * AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA enables dumping the raw PCM data
23 * to a file on the host. Be sure to adjust AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA_PATH
24 * to your needs before using this!
25 */
26# define AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA
27# ifdef RT_OS_WINDOWS
28# define AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA_PATH "c:\\temp\\"
29# else
30# define AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA_PATH "/tmp/"
31# endif
32/* Warning: Enabling this will generate *huge* logs! */
33//# define AUDIOMIXBUF_DEBUG_MACROS
34#endif
35
36#include <iprt/asm-math.h>
37#include <iprt/assert.h>
38#ifdef AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA
39# include <iprt/file.h>
40#endif
41#include <iprt/mem.h>
42#include <iprt/string.h> /* For RT_BZERO. */
43
44#ifdef VBOX_AUDIO_TESTCASE
45# define LOG_ENABLED
46# include <iprt/stream.h>
47#endif
48#include <iprt/errcore.h>
49#include <VBox/vmm/pdmaudioinline.h>
50
51#include "AudioMixBuffer.h"
52
53#ifndef VBOX_AUDIO_TESTCASE
54# ifdef DEBUG
55# define AUDMIXBUF_LOG(x) LogFlowFunc(x)
56# define AUDMIXBUF_LOG_ENABLED
57# else
58# define AUDMIXBUF_LOG(x) do {} while (0)
59# endif
60#else /* VBOX_AUDIO_TESTCASE */
61# define AUDMIXBUF_LOG(x) RTPrintf x
62# define AUDMIXBUF_LOG_ENABLED
63#endif
64
65#ifdef DEBUG
66DECLINLINE(void) audioMixBufDbgPrintInternal(PAUDIOMIXBUF pMixBuf, const char *pszFunc);
67DECL_FORCE_INLINE(bool) audioMixBufDbgValidate(PAUDIOMIXBUF pMixBuf);
68#endif
69
70/*
71 * Soft Volume Control
72 *
73 * The external code supplies an 8-bit volume (attenuation) value in the
74 * 0 .. 255 range. This represents 0 to -96dB attenuation where an input
75 * value of 0 corresponds to -96dB and 255 corresponds to 0dB (unchanged).
76 *
77 * Each step thus corresponds to 96 / 256 or 0.375dB. Every 6dB (16 steps)
78 * represents doubling the sample value.
79 *
80 * For internal use, the volume control needs to be converted to a 16-bit
81 * (sort of) exponential value between 1 and 65536. This is used with fixed
82 * point arithmetic such that 65536 means 1.0 and 1 means 1/65536.
83 *
84 * For actual volume calculation, 33.31 fixed point is used. Maximum (or
85 * unattenuated) volume is represented as 0x40000000; conveniently, this
86 * value fits into a uint32_t.
87 *
88 * To enable fast processing, the maximum volume must be a power of two
89 * and must not have a sign when converted to int32_t. While 0x80000000
90 * violates these constraints, 0x40000000 does not.
91 */
92
93
94/** Logarithmic/exponential volume conversion table. */
95static uint32_t const s_aVolumeConv[256] = {
96 1, 1, 1, 1, 1, 1, 1, 1, /* 7 */
97 1, 2, 2, 2, 2, 2, 2, 2, /* 15 */
98 2, 2, 2, 2, 2, 3, 3, 3, /* 23 */
99 3, 3, 3, 3, 4, 4, 4, 4, /* 31 */
100 4, 4, 5, 5, 5, 5, 5, 6, /* 39 */
101 6, 6, 6, 7, 7, 7, 8, 8, /* 47 */
102 8, 9, 9, 10, 10, 10, 11, 11, /* 55 */
103 12, 12, 13, 13, 14, 15, 15, 16, /* 63 */
104 17, 17, 18, 19, 20, 21, 22, 23, /* 71 */
105 24, 25, 26, 27, 28, 29, 31, 32, /* 79 */
106 33, 35, 36, 38, 40, 41, 43, 45, /* 87 */
107 47, 49, 52, 54, 56, 59, 61, 64, /* 95 */
108 67, 70, 73, 76, 79, 83, 87, 91, /* 103 */
109 95, 99, 103, 108, 112, 117, 123, 128, /* 111 */
110 134, 140, 146, 152, 159, 166, 173, 181, /* 119 */
111 189, 197, 206, 215, 225, 235, 245, 256, /* 127 */
112 267, 279, 292, 304, 318, 332, 347, 362, /* 135 */
113 378, 395, 412, 431, 450, 470, 490, 512, /* 143 */
114 535, 558, 583, 609, 636, 664, 693, 724, /* 151 */
115 756, 790, 825, 861, 899, 939, 981, 1024, /* 159 */
116 1069, 1117, 1166, 1218, 1272, 1328, 1387, 1448, /* 167 */
117 1512, 1579, 1649, 1722, 1798, 1878, 1961, 2048, /* 175 */
118 2139, 2233, 2332, 2435, 2543, 2656, 2774, 2896, /* 183 */
119 3025, 3158, 3298, 3444, 3597, 3756, 3922, 4096, /* 191 */
120 4277, 4467, 4664, 4871, 5087, 5312, 5547, 5793, /* 199 */
121 6049, 6317, 6597, 6889, 7194, 7512, 7845, 8192, /* 207 */
122 8555, 8933, 9329, 9742, 10173, 10624, 11094, 11585, /* 215 */
123 12098, 12634, 13193, 13777, 14387, 15024, 15689, 16384, /* 223 */
124 17109, 17867, 18658, 19484, 20347, 21247, 22188, 23170, /* 231 */
125 24196, 25268, 26386, 27554, 28774, 30048, 31379, 32768, /* 239 */
126 34219, 35734, 37316, 38968, 40693, 42495, 44376, 46341, /* 247 */
127 48393, 50535, 52773, 55109, 57549, 60097, 62757, 65536, /* 255 */
128};
129
130/* Bit shift for fixed point conversion. */
131#define AUDIOMIXBUF_VOL_SHIFT 30
132
133/* Internal representation of 0dB volume (1.0 in fixed point). */
134#define AUDIOMIXBUF_VOL_0DB (1 << AUDIOMIXBUF_VOL_SHIFT)
135
136AssertCompile(AUDIOMIXBUF_VOL_0DB <= 0x40000000); /* Must always hold. */
137AssertCompile(AUDIOMIXBUF_VOL_0DB == 0x40000000); /* For now -- when only attenuation is used. */
138
139
140/**
141 * Returns a mutable pointer to the mixing buffer's audio frame buffer for writing raw
142 * audio frames.
143 *
144 * @returns VBox status code. VINF_TRY_AGAIN for getting next pointer at beginning (circular).
145 * @param pMixBuf Mixing buffer to acquire audio frames from.
146 * @param cFrames Number of requested audio frames to write.
147 * @param ppvFrames Returns a mutable pointer to the buffer's audio frame data.
148 * @param pcFramesToWrite Number of available audio frames to write.
149 *
150 * @remark This function is not thread safe!
151 */
152/** @todo r=bird: This isn't a 'ing Peek function, it's a Read function!
153 * Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaarg!!!!!!!!!!!!!!!!!!! */
154int AudioMixBufPeekMutable(PAUDIOMIXBUF pMixBuf, uint32_t cFrames,
155 PPDMAUDIOFRAME *ppvFrames, uint32_t *pcFramesToWrite)
156{
157 AssertPtrReturn(pMixBuf, VERR_INVALID_POINTER);
158 AssertPtrReturn(ppvFrames, VERR_INVALID_POINTER);
159 AssertPtrReturn(pcFramesToWrite, VERR_INVALID_POINTER);
160
161 int rc;
162
163 if (!cFrames)
164 {
165 *pcFramesToWrite = 0;
166 return VINF_SUCCESS;
167 }
168
169 uint32_t cFramesToWrite;
170 if (pMixBuf->offWrite + cFrames > pMixBuf->cFrames)
171 {
172 cFramesToWrite = pMixBuf->cFrames - pMixBuf->offWrite;
173 rc = VINF_TRY_AGAIN;
174 }
175 else
176 {
177 cFramesToWrite = cFrames;
178 rc = VINF_SUCCESS;
179 }
180
181 *ppvFrames = &pMixBuf->pFrames[pMixBuf->offWrite];
182 AssertPtr(ppvFrames);
183
184 pMixBuf->offWrite = (pMixBuf->offWrite + cFramesToWrite) % pMixBuf->cFrames;
185 Assert(pMixBuf->offWrite <= pMixBuf->cFrames);
186 pMixBuf->cUsed += RT_MIN(cFramesToWrite, pMixBuf->cUsed);
187
188 *pcFramesToWrite = cFramesToWrite;
189
190 return rc;
191}
192
193/**
194 * Clears the entire frame buffer.
195 *
196 * @param pMixBuf Mixing buffer to clear.
197 *
198 */
199void AudioMixBufClear(PAUDIOMIXBUF pMixBuf)
200{
201 AssertPtrReturnVoid(pMixBuf);
202
203 if (pMixBuf->cFrames)
204 RT_BZERO(pMixBuf->pFrames, pMixBuf->cFrames * sizeof(PDMAUDIOFRAME));
205}
206
207/**
208 * Clears (zeroes) the buffer by a certain amount of (used) frames and
209 * keeps track to eventually assigned children buffers.
210 *
211 * @param pMixBuf Mixing buffer to clear.
212 * @param cFramesToClear Number of audio frames to clear.
213 */
214void AudioMixBufFinish(PAUDIOMIXBUF pMixBuf, uint32_t cFramesToClear)
215{
216 AUDMIXBUF_LOG(("cFramesToClear=%RU32\n", cFramesToClear));
217 AUDMIXBUF_LOG(("%s: offRead=%RU32, cUsed=%RU32\n",
218 pMixBuf->pszName, pMixBuf->offRead, pMixBuf->cUsed));
219
220 AssertStmt(cFramesToClear <= pMixBuf->cFrames, cFramesToClear = pMixBuf->cFrames);
221
222/** @todo r=bird: Why isn't this done when reading/releaseing ? */
223 PAUDIOMIXBUF pIter;
224 RTListForEach(&pMixBuf->lstChildren, pIter, AUDIOMIXBUF, Node)
225 {
226 AUDMIXBUF_LOG(("\t%s: cMixed=%RU32 -> %RU32\n",
227 pIter->pszName, pIter->cMixed, pIter->cMixed - cFramesToClear));
228
229 pIter->cMixed -= RT_MIN(pIter->cMixed, cFramesToClear);
230 /* Note: Do not increment pIter->cUsed here, as this gets done when reading from that buffer using AudioMixBufReadXXX. */
231 }
232
233/** @todo r=bird: waste of time? */
234 uint32_t cClearOff;
235 uint32_t cClearLen;
236
237 /* Clear end of buffer (wrap around). */
238 if (cFramesToClear > pMixBuf->offRead)
239 {
240 cClearOff = pMixBuf->cFrames - (cFramesToClear - pMixBuf->offRead);
241 cClearLen = pMixBuf->cFrames - cClearOff;
242
243 AUDMIXBUF_LOG(("Clearing1: %RU32 - %RU32\n", cClearOff, cClearOff + cClearLen));
244
245 RT_BZERO(pMixBuf->pFrames + cClearOff, cClearLen * sizeof(PDMAUDIOFRAME));
246
247 Assert(cFramesToClear >= cClearLen);
248 cFramesToClear -= cClearLen;
249 }
250
251 /* Clear beginning of buffer. */
252 if ( cFramesToClear
253 && pMixBuf->offRead)
254 {
255 Assert(pMixBuf->offRead >= cFramesToClear);
256
257 cClearOff = pMixBuf->offRead - cFramesToClear;
258 cClearLen = cFramesToClear;
259
260 Assert(cClearOff + cClearLen <= pMixBuf->cFrames);
261
262 AUDMIXBUF_LOG(("Clearing2: %RU32 - %RU32\n", cClearOff, cClearOff + cClearLen));
263
264 RT_BZERO(pMixBuf->pFrames + cClearOff, cClearLen * sizeof(PDMAUDIOFRAME));
265 }
266}
267
268/**
269 * Destroys (uninitializes) a mixing buffer.
270 *
271 * @param pMixBuf Mixing buffer to destroy.
272 */
273void AudioMixBufDestroy(PAUDIOMIXBUF pMixBuf)
274{
275 if (!pMixBuf)
276 return;
277
278 /* Ignore calls for an uninitialized (zeroed) or already destroyed instance. Happens a lot. */
279 if ( pMixBuf->uMagic == 0
280 || pMixBuf->uMagic == ~AUDIOMIXBUF_MAGIC)
281 {
282 Assert(!pMixBuf->pszName);
283 Assert(!pMixBuf->pRate);
284 Assert(!pMixBuf->pFrames);
285 Assert(!pMixBuf->cFrames);
286 return;
287 }
288
289 Assert(pMixBuf->uMagic == AUDIOMIXBUF_MAGIC);
290 pMixBuf->uMagic = ~AUDIOMIXBUF_MAGIC;
291
292 AudioMixBufUnlink(pMixBuf);
293
294 if (pMixBuf->pszName)
295 {
296 AUDMIXBUF_LOG(("%s\n", pMixBuf->pszName));
297
298 RTStrFree(pMixBuf->pszName);
299 pMixBuf->pszName = NULL;
300 }
301
302 if (pMixBuf->pRate)
303 {
304 RTMemFree(pMixBuf->pRate);
305 pMixBuf->pRate = NULL;
306 }
307
308 if (pMixBuf->pFrames)
309 {
310 Assert(pMixBuf->cFrames);
311
312 RTMemFree(pMixBuf->pFrames);
313 pMixBuf->pFrames = NULL;
314 }
315
316 pMixBuf->cFrames = 0;
317}
318
319/**
320 * Returns the size (in audio frames) of free audio buffer space.
321 *
322 * @return uint32_t Size (in audio frames) of free audio buffer space.
323 * @param pMixBuf Mixing buffer to return free size for.
324 */
325uint32_t AudioMixBufFree(PAUDIOMIXBUF pMixBuf)
326{
327 AssertPtrReturn(pMixBuf, 0);
328
329 uint32_t cFrames, cFramesFree;
330 if (pMixBuf->pParent)
331 {
332 /*
333 * As a linked child buffer we want to know how many frames
334 * already have been consumed by the parent.
335 */
336 cFrames = pMixBuf->pParent->cFrames;
337
338 Assert(pMixBuf->cMixed <= cFrames);
339 cFramesFree = cFrames - pMixBuf->cMixed;
340 }
341 else /* As a parent. */
342 {
343 cFrames = pMixBuf->cFrames;
344 Assert(cFrames >= pMixBuf->cUsed);
345 cFramesFree = pMixBuf->cFrames - pMixBuf->cUsed;
346 }
347
348 AUDMIXBUF_LOG(("%s: %RU32 of %RU32\n", pMixBuf->pszName, cFramesFree, cFrames));
349 return cFramesFree;
350}
351
352/**
353 * Returns the size (in bytes) of free audio buffer space.
354 *
355 * @return uint32_t Size (in bytes) of free audio buffer space.
356 * @param pMixBuf Mixing buffer to return free size for.
357 */
358uint32_t AudioMixBufFreeBytes(PAUDIOMIXBUF pMixBuf)
359{
360 return AUDIOMIXBUF_F2B(pMixBuf, AudioMixBufFree(pMixBuf));
361}
362
363/**
364 * Allocates the internal audio frame buffer.
365 *
366 * @returns VBox status code.
367 * @param pMixBuf Mixing buffer to allocate frame buffer for.
368 * @param cFrames Number of audio frames to allocate.
369 */
370static int audioMixBufAlloc(PAUDIOMIXBUF pMixBuf, uint32_t cFrames)
371{
372 AssertPtrReturn(pMixBuf, VERR_INVALID_POINTER);
373 AssertReturn(cFrames, VERR_INVALID_PARAMETER);
374
375 AUDMIXBUF_LOG(("%s: cFrames=%RU32\n", pMixBuf->pszName, cFrames));
376
377 size_t cbFrames = cFrames * sizeof(PDMAUDIOFRAME);
378 pMixBuf->pFrames = (PPDMAUDIOFRAME)RTMemAllocZ(cbFrames);
379 if (pMixBuf->pFrames)
380 {
381 pMixBuf->cFrames = cFrames;
382 return VINF_SUCCESS;
383 }
384 return VERR_NO_MEMORY;
385}
386
387#ifdef AUDIOMIXBUF_DEBUG_MACROS
388# define AUDMIXBUF_MACRO_LOG(x) AUDMIXBUF_LOG(x)
389#elif defined(VBOX_AUDIO_TESTCASE_VERBOSE) /* Warning: VBOX_AUDIO_TESTCASE_VERBOSE will generate huge logs! */
390# define AUDMIXBUF_MACRO_LOG(x) RTPrintf x
391#else
392# define AUDMIXBUF_MACRO_LOG(x) do {} while (0)
393#endif
394
395/**
396 * Macro for generating the conversion routines from/to different formats.
397 * Be careful what to pass in/out, as most of the macros are optimized for speed and
398 * thus don't do any bounds checking!
399 *
400 * Note: Currently does not handle any endianness conversion yet!
401 */
402#define AUDMIXBUF_CONVERT(a_Name, a_Type, _aMin, _aMax, _aSigned, _aShift) \
403 /* Clips a specific output value to a single sample value. */ \
404 DECLINLINE(int64_t) audioMixBufClipFrom##a_Name(a_Type aVal) \
405 { \
406 /* left shifting of signed values is not defined, therefore the intermediate uint64_t cast */ \
407 if (_aSigned) \
408 return (int64_t) (((uint64_t) ((int64_t) aVal )) << (32 - _aShift)); \
409 return (int64_t) (((uint64_t) ((int64_t) aVal - ((_aMax >> 1) + 1))) << (32 - _aShift)); \
410 } \
411 \
412 /* Clips a single sample value to a specific output value. */ \
413 DECLINLINE(a_Type) audioMixBufClipTo##a_Name(int64_t iVal) \
414 { \
415 /*if (iVal >= 0x7fffffff) return _aMax; if (iVal < -INT64_C(0x80000000)) return _aMin;*/ \
416 if (!(((uint64_t)iVal + UINT64_C(0x80000000)) & UINT64_C(0xffffffff00000000))) \
417 { \
418 if (_aSigned) \
419 return (a_Type) (iVal >> (32 - _aShift)); \
420 return (a_Type) ((iVal >> (32 - _aShift)) + ((_aMax >> 1) + 1)); \
421 } \
422 return iVal >= 0 ? _aMax : _aMin; \
423 } \
424 \
425 DECLCALLBACK(uint32_t) audioMixBufConvFrom##a_Name##Stereo(PPDMAUDIOFRAME paDst, const void *pvSrc, uint32_t cbSrc, \
426 PCAUDMIXBUFCONVOPTS pOpts) \
427 { \
428 a_Type const *pSrc = (a_Type const *)pvSrc; \
429 uint32_t cFrames = RT_MIN(pOpts->cFrames, cbSrc / sizeof(a_Type)); \
430 AUDMIXBUF_MACRO_LOG(("cFrames=%RU32, BpS=%zu, lVol=%RU32, rVol=%RU32\n", \
431 pOpts->cFrames, sizeof(a_Type), pOpts->From.Volume.uLeft, pOpts->From.Volume.uRight)); \
432 for (uint32_t i = 0; i < cFrames; i++) \
433 { \
434 paDst->i64LSample = ASMMult2xS32RetS64((int32_t)audioMixBufClipFrom##a_Name(*pSrc++), pOpts->From.Volume.uLeft ) >> AUDIOMIXBUF_VOL_SHIFT; \
435 paDst->i64RSample = ASMMult2xS32RetS64((int32_t)audioMixBufClipFrom##a_Name(*pSrc++), pOpts->From.Volume.uRight) >> AUDIOMIXBUF_VOL_SHIFT; \
436 paDst++; \
437 } \
438 \
439 return cFrames; \
440 } \
441 \
442 DECLCALLBACK(uint32_t) audioMixBufConvFrom##a_Name##Mono(PPDMAUDIOFRAME paDst, const void *pvSrc, uint32_t cbSrc, \
443 PCAUDMIXBUFCONVOPTS pOpts) \
444 { \
445 a_Type const *pSrc = (a_Type const *)pvSrc; \
446 const uint32_t cFrames = RT_MIN(pOpts->cFrames, cbSrc / sizeof(a_Type)); \
447 AUDMIXBUF_MACRO_LOG(("cFrames=%RU32, BpS=%zu, lVol=%RU32, rVol=%RU32\n", \
448 cFrames, sizeof(a_Type), pOpts->From.Volume.uLeft, pOpts->From.Volume.uRight)); \
449 for (uint32_t i = 0; i < cFrames; i++) \
450 { \
451 paDst->i64LSample = ASMMult2xS32RetS64((int32_t)audioMixBufClipFrom##a_Name(*pSrc), pOpts->From.Volume.uLeft) >> AUDIOMIXBUF_VOL_SHIFT; \
452 paDst->i64RSample = ASMMult2xS32RetS64((int32_t)audioMixBufClipFrom##a_Name(*pSrc), pOpts->From.Volume.uRight) >> AUDIOMIXBUF_VOL_SHIFT; \
453 pSrc++; \
454 paDst++; \
455 } \
456 \
457 return cFrames; \
458 } \
459 \
460 DECLCALLBACK(void) audioMixBufConvTo##a_Name##Stereo(void *pvDst, PCPDMAUDIOFRAME paSrc, PCAUDMIXBUFCONVOPTS pOpts) \
461 { \
462 PCPDMAUDIOFRAME pSrc = paSrc; \
463 a_Type *pDst = (a_Type *)pvDst; \
464 uint32_t cFrames = pOpts->cFrames; \
465 while (cFrames--) \
466 { \
467 AUDMIXBUF_MACRO_LOG(("%p: l=%RI64, r=%RI64\n", pSrc, pSrc->i64LSample, pSrc->i64RSample)); \
468 pDst[0] = audioMixBufClipTo##a_Name(pSrc->i64LSample); \
469 pDst[1] = audioMixBufClipTo##a_Name(pSrc->i64RSample); \
470 AUDMIXBUF_MACRO_LOG(("\t-> l=%RI16, r=%RI16\n", pDst[0], pDst[1])); \
471 pDst += 2; \
472 pSrc++; \
473 } \
474 } \
475 \
476 DECLCALLBACK(void) audioMixBufConvTo##a_Name##Mono(void *pvDst, PCPDMAUDIOFRAME paSrc, PCAUDMIXBUFCONVOPTS pOpts) \
477 { \
478 PCPDMAUDIOFRAME pSrc = paSrc; \
479 a_Type *pDst = (a_Type *)pvDst; \
480 uint32_t cFrames = pOpts->cFrames; \
481 while (cFrames--) \
482 { \
483 *pDst++ = audioMixBufClipTo##a_Name((pSrc->i64LSample + pSrc->i64RSample) / 2); \
484 pSrc++; \
485 } \
486 } \
487 /* Encoders for peek: */ \
488 \
489 /* 2ch -> 2ch */ \
490 static DECLCALLBACK(void) RT_CONCAT(audioMixBufEncode2ChTo2Ch,a_Name)(void *pvDst, int64_t const *pi64Src, uint32_t cFrames, \
491 PAUDIOMIXBUFPEEKSTATE pState) \
492 { \
493 RT_NOREF_PV(pState); \
494 a_Type *pDst = (a_Type *)pvDst; \
495 while (cFrames-- > 0) \
496 { \
497 pDst[0] = audioMixBufClipTo##a_Name(pi64Src[0]); \
498 pDst[1] = audioMixBufClipTo##a_Name(pi64Src[1]); \
499 AUDMIXBUF_MACRO_LOG(("%p: %RI64 / %RI64 => %RI64 / %RI64\n", \
500 pi64Src[0], pi64Src[0], pi64Src[1], (int64_t)pDst[0], (int64_t)pDst[1])); \
501 pDst += 2; \
502 pi64Src += 2; \
503 } \
504 } \
505 \
506 /* 2ch -> 1ch */ \
507 static DECLCALLBACK(void) RT_CONCAT(audioMixBufEncode2ChTo1Ch,a_Name)(void *pvDst, int64_t const *pi64Src, uint32_t cFrames, \
508 PAUDIOMIXBUFPEEKSTATE pState) \
509 { \
510 RT_NOREF_PV(pState); \
511 a_Type *pDst = (a_Type *)pvDst; \
512 while (cFrames-- > 0) \
513 { \
514 pDst[0] = audioMixBufClipTo##a_Name((pi64Src[0] + pi64Src[1]) / 2); \
515 pDst += 1; \
516 pi64Src += 2; \
517 } \
518 } \
519 \
520 /* 1ch -> 2ch */ \
521 static DECLCALLBACK(void) RT_CONCAT(audioMixBufEncode1ChTo2Ch,a_Name)(void *pvDst, int64_t const *pi64Src, uint32_t cFrames, \
522 PAUDIOMIXBUFPEEKSTATE pState) \
523 { \
524 RT_NOREF_PV(pState); \
525 a_Type *pDst = (a_Type *)pvDst; \
526 while (cFrames-- > 0) \
527 { \
528 pDst[0] = pDst[1] = audioMixBufClipTo##a_Name(pi64Src[0]); \
529 pDst += 2; \
530 pi64Src += 2; /** @todo when we do multi channel mixbuf support, this can change to 1 */ \
531 } \
532 } \
533 /* 1ch -> 1ch */ \
534 static DECLCALLBACK(void) RT_CONCAT(audioMixBufEncode1ChTo1Ch,a_Name)(void *pvDst, int64_t const *pi64Src, uint32_t cFrames, \
535 PAUDIOMIXBUFPEEKSTATE pState) \
536 { \
537 RT_NOREF_PV(pState); \
538 a_Type *pDst = (a_Type *)pvDst; \
539 while (cFrames-- > 0) \
540 { \
541 pDst[0] = audioMixBufClipTo##a_Name(pi64Src[0]); \
542 pDst += 1; \
543 pi64Src += 2; /** @todo when we do multi channel mixbuf support, this can change to 1 */ \
544 } \
545 }
546
547
548/* audioMixBufConvXXXS8: 8 bit, signed. */
549AUDMIXBUF_CONVERT(S8 /* Name */, int8_t, INT8_MIN /* Min */, INT8_MAX /* Max */, true /* fSigned */, 8 /* cShift */)
550/* audioMixBufConvXXXU8: 8 bit, unsigned. */
551AUDMIXBUF_CONVERT(U8 /* Name */, uint8_t, 0 /* Min */, UINT8_MAX /* Max */, false /* fSigned */, 8 /* cShift */)
552/* audioMixBufConvXXXS16: 16 bit, signed. */
553AUDMIXBUF_CONVERT(S16 /* Name */, int16_t, INT16_MIN /* Min */, INT16_MAX /* Max */, true /* fSigned */, 16 /* cShift */)
554/* audioMixBufConvXXXU16: 16 bit, unsigned. */
555AUDMIXBUF_CONVERT(U16 /* Name */, uint16_t, 0 /* Min */, UINT16_MAX /* Max */, false /* fSigned */, 16 /* cShift */)
556/* audioMixBufConvXXXS32: 32 bit, signed. */
557AUDMIXBUF_CONVERT(S32 /* Name */, int32_t, INT32_MIN /* Min */, INT32_MAX /* Max */, true /* fSigned */, 32 /* cShift */)
558/* audioMixBufConvXXXU32: 32 bit, unsigned. */
559AUDMIXBUF_CONVERT(U32 /* Name */, uint32_t, 0 /* Min */, UINT32_MAX /* Max */, false /* fSigned */, 32 /* cShift */)
560
561#undef AUDMIXBUF_CONVERT
562
563/*
564 * Manually coded signed 64-bit conversion.
565 */
566#if 0
567DECLCALLBACK(uint32_t) audioMixBufConvFromS64Stereo(PPDMAUDIOFRAME paDst, const void *pvSrc, uint32_t cbSrc,
568 PCAUDMIXBUFCONVOPTS pOpts)
569{
570 _aType const *pSrc = (_aType const *)pvSrc;
571 uint32_t cFrames = RT_MIN(pOpts->cFrames, cbSrc / sizeof(_aType));
572 AUDMIXBUF_MACRO_LOG(("cFrames=%RU32, BpS=%zu, lVol=%RU32, rVol=%RU32\n",
573 pOpts->cFrames, sizeof(_aType), pOpts->From.Volume.uLeft, pOpts->From.Volume.uRight));
574 for (uint32_t i = 0; i < cFrames; i++)
575 {
576 paDst->i64LSample = ASMMult2xS32RetS64((int32_t)audioMixBufClipFrom##_aName(*pSrc++), pOpts->From.Volume.uLeft ) >> AUDIOMIXBUF_VOL_SHIFT; \
577 paDst->i64RSample = ASMMult2xS32RetS64((int32_t)audioMixBufClipFrom##_aName(*pSrc++), pOpts->From.Volume.uRight) >> AUDIOMIXBUF_VOL_SHIFT; \
578 paDst++;
579 }
580
581 return cFrames;
582}
583#endif
584
585DECLCALLBACK(void) audioMixBufConvToRawS64Stereo(void *pvDst, PCPDMAUDIOFRAME paSrc, PCAUDMIXBUFCONVOPTS pOpts)
586{
587 AssertCompile(sizeof(paSrc[0]) == sizeof(int64_t) * 2);
588 memcpy(pvDst, paSrc, sizeof(int64_t) * 2 * pOpts->cFrames);
589}
590
591
592static DECLCALLBACK(void)
593audioMixBufEncode2ChTo2ChRaw(void *pvDst, int64_t const *pi64Src, uint32_t cFrames, PAUDIOMIXBUFPEEKSTATE pState)
594{
595 RT_NOREF_PV(pState);
596 memcpy(pvDst, pi64Src, sizeof(int64_t) * 2 * cFrames);
597}
598
599static DECLCALLBACK(void)
600audioMixBufEncode2ChTo1ChRaw(void *pvDst, int64_t const *pi64Src, uint32_t cFrames, PAUDIOMIXBUFPEEKSTATE pState)
601{
602 RT_NOREF_PV(pState);
603 int64_t *pi64Dst = (int64_t *)pvDst;
604 while (cFrames-- > 0)
605 {
606 *pi64Dst = (pi64Src[0] + pi64Src[1]) / 2;
607 pi64Dst += 1;
608 pi64Src += 2;
609 }
610}
611
612static DECLCALLBACK(void)
613audioMixBufEncode1ChTo2ChRaw(void *pvDst, int64_t const *pi64Src, uint32_t cFrames, PAUDIOMIXBUFPEEKSTATE pState)
614{
615 RT_NOREF_PV(pState);
616 int64_t *pi64Dst = (int64_t *)pvDst;
617 while (cFrames-- > 0)
618 {
619 pi64Dst[0] = pi64Dst[1] = *pi64Src;
620 pi64Dst += 2;
621 pi64Src += 2; /** @todo when we do multi channel mixbuf support, this can change to 1 */
622 }
623}
624
625static DECLCALLBACK(void)
626audioMixBufEncode1ChTo1ChRaw(void *pvDst, int64_t const *pi64Src, uint32_t cFrames, PAUDIOMIXBUFPEEKSTATE pState)
627{
628 RT_NOREF_PV(pState);
629 /** @todo memcpy(pvDst, pi64Src, sizeof(int64_t) * 1 * cFrames); when we do
630 * multi channel mixbuf support. */
631 int64_t *pi64Dst = (int64_t *)pvDst;
632 while (cFrames-- > 0)
633 {
634 *pi64Dst = *pi64Src;
635 pi64Dst += 1;
636 pi64Src += 2;
637 }
638}
639
640
641
642#define AUDMIXBUF_MIXOP(_aName, _aOp) \
643 static void audioMixBufOp##_aName(PPDMAUDIOFRAME paDst, uint32_t cDstFrames, \
644 PPDMAUDIOFRAME paSrc, uint32_t cSrcFrames, \
645 PAUDIOSTREAMRATE pRate, \
646 uint32_t *pcDstWritten, uint32_t *pcSrcRead) \
647 { \
648 AUDMIXBUF_MACRO_LOG(("cSrcFrames=%RU32, cDstFrames=%RU32\n", cSrcFrames, cDstFrames)); \
649 AUDMIXBUF_MACRO_LOG(("Rate: offSrc=%RU32, offDst=%RU32, uDstInc=%RU32\n", \
650 pRate->offSrc, \
651 (uint32_t)(pRate->offDst >> 32), (uint32_t)(pRate->uDstInc >> 32))); \
652 \
653 if (pRate->uDstInc == RT_BIT_64(32)) /* No conversion needed? */ \
654 { \
655 uint32_t cFrames = RT_MIN(cSrcFrames, cDstFrames); \
656 AUDMIXBUF_MACRO_LOG(("cFrames=%RU32\n", cFrames)); \
657 for (uint32_t i = 0; i < cFrames; i++) \
658 { \
659 paDst[i].i64LSample _aOp paSrc[i].i64LSample; \
660 paDst[i].i64RSample _aOp paSrc[i].i64RSample; \
661 } \
662 \
663 if (pcDstWritten) \
664 *pcDstWritten = cFrames; \
665 if (pcSrcRead) \
666 *pcSrcRead = cFrames; \
667 return; \
668 } \
669 \
670 PPDMAUDIOFRAME pSrc = paSrc; \
671 PPDMAUDIOFRAME pSrcEnd = &paSrc[cSrcFrames]; \
672 PPDMAUDIOFRAME pDst = paDst; \
673 PPDMAUDIOFRAME pDstEnd = &paDst[cDstFrames]; \
674 PDMAUDIOFRAME frameLast = pRate->SrcLast.Frame; \
675 \
676 while ((uintptr_t)pDst < (uintptr_t)pDstEnd) \
677 { \
678 Assert((uintptr_t)pSrc <= (uintptr_t)pSrcEnd); \
679 if ((uintptr_t)pSrc >= (uintptr_t)pSrcEnd) \
680 break; \
681 \
682 while (pRate->offSrc <= (pRate->offDst >> 32)) \
683 { \
684 Assert((uintptr_t)pSrc < (uintptr_t)pSrcEnd); \
685 frameLast = *pSrc++; \
686 pRate->offSrc++; \
687 if (pSrc == pSrcEnd) \
688 break; \
689 } \
690 \
691 Assert((uintptr_t)pSrc <= (uintptr_t)pSrcEnd); \
692 if (pSrc == pSrcEnd) \
693 break; \
694 \
695 PDMAUDIOFRAME frameCur = *pSrc; \
696 \
697 /* Interpolate. */ \
698 int64_t offDstLow = pRate->offDst & UINT32_MAX; \
699 \
700 PDMAUDIOFRAME frameOut; \
701 frameOut.i64LSample = ( frameLast.i64LSample * ((int64_t)_4G - offDstLow) \
702 + frameCur.i64LSample * offDstLow) >> 32; \
703 frameOut.i64RSample = ( frameLast.i64RSample * ((int64_t)_4G - offDstLow) \
704 + frameCur.i64RSample * offDstLow) >> 32; \
705 \
706 pDst->i64LSample _aOp frameOut.i64LSample; \
707 pDst->i64RSample _aOp frameOut.i64RSample; \
708 \
709 pDst++; \
710 pRate->offDst += pRate->uDstInc; \
711 \
712 AUDMIXBUF_MACRO_LOG((" offDstLow=%RI64, l=%RI64, r=%RI64 (cur l=%RI64, r=%RI64); offDst=%#'RX64\n", offDstLow, \
713 pDst->i64LSample >> 32, pDst->i64RSample >> 32, \
714 frameCur.i64LSample >> 32, frameCur.i64RSample >> 32, \
715 pRate->offDst)); \
716 } \
717 \
718 pRate->SrcLast.Frame = frameLast; \
719 if (pcDstWritten) \
720 *pcDstWritten = pDst - paDst; \
721 if (pcSrcRead) \
722 *pcSrcRead = pSrc - paSrc; \
723 \
724 AUDMIXBUF_MACRO_LOG(("%zu source frames -> %zu dest frames\n", pSrc - paSrc, pDst - paDst)); \
725 AUDMIXBUF_MACRO_LOG(("pRate->srcSampleLast l=%RI64, r=%RI64\n", \
726 pRate->SrcFrameLast.i64LSample, pRate->SrcFrameLast.i64RSample)); \
727 }
728
729/* audioMixBufOpAssign: Assigns values from source buffer to destination bufffer, overwriting the destination. */
730AUDMIXBUF_MIXOP(Assign /* Name */, = /* Operation */)
731#if 0 /* unused */
732/* audioMixBufOpBlend: Blends together the values from both, the source and the destination buffer. */
733AUDMIXBUF_MIXOP(Blend /* Name */, += /* Operation */)
734#endif
735
736#undef AUDMIXBUF_MIXOP
737#undef AUDMIXBUF_MACRO_LOG
738
739/** Dummy conversion used when the source is muted. */
740static DECLCALLBACK(uint32_t)
741audioMixBufConvFromSilence(PPDMAUDIOFRAME paDst, const void *pvSrc, uint32_t cbSrc, PCAUDMIXBUFCONVOPTS pOpts)
742{
743 RT_NOREF(cbSrc, pvSrc);
744
745 /* Internally zero always corresponds to silence. */
746 RT_BZERO(paDst, pOpts->cFrames * sizeof(paDst[0]));
747 return pOpts->cFrames;
748}
749
750/**
751 * Looks up the matching conversion function for converting audio frames from a
752 * source format.
753 *
754 * @returns Pointer to matching conversion function, NULL if not supported.
755 * @param pProps The audio format to find a "from" converter for.
756 */
757static PFNAUDIOMIXBUFCONVFROM audioMixBufConvFromLookup(PCPDMAUDIOPCMPROPS pProps)
758{
759 if (PDMAudioPropsIsSigned(pProps))
760 {
761 switch (PDMAudioPropsChannels(pProps))
762 {
763 case 2:
764 switch (PDMAudioPropsSampleSize(pProps))
765 {
766 case 1: return audioMixBufConvFromS8Stereo;
767 case 2: return audioMixBufConvFromS16Stereo;
768 case 4: return audioMixBufConvFromS32Stereo;
769 //case 8: return pProps->fRaw ? audioMixBufConvToRawS64Stereo : NULL;
770 default: return NULL;
771 }
772
773 case 1:
774 switch (PDMAudioPropsSampleSize(pProps))
775 {
776 case 1: return audioMixBufConvFromS8Mono;
777 case 2: return audioMixBufConvFromS16Mono;
778 case 4: return audioMixBufConvFromS32Mono;
779 default: return NULL;
780 }
781 default:
782 return NULL;
783 }
784 }
785 else /* Unsigned */
786 {
787 switch (PDMAudioPropsChannels(pProps))
788 {
789 case 2:
790 switch (PDMAudioPropsSampleSize(pProps))
791 {
792 case 1: return audioMixBufConvFromU8Stereo;
793 case 2: return audioMixBufConvFromU16Stereo;
794 case 4: return audioMixBufConvFromU32Stereo;
795 default: return NULL;
796 }
797
798 case 1:
799 switch (PDMAudioPropsSampleSize(pProps))
800 {
801 case 1: return audioMixBufConvFromU8Mono;
802 case 2: return audioMixBufConvFromU16Mono;
803 case 4: return audioMixBufConvFromU32Mono;
804 default: return NULL;
805 }
806 default:
807 return NULL;
808 }
809 }
810 /* not reached */
811}
812
813/**
814 * Looks up the matching conversion function for converting audio frames to a
815 * destination format.
816 *
817 * @returns Pointer to matching conversion function, NULL if not supported.
818 * @param pProps The audio format to find a "to" converter for.
819 */
820static PFNAUDIOMIXBUFCONVTO audioMixBufConvToLookup(PCPDMAUDIOPCMPROPS pProps)
821{
822 if (PDMAudioPropsIsSigned(pProps))
823 {
824 switch (PDMAudioPropsChannels(pProps))
825 {
826 case 2:
827 switch (PDMAudioPropsSampleSize(pProps))
828 {
829 case 1: return audioMixBufConvToS8Stereo;
830 case 2: return audioMixBufConvToS16Stereo;
831 case 4: return audioMixBufConvToS32Stereo;
832 case 8: return pProps->fRaw ? audioMixBufConvToRawS64Stereo : NULL;
833 default: return NULL;
834 }
835
836 case 1:
837 switch (PDMAudioPropsSampleSize(pProps))
838 {
839 case 1: return audioMixBufConvToS8Mono;
840 case 2: return audioMixBufConvToS16Mono;
841 case 4: return audioMixBufConvToS32Mono;
842 default: return NULL;
843 }
844 default:
845 return NULL;
846 }
847 }
848 else /* Unsigned */
849 {
850 switch (PDMAudioPropsChannels(pProps))
851 {
852 case 2:
853 switch (PDMAudioPropsSampleSize(pProps))
854 {
855 case 1: return audioMixBufConvToU8Stereo;
856 case 2: return audioMixBufConvToU16Stereo;
857 case 4: return audioMixBufConvToU32Stereo;
858 default: return NULL;
859 }
860
861 case 1:
862 switch (PDMAudioPropsSampleSize(pProps))
863 {
864 case 1: return audioMixBufConvToU8Mono;
865 case 2: return audioMixBufConvToU16Mono;
866 case 4: return audioMixBufConvToU32Mono;
867 default: return NULL;
868 }
869 default:
870 return NULL;
871 }
872 }
873 /* not reached */
874}
875
876/**
877 * Converts a PDM audio volume to an internal mixing buffer volume.
878 *
879 * @returns VBox status code.
880 * @param pVolDst Where to store the converted mixing buffer volume.
881 * @param pVolSrc Volume to convert.
882 */
883static int audioMixBufConvVol(PAUDMIXBUFVOL pVolDst, PPDMAUDIOVOLUME pVolSrc)
884{
885 if (!pVolSrc->fMuted) /* Only change/convert the volume value if we're not muted. */
886 {
887 uint8_t uVolL = pVolSrc->uLeft & 0xFF;
888 uint8_t uVolR = pVolSrc->uRight & 0xFF;
889
890 /** @todo Ensure that the input is in the correct range/initialized! */
891 pVolDst->uLeft = s_aVolumeConv[uVolL] * (AUDIOMIXBUF_VOL_0DB >> 16);
892 pVolDst->uRight = s_aVolumeConv[uVolR] * (AUDIOMIXBUF_VOL_0DB >> 16);
893 }
894
895 pVolDst->fMuted = pVolSrc->fMuted;
896
897 return VINF_SUCCESS;
898}
899
900/**
901 * Initializes a mixing buffer.
902 *
903 * @returns VBox status code.
904 * @param pMixBuf Mixing buffer to initialize.
905 * @param pszName Name of mixing buffer for easier identification. Optional.
906 * @param pProps PCM audio properties to use for the mixing buffer.
907 * @param cFrames Maximum number of audio frames the mixing buffer can hold.
908 */
909int AudioMixBufInit(PAUDIOMIXBUF pMixBuf, const char *pszName, PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames)
910{
911 AssertPtrReturn(pMixBuf, VERR_INVALID_POINTER);
912 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
913 AssertPtrReturn(pProps, VERR_INVALID_POINTER);
914 Assert(PDMAudioPropsAreValid(pProps));
915
916 pMixBuf->uMagic = AUDIOMIXBUF_MAGIC;
917 pMixBuf->pParent = NULL;
918
919 RTListInit(&pMixBuf->lstChildren);
920 pMixBuf->cChildren = 0;
921
922 pMixBuf->pFrames = NULL;
923 pMixBuf->cFrames = 0;
924
925 pMixBuf->offRead = 0;
926 pMixBuf->offWrite = 0;
927 pMixBuf->cMixed = 0;
928 pMixBuf->cUsed = 0;
929
930 /* Set initial volume to max. */
931 pMixBuf->Volume.fMuted = false;
932 pMixBuf->Volume.uLeft = AUDIOMIXBUF_VOL_0DB;
933 pMixBuf->Volume.uRight = AUDIOMIXBUF_VOL_0DB;
934
935 /* Prevent division by zero.
936 * Do a 1:1 conversion according to AUDIOMIXBUF_S2B_RATIO. */
937 pMixBuf->iFreqRatio = 1 << 20;
938
939 pMixBuf->pRate = NULL;
940
941 /** @todo r=bird: Why invent a new representation for the mixer? See also
942 * comment in pdmaudioifs.h about missing MAKE macros. */
943 pMixBuf->uAudioFmt = AUDMIXBUF_AUDIO_FMT_MAKE(pProps->uHz,
944 PDMAudioPropsChannels(pProps),
945 PDMAudioPropsSampleBits(pProps),
946 pProps->fSigned);
947
948 pMixBuf->Props = *pProps;
949 pMixBuf->pfnConvFrom = audioMixBufConvFromLookup(pProps);
950 pMixBuf->pfnConvTo = audioMixBufConvToLookup(pProps);
951
952 pMixBuf->pszName = RTStrDup(pszName);
953 if (!pMixBuf->pszName)
954 return VERR_NO_MEMORY;
955
956
957#ifdef AUDMIXBUF_LOG_ENABLED
958 char szTmp[PDMAUDIOPROPSTOSTRING_MAX];
959 AUDMIXBUF_LOG(("%s: %s\n", pMixBuf->pszName, PDMAudioPropsToString(pProps, szTmp, sizeof(szTmp))));
960#endif
961
962 return audioMixBufAlloc(pMixBuf, cFrames);
963}
964
965/**
966 * Returns @c true if there are any audio frames available for processing,
967 * @c false if not.
968 *
969 * @return bool @c true if there are any audio frames available for processing, @c false if not.
970 * @param pMixBuf Mixing buffer to return value for.
971 */
972bool AudioMixBufIsEmpty(PAUDIOMIXBUF pMixBuf)
973{
974 AssertPtrReturn(pMixBuf, true);
975
976 if (pMixBuf->pParent)
977 return (pMixBuf->cMixed == 0);
978 return (pMixBuf->cUsed == 0);
979}
980
981/**
982 * Calculates the frequency (sample rate) ratio of mixing buffer A in relation to mixing buffer B.
983 *
984 * @returns Calculated frequency ratio.
985 * @param pMixBufA First mixing buffer.
986 * @param pMixBufB Second mixing buffer.
987 */
988static int64_t audioMixBufCalcFreqRatio(PAUDIOMIXBUF pMixBufA, PAUDIOMIXBUF pMixBufB)
989{
990 int64_t iRatio = (int64_t)((uint64_t)PDMAudioPropsHz(&pMixBufA->Props) << 32) / PDMAudioPropsHz(&pMixBufB->Props);
991 AssertStmt(iRatio, iRatio = RT_BIT_64(32) /*1:1*/);
992 return iRatio;
993}
994
995/**
996 * Links an audio mixing buffer to a parent mixing buffer.
997 *
998 * A parent mixing buffer can have multiple children mixing buffers [1:N],
999 * whereas a child only can have one parent mixing buffer [N:1].
1000 *
1001 * The mixing direction always goes from the child/children buffer(s) to the
1002 * parent buffer.
1003 *
1004 * For guest audio output the host backend "owns" the parent mixing buffer, the
1005 * device emulation "owns" the child/children.
1006 *
1007 * The audio format of each mixing buffer can vary; the internal mixing code
1008 * then will automatically do the (needed) conversion.
1009 *
1010 * @returns VBox status code.
1011 * @param pMixBuf Mixing buffer to link parent to.
1012 * @param pParent Parent mixing buffer to use for linking.
1013 *
1014 * @remark Circular linking is not allowed.
1015 */
1016int AudioMixBufLinkTo(PAUDIOMIXBUF pMixBuf, PAUDIOMIXBUF pParent)
1017{
1018 AssertPtrReturn(pMixBuf, VERR_INVALID_POINTER);
1019 AssertPtrReturn(pParent, VERR_INVALID_POINTER);
1020
1021 AssertMsgReturn(AUDMIXBUF_FMT_SAMPLE_FREQ(pParent->uAudioFmt),
1022 ("Parent frame frequency (Hz) not set\n"), VERR_INVALID_PARAMETER);
1023 AssertMsgReturn(AUDMIXBUF_FMT_SAMPLE_FREQ(pMixBuf->uAudioFmt),
1024 ("Buffer sample frequency (Hz) not set\n"), VERR_INVALID_PARAMETER);
1025 AssertMsgReturn(pMixBuf != pParent,
1026 ("Circular linking not allowed\n"), VERR_INVALID_PARAMETER);
1027
1028 if (pMixBuf->pParent) /* Already linked? */
1029 {
1030 AUDMIXBUF_LOG(("%s: Already linked to parent '%s'\n",
1031 pMixBuf->pszName, pMixBuf->pParent->pszName));
1032 return VERR_ACCESS_DENIED;
1033 }
1034
1035 RTListAppend(&pParent->lstChildren, &pMixBuf->Node);
1036 pParent->cChildren++;
1037
1038 /* Set the parent. */
1039 pMixBuf->pParent = pParent;
1040
1041 /* Calculate the frequency ratios. */
1042 pMixBuf->iFreqRatio = audioMixBufCalcFreqRatio(pParent, pMixBuf);
1043
1044 int rc = VINF_SUCCESS;
1045#if 0
1046 uint32_t cFrames = (uint32_t)RT_MIN( ((uint64_t)pParent->cFrames << 32)
1047 / pMixBuf->iFreqRatio, _64K /* 64K frames max. */);
1048 if (!cFrames)
1049 cFrames = pParent->cFrames;
1050
1051 int rc = VINF_SUCCESS;
1052
1053 if (cFrames != pMixBuf->cFrames)
1054 {
1055 AUDMIXBUF_LOG(("%s: Reallocating frames %RU32 -> %RU32\n",
1056 pMixBuf->pszName, pMixBuf->cFrames, cFrames));
1057
1058 uint32_t cbSamples = cFrames * sizeof(PDMAUDIOSAMPLE);
1059 Assert(cbSamples);
1060 pMixBuf->pSamples = (PPDMAUDIOSAMPLE)RTMemRealloc(pMixBuf->pSamples, cbSamples);
1061 if (!pMixBuf->pSamples)
1062 rc = VERR_NO_MEMORY;
1063
1064 if (RT_SUCCESS(rc))
1065 {
1066 pMixBuf->cFrames = cFrames;
1067
1068 /* Make sure to zero the reallocated buffer so that it can be
1069 * used properly when blending with another buffer later. */
1070 RT_BZERO(pMixBuf->pSamples, cbSamples);
1071 }
1072 }
1073#endif
1074
1075 if (RT_SUCCESS(rc))
1076 {
1077 if (!pMixBuf->pRate)
1078 {
1079 pMixBuf->pRate = (PAUDIOSTREAMRATE)RTMemAllocZ(sizeof(AUDIOSTREAMRATE));
1080 AssertReturn(pMixBuf->pRate, VERR_NO_MEMORY);
1081 }
1082 else
1083 RT_BZERO(pMixBuf->pRate, sizeof(AUDIOSTREAMRATE));
1084
1085 /*
1086 * Some examples to get an idea of what uDstInc holds:
1087 * 44100 to 44100 -> (44100<<32) / 44100 = 0x01'00000000 (4294967296)
1088 * 22050 to 44100 -> (22050<<32) / 44100 = 0x00'80000000 (2147483648)
1089 * 44100 to 22050 -> (44100<<32) / 22050 = 0x02'00000000 (8589934592)
1090 * 44100 to 48000 -> (44100<<32) / 48000 = 0x00'EB333333 (3946001203.2)
1091 * 48000 to 44100 -> (48000<<32) / 44100 = 0x01'16A3B35F (4674794335.7823129251700680272109)
1092 *
1093 * Note! The iFreqRatio is the same but with the frequencies switched.
1094 */
1095 pMixBuf->pRate->uDstInc = ((uint64_t)PDMAudioPropsHz(&pMixBuf->Props) << 32) / PDMAudioPropsHz(&pParent->Props);
1096
1097 AUDMIXBUF_LOG(("%RU32 Hz vs parent %RU32 Hz => iFreqRatio=0x%'RX64 uDstInc=0x%'RX64; cFrames=%RU32 (%RU32 parent); name: %s, parent: %s\n",
1098 PDMAudioPropsHz(&pMixBuf->Props), PDMAudioPropsHz(&pParent->Props), pMixBuf->iFreqRatio,
1099 pMixBuf->pRate->uDstInc, pMixBuf->cFrames, pParent->cFrames, pMixBuf->pszName, pMixBuf->pParent->pszName));
1100 }
1101
1102 return rc;
1103}
1104
1105/**
1106 * Returns number of available live frames, that is, frames that
1107 * have been written into the mixing buffer but not have been processed yet.
1108 *
1109 * For a parent buffer, this simply returns the currently used number of frames
1110 * in the buffer.
1111 *
1112 * For a child buffer, this returns the number of frames which have been mixed
1113 * to the parent and were not processed by the parent yet.
1114 *
1115 * @return uint32_t Number of live frames available.
1116 * @param pMixBuf Mixing buffer to return value for.
1117 */
1118uint32_t AudioMixBufLive(PAUDIOMIXBUF pMixBuf)
1119{
1120 AssertPtrReturn(pMixBuf, 0);
1121
1122#ifdef RT_STRICT
1123 uint32_t cFrames;
1124#endif
1125 uint32_t cAvail;
1126 if (pMixBuf->pParent) /* Is this a child buffer? */
1127 {
1128#ifdef RT_STRICT
1129 /* Use the frame count from the parent, as
1130 * pMixBuf->cMixed specifies the frame count
1131 * in parent frames. */
1132 cFrames = pMixBuf->pParent->cFrames;
1133#endif
1134 cAvail = pMixBuf->cMixed;
1135 }
1136 else
1137 {
1138#ifdef RT_STRICT
1139 cFrames = pMixBuf->cFrames;
1140#endif
1141 cAvail = pMixBuf->cUsed;
1142 }
1143
1144 Assert(cAvail <= cFrames);
1145 return cAvail;
1146}
1147
1148/**
1149 * Mixes audio frames from a source mixing buffer to a destination mixing buffer.
1150 *
1151 * @returns VBox status code.
1152 * VERR_BUFFER_UNDERFLOW if the source did not have enough audio data.
1153 * VERR_BUFFER_OVERFLOW if the destination did not have enough space to store the converted source audio data.
1154 *
1155 * @param pDst Destination mixing buffer.
1156 * @param pSrc Source mixing buffer.
1157 * @param cSrcOff Offset of source audio frames to mix.
1158 * @param cSrcFrames Number of source audio frames to mix.
1159 * @param pcSrcMixed Number of source audio frames successfully mixed. Optional.
1160 */
1161static int audioMixBufMixTo(PAUDIOMIXBUF pDst, PAUDIOMIXBUF pSrc, uint32_t cSrcOff, uint32_t cSrcFrames,
1162 uint32_t *pcSrcMixed)
1163{
1164 AssertPtrReturn(pDst, VERR_INVALID_POINTER);
1165 AssertPtrReturn(pSrc, VERR_INVALID_POINTER);
1166 /* pcSrcMixed is optional. */
1167
1168 AssertMsgReturn(pDst == pSrc->pParent, ("Source buffer '%s' is not a child of destination '%s'\n",
1169 pSrc->pszName, pDst->pszName), VERR_INVALID_PARAMETER);
1170 uint32_t cReadTotal = 0;
1171 uint32_t cWrittenTotal = 0;
1172
1173 Assert(pSrc->cMixed <= pDst->cFrames);
1174
1175 Assert(pSrc->cUsed >= pDst->cMixed);
1176 Assert(pDst->cUsed <= pDst->cFrames);
1177
1178 uint32_t offSrcRead = cSrcOff;
1179
1180 uint32_t offDstWrite = pDst->offWrite;
1181 uint32_t cDstMixed = pSrc->cMixed;
1182
1183 uint32_t cSrcAvail = RT_MIN(cSrcFrames, pSrc->cUsed);
1184 uint32_t cDstAvail = pDst->cFrames - pDst->cUsed; /** @todo Use pDst->cMixed later? */
1185
1186 AUDMIXBUF_LOG(("%s (%RU32 available) -> %s (%RU32 available)\n",
1187 pSrc->pszName, cSrcAvail, pDst->pszName, cDstAvail));
1188#ifdef DEBUG
1189 audioMixBufDbgPrintInternal(pDst, __FUNCTION__);
1190#endif
1191
1192 if (!cSrcAvail)
1193 return VERR_BUFFER_UNDERFLOW;
1194
1195 if (!cDstAvail)
1196 return VERR_BUFFER_OVERFLOW;
1197
1198 uint32_t cSrcToRead = 0;
1199 uint32_t cSrcRead;
1200
1201 uint32_t cDstToWrite;
1202 uint32_t cDstWritten;
1203
1204 int rc = VINF_SUCCESS;
1205
1206 while (cSrcAvail && cDstAvail)
1207 {
1208 cSrcToRead = RT_MIN(cSrcAvail, pSrc->cFrames - offSrcRead);
1209 cDstToWrite = RT_MIN(cDstAvail, pDst->cFrames - offDstWrite);
1210
1211 AUDMIXBUF_LOG((" Src: %RU32 @ %RU32 -> reading %RU32\n", cSrcAvail, offSrcRead, cSrcToRead));
1212 AUDMIXBUF_LOG((" Dst: %RU32 @ %RU32 -> writing %RU32\n", cDstAvail, offDstWrite, cDstToWrite));
1213
1214 if ( !cDstToWrite
1215 || !cSrcToRead)
1216 {
1217 break;
1218 }
1219
1220 cDstWritten = cSrcRead = 0;
1221
1222 Assert(offSrcRead < pSrc->cFrames);
1223 Assert(offSrcRead + cSrcToRead <= pSrc->cFrames);
1224
1225 Assert(offDstWrite < pDst->cFrames);
1226 Assert(offDstWrite + cDstToWrite <= pDst->cFrames);
1227
1228 audioMixBufOpAssign(pDst->pFrames + offDstWrite, cDstToWrite,
1229 pSrc->pFrames + offSrcRead, cSrcToRead,
1230 pSrc->pRate, &cDstWritten, &cSrcRead);
1231
1232 cReadTotal += cSrcRead;
1233 cWrittenTotal += cDstWritten;
1234
1235 offSrcRead = (offSrcRead + cSrcRead) % pSrc->cFrames;
1236 offDstWrite = (offDstWrite + cDstWritten) % pDst->cFrames;
1237
1238 cDstMixed += cDstWritten;
1239
1240 Assert(cSrcAvail >= cSrcRead);
1241 cSrcAvail -= cSrcRead;
1242
1243 Assert(cDstAvail >= cDstWritten);
1244 cDstAvail -= cDstWritten;
1245
1246 AUDMIXBUF_LOG((" %RU32 read (%RU32 left @ %RU32), %RU32 written (%RU32 left @ %RU32)\n",
1247 cSrcRead, cSrcAvail, offSrcRead,
1248 cDstWritten, cDstAvail, offDstWrite));
1249 }
1250
1251 pSrc->offRead = offSrcRead;
1252 Assert(pSrc->cUsed >= cReadTotal);
1253 pSrc->cUsed -= RT_MIN(pSrc->cUsed, cReadTotal);
1254
1255 /* Note: Always count in parent frames, as the rate can differ! */
1256 pSrc->cMixed = RT_MIN(cDstMixed, pDst->cFrames);
1257
1258 pDst->offWrite = offDstWrite;
1259 Assert(pDst->offWrite <= pDst->cFrames);
1260 Assert((pDst->cUsed + cWrittenTotal) <= pDst->cFrames);
1261 pDst->cUsed += cWrittenTotal;
1262
1263 /* If there are more used frames than fitting in the destination buffer,
1264 * adjust the values accordingly.
1265 *
1266 * This can happen if this routine has been called too often without
1267 * actually processing the destination buffer in between. */
1268 if (pDst->cUsed > pDst->cFrames)
1269 {
1270 LogFunc(("%s: Warning: Destination buffer used %RU32 / %RU32 frames\n", pDst->pszName, pDst->cUsed, pDst->cFrames));
1271 pDst->offWrite = 0;
1272 pDst->cUsed = pDst->cFrames;
1273
1274 rc = VERR_BUFFER_OVERFLOW;
1275 }
1276
1277#ifdef DEBUG
1278 audioMixBufDbgValidate(pSrc);
1279 audioMixBufDbgValidate(pDst);
1280
1281 Assert(pSrc->cMixed <= pDst->cFrames);
1282#endif
1283
1284#ifdef AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA
1285 uint32_t offRead = pDst->offRead;
1286
1287 uint32_t cLeft = cWrittenTotal;
1288 while (cLeft)
1289 {
1290 uint8_t auBuf[256];
1291 RT_ZERO(auBuf);
1292
1293 Assert(sizeof(auBuf) >= 4);
1294 Assert(sizeof(auBuf) % 4 == 0);
1295
1296 uint32_t cToRead = RT_MIN(AUDIOMIXBUF_B2F(pDst, sizeof(auBuf)), RT_MIN(cLeft, pDst->cFrames - offRead));
1297 Assert(cToRead <= pDst->cUsed);
1298
1299 AUDMIXBUFCONVOPTS convOpts;
1300 RT_ZERO(convOpts);
1301 convOpts.cFrames = cToRead;
1302
1303 pDst->pfnConvTo(auBuf, pDst->pFrames + offRead, &convOpts);
1304
1305 RTFILE fh;
1306 int rc2 = RTFileOpen(&fh, AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA_PATH "mixbuf_mixto.pcm",
1307 RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
1308 if (RT_SUCCESS(rc2))
1309 {
1310 RTFileWrite(fh, auBuf, AUDIOMIXBUF_F2B(pDst, cToRead), NULL);
1311 RTFileClose(fh);
1312 }
1313
1314 offRead = (offRead + cToRead) % pDst->cFrames;
1315 cLeft -= cToRead;
1316 }
1317#endif /* AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA */
1318
1319#ifdef DEBUG
1320 audioMixBufDbgPrintInternal(pDst, __FUNCTION__);
1321#endif
1322
1323 if (pcSrcMixed)
1324 *pcSrcMixed = cReadTotal;
1325
1326 AUDMIXBUF_LOG(("cReadTotal=%RU32, cWrittenTotal=%RU32, cSrcMixed=%RU32, cDstUsed=%RU32, rc=%Rrc\n",
1327 cReadTotal, cWrittenTotal, pSrc->cMixed, pDst->cUsed, rc));
1328 return rc;
1329}
1330
1331/**
1332 * Mixes audio frames down to the parent mixing buffer, extended version.
1333 *
1334 * @returns VBox status code. See audioMixBufMixTo() for a more detailed explanation.
1335 * @param pMixBuf Source mixing buffer to mix to its parent.
1336 * @param cSrcOffset Offset (in frames) of source mixing buffer.
1337 * @param cSrcFrames Number of source audio frames to mix to its parent.
1338 * @param pcSrcMixed Number of source audio frames successfully mixed. Optional.
1339 */
1340int AudioMixBufMixToParentEx(PAUDIOMIXBUF pMixBuf, uint32_t cSrcOffset, uint32_t cSrcFrames, uint32_t *pcSrcMixed)
1341{
1342 AssertMsgReturn(VALID_PTR(pMixBuf->pParent),
1343 ("Buffer is not linked to a parent buffer\n"),
1344 VERR_INVALID_PARAMETER);
1345
1346 return audioMixBufMixTo(pMixBuf->pParent, pMixBuf, cSrcOffset, cSrcFrames, pcSrcMixed);
1347}
1348
1349/**
1350 * Mixes audio frames down to the parent mixing buffer.
1351 *
1352 * @returns VBox status code. See audioMixBufMixTo() for a more detailed explanation.
1353 * @param pMixBuf Source mixing buffer to mix to its parent.
1354 * @param cSrcFrames Number of source audio frames to mix to its parent.
1355 * @param pcSrcMixed Number of source audio frames successfully mixed. Optional.
1356 */
1357int AudioMixBufMixToParent(PAUDIOMIXBUF pMixBuf, uint32_t cSrcFrames, uint32_t *pcSrcMixed)
1358{
1359 return audioMixBufMixTo(pMixBuf->pParent, pMixBuf, pMixBuf->offRead, cSrcFrames, pcSrcMixed);
1360}
1361
1362#ifdef DEBUG
1363
1364/**
1365 * Prints a single mixing buffer.
1366 * Internal helper function for debugging. Do not use directly.
1367 *
1368 * @returns VBox status code.
1369 * @param pMixBuf Mixing buffer to print.
1370 * @param pszFunc Function name to log this for.
1371 * @param fIsParent Whether this is a parent buffer or not.
1372 * @param uIdtLvl Indention level to use.
1373 */
1374DECL_FORCE_INLINE(void) audioMixBufDbgPrintSingle(PAUDIOMIXBUF pMixBuf, const char *pszFunc, bool fIsParent, uint16_t uIdtLvl)
1375{
1376 Log(("%s: %*s[%s] %s: offRead=%RU32, offWrite=%RU32, cMixed=%RU32 -> %RU32/%RU32\n",
1377 pszFunc, uIdtLvl * 4, "", fIsParent ? "PARENT" : "CHILD",
1378 pMixBuf->pszName, pMixBuf->offRead, pMixBuf->offWrite, pMixBuf->cMixed, pMixBuf->cUsed, pMixBuf->cFrames));
1379}
1380
1381/**
1382 * Validates a single mixing buffer.
1383 *
1384 * @return @true if the buffer state is valid or @false if not.
1385 * @param pMixBuf Mixing buffer to validate.
1386 */
1387DECL_FORCE_INLINE(bool) audioMixBufDbgValidate(PAUDIOMIXBUF pMixBuf)
1388{
1389 //const uint32_t offReadEnd = (pMixBuf->offRead + pMixBuf->cUsed) % pMixBuf->cFrames;
1390 //const uint32_t offWriteEnd = (pMixBuf->offWrite + (pMixBuf->cFrames - pMixBuf->cUsed)) % pMixBuf->cFrames;
1391
1392 bool fValid = true;
1393
1394 AssertStmt(pMixBuf->offRead <= pMixBuf->cFrames, fValid = false);
1395 AssertStmt(pMixBuf->offWrite <= pMixBuf->cFrames, fValid = false);
1396 AssertStmt(pMixBuf->cUsed <= pMixBuf->cFrames, fValid = false);
1397
1398 if (pMixBuf->offWrite > pMixBuf->offRead)
1399 {
1400 if (pMixBuf->offWrite - pMixBuf->offRead != pMixBuf->cUsed)
1401 fValid = false;
1402 }
1403 else if (pMixBuf->offWrite < pMixBuf->offRead)
1404 {
1405 if (pMixBuf->offWrite + pMixBuf->cFrames - pMixBuf->offRead != pMixBuf->cUsed)
1406 fValid = false;
1407 }
1408
1409 if (!fValid)
1410 {
1411 audioMixBufDbgPrintInternal(pMixBuf, __FUNCTION__);
1412 AssertFailed();
1413 }
1414
1415 return fValid;
1416}
1417
1418/**
1419 * Internal helper function for audioMixBufPrintChain().
1420 * Do not use directly.
1421 *
1422 * @returns VBox status code.
1423 * @param pMixBuf Mixing buffer to print.
1424 * @param pszFunc Function name to print the chain for.
1425 * @param uIdtLvl Indention level to use.
1426 * @param pcChildren Pointer to children counter.
1427 */
1428DECL_FORCE_INLINE(void) audioMixBufDbgPrintChainHelper(PAUDIOMIXBUF pMixBuf, const char *pszFunc, uint16_t uIdtLvl,
1429 size_t *pcChildren)
1430{
1431 PAUDIOMIXBUF pIter;
1432 RTListForEach(&pMixBuf->lstChildren, pIter, AUDIOMIXBUF, Node)
1433 {
1434 audioMixBufDbgPrintSingle(pIter, pszFunc, false /* ifIsParent */, uIdtLvl + 1);
1435 *pcChildren++;
1436 }
1437}
1438
1439DECL_FORCE_INLINE(void) audioMixBufDbgPrintChainInternal(PAUDIOMIXBUF pMixBuf, const char *pszFunc)
1440{
1441 PAUDIOMIXBUF pParent = pMixBuf->pParent;
1442 while (pParent)
1443 {
1444 if (!pParent->pParent)
1445 break;
1446
1447 pParent = pParent->pParent;
1448 }
1449
1450 if (!pParent)
1451 pParent = pMixBuf;
1452
1453 audioMixBufDbgPrintSingle(pParent, pszFunc, true /* fIsParent */, 0 /* uIdtLvl */);
1454
1455 /* Recursively iterate children. */
1456 size_t cChildren = 0;
1457 audioMixBufDbgPrintChainHelper(pParent, pszFunc, 0 /* uIdtLvl */, &cChildren);
1458
1459 Log(("%s: Children: %zu\n", pszFunc, cChildren));
1460}
1461
1462/**
1463 * Prints statistics and status of the full chain of a mixing buffer to the logger,
1464 * starting from the top root mixing buffer.
1465 * For debug versions only.
1466 *
1467 * @returns VBox status code.
1468 * @param pMixBuf Mixing buffer to print.
1469 */
1470void AudioMixBufDbgPrintChain(PAUDIOMIXBUF pMixBuf)
1471{
1472 audioMixBufDbgPrintChainInternal(pMixBuf, __FUNCTION__);
1473}
1474
1475DECL_FORCE_INLINE(void) audioMixBufDbgPrintInternal(PAUDIOMIXBUF pMixBuf, const char *pszFunc)
1476{
1477 PAUDIOMIXBUF pParent = pMixBuf;
1478 if (pMixBuf->pParent)
1479 pParent = pMixBuf->pParent;
1480
1481 audioMixBufDbgPrintSingle(pMixBuf, pszFunc, pParent == pMixBuf /* fIsParent */, 0 /* iIdtLevel */);
1482
1483 PAUDIOMIXBUF pIter;
1484 RTListForEach(&pMixBuf->lstChildren, pIter, AUDIOMIXBUF, Node)
1485 {
1486 if (pIter == pMixBuf)
1487 continue;
1488 audioMixBufDbgPrintSingle(pIter, pszFunc, false /* fIsParent */, 1 /* iIdtLevel */);
1489 }
1490}
1491
1492/**
1493 * Prints statistics and status of a mixing buffer to the logger.
1494 * For debug versions only.
1495 *
1496 * @returns VBox status code.
1497 * @param pMixBuf Mixing buffer to print.
1498 */
1499void AudioMixBufDbgPrint(PAUDIOMIXBUF pMixBuf)
1500{
1501 audioMixBufDbgPrintInternal(pMixBuf, __FUNCTION__);
1502}
1503
1504#endif /* DEBUG */
1505
1506/**
1507 * Returns the total number of audio frames used.
1508 *
1509 * @return uint32_t
1510 * @param pMixBuf
1511 */
1512uint32_t AudioMixBufUsed(PAUDIOMIXBUF pMixBuf)
1513{
1514 AssertPtrReturn(pMixBuf, 0);
1515 return pMixBuf->cUsed;
1516}
1517
1518/**
1519 * Returns the total number of bytes used.
1520 *
1521 * @return uint32_t
1522 * @param pMixBuf
1523 */
1524uint32_t AudioMixBufUsedBytes(PAUDIOMIXBUF pMixBuf)
1525{
1526 AssertPtrReturn(pMixBuf, 0);
1527 return AUDIOMIXBUF_F2B(pMixBuf, pMixBuf->cUsed);
1528}
1529
1530/**
1531 * Reads audio frames at a specific offset.
1532 *
1533 * @returns VBox status code.
1534 * @param pMixBuf Mixing buffer to read audio frames from.
1535 * @param offFrames Offset (in audio frames) to start reading from.
1536 * @param pvBuf Pointer to buffer to write output to.
1537 * @param cbBuf Size (in bytes) of buffer to write to.
1538 * @param pcbRead Size (in bytes) of data read. Optional.
1539 */
1540int AudioMixBufReadAt(PAUDIOMIXBUF pMixBuf, uint32_t offFrames, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
1541{
1542 return AudioMixBufReadAtEx(pMixBuf, &pMixBuf->Props, offFrames, pvBuf, cbBuf, pcbRead);
1543}
1544
1545/**
1546 * Reads audio frames at a specific offset.
1547 * If the audio format of the mixing buffer and the requested audio format do
1548 * not match the output will be converted accordingly.
1549 *
1550 * @returns VBox status code.
1551 * @param pMixBuf Mixing buffer to read audio frames from.
1552 * @param pDstProps The target format.
1553 * @param offFrames Offset (in audio frames) to start reading from.
1554 * @param pvBuf Pointer to buffer to write output to.
1555 * @param cbBuf Size (in bytes) of buffer to write to.
1556 * @param pcbRead Size (in bytes) of data read. Optional.
1557 */
1558int AudioMixBufReadAtEx(PAUDIOMIXBUF pMixBuf, PCPDMAUDIOPCMPROPS pDstProps,
1559 uint32_t offFrames, void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)
1560{
1561 AssertPtrReturn(pMixBuf, VERR_INVALID_POINTER);
1562 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
1563 /* pcbRead is optional. */
1564
1565 uint32_t cDstFrames = pMixBuf->cFrames;
1566 uint32_t cLive = pMixBuf->cUsed;
1567
1568 uint32_t cDead = cDstFrames - cLive;
1569 uint32_t cToProcess = (uint32_t)AUDIOMIXBUF_F2F_RATIO(pMixBuf, cDead);
1570 cToProcess = RT_MIN(cToProcess, AUDIOMIXBUF_B2F(pMixBuf, cbBuf));
1571
1572 AUDMIXBUF_LOG(("%s: offFrames=%RU32, cLive=%RU32, cDead=%RU32, cToProcess=%RU32\n",
1573 pMixBuf->pszName, offFrames, cLive, cDead, cToProcess));
1574
1575 int rc;
1576 if (cToProcess)
1577 {
1578 PFNAUDIOMIXBUFCONVTO pfnConvTo = NULL;
1579 if (PDMAudioPropsAreEqual(&pMixBuf->Props, pDstProps))
1580 pfnConvTo = pMixBuf->pfnConvTo;
1581 else
1582 pfnConvTo = audioMixBufConvToLookup(pDstProps);
1583 if (pfnConvTo)
1584 {
1585 AUDMIXBUFCONVOPTS convOpts;
1586 RT_ZERO(convOpts);
1587 /* Note: No volume handling/conversion done in the conversion-to macros (yet). */
1588
1589 convOpts.cFrames = cToProcess;
1590
1591 pfnConvTo(pvBuf, pMixBuf->pFrames + offFrames, &convOpts);
1592
1593#ifdef DEBUG
1594 AudioMixBufDbgPrint(pMixBuf);
1595#endif
1596 rc = VINF_SUCCESS;
1597 }
1598 else
1599 {
1600 AssertFailed();
1601 rc = VERR_NOT_SUPPORTED;
1602 }
1603 }
1604 else
1605 rc = VINF_SUCCESS;
1606
1607 if (RT_SUCCESS(rc))
1608 {
1609 if (pcbRead)
1610 *pcbRead = AUDIOMIXBUF_F2B(pMixBuf, cToProcess);
1611 }
1612
1613 AUDMIXBUF_LOG(("cbRead=%RU32, rc=%Rrc\n", AUDIOMIXBUF_F2B(pMixBuf, cToProcess), rc));
1614 return rc;
1615}
1616
1617/**
1618 * Reads audio frames. The audio format of the mixing buffer will be used.
1619 *
1620 * @returns VBox status code.
1621 * @param pMixBuf Mixing buffer to read audio frames from.
1622 * @param pvBuf Pointer to buffer to write output to.
1623 * @param cbBuf Size (in bytes) of buffer to write to.
1624 * @param pcAcquiredFrames Where to return the number of frames in
1625 * the block that was acquired.
1626 */
1627int AudioMixBufAcquireReadBlock(PAUDIOMIXBUF pMixBuf, void *pvBuf, uint32_t cbBuf, uint32_t *pcAcquiredFrames)
1628{
1629 return AudioMixBufAcquireReadBlockEx(pMixBuf, &pMixBuf->Props, pvBuf, cbBuf, pcAcquiredFrames);
1630}
1631
1632/**
1633 * Reads audio frames in a specific audio format.
1634 *
1635 * If the audio format of the mixing buffer and the requested audio format do
1636 * not match the output will be converted accordingly.
1637 *
1638 * @returns VBox status code.
1639 * @param pMixBuf Mixing buffer to read audio frames from.
1640 * @param pDstProps The target format.
1641 * @param pvBuf Pointer to buffer to write output to.
1642 * @param cbBuf Size (in bytes) of buffer to write to.
1643 * @param pcAcquiredFrames Where to return the number of frames in
1644 * the block that was acquired.
1645 */
1646int AudioMixBufAcquireReadBlockEx(PAUDIOMIXBUF pMixBuf, PCPDMAUDIOPCMPROPS pDstProps,
1647 void *pvBuf, uint32_t cbBuf, uint32_t *pcAcquiredFrames)
1648{
1649 AssertPtrReturn(pMixBuf, VERR_INVALID_POINTER);
1650 AssertReturn(cbBuf, VERR_INVALID_PARAMETER);
1651 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
1652 AssertPtrReturn(pcAcquiredFrames, VERR_INVALID_POINTER);
1653
1654 /* Make sure that we at least have space for a full audio frame. */
1655 AssertReturn(AUDIOMIXBUF_B2F(pMixBuf, cbBuf), VERR_INVALID_PARAMETER);
1656
1657 uint32_t cFramesToRead = RT_MIN(pMixBuf->cUsed, AUDIOMIXBUF_B2F(pMixBuf, cbBuf));
1658
1659#ifdef AUDMIXBUF_LOG_ENABLED
1660 char szTmp1[PDMAUDIOPROPSTOSTRING_MAX], szTmp2[PDMAUDIOPROPSTOSTRING_MAX];
1661#endif
1662 AUDMIXBUF_LOG(("%s: cbBuf=%RU32 (%RU32 frames), cFramesToRead=%RU32, MixBuf=%s, pDstProps=%s\n",
1663 pMixBuf->pszName, cbBuf, AUDIOMIXBUF_B2F(pMixBuf, cbBuf), cFramesToRead,
1664 PDMAudioPropsToString(&pMixBuf->Props, szTmp1, sizeof(szTmp1)),
1665 PDMAudioPropsToString(pDstProps, szTmp2, sizeof(szTmp2))));
1666 if (!cFramesToRead)
1667 {
1668#ifdef DEBUG
1669 audioMixBufDbgPrintInternal(pMixBuf, __FUNCTION__);
1670#endif
1671 *pcAcquiredFrames = 0;
1672 return VINF_SUCCESS;
1673 }
1674
1675 PFNAUDIOMIXBUFCONVTO pfnConvTo;
1676 if (PDMAudioPropsAreEqual(&pMixBuf->Props, pDstProps))
1677 pfnConvTo = pMixBuf->pfnConvTo;
1678 else
1679 pfnConvTo = audioMixBufConvToLookup(pDstProps);
1680 AssertReturn(pfnConvTo, VERR_NOT_SUPPORTED);
1681
1682 cFramesToRead = RT_MIN(cFramesToRead, pMixBuf->cFrames - pMixBuf->offRead);
1683 if (cFramesToRead)
1684 {
1685 AUDMIXBUFCONVOPTS convOpts;
1686 RT_ZERO(convOpts);
1687 convOpts.cFrames = cFramesToRead;
1688
1689 AUDMIXBUF_LOG(("cFramesToRead=%RU32\n", cFramesToRead));
1690
1691 pfnConvTo(pvBuf, pMixBuf->pFrames + pMixBuf->offRead, &convOpts);
1692
1693#ifdef AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA
1694 RTFILE fh;
1695 int rc2 = RTFileOpen(&fh, AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA_PATH "mixbuf_readcirc.pcm",
1696 RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
1697 if (RT_SUCCESS(rc2))
1698 {
1699 RTFileWrite(fh, pvBuf, AUDIOMIXBUF_F2B(pMixBuf, cFramesToRead), NULL);
1700 RTFileClose(fh);
1701 }
1702#endif
1703 }
1704
1705 *pcAcquiredFrames = cFramesToRead;
1706
1707#ifdef DEBUG
1708 audioMixBufDbgValidate(pMixBuf);
1709#endif
1710
1711 AUDMIXBUF_LOG(("*pcAcquiredFrames=%RU32 (%RU32 bytes)\n", cFramesToRead, AUDIOMIXBUF_F2B(pMixBuf, cFramesToRead)));
1712 return VINF_SUCCESS;
1713}
1714
1715/**
1716 * Releases a formerly acquired read block.
1717 *
1718 * @param pMixBuf Mixing buffer to release acquired read block for.
1719 * @param cFrames The number of frames to release. (Can be less than the
1720 * acquired count.)
1721 */
1722void AudioMixBufReleaseReadBlock(PAUDIOMIXBUF pMixBuf, uint32_t cFrames)
1723{
1724 AssertPtrReturnVoid(pMixBuf);
1725
1726 if (cFrames)
1727 {
1728 AssertStmt(pMixBuf->cUsed >= cFrames, cFrames = pMixBuf->cUsed);
1729 pMixBuf->offRead = (pMixBuf->offRead + cFrames) % pMixBuf->cFrames;
1730 pMixBuf->cUsed -= cFrames;
1731 }
1732}
1733
1734/**
1735 * Returns the current read position of a mixing buffer.
1736 *
1737 * @returns VBox status code.
1738 * @param pMixBuf Mixing buffer to return position for.
1739 */
1740uint32_t AudioMixBufReadPos(PAUDIOMIXBUF pMixBuf)
1741{
1742 AssertPtrReturn(pMixBuf, 0);
1743
1744 return pMixBuf->offRead;
1745}
1746
1747/**
1748 * Resets a mixing buffer.
1749 *
1750 * @param pMixBuf Mixing buffer to reset.
1751 */
1752void AudioMixBufReset(PAUDIOMIXBUF pMixBuf)
1753{
1754 AssertPtrReturnVoid(pMixBuf);
1755
1756 AUDMIXBUF_LOG(("%s\n", pMixBuf->pszName));
1757
1758 pMixBuf->offRead = 0;
1759 pMixBuf->offWrite = 0;
1760 pMixBuf->cMixed = 0;
1761 pMixBuf->cUsed = 0;
1762
1763 AudioMixBufClear(pMixBuf);
1764}
1765
1766
1767/**
1768 * Drops all the frames in the given mixing buffer.
1769 *
1770 * Similar to AudioMixBufReset, only it doesn't bother clearing the buffer.
1771 *
1772 * @param pMixBuf The mixing buffer.
1773 */
1774void AudioMixBufDrop(PAUDIOMIXBUF pMixBuf)
1775{
1776 AssertPtrReturnVoid(pMixBuf);
1777 AssertReturnVoid(pMixBuf->uMagic == AUDIOMIXBUF_MAGIC);
1778
1779 AUDMIXBUF_LOG(("%s\n", pMixBuf->pszName));
1780
1781 pMixBuf->offRead = 0;
1782 pMixBuf->offWrite = 0;
1783 pMixBuf->cMixed = 0;
1784 pMixBuf->cUsed = 0;
1785}
1786
1787
1788/*
1789 * Resampling core.
1790 */
1791/** @todo Separate down- and up-sampling, borrow filter code from RDP. */
1792#define COPY_LAST_FRAME_1CH(a_pi64Dst, a_pi64Src, a_cChannels) do { \
1793 (a_pi64Dst)[0] = (a_pi64Src)[0]; \
1794 } while (0)
1795#define COPY_LAST_FRAME_2CH(a_pi64Dst, a_pi64Src, a_cChannels) do { \
1796 (a_pi64Dst)[0] = (a_pi64Src)[0]; \
1797 (a_pi64Dst)[1] = (a_pi64Src)[1]; \
1798 } while (0)
1799
1800#define INTERPOLATE_ONE(a_pi64Dst, a_pi64Src, a_pi64Last, a_i64FactorCur, a_i64FactorLast, a_iCh) \
1801 (a_pi64Dst)[a_iCh] = ((a_pi64Last)[a_iCh] * a_i64FactorLast + (a_pi64Src)[a_iCh] * a_i64FactorCur) >> 32
1802#define INTERPOLATE_1CH(a_pi64Dst, a_pi64Src, a_pi64Last, a_i64FactorCur, a_i64FactorLast, a_cChannels) do { \
1803 INTERPOLATE_ONE(a_pi64Dst, a_pi64Src, a_pi64Last, a_i64FactorCur, a_i64FactorLast, 0); \
1804 } while (0)
1805#define INTERPOLATE_2CH(a_pi64Dst, a_pi64Src, a_pi64Last, a_i64FactorCur, a_i64FactorLast, a_cChannels) do { \
1806 INTERPOLATE_ONE(a_pi64Dst, a_pi64Src, a_pi64Last, a_i64FactorCur, a_i64FactorLast, 0); \
1807 INTERPOLATE_ONE(a_pi64Dst, a_pi64Src, a_pi64Last, a_i64FactorCur, a_i64FactorLast, 1); \
1808 } while (0)
1809
1810#define AUDIOMIXBUF_RESAMPLE(a_cChannels, a_Suffix) \
1811 /** @returns Number of destination frames written. */ \
1812 static DECLCALLBACK(uint32_t) \
1813 audioMixBufResample##a_cChannels##Ch##a_Suffix(int64_t *pi64Dst, uint32_t cDstFrames, \
1814 int64_t const *pi64Src, uint32_t cSrcFrames, uint32_t *pcSrcFramesRead, \
1815 PAUDIOSTREAMRATE pRate) \
1816 { \
1817 Log5(("Src: %RU32 L %RU32; Dst: %RU32 L%RU32; uDstInc=%#RX64\n", \
1818 pRate->offSrc, cSrcFrames, RT_HI_U32(pRate->offDst), cDstFrames, pRate->uDstInc)); \
1819 int64_t * const pi64DstStart = pi64Dst; \
1820 int64_t const * const pi64SrcStart = pi64Src; \
1821 \
1822 int64_t ai64LastFrame[a_cChannels]; \
1823 COPY_LAST_FRAME_##a_cChannels##CH(ai64LastFrame, pRate->SrcLast.ai64Samples, a_cChannels); \
1824 \
1825 while (cDstFrames > 0 && cSrcFrames > 0) \
1826 { \
1827 int32_t const cSrcNeeded = RT_HI_U32(pRate->offDst) - pRate->offSrc + 1; \
1828 if (cSrcNeeded > 0) \
1829 { \
1830 if ((uint32_t)cSrcNeeded + 1 < cSrcFrames) \
1831 { \
1832 pRate->offSrc += (uint32_t)cSrcNeeded; \
1833 cSrcFrames -= (uint32_t)cSrcNeeded; \
1834 pi64Src += (uint32_t)cSrcNeeded * a_cChannels; \
1835 COPY_LAST_FRAME_##a_cChannels##CH(ai64LastFrame, &pi64Src[-a_cChannels], a_cChannels); \
1836 } \
1837 else \
1838 { \
1839 pi64Src += cSrcFrames * a_cChannels; \
1840 pRate->offSrc += cSrcFrames; \
1841 COPY_LAST_FRAME_##a_cChannels##CH(pRate->SrcLast.ai64Samples, &pi64Src[-a_cChannels], a_cChannels); \
1842 *pcSrcFramesRead = (pi64Src - pi64SrcStart) / a_cChannels; \
1843 return (pi64Dst - pi64DstStart) / a_cChannels; \
1844 } \
1845 } \
1846 \
1847 /* Interpolate. */ \
1848 int64_t const offFactorCur = pRate->offDst & UINT32_MAX; \
1849 int64_t const offFactorLast = (int64_t)_4G - offFactorCur; \
1850 INTERPOLATE_##a_cChannels##CH(pi64Dst, pi64Src, ai64LastFrame, offFactorCur, offFactorLast, a_cChannels); \
1851 \
1852 /* Advance. */ \
1853 pRate->offDst += pRate->uDstInc; \
1854 pi64Dst += a_cChannels; \
1855 cDstFrames -= 1; \
1856 } \
1857 \
1858 COPY_LAST_FRAME_##a_cChannels##CH(pRate->SrcLast.ai64Samples, ai64LastFrame, a_cChannels); \
1859 *pcSrcFramesRead = (pi64Src - pi64SrcStart) / a_cChannels; \
1860 return (pi64Dst - pi64DstStart) / a_cChannels; \
1861 }
1862
1863AUDIOMIXBUF_RESAMPLE(1,Generic)
1864AUDIOMIXBUF_RESAMPLE(2,Generic)
1865
1866
1867/**
1868 * Initializes the peek state, setting up encoder and (if necessary) resampling.
1869 *
1870 * @returns VBox status code.
1871 */
1872int AudioMixBufInitPeekState(PCAUDIOMIXBUF pMixBuf, PAUDIOMIXBUFPEEKSTATE pState, PCPDMAUDIOPCMPROPS pProps)
1873{
1874 AssertPtr(pMixBuf);
1875 AssertPtr(pState);
1876 AssertPtr(pProps);
1877
1878 /*
1879 * Pick the encoding function first.
1880 */
1881 uint8_t const cSrcCh = PDMAudioPropsChannels(&pMixBuf->Props);
1882 uint8_t const cDstCh = PDMAudioPropsChannels(pProps);
1883 pState->cSrcChannels = cSrcCh;
1884 pState->cDstChannels = cDstCh;
1885 pState->cbDstFrame = PDMAudioPropsFrameSize(pProps);
1886 if (PDMAudioPropsIsSigned(pProps))
1887 {
1888 switch (cDstCh)
1889 {
1890 case 1:
1891 AssertReturn(cSrcCh == 1 || cSrcCh == 2, VERR_OUT_OF_RANGE);
1892 switch (PDMAudioPropsSampleSize(pProps))
1893 {
1894 case 1:
1895 pState->pfnEncode = cSrcCh == 1 ? audioMixBufEncode1ChTo1ChS8 : audioMixBufEncode2ChTo1ChS8;
1896 break;
1897 case 2:
1898 pState->pfnEncode = cSrcCh == 1 ? audioMixBufEncode1ChTo1ChS16 : audioMixBufEncode2ChTo1ChS16;
1899 break;
1900 case 4:
1901 pState->pfnEncode = cSrcCh == 1 ? audioMixBufEncode1ChTo1ChS32 : audioMixBufEncode2ChTo1ChS32;
1902 break;
1903 case 8:
1904 AssertReturn(pProps->fRaw, VERR_DISK_INVALID_FORMAT);
1905 pState->pfnEncode = cSrcCh == 1 ? audioMixBufEncode1ChTo1ChRaw : audioMixBufEncode2ChTo1ChRaw;
1906 break;
1907 default:
1908 AssertMsgFailedReturn(("%u bytes\n", PDMAudioPropsSampleSize(pProps)), VERR_OUT_OF_RANGE);
1909 }
1910 break;
1911 case 2:
1912 AssertReturn(cSrcCh == 1 || cSrcCh == 2, VERR_OUT_OF_RANGE);
1913 switch (PDMAudioPropsSampleSize(pProps))
1914 {
1915 case 1:
1916 pState->pfnEncode = cSrcCh == 1 ? audioMixBufEncode1ChTo2ChS8 : audioMixBufEncode2ChTo2ChS8;
1917 break;
1918 case 2:
1919 pState->pfnEncode = cSrcCh == 1 ? audioMixBufEncode1ChTo2ChS16 : audioMixBufEncode2ChTo2ChS16;
1920 break;
1921 case 4:
1922 pState->pfnEncode = cSrcCh == 1 ? audioMixBufEncode1ChTo2ChS32 : audioMixBufEncode2ChTo2ChS32;
1923 break;
1924 case 8:
1925 AssertReturn(pProps->fRaw, VERR_DISK_INVALID_FORMAT);
1926 pState->pfnEncode = cSrcCh == 1 ? audioMixBufEncode1ChTo2ChRaw : audioMixBufEncode2ChTo2ChRaw;
1927 break;
1928 default:
1929 AssertMsgFailedReturn(("%u bytes\n", PDMAudioPropsSampleSize(pProps)), VERR_OUT_OF_RANGE);
1930 }
1931 break;
1932 default:
1933 /* Note: We may have dedicated encoders for a few selected multichannel
1934 configurations, and generic ones that encodes channel by channel (i.e.
1935 add the mixer channel count, destination frame size, and an array of
1936 destination channel frame offsets to the state). */
1937 AssertMsgFailedReturn(("from %u to %u channels is not implemented yet\n", cSrcCh, cDstCh), VERR_OUT_OF_RANGE);
1938 }
1939 }
1940 else
1941 {
1942 switch (cDstCh)
1943 {
1944 case 1:
1945 AssertReturn(cSrcCh == 1 || cSrcCh == 2, VERR_OUT_OF_RANGE);
1946 switch (PDMAudioPropsSampleSize(pProps))
1947 {
1948 case 1:
1949 pState->pfnEncode = cSrcCh == 1 ? audioMixBufEncode1ChTo1ChU8 : audioMixBufEncode2ChTo1ChU8;
1950 break;
1951 case 2:
1952 pState->pfnEncode = cSrcCh == 1 ? audioMixBufEncode1ChTo1ChU16 : audioMixBufEncode2ChTo1ChU16;
1953 break;
1954 case 4:
1955 pState->pfnEncode = cSrcCh == 1 ? audioMixBufEncode1ChTo1ChU32 : audioMixBufEncode2ChTo1ChU32;
1956 break;
1957 default:
1958 AssertMsgFailedReturn(("%u bytes\n", PDMAudioPropsSampleSize(pProps)), VERR_OUT_OF_RANGE);
1959 }
1960 break;
1961 case 2:
1962 AssertReturn(cSrcCh == 1 || cSrcCh == 2, VERR_OUT_OF_RANGE);
1963 switch (PDMAudioPropsSampleSize(pProps))
1964 {
1965 case 1:
1966 pState->pfnEncode = cSrcCh == 1 ? audioMixBufEncode1ChTo2ChU8 : audioMixBufEncode2ChTo2ChU8;
1967 break;
1968 case 2:
1969 pState->pfnEncode = cSrcCh == 1 ? audioMixBufEncode1ChTo2ChU16 : audioMixBufEncode2ChTo2ChU16;
1970 break;
1971 case 4:
1972 pState->pfnEncode = cSrcCh == 1 ? audioMixBufEncode1ChTo2ChU32 : audioMixBufEncode2ChTo2ChU32;
1973 break;
1974 default:
1975 AssertMsgFailedReturn(("%u bytes\n", PDMAudioPropsSampleSize(pProps)), VERR_OUT_OF_RANGE);
1976 }
1977 break;
1978 default:
1979 /* Note: We may have dedicated encoders for a few selected multichannel
1980 configurations, and generic ones that encodes channel by channel (i.e.
1981 add an array of destination channel frame offsets to the state). */
1982 AssertMsgFailedReturn(("from %u to %u channels is not implemented yet\n", cSrcCh, cDstCh), VERR_OUT_OF_RANGE);
1983 }
1984
1985 }
1986
1987 /*
1988 * Do we need to set up frequency conversion?
1989 *
1990 * Some examples to get an idea of what uDstInc holds:
1991 * 44100 to 44100 -> (44100<<32) / 44100 = 0x01'00000000 (4294967296)
1992 * 22050 to 44100 -> (22050<<32) / 44100 = 0x00'80000000 (2147483648)
1993 * 44100 to 22050 -> (44100<<32) / 22050 = 0x02'00000000 (8589934592)
1994 * 44100 to 48000 -> (44100<<32) / 48000 = 0x00'EB333333 (3946001203.2)
1995 * 48000 to 44100 -> (48000<<32) / 44100 = 0x01'16A3B35F (4674794335.7823129251700680272109)
1996 */
1997 uint32_t const uSrcHz = PDMAudioPropsHz(&pMixBuf->Props);
1998 uint32_t const uDstHz = PDMAudioPropsHz(pProps);
1999 RT_ZERO(pState->Rate);
2000 if (uSrcHz == uDstHz)
2001 {
2002 pState->Rate.fNoConversionNeeded = true;
2003 pState->Rate.uDstInc = RT_BIT_64(32);
2004 pState->Rate.pfnResample = NULL;
2005 }
2006 else
2007 {
2008 AssertReturn(uSrcHz != 0, VERR_INVALID_PARAMETER);
2009 pState->Rate.fNoConversionNeeded = false;
2010 pState->Rate.uDstInc = ((uint64_t)uSrcHz << 32) / uDstHz;
2011 switch (cSrcCh)
2012 {
2013 case 1: pState->Rate.pfnResample = audioMixBufResample1ChGeneric; break;
2014 case 2: pState->Rate.pfnResample = audioMixBufResample2ChGeneric; break;
2015 default:
2016 AssertMsgFailedReturn(("resampling %u changes is not implemented yet\n", cSrcCh), VERR_OUT_OF_RANGE);
2017 }
2018 }
2019 AUDMIXBUF_LOG(("%s: %RU32 Hz to %RU32 Hz => uDstInc=0x%'RX64\n", pMixBuf->pszName, uSrcHz, uDstHz, pState->Rate.uDstInc));
2020 return VINF_SUCCESS;
2021}
2022
2023
2024/**
2025 * Worker for AudioMixBufPeek that handles the rate conversion case.
2026 */
2027DECL_NO_INLINE(static, void)
2028AudioMixBufPeekResampling(PCAUDIOMIXBUF pMixBuf, uint32_t offSrcFrame, uint32_t cMaxSrcFrames, uint32_t *pcSrcFramesPeeked,
2029 PAUDIOMIXBUFPEEKSTATE pState, void *pvDst, uint32_t cbDst, uint32_t *pcbDstPeeked)
2030{
2031 *pcSrcFramesPeeked = 0;
2032 *pcbDstPeeked = 0;
2033 while (cMaxSrcFrames > 0 && cbDst >= pState->cbDstFrame)
2034 {
2035 /* Rate conversion into temporary buffer. */
2036 int64_t ai64DstRate[1024];
2037 uint32_t cSrcFrames = RT_MIN(pMixBuf->cFrames - offSrcFrame, cMaxSrcFrames);
2038 uint32_t cMaxDstFrames = RT_MIN(RT_ELEMENTS(ai64DstRate) / pState->cDstChannels, cbDst / pState->cbDstFrame);
2039 uint32_t const cDstFrames = pState->Rate.pfnResample(ai64DstRate, cMaxDstFrames,
2040 &pMixBuf->pFrames[offSrcFrame].i64LSample, cSrcFrames, &cSrcFrames,
2041 &pState->Rate);
2042 *pcSrcFramesPeeked += cSrcFrames;
2043 cMaxSrcFrames -= cSrcFrames;
2044 offSrcFrame = (offSrcFrame + cSrcFrames) % pMixBuf->cFrames;
2045
2046 /* Encode the converted frames. */
2047 uint32_t const cbDstEncoded = cDstFrames * pState->cbDstFrame;
2048 pState->pfnEncode(pvDst, ai64DstRate, cDstFrames, pState);
2049 *pcbDstPeeked += cbDstEncoded;
2050 cbDst -= cbDstEncoded;
2051 pvDst = (uint8_t *)pvDst + cbDstEncoded;
2052 }
2053}
2054
2055
2056
2057/**
2058 * Copies data out of the mixing buffer, converting it if needed, but leaves the
2059 * read offset untouched.
2060 *
2061 * @param pMixBuf The mixing buffer.
2062 * @param offSrcFrame The offset to start reading at relative to
2063 * current read position (offRead). The caller has
2064 * made sure there is at least this number of
2065 * frames available in the buffer before calling.
2066 * @param cMaxSrcFrames Maximum number of frames to read.
2067 * @param pcSrcFramesPeeked Where to return the actual number of frames read
2068 * from the mixing buffer.
2069 * @param pState Output configuration & conversion state.
2070 * @param pvDst The destination buffer.
2071 * @param cbDst The size of the destination buffer in bytes.
2072 * @param pcbDstPeeked Where to put the actual number of bytes
2073 * returned.
2074 */
2075void AudioMixBufPeek(PCAUDIOMIXBUF pMixBuf, uint32_t offSrcFrame, uint32_t cMaxSrcFrames, uint32_t *pcSrcFramesPeeked,
2076 PAUDIOMIXBUFPEEKSTATE pState, void *pvDst, uint32_t cbDst, uint32_t *pcbDstPeeked)
2077{
2078 /*
2079 * Check inputs.
2080 */
2081 AssertPtr(pMixBuf);
2082 Assert(pMixBuf->uMagic == AUDIOMIXBUF_MAGIC);
2083 AssertPtr(pState);
2084 AssertPtr(pState->pfnEncode);
2085 Assert(pState->cSrcChannels == PDMAudioPropsChannels(&pMixBuf->Props));
2086 Assert(cMaxSrcFrames > 0);
2087 Assert(cMaxSrcFrames <= pMixBuf->cFrames);
2088 Assert(offSrcFrame <= pMixBuf->cFrames);
2089 Assert(offSrcFrame + cMaxSrcFrames <= pMixBuf->cUsed);
2090 AssertPtr(pcSrcFramesPeeked);
2091 AssertPtr(pvDst);
2092 Assert(cbDst >= pState->cbDstFrame);
2093 AssertPtr(pcbDstPeeked);
2094
2095 /*
2096 * Make start frame absolute.
2097 */
2098 offSrcFrame = (pMixBuf->offRead + offSrcFrame) % pMixBuf->cFrames;
2099
2100 /*
2101 * Hopefully no sample rate conversion is necessary...
2102 */
2103 if (pState->Rate.fNoConversionNeeded)
2104 {
2105 /* Figure out how much we should convert. */
2106 cMaxSrcFrames = RT_MIN(cMaxSrcFrames, cbDst / pState->cbDstFrame);
2107 *pcSrcFramesPeeked = cMaxSrcFrames;
2108 *pcbDstPeeked = cMaxSrcFrames * pState->cbDstFrame;
2109
2110 /* First chunk. */
2111 uint32_t const cSrcFrames1 = RT_MIN(pMixBuf->cFrames - offSrcFrame, cMaxSrcFrames);
2112 pState->pfnEncode(pvDst, &pMixBuf->pFrames[offSrcFrame].i64LSample, cSrcFrames1, pState);
2113
2114 /* Another chunk from the start of the mixing buffer? */
2115 if (cMaxSrcFrames > cSrcFrames1)
2116 pState->pfnEncode((uint8_t *)pvDst + cSrcFrames1 * pState->cbDstFrame,
2117 &pMixBuf->pFrames[0].i64LSample, cMaxSrcFrames - cSrcFrames1, pState);
2118 }
2119 else
2120 AudioMixBufPeekResampling(pMixBuf, offSrcFrame, cMaxSrcFrames, pcSrcFramesPeeked, pState, pvDst, cbDst, pcbDstPeeked);
2121}
2122
2123
2124/**
2125 * Advances the read position of the buffer.
2126 *
2127 * For use after done peeking with AudioMixBufPeek().
2128 *
2129 * @param pMixBuf The mixing buffer.
2130 * @param cFrames Number of frames to advance.
2131 */
2132void AudioMixBufAdvance(PAUDIOMIXBUF pMixBuf, uint32_t cFrames)
2133{
2134 AssertPtrReturnVoid(pMixBuf);
2135 AssertReturnVoid(pMixBuf->uMagic == AUDIOMIXBUF_MAGIC);
2136
2137 AssertStmt(cFrames <= pMixBuf->cUsed, cFrames = pMixBuf->cUsed);
2138 pMixBuf->cUsed -= cFrames;
2139 pMixBuf->offRead = (pMixBuf->offRead + cFrames) % pMixBuf->cFrames;
2140 LogFlowFunc(("%s: Advanced %u frames: offRead=%u cUsed=%u\n", pMixBuf->pszName, cFrames, pMixBuf->offRead, pMixBuf->cUsed));
2141}
2142
2143
2144/**
2145 * Sets the overall (master) volume.
2146 *
2147 * @param pMixBuf Mixing buffer to set volume for.
2148 * @param pVol Pointer to volume structure to set.
2149 */
2150void AudioMixBufSetVolume(PAUDIOMIXBUF pMixBuf, PPDMAUDIOVOLUME pVol)
2151{
2152 AssertPtrReturnVoid(pMixBuf);
2153 AssertPtrReturnVoid(pVol);
2154
2155 LogFlowFunc(("%s: lVol=%RU8, rVol=%RU8, fMuted=%RTbool\n", pMixBuf->pszName, pVol->uLeft, pVol->uRight, pVol->fMuted));
2156
2157 int rc2 = audioMixBufConvVol(&pMixBuf->Volume /* Dest */, pVol /* Source */);
2158 AssertRC(rc2);
2159}
2160
2161/**
2162 * Returns the maximum amount of audio frames this buffer can hold.
2163 *
2164 * @return uint32_t Size (in audio frames) the mixing buffer can hold.
2165 * @param pMixBuf Mixing buffer to retrieve maximum for.
2166 */
2167uint32_t AudioMixBufSize(PAUDIOMIXBUF pMixBuf)
2168{
2169 AssertPtrReturn(pMixBuf, 0);
2170 return pMixBuf->cFrames;
2171}
2172
2173/**
2174 * Returns the maximum amount of bytes this buffer can hold.
2175 *
2176 * @return uint32_t Size (in bytes) the mixing buffer can hold.
2177 * @param pMixBuf Mixing buffer to retrieve maximum for.
2178 */
2179uint32_t AudioMixBufSizeBytes(PAUDIOMIXBUF pMixBuf)
2180{
2181 AssertPtrReturn(pMixBuf, 0);
2182 return AUDIOMIXBUF_F2B(pMixBuf, pMixBuf->cFrames);
2183}
2184
2185/**
2186 * Unlinks a mixing buffer from its parent, if any.
2187 *
2188 * @returns VBox status code.
2189 * @param pMixBuf Mixing buffer to unlink from parent.
2190 */
2191void AudioMixBufUnlink(PAUDIOMIXBUF pMixBuf)
2192{
2193 if (!pMixBuf || !pMixBuf->pszName)
2194 return;
2195
2196 AUDMIXBUF_LOG(("%s\n", pMixBuf->pszName));
2197
2198 if (pMixBuf->pParent) /* IS this a children buffer? */
2199 {
2200 AUDMIXBUF_LOG(("%s: Unlinking from parent \"%s\"\n",
2201 pMixBuf->pszName, pMixBuf->pParent->pszName));
2202
2203 RTListNodeRemove(&pMixBuf->Node);
2204
2205 /* Decrease the paren't children count. */
2206 Assert(pMixBuf->pParent->cChildren);
2207 pMixBuf->pParent->cChildren--;
2208
2209 /* Make sure to reset the parent mixing buffer each time it gets linked
2210 * to a new child. */
2211 AudioMixBufReset(pMixBuf->pParent);
2212 pMixBuf->pParent = NULL;
2213 }
2214
2215 PAUDIOMIXBUF pChild, pChildNext;
2216 RTListForEachSafe(&pMixBuf->lstChildren, pChild, pChildNext, AUDIOMIXBUF, Node)
2217 {
2218 AUDMIXBUF_LOG(("\tUnlinking \"%s\"\n", pChild->pszName));
2219
2220 AudioMixBufReset(pChild);
2221
2222 Assert(pChild->pParent == pMixBuf);
2223 pChild->pParent = NULL;
2224
2225 RTListNodeRemove(&pChild->Node);
2226
2227 /* Decrease the children count. */
2228 Assert(pMixBuf->cChildren);
2229 pMixBuf->cChildren--;
2230 }
2231
2232 Assert(RTListIsEmpty(&pMixBuf->lstChildren));
2233 Assert(pMixBuf->cChildren == 0);
2234
2235 AudioMixBufReset(pMixBuf);
2236
2237 if (pMixBuf->pRate)
2238 {
2239 pMixBuf->pRate->offDst = pMixBuf->pRate->offSrc = 0;
2240 pMixBuf->pRate->uDstInc = 0;
2241 }
2242
2243 pMixBuf->iFreqRatio = 1; /* Prevent division by zero. */
2244}
2245
2246/**
2247 * Writes audio frames at a specific offset.
2248 * The sample format being written must match the format of the mixing buffer.
2249 *
2250 * @returns VBox status code.
2251 * @param pMixBuf Pointer to mixing buffer to write to.
2252 * @param offFrames Offset (in frames) starting to write at.
2253 * @param pvBuf Pointer to audio buffer to be written.
2254 * @param cbBuf Size (in bytes) of audio buffer.
2255 * @param pcWritten Returns number of audio frames written. Optional.
2256 */
2257int AudioMixBufWriteAt(PAUDIOMIXBUF pMixBuf, uint32_t offFrames, const void *pvBuf, uint32_t cbBuf, uint32_t *pcWritten)
2258{
2259 return AudioMixBufWriteAtEx(pMixBuf, &pMixBuf->Props, offFrames, pvBuf, cbBuf, pcWritten);
2260}
2261
2262/**
2263 * Writes audio frames at a specific offset.
2264 *
2265 * Note that this operation also modifies the current read and write position
2266 * to \a offFrames + written frames on success.
2267 *
2268 * The audio sample format to be written can be different from the audio format
2269 * the mixing buffer operates on.
2270 *
2271 * @returns VBox status code.
2272 * @param pMixBuf Pointer to mixing buffer to write to.
2273 * @param pSrcProps The source format.
2274 * @param offFrames Offset (in frames) starting to write at.
2275 * @param pvBuf Pointer to audio buffer to be written.
2276 * @param cbBuf Size (in bytes) of audio buffer.
2277 * @param pcWritten Returns number of audio frames written. Optional.
2278 */
2279int AudioMixBufWriteAtEx(PAUDIOMIXBUF pMixBuf, PCPDMAUDIOPCMPROPS pSrcProps,
2280 uint32_t offFrames, const void *pvBuf, uint32_t cbBuf, uint32_t *pcWritten)
2281{
2282 AssertPtrReturn(pMixBuf, VERR_INVALID_POINTER);
2283 AssertReturn(cbBuf, VERR_INVALID_PARAMETER);
2284 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
2285 /* pcbWritten is optional. */
2286
2287 if (offFrames >= pMixBuf->cFrames)
2288 {
2289 if (pcWritten)
2290 *pcWritten = 0;
2291 return VERR_BUFFER_OVERFLOW;
2292 }
2293
2294 /*
2295 * Adjust cToWrite so we don't overflow our buffers.
2296 */
2297 uint32_t cToWrite = RT_MIN(AUDIOMIXBUF_B2F(pMixBuf, cbBuf), pMixBuf->cFrames - offFrames);
2298
2299#ifdef AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA
2300 /*
2301 * Now that we know how much we'll be converting we can log it.
2302 */
2303 RTFILE hFile;
2304 int rc2 = RTFileOpen(&hFile, AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA_PATH "mixbuf_writeat.pcm",
2305 RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
2306 if (RT_SUCCESS(rc2))
2307 {
2308 RTFileWrite(hFile, pvBuf, AUDIOMIXBUF_F2B(pMixBuf, cToWrite), NULL);
2309 RTFileClose(hFile);
2310 }
2311#endif
2312
2313 /*
2314 * Pick the conversion function and do the conversion.
2315 */
2316 PFNAUDIOMIXBUFCONVFROM pfnConvFrom = NULL;
2317 if (!pMixBuf->Volume.fMuted)
2318 {
2319 if (PDMAudioPropsAreEqual(&pMixBuf->Props, pSrcProps))
2320 pfnConvFrom = pMixBuf->pfnConvFrom;
2321 else
2322 pfnConvFrom = audioMixBufConvFromLookup(pSrcProps);
2323 AssertReturn(pfnConvFrom, VERR_NOT_SUPPORTED);
2324 }
2325 else
2326 pfnConvFrom = &audioMixBufConvFromSilence;
2327
2328 int rc = VINF_SUCCESS;
2329
2330 uint32_t cWritten;
2331 if (cToWrite)
2332 {
2333 AUDMIXBUFCONVOPTS convOpts;
2334
2335 convOpts.cFrames = cToWrite;
2336 convOpts.From.Volume.fMuted = pMixBuf->Volume.fMuted;
2337 convOpts.From.Volume.uLeft = pMixBuf->Volume.uLeft;
2338 convOpts.From.Volume.uRight = pMixBuf->Volume.uRight;
2339
2340 cWritten = pfnConvFrom(pMixBuf->pFrames + offFrames, pvBuf, AUDIOMIXBUF_F2B(pMixBuf, cToWrite), &convOpts);
2341 }
2342 else
2343 cWritten = 0;
2344
2345 AUDMIXBUF_LOG(("%s: offFrames=%RU32, cbBuf=%RU32, cToWrite=%RU32 (%zu bytes), cWritten=%RU32 (%zu bytes), rc=%Rrc\n",
2346 pMixBuf->pszName, offFrames, cbBuf,
2347 cToWrite, AUDIOMIXBUF_F2B(pMixBuf, cToWrite),
2348 cWritten, AUDIOMIXBUF_F2B(pMixBuf, cWritten), rc));
2349
2350 if (RT_SUCCESS(rc))
2351 {
2352 pMixBuf->offRead = offFrames % pMixBuf->cFrames;
2353 pMixBuf->offWrite = (offFrames + cWritten) % pMixBuf->cFrames;
2354 pMixBuf->cUsed = cWritten;
2355 pMixBuf->cMixed = 0;
2356
2357#ifdef DEBUG
2358 audioMixBufDbgValidate(pMixBuf);
2359#endif
2360 if (pcWritten)
2361 *pcWritten = cWritten;
2362 }
2363 else
2364 AUDMIXBUF_LOG(("%s: Failed with %Rrc\n", pMixBuf->pszName, rc));
2365
2366 return rc;
2367}
2368
2369/**
2370 * Writes audio frames.
2371 *
2372 * The sample format being written must match the format of the mixing buffer.
2373 *
2374 * @returns VBox status code
2375 * @retval VERR_BUFFER_OVERFLOW if frames which not have been processed yet
2376 * have been overwritten (due to cyclic buffer).
2377 * @param pMixBuf Pointer to mixing buffer to write to.
2378 * @param pvBuf Pointer to audio buffer to be written.
2379 * @param cbBuf Size (in bytes) of audio buffer.
2380 * @param pcWritten Returns number of audio frames written. Optional.
2381 */
2382int AudioMixBufWriteCirc(PAUDIOMIXBUF pMixBuf, const void *pvBuf, uint32_t cbBuf, uint32_t *pcWritten)
2383{
2384 return AudioMixBufWriteCircEx(pMixBuf, &pMixBuf->Props, pvBuf, cbBuf, pcWritten);
2385}
2386
2387/**
2388 * Writes audio frames of a specific format.
2389 * This function might write less data at once than requested.
2390 *
2391 * @returns VBox status code
2392 * @retval VERR_BUFFER_OVERFLOW no space is available for writing anymore.
2393 * @param pMixBuf Pointer to mixing buffer to write to.
2394 * @param pSrcProps The source format.
2395 * @param pvBuf Pointer to audio buffer to be written.
2396 * @param cbBuf Size (in bytes) of audio buffer.
2397 * @param pcWritten Returns number of audio frames written. Optional.
2398 */
2399int AudioMixBufWriteCircEx(PAUDIOMIXBUF pMixBuf, PCPDMAUDIOPCMPROPS pSrcProps,
2400 const void *pvBuf, uint32_t cbBuf, uint32_t *pcWritten)
2401{
2402 /*
2403 * Assert sanity.
2404 */
2405 AssertPtrReturn(pMixBuf, VERR_INVALID_POINTER);
2406 AssertReturn(pMixBuf->uMagic == AUDIOMIXBUF_MAGIC, VERR_INVALID_HANDLE);
2407 Assert(pMixBuf->cFrames);
2408 AssertPtr(pMixBuf->pFrames);
2409 AssertPtrReturn(pvBuf, VERR_INVALID_POINTER);
2410 AssertPtrNullReturn(pcWritten, VERR_INVALID_POINTER);
2411
2412 /*
2413 * Make sure that we at least write a full audio frame.
2414 */
2415 uint32_t const cFramesInBuf = PDMAudioPropsBytesToFrames(pSrcProps, cbBuf);
2416 if (cFramesInBuf > 0)
2417 { /* likely */ }
2418 else
2419 {
2420 if (pcWritten)
2421 *pcWritten = 0;
2422 AssertReturn(cbBuf == 0, VERR_INVALID_PARAMETER);
2423 return VINF_SUCCESS;
2424 }
2425
2426 /*
2427 * Get the conversion function matching pSrcProps, doing special
2428 * optimizations for a muted buffer.
2429 */
2430 PFNAUDIOMIXBUFCONVFROM pfnConvFrom = NULL;
2431 if (!pMixBuf->Volume.fMuted)
2432 {
2433 if (PDMAudioPropsAreEqual(&pMixBuf->Props, pSrcProps))
2434 pfnConvFrom = pMixBuf->pfnConvFrom;
2435 else
2436 pfnConvFrom = audioMixBufConvFromLookup(pSrcProps);
2437 AssertReturn(pfnConvFrom, VERR_NOT_SUPPORTED);
2438 }
2439 else
2440 pfnConvFrom = &audioMixBufConvFromSilence;
2441
2442 /*
2443 * Is there any free space left in the buffer?
2444 */
2445 int rc = VINF_SUCCESS;
2446 uint32_t cFramesWritten = 0;
2447 uint32_t cFramesFree = pMixBuf->cFrames - pMixBuf->cUsed;
2448 if (cFramesFree > 0)
2449 {
2450 /*
2451 * There are potentially two writes we can make, one from offWrite and
2452 * a 2nd one from the start of the buffer.
2453 */
2454 uint32_t cFramesToWrite1 = RT_MIN(pMixBuf->cFrames - pMixBuf->offWrite, cFramesFree);
2455 uint32_t cFramesToWrite2 = 0;
2456 if (cFramesToWrite1 >= cFramesInBuf)
2457 cFramesToWrite1 = cFramesInBuf; /* The first write can hold it all. */
2458 else if (cFramesFree >= cFramesInBuf)
2459 cFramesToWrite2 = cFramesInBuf - cFramesToWrite1; /* If we wrap around, we can make it all fit. */
2460 else if (cFramesToWrite1 < cFramesFree)
2461 cFramesToWrite2 = cFramesFree - cFramesToWrite1; /* Not enough free space. Must wrap around to fill it all, though. */
2462 else
2463 cFramesToWrite1 = cFramesFree; /* Not enough free space, the read position is before the wraparound. */
2464 Assert(cFramesToWrite1);
2465 Log4Func(("cbBuf=%#x cFramesInBuf=%#x cFramesFree=%#x offWrite=%#x cFrames=%#x => %#x + %#x\n",
2466 cbBuf, cFramesInBuf, cFramesFree, pMixBuf->offWrite, pMixBuf->cFrames, cFramesToWrite1, cFramesToWrite2));
2467
2468 /*
2469 * Set up the conversion and do the first chunk.
2470 */
2471 AUDMIXBUFCONVOPTS ConvOpts;
2472 ConvOpts.From.Volume.fMuted = pMixBuf->Volume.fMuted;
2473 ConvOpts.From.Volume.uLeft = pMixBuf->Volume.uLeft;
2474 ConvOpts.From.Volume.uRight = pMixBuf->Volume.uRight;
2475 ConvOpts.cFrames = cFramesToWrite1;
2476
2477 uint32_t const cbToWrite1 = PDMAudioPropsFramesToBytes(pSrcProps, cFramesToWrite1);
2478 cFramesWritten = pfnConvFrom(&pMixBuf->pFrames[pMixBuf->offWrite],
2479 pvBuf, PDMAudioPropsFramesToBytes(pSrcProps, cFramesToWrite1), &ConvOpts);
2480 Assert(cFramesWritten == cFramesToWrite1);
2481
2482 /*
2483 * Any 2nd buffer?
2484 */
2485 if (cFramesToWrite2 > 0 && cFramesWritten == cFramesToWrite1)
2486 {
2487 ConvOpts.cFrames = cFramesToWrite2;
2488 uint32_t const cbToWrite2 = PDMAudioPropsFramesToBytes(pSrcProps, cFramesToWrite2);
2489 cFramesWritten += pfnConvFrom(&pMixBuf->pFrames[0], (uint8_t const *)pvBuf + cbToWrite1, cbToWrite2, &ConvOpts);
2490 Assert(cFramesWritten == cFramesToWrite2 + cFramesToWrite1);
2491 }
2492
2493 /*
2494 * Advance the buffer position.
2495 */
2496 pMixBuf->cUsed += cFramesWritten;
2497 Assert(pMixBuf->cUsed <= pMixBuf->cFrames);
2498
2499 pMixBuf->offWrite = (pMixBuf->offWrite + cFramesWritten) % pMixBuf->cFrames;
2500 Assert(pMixBuf->offWrite < pMixBuf->cFrames);
2501
2502 /*
2503 * Debug stuff.
2504 */
2505#ifdef AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA
2506 RTFILE fh;
2507 RTFileOpen(&fh, AUDIOMIXBUF_DEBUG_DUMP_PCM_DATA_PATH "mixbuf_writecirc_ex.pcm",
2508 RTFILE_O_OPEN_CREATE | RTFILE_O_APPEND | RTFILE_O_WRITE | RTFILE_O_DENY_NONE);
2509 RTFileWrite(fh, pvBuf, PDMAudioPropsFramesToBytes(pSrcProps, cFramesWritten), NULL);
2510 RTFileClose(fh);
2511#endif
2512 }
2513 else
2514 rc = VERR_BUFFER_OVERFLOW;
2515
2516#ifdef DEBUG
2517 audioMixBufDbgPrintInternal(pMixBuf, __FUNCTION__);
2518 audioMixBufDbgValidate(pMixBuf);
2519#endif
2520
2521 if (pcWritten)
2522 *pcWritten = cFramesWritten;
2523
2524#ifdef AUDMIXBUF_LOG_ENABLED
2525 char szTmp[PDMAUDIOPROPSTOSTRING_MAX];
2526#endif
2527 AUDMIXBUF_LOG(("%s: pSrcProps=%s, cbBuf=%RU32 (%RU32 frames), cFramesWritten=%RU32, rc=%Rrc\n", pMixBuf->pszName,
2528 PDMAudioPropsToString(pSrcProps, szTmp, sizeof(szTmp)), cbBuf, AUDIOMIXBUF_B2F(pMixBuf, cbBuf), cFramesWritten, rc));
2529 return rc;
2530}
2531
2532/**
2533 * Returns the current write position of a mixing buffer.
2534 *
2535 * @returns VBox status code.
2536 * @param pMixBuf Mixing buffer to return position for.
2537 */
2538uint32_t AudioMixBufWritePos(PAUDIOMIXBUF pMixBuf)
2539{
2540 AssertPtrReturn(pMixBuf, 0);
2541
2542 return pMixBuf->offWrite;
2543}
2544
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