VirtualBox

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

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

Audio: Update on infrastructure:

  • More work on HDA stream interleaving + surround support
  • The mixer can now (optionally) act as a supplemental layer between audio connector interface and device emulation (where applicable)
  • Multiple LUN streams can be bound to a certain sink, which in turn then can be treated as separate input/output channels
  • Unified more code which was duplicated between different audio device emulations
  • Tiny bit of documentation

Work in progress.

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