VirtualBox

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

最後變更 在這個檔案從88253是 88253,由 vboxsync 提交於 4 年 前

DrvAudio,++: Started going over and tidying up the StreamPlay functionality. First major change is to treat the RAW layout just like non-RAW ones and count all in bytes. bugref:9890

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

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