VirtualBox

source: vbox/trunk/src/VBox/Devices/Audio/testcase/tstAudioMixBuffer.cpp@ 87990

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

Audio: Fixed broken DrvAudioHlpBytesToNano and DrvAudioHlpBytesToMicro implementation (overflow), the latter is the only one used. Also fixed silly confusion about 'const' and pointers (you want what they point to to be const, not the pointers themselves. duh) bugref:9890

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 28.5 KB
 
1/* $Id: tstAudioMixBuffer.cpp 87990 2021-03-07 14:29:40Z vboxsync $ */
2/** @file
3 * Audio testcase - Mixing buffer.
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
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#include <iprt/errcore.h>
23#include <iprt/initterm.h>
24#include <iprt/mem.h>
25#include <iprt/rand.h>
26#include <iprt/stream.h>
27#include <iprt/string.h>
28#include <iprt/test.h>
29
30
31#include "../AudioMixBuffer.h"
32#include "../DrvAudio.h"
33
34
35static void tstBasics(RTTEST hTest)
36{
37 RTTestSubF(hTest, "Single buffer");
38
39 static const PDMAUDIOPCMPROPS s_Cfg441StereoS16 = PDMAUDIOPCMPROPS_INITIALIZOR(
40 /* a_cb: */ 2,
41 /* a_fSigned: */ true,
42 /* a_cChannels: */ 2,
43 /* a_uHz: */ 44100,
44 /* a_cShift: */ PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(2 /* cb */, 2 /* cChannels */),
45 /* a_fSwapEndian: */ false
46 );
47
48 RTTESTI_CHECK_MSG(PDMAUDIOPCMPROPS_F2B(&s_Cfg441StereoS16, 1) == 4,
49 ("got %x, expected 4\n", PDMAUDIOPCMPROPS_F2B(&s_Cfg441StereoS16, 1)));
50
51 uint32_t u32;
52 RTTESTI_CHECK_MSG((u32 = DrvAudioHlpFramesToBytes(44100, &s_Cfg441StereoS16)) == 44100 * 2 * 2,
53 ("cb=%RU32\n", u32));
54 RTTESTI_CHECK_MSG((u32 = DrvAudioHlpFramesToBytes(2, &s_Cfg441StereoS16)) == 2 * 2 * 2,
55 ("cb=%RU32\n", u32));
56
57 uint64_t u64;
58 RTTESTI_CHECK_MSG((u64 = DrvAudioHlpBytesToNano(&s_Cfg441StereoS16, 44100 * 2 * 2)) == RT_NS_1SEC,
59 ("ns=%RU64\n", u64));
60 RTTESTI_CHECK_MSG((u64 = DrvAudioHlpBytesToMicro(&s_Cfg441StereoS16, 44100 * 2 * 2)) == RT_US_1SEC,
61 ("us=%RU64\n", u64));
62 RTTESTI_CHECK_MSG((u64 = DrvAudioHlpBytesToMilli(44100 * 2 * 2, &s_Cfg441StereoS16)) == RT_MS_1SEC,
63 ("ms=%RU64\n", u64));
64
65
66
67}
68
69
70static int tstSingle(RTTEST hTest)
71{
72 RTTestSub(hTest, "Single buffer");
73
74 /* 44100Hz, 2 Channels, S16 */
75 PDMAUDIOPCMPROPS config = PDMAUDIOPCMPROPS_INITIALIZOR(
76 2, /* Bytes */
77 true, /* Signed */
78 2, /* Channels */
79 44100, /* Hz */
80 PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(2 /* Bytes */, 2 /* Channels */), /* Shift */
81 false /* Swap Endian */
82 );
83
84 RTTESTI_CHECK(DrvAudioHlpPCMPropsAreValid(&config));
85
86 uint32_t cBufSize = _1K;
87
88 /*
89 * General stuff.
90 */
91 PDMAUDIOMIXBUF mb;
92 RTTESTI_CHECK_RC_OK(AudioMixBufInit(&mb, "Single", &config, cBufSize));
93 RTTESTI_CHECK(AudioMixBufSize(&mb) == cBufSize);
94 RTTESTI_CHECK(AUDIOMIXBUF_B2F(&mb, AudioMixBufSizeBytes(&mb)) == cBufSize);
95 RTTESTI_CHECK(AUDIOMIXBUF_F2B(&mb, AudioMixBufSize(&mb)) == AudioMixBufSizeBytes(&mb));
96 RTTESTI_CHECK(AudioMixBufFree(&mb) == cBufSize);
97 RTTESTI_CHECK(AUDIOMIXBUF_F2B(&mb, AudioMixBufFree(&mb)) == AudioMixBufFreeBytes(&mb));
98
99 /*
100 * Absolute writes.
101 */
102 uint32_t cFramesRead = 0, cFramesWritten = 0, cFramesWrittenAbs = 0;
103 int8_t aFrames8 [2] = { 0x12, 0x34 };
104 int16_t aFrames16[2] = { 0xAA, 0xBB };
105 int32_t aFrames32[2] = { 0xCC, 0xDD };
106
107 RTTESTI_CHECK_RC_OK(AudioMixBufWriteAt(&mb, 0 /* Offset */, &aFrames8, sizeof(aFrames8), &cFramesWritten));
108 RTTESTI_CHECK(cFramesWritten == 0 /* Frames */);
109 RTTESTI_CHECK(AudioMixBufUsed(&mb) == 0);
110
111 RTTESTI_CHECK_RC_OK(AudioMixBufWriteAt(&mb, 0 /* Offset */, &aFrames16, sizeof(aFrames16), &cFramesWritten));
112 RTTESTI_CHECK(cFramesWritten == 1 /* Frames */);
113 RTTESTI_CHECK(AudioMixBufUsed(&mb) == 1);
114
115 RTTESTI_CHECK_RC_OK(AudioMixBufWriteAt(&mb, 2 /* Offset */, &aFrames32, sizeof(aFrames32), &cFramesWritten));
116 RTTESTI_CHECK(cFramesWritten == 2 /* Frames */);
117 RTTESTI_CHECK(AudioMixBufUsed(&mb) == 2);
118
119 /* Beyond buffer. */
120 RTTESTI_CHECK_RC(AudioMixBufWriteAt(&mb, AudioMixBufSize(&mb) + 1, &aFrames16, sizeof(aFrames16),
121 &cFramesWritten), VERR_BUFFER_OVERFLOW);
122
123 /* Offset wrap-around: When writing as much (or more) frames the mixing buffer can hold. */
124 uint32_t cbSamples = cBufSize * sizeof(int16_t) * 2 /* Channels */;
125 RTTESTI_CHECK(cbSamples);
126 uint16_t *paSamples = (uint16_t *)RTMemAlloc(cbSamples);
127 RTTESTI_CHECK(paSamples);
128 RTTESTI_CHECK_RC_OK(AudioMixBufWriteAt(&mb, 0 /* Offset */, paSamples, cbSamples, &cFramesWritten));
129 RTTESTI_CHECK(cFramesWritten == cBufSize /* Frames */);
130 RTTESTI_CHECK(AudioMixBufUsed(&mb) == cBufSize);
131 RTTESTI_CHECK(AudioMixBufReadPos(&mb) == 0);
132 RTTESTI_CHECK(AudioMixBufWritePos(&mb) == 0);
133 RTMemFree(paSamples);
134 cbSamples = 0;
135
136 /*
137 * Circular writes.
138 */
139 AudioMixBufReset(&mb);
140
141 RTTESTI_CHECK_RC_OK(AudioMixBufWriteAt(&mb, 2 /* Offset */, &aFrames32, sizeof(aFrames32), &cFramesWritten));
142 RTTESTI_CHECK(cFramesWritten == 2 /* Frames */);
143 RTTESTI_CHECK(AudioMixBufUsed(&mb) == 2);
144
145 cFramesWrittenAbs = AudioMixBufUsed(&mb);
146
147 uint32_t cToWrite = AudioMixBufSize(&mb) - cFramesWrittenAbs - 1; /* -1 as padding plus -2 frames for above. */
148 for (uint32_t i = 0; i < cToWrite; i++)
149 {
150 RTTESTI_CHECK_RC_OK(AudioMixBufWriteCirc(&mb, &aFrames16, sizeof(aFrames16), &cFramesWritten));
151 RTTESTI_CHECK(cFramesWritten == 1);
152 }
153 RTTESTI_CHECK(!AudioMixBufIsEmpty(&mb));
154 RTTESTI_CHECK(AudioMixBufFree(&mb) == 1);
155 RTTESTI_CHECK(AudioMixBufFreeBytes(&mb) == AUDIOMIXBUF_F2B(&mb, 1U));
156 RTTESTI_CHECK(AudioMixBufUsed(&mb) == cToWrite + cFramesWrittenAbs /* + last absolute write */);
157
158 RTTESTI_CHECK_RC_OK(AudioMixBufWriteCirc(&mb, &aFrames16, sizeof(aFrames16), &cFramesWritten));
159 RTTESTI_CHECK(cFramesWritten == 1);
160 RTTESTI_CHECK(AudioMixBufFree(&mb) == 0);
161 RTTESTI_CHECK(AudioMixBufFreeBytes(&mb) == AUDIOMIXBUF_F2B(&mb, 0U));
162 RTTESTI_CHECK(AudioMixBufUsed(&mb) == cBufSize);
163
164 /* Circular reads. */
165 uint32_t cToRead = AudioMixBufSize(&mb) - cFramesWrittenAbs - 1;
166 for (uint32_t i = 0; i < cToRead; i++)
167 {
168 RTTESTI_CHECK_RC_OK(AudioMixBufAcquireReadBlock(&mb, &aFrames16, sizeof(aFrames16), &cFramesRead));
169 RTTESTI_CHECK(cFramesRead == 1);
170 AudioMixBufReleaseReadBlock(&mb, cFramesRead);
171 AudioMixBufFinish(&mb, cFramesRead);
172 }
173 RTTESTI_CHECK(!AudioMixBufIsEmpty(&mb));
174 RTTESTI_CHECK(AudioMixBufFree(&mb) == AudioMixBufSize(&mb) - cFramesWrittenAbs - 1);
175 RTTESTI_CHECK(AudioMixBufFreeBytes(&mb) == AUDIOMIXBUF_F2B(&mb, cBufSize - cFramesWrittenAbs - 1));
176 RTTESTI_CHECK(AudioMixBufUsed(&mb) == cBufSize - cToRead);
177
178 RTTESTI_CHECK_RC_OK(AudioMixBufAcquireReadBlock(&mb, &aFrames16, sizeof(aFrames16), &cFramesRead));
179 RTTESTI_CHECK(cFramesRead == 1);
180 AudioMixBufReleaseReadBlock(&mb, cFramesRead);
181 AudioMixBufFinish(&mb, cFramesRead);
182 RTTESTI_CHECK(AudioMixBufFree(&mb) == cBufSize - cFramesWrittenAbs);
183 RTTESTI_CHECK(AudioMixBufFreeBytes(&mb) == AUDIOMIXBUF_F2B(&mb, cBufSize - cFramesWrittenAbs));
184 RTTESTI_CHECK(AudioMixBufUsed(&mb) == cFramesWrittenAbs);
185
186 AudioMixBufDestroy(&mb);
187
188 return RTTestSubErrorCount(hTest) ? VERR_GENERAL_FAILURE : VINF_SUCCESS;
189}
190
191static int tstParentChild(RTTEST hTest)
192{
193 uint32_t cParentBufSize = RTRandU32Ex(_1K /* Min */, _16K /* Max */); /* Enough room for random sizes */
194
195 /* 44100Hz, 2 Channels, S16 */
196 PDMAUDIOPCMPROPS cfg_p = PDMAUDIOPCMPROPS_INITIALIZOR(
197 2, /* Bytes */
198 true, /* Signed */
199 2, /* Channels */
200 44100, /* Hz */
201 PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(2 /* Bytes */, 2 /* Channels */), /* Shift */
202 false /* Swap Endian */
203 );
204
205 RTTESTI_CHECK(DrvAudioHlpPCMPropsAreValid(&cfg_p));
206
207 PDMAUDIOMIXBUF parent;
208 RTTESTI_CHECK_RC_OK(AudioMixBufInit(&parent, "Parent", &cfg_p, cParentBufSize));
209
210 /* 22050Hz, 2 Channels, S16 */
211 PDMAUDIOPCMPROPS cfg_c1 = PDMAUDIOPCMPROPS_INITIALIZOR(/* Upmixing to parent */
212 2, /* Bytes */
213 true, /* Signed */
214 2, /* Channels */
215 22050, /* Hz */
216 PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(2 /* Bytes */, 2 /* Channels */), /* Shift */
217 false /* Swap Endian */
218 );
219
220 RTTESTI_CHECK(DrvAudioHlpPCMPropsAreValid(&cfg_c1));
221
222 uint32_t cFrames = 16;
223 uint32_t cChildBufSize = RTRandU32Ex(cFrames /* Min */, 64 /* Max */);
224
225 PDMAUDIOMIXBUF child1;
226 RTTESTI_CHECK_RC_OK(AudioMixBufInit(&child1, "Child1", &cfg_c1, cChildBufSize));
227 RTTESTI_CHECK_RC_OK(AudioMixBufLinkTo(&child1, &parent));
228
229 /* 48000Hz, 2 Channels, S16 */
230 PDMAUDIOPCMPROPS cfg_c2 = PDMAUDIOPCMPROPS_INITIALIZOR(/* Downmixing to parent */
231 2, /* Bytes */
232 true, /* Signed */
233 2, /* Channels */
234 48000, /* Hz */
235 PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(2 /* Bytes */, 2 /* Channels */), /* Shift */
236 false /* Swap Endian */
237 );
238
239 RTTESTI_CHECK(DrvAudioHlpPCMPropsAreValid(&cfg_c2));
240
241 PDMAUDIOMIXBUF child2;
242 RTTESTI_CHECK_RC_OK(AudioMixBufInit(&child2, "Child2", &cfg_c2, cChildBufSize));
243 RTTESTI_CHECK_RC_OK(AudioMixBufLinkTo(&child2, &parent));
244
245 /*
246 * Writing + mixing from child/children -> parent, sequential.
247 */
248 uint32_t cbBuf = _1K;
249 char pvBuf[_1K];
250 int16_t aFrames16[32] = { 0xAA, 0xBB };
251 uint32_t cFramesRead, cFramesWritten, cFramesMixed;
252
253 uint32_t cFramesChild1 = cFrames;
254 uint32_t cFramesChild2 = cFrames;
255
256 uint32_t t = RTRandU32() % 32;
257
258 RTTestPrintf(hTest, RTTESTLVL_DEBUG,
259 "cParentBufSize=%RU32, cChildBufSize=%RU32, %RU32 frames -> %RU32 iterations total\n",
260 cParentBufSize, cChildBufSize, cFrames, t);
261
262 /*
263 * Using AudioMixBufWriteAt for writing to children.
264 */
265 RTTestSub(hTest, "2 Children -> Parent (AudioMixBufWriteAt)");
266
267 uint32_t cChildrenSamplesMixedTotal = 0;
268
269 for (uint32_t i = 0; i < t; i++)
270 {
271 RTTestPrintf(hTest, RTTESTLVL_DEBUG, "i=%RU32\n", i);
272
273 uint32_t cChild1Writes = RTRandU32() % 8;
274
275 for (uint32_t c1 = 0; c1 < cChild1Writes; c1++)
276 {
277 /* Child 1. */
278 RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufWriteAt(&child1, 0, &aFrames16, sizeof(aFrames16), &cFramesWritten));
279 RTTESTI_CHECK_MSG_BREAK(cFramesWritten == cFramesChild1, ("Child1: Expected %RU32 written frames, got %RU32\n", cFramesChild1, cFramesWritten));
280 RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufMixToParent(&child1, cFramesWritten, &cFramesMixed));
281
282 cChildrenSamplesMixedTotal += cFramesMixed;
283
284 RTTESTI_CHECK_MSG_BREAK(cFramesWritten == cFramesMixed, ("Child1: Expected %RU32 mixed frames, got %RU32\n", cFramesWritten, cFramesMixed));
285 RTTESTI_CHECK_MSG_BREAK(AudioMixBufUsed(&child1) == 0, ("Child1: Expected %RU32 used frames, got %RU32\n", 0, AudioMixBufUsed(&child1)));
286 }
287
288 uint32_t cChild2Writes = RTRandU32() % 8;
289
290 for (uint32_t c2 = 0; c2 < cChild2Writes; c2++)
291 {
292 /* Child 2. */
293 RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufWriteAt(&child2, 0, &aFrames16, sizeof(aFrames16), &cFramesWritten));
294 RTTESTI_CHECK_MSG_BREAK(cFramesWritten == cFramesChild2, ("Child2: Expected %RU32 written frames, got %RU32\n", cFramesChild2, cFramesWritten));
295 RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufMixToParent(&child2, cFramesWritten, &cFramesMixed));
296
297 cChildrenSamplesMixedTotal += cFramesMixed;
298
299 RTTESTI_CHECK_MSG_BREAK(cFramesWritten == cFramesMixed, ("Child2: Expected %RU32 mixed frames, got %RU32\n", cFramesWritten, cFramesMixed));
300 RTTESTI_CHECK_MSG_BREAK(AudioMixBufUsed(&child2) == 0, ("Child2: Expected %RU32 used frames, got %RU32\n", 0, AudioMixBufUsed(&child2)));
301 }
302
303 /*
304 * Read out all frames from the parent buffer and also mark the just-read frames as finished
305 * so that both connected children buffers can keep track of their stuff.
306 */
307 uint32_t cParentSamples = AudioMixBufUsed(&parent);
308 while (cParentSamples)
309 {
310 RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufAcquireReadBlock(&parent, pvBuf, cbBuf, &cFramesRead));
311 if (!cFramesRead)
312 break;
313
314 AudioMixBufReleaseReadBlock(&parent, cFramesRead);
315 AudioMixBufFinish(&parent, cFramesRead);
316
317 RTTESTI_CHECK(cParentSamples >= cFramesRead);
318 cParentSamples -= cFramesRead;
319 }
320
321 RTTESTI_CHECK(cParentSamples == 0);
322 }
323
324 RTTESTI_CHECK(AudioMixBufUsed(&parent) == 0);
325 RTTESTI_CHECK(AudioMixBufLive(&child1) == 0);
326 RTTESTI_CHECK(AudioMixBufLive(&child2) == 0);
327
328 AudioMixBufDestroy(&parent);
329 AudioMixBufDestroy(&child1);
330 AudioMixBufDestroy(&child2);
331
332 return RTTestSubErrorCount(hTest) ? VERR_GENERAL_FAILURE : VINF_SUCCESS;
333}
334
335/* Test 8-bit sample conversion (8-bit -> internal -> 8-bit). */
336static int tstConversion8(RTTEST hTest)
337{
338 unsigned i;
339 uint32_t cBufSize = 256;
340
341 RTTestSub(hTest, "Sample conversion (U8)");
342
343 /* 44100Hz, 1 Channel, U8 */
344 PDMAUDIOPCMPROPS cfg_p = PDMAUDIOPCMPROPS_INITIALIZOR(
345 1, /* Bytes */
346 false, /* Signed */
347 1, /* Channels */
348 44100, /* Hz */
349 PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(1 /* Bytes */, 1 /* Channels */), /* Shift */
350 false /* Swap Endian */
351 );
352
353 RTTESTI_CHECK(DrvAudioHlpPCMPropsAreValid(&cfg_p));
354
355 PDMAUDIOMIXBUF parent;
356 RTTESTI_CHECK_RC_OK(AudioMixBufInit(&parent, "Parent", &cfg_p, cBufSize));
357
358 /* Child uses half the sample rate; that ensures the mixing engine can't
359 * take shortcuts and performs conversion. Because conversion to double
360 * the sample rate effectively inserts one additional sample between every
361 * two source frames, N source frames will be converted to N * 2 - 1
362 * frames. However, the last source sample will be saved for later
363 * interpolation and not immediately output.
364 */
365
366 /* 22050Hz, 1 Channel, U8 */
367 PDMAUDIOPCMPROPS cfg_c = PDMAUDIOPCMPROPS_INITIALIZOR( /* Upmixing to parent */
368 1, /* Bytes */
369 false, /* Signed */
370 1, /* Channels */
371 22050, /* Hz */
372 PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(1 /* Bytes */, 1 /* Channels */), /* Shift */
373 false /* Swap Endian */
374 );
375
376 RTTESTI_CHECK(DrvAudioHlpPCMPropsAreValid(&cfg_c));
377
378 PDMAUDIOMIXBUF child;
379 RTTESTI_CHECK_RC_OK(AudioMixBufInit(&child, "Child", &cfg_c, cBufSize));
380 RTTESTI_CHECK_RC_OK(AudioMixBufLinkTo(&child, &parent));
381
382 /* 8-bit unsigned frames. Often used with SB16 device. */
383 uint8_t aFrames8U[16] = { 0xAA, 0xBB, 0, 1, 43, 125, 126, 127,
384 128, 129, 130, 131, 132, UINT8_MAX - 1, UINT8_MAX, 0 };
385
386 /*
387 * Writing + mixing from child -> parent, sequential.
388 */
389 uint32_t cbBuf = 256;
390 char achBuf[256];
391 uint32_t cFramesRead, cFramesWritten, cFramesMixed;
392
393 uint32_t cFramesChild = 16;
394 uint32_t cFramesParent = cFramesChild * 2 - 2;
395 uint32_t cFramesTotalRead = 0;
396
397 /**** 8-bit unsigned samples ****/
398 RTTestPrintf(hTest, RTTESTLVL_DEBUG, "Conversion test %uHz %uch 8-bit\n", cfg_c.uHz, cfg_c.cChannels);
399 RTTESTI_CHECK_RC_OK(AudioMixBufWriteCirc(&child, &aFrames8U, sizeof(aFrames8U), &cFramesWritten));
400 RTTESTI_CHECK_MSG(cFramesWritten == cFramesChild, ("Child: Expected %RU32 written frames, got %RU32\n", cFramesChild, cFramesWritten));
401 RTTESTI_CHECK_RC_OK(AudioMixBufMixToParent(&child, cFramesWritten, &cFramesMixed));
402 uint32_t cFrames = AudioMixBufUsed(&parent);
403 RTTESTI_CHECK_MSG(AudioMixBufLive(&child) == cFrames, ("Child: Expected %RU32 mixed frames, got %RU32\n", AudioMixBufLive(&child), cFrames));
404
405 RTTESTI_CHECK(AudioMixBufUsed(&parent) == AudioMixBufLive(&child));
406
407 for (;;)
408 {
409 RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufAcquireReadBlock(&parent, achBuf, cbBuf, &cFramesRead));
410 if (!cFramesRead)
411 break;
412 cFramesTotalRead += cFramesRead;
413 AudioMixBufReleaseReadBlock(&parent, cFramesRead);
414 AudioMixBufFinish(&parent, cFramesRead);
415 }
416
417 RTTESTI_CHECK_MSG(cFramesTotalRead == cFramesParent, ("Parent: Expected %RU32 mixed frames, got %RU32\n", cFramesParent, cFramesTotalRead));
418
419 /* Check that the frames came out unharmed. Every other sample is interpolated and we ignore it. */
420 /* NB: This also checks that the default volume setting is 0dB attenuation. */
421 uint8_t *pSrc8 = &aFrames8U[0];
422 uint8_t *pDst8 = (uint8_t *)achBuf;
423
424 for (i = 0; i < cFramesChild - 1; ++i)
425 {
426 RTTESTI_CHECK_MSG(*pSrc8 == *pDst8, ("index %u: Dst=%d, Src=%d\n", i, *pDst8, *pSrc8));
427 pSrc8 += 1;
428 pDst8 += 2;
429 }
430
431 RTTESTI_CHECK(AudioMixBufUsed(&parent) == 0);
432 RTTESTI_CHECK(AudioMixBufLive(&child) == 0);
433
434 AudioMixBufDestroy(&parent);
435 AudioMixBufDestroy(&child);
436
437 return RTTestSubErrorCount(hTest) ? VERR_GENERAL_FAILURE : VINF_SUCCESS;
438}
439
440/* Test 16-bit sample conversion (16-bit -> internal -> 16-bit). */
441static int tstConversion16(RTTEST hTest)
442{
443 unsigned i;
444 uint32_t cBufSize = 256;
445
446 RTTestSub(hTest, "Sample conversion (S16)");
447
448 /* 44100Hz, 1 Channel, S16 */
449 PDMAUDIOPCMPROPS cfg_p = PDMAUDIOPCMPROPS_INITIALIZOR(
450 2, /* Bytes */
451 true, /* Signed */
452 1, /* Channels */
453 44100, /* Hz */
454 PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(2 /* Bytes */, 1 /* Channels */), /* Shift */
455 false /* Swap Endian */
456 );
457
458 RTTESTI_CHECK(DrvAudioHlpPCMPropsAreValid(&cfg_p));
459
460 PDMAUDIOMIXBUF parent;
461 RTTESTI_CHECK_RC_OK(AudioMixBufInit(&parent, "Parent", &cfg_p, cBufSize));
462
463 /* 22050Hz, 1 Channel, S16 */
464 PDMAUDIOPCMPROPS cfg_c = PDMAUDIOPCMPROPS_INITIALIZOR( /* Upmixing to parent */
465 2, /* Bytes */
466 true, /* Signed */
467 1, /* Channels */
468 22050, /* Hz */
469 PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(2 /* Bytes */, 1 /* Channels */), /* Shift */
470 false /* Swap Endian */
471 );
472
473 RTTESTI_CHECK(DrvAudioHlpPCMPropsAreValid(&cfg_c));
474
475 PDMAUDIOMIXBUF child;
476 RTTESTI_CHECK_RC_OK(AudioMixBufInit(&child, "Child", &cfg_c, cBufSize));
477 RTTESTI_CHECK_RC_OK(AudioMixBufLinkTo(&child, &parent));
478
479 /* 16-bit signed. More or less exclusively used as output, and usually as input, too. */
480 int16_t aFrames16S[16] = { 0xAA, 0xBB, INT16_MIN, INT16_MIN + 1, INT16_MIN / 2, -3, -2, -1,
481 0, 1, 2, 3, INT16_MAX / 2, INT16_MAX - 1, INT16_MAX, 0 };
482
483 /*
484 * Writing + mixing from child -> parent, sequential.
485 */
486 uint32_t cbBuf = 256;
487 char achBuf[256];
488 uint32_t cFramesRead, cFramesWritten, cFramesMixed;
489
490 uint32_t cFramesChild = 16;
491 uint32_t cFramesParent = cFramesChild * 2 - 2;
492 uint32_t cFramesTotalRead = 0;
493
494 /**** 16-bit signed samples ****/
495 RTTestPrintf(hTest, RTTESTLVL_DEBUG, "Conversion test %uHz %uch 16-bit\n", cfg_c.uHz, cfg_c.cChannels);
496 RTTESTI_CHECK_RC_OK(AudioMixBufWriteCirc(&child, &aFrames16S, sizeof(aFrames16S), &cFramesWritten));
497 RTTESTI_CHECK_MSG(cFramesWritten == cFramesChild, ("Child: Expected %RU32 written frames, got %RU32\n", cFramesChild, cFramesWritten));
498 RTTESTI_CHECK_RC_OK(AudioMixBufMixToParent(&child, cFramesWritten, &cFramesMixed));
499 uint32_t cFrames = AudioMixBufUsed(&parent);
500 RTTESTI_CHECK_MSG(AudioMixBufLive(&child) == cFrames, ("Child: Expected %RU32 mixed frames, got %RU32\n", AudioMixBufLive(&child), cFrames));
501
502 RTTESTI_CHECK(AudioMixBufUsed(&parent) == AudioMixBufLive(&child));
503
504 for (;;)
505 {
506 RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufAcquireReadBlock(&parent, achBuf, cbBuf, &cFramesRead));
507 if (!cFramesRead)
508 break;
509 cFramesTotalRead += cFramesRead;
510 AudioMixBufReleaseReadBlock(&parent, cFramesRead);
511 AudioMixBufFinish(&parent, cFramesRead);
512 }
513 RTTESTI_CHECK_MSG(cFramesTotalRead == cFramesParent, ("Parent: Expected %RU32 mixed frames, got %RU32\n", cFramesParent, cFramesTotalRead));
514
515 /* Check that the frames came out unharmed. Every other sample is interpolated and we ignore it. */
516 /* NB: This also checks that the default volume setting is 0dB attenuation. */
517 int16_t *pSrc16 = &aFrames16S[0];
518 int16_t *pDst16 = (int16_t *)achBuf;
519
520 for (i = 0; i < cFramesChild - 1; ++i)
521 {
522 RTTESTI_CHECK_MSG(*pSrc16 == *pDst16, ("index %u: Dst=%d, Src=%d\n", i, *pDst16, *pSrc16));
523 pSrc16 += 1;
524 pDst16 += 2;
525 }
526
527 RTTESTI_CHECK(AudioMixBufUsed(&parent) == 0);
528 RTTESTI_CHECK(AudioMixBufLive(&child) == 0);
529
530 AudioMixBufDestroy(&parent);
531 AudioMixBufDestroy(&child);
532
533 return RTTestSubErrorCount(hTest) ? VERR_GENERAL_FAILURE : VINF_SUCCESS;
534}
535
536/* Test volume control. */
537static int tstVolume(RTTEST hTest)
538{
539 unsigned i;
540 uint32_t cBufSize = 256;
541
542 RTTestSub(hTest, "Volume control");
543
544 /* Same for parent/child. */
545 /* 44100Hz, 2 Channels, S16 */
546 PDMAUDIOPCMPROPS cfg = PDMAUDIOPCMPROPS_INITIALIZOR(
547 2, /* Bytes */
548 true, /* Signed */
549 2, /* Channels */
550 44100, /* Hz */
551 PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(2 /* Bytes */, 2 /* Channels */), /* Shift */
552 false /* Swap Endian */
553 );
554
555 RTTESTI_CHECK(DrvAudioHlpPCMPropsAreValid(&cfg));
556
557 PDMAUDIOVOLUME vol = { false, 0, 0 }; /* Not muted. */
558 PDMAUDIOMIXBUF parent;
559 RTTESTI_CHECK_RC_OK(AudioMixBufInit(&parent, "Parent", &cfg, cBufSize));
560
561 PDMAUDIOMIXBUF child;
562 RTTESTI_CHECK_RC_OK(AudioMixBufInit(&child, "Child", &cfg, cBufSize));
563 RTTESTI_CHECK_RC_OK(AudioMixBufLinkTo(&child, &parent));
564
565 /* A few 16-bit signed samples. */
566 int16_t aFrames16S[16] = { INT16_MIN, INT16_MIN + 1, -128, -64, -4, -1, 0, 1,
567 2, 255, 256, INT16_MAX / 2, INT16_MAX - 2, INT16_MAX - 1, INT16_MAX, 0 };
568
569 /*
570 * Writing + mixing from child -> parent.
571 */
572 uint32_t cbBuf = 256;
573 char achBuf[256];
574 uint32_t cFramesRead, cFramesWritten, cFramesMixed;
575
576 uint32_t cFramesChild = 8;
577 uint32_t cFramesParent = cFramesChild;
578 uint32_t cFramesTotalRead;
579 int16_t *pSrc16;
580 int16_t *pDst16;
581
582 /**** Volume control test ****/
583 RTTestPrintf(hTest, RTTESTLVL_DEBUG, "Volume control test %uHz %uch \n", cfg.uHz, cfg.cChannels);
584
585 /* 1) Full volume/0dB attenuation (255). */
586 vol.uLeft = vol.uRight = 255;
587 AudioMixBufSetVolume(&child, &vol);
588
589 RTTESTI_CHECK_RC_OK(AudioMixBufWriteCirc(&child, &aFrames16S, sizeof(aFrames16S), &cFramesWritten));
590 RTTESTI_CHECK_MSG(cFramesWritten == cFramesChild, ("Child: Expected %RU32 written frames, got %RU32\n", cFramesChild, cFramesWritten));
591 RTTESTI_CHECK_RC_OK(AudioMixBufMixToParent(&child, cFramesWritten, &cFramesMixed));
592
593 cFramesTotalRead = 0;
594 for (;;)
595 {
596 RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufAcquireReadBlock(&parent, achBuf, cbBuf, &cFramesRead));
597 if (!cFramesRead)
598 break;
599 cFramesTotalRead += cFramesRead;
600 AudioMixBufReleaseReadBlock(&parent, cFramesRead);
601 AudioMixBufFinish(&parent, cFramesRead);
602 }
603 RTTESTI_CHECK_MSG(cFramesTotalRead == cFramesParent, ("Parent: Expected %RU32 mixed frames, got %RU32\n", cFramesParent, cFramesTotalRead));
604
605 /* Check that at 0dB the frames came out unharmed. */
606 pSrc16 = &aFrames16S[0];
607 pDst16 = (int16_t *)achBuf;
608
609 for (i = 0; i < cFramesParent * 2 /* stereo */; ++i)
610 {
611 RTTESTI_CHECK_MSG(*pSrc16 == *pDst16, ("index %u: Dst=%d, Src=%d\n", i, *pDst16, *pSrc16));
612 ++pSrc16;
613 ++pDst16;
614 }
615 AudioMixBufReset(&child);
616
617 /* 2) Half volume/-6dB attenuation (16 steps down). */
618 vol.uLeft = vol.uRight = 255 - 16;
619 AudioMixBufSetVolume(&child, &vol);
620
621 RTTESTI_CHECK_RC_OK(AudioMixBufWriteCirc(&child, &aFrames16S, sizeof(aFrames16S), &cFramesWritten));
622 RTTESTI_CHECK_MSG(cFramesWritten == cFramesChild, ("Child: Expected %RU32 written frames, got %RU32\n", cFramesChild, cFramesWritten));
623 RTTESTI_CHECK_RC_OK(AudioMixBufMixToParent(&child, cFramesWritten, &cFramesMixed));
624
625 cFramesTotalRead = 0;
626 for (;;)
627 {
628 RTTESTI_CHECK_RC_OK_BREAK(AudioMixBufAcquireReadBlock(&parent, achBuf, cbBuf, &cFramesRead));
629 if (!cFramesRead)
630 break;
631 cFramesTotalRead += cFramesRead;
632 AudioMixBufReleaseReadBlock(&parent, cFramesRead);
633 AudioMixBufFinish(&parent, cFramesRead);
634 }
635 RTTESTI_CHECK_MSG(cFramesTotalRead == cFramesParent, ("Parent: Expected %RU32 mixed frames, got %RU32\n", cFramesParent, cFramesTotalRead));
636
637 /* Check that at -6dB the sample values are halved. */
638 pSrc16 = &aFrames16S[0];
639 pDst16 = (int16_t *)achBuf;
640
641 for (i = 0; i < cFramesParent * 2 /* stereo */; ++i)
642 {
643 /* Watch out! For negative values, x >> 1 is not the same as x / 2. */
644 RTTESTI_CHECK_MSG(*pSrc16 >> 1 == *pDst16, ("index %u: Dst=%d, Src=%d\n", i, *pDst16, *pSrc16));
645 ++pSrc16;
646 ++pDst16;
647 }
648
649 AudioMixBufDestroy(&parent);
650 AudioMixBufDestroy(&child);
651
652 return RTTestSubErrorCount(hTest) ? VERR_GENERAL_FAILURE : VINF_SUCCESS;
653}
654
655int main(int argc, char **argv)
656{
657 RTR3InitExe(argc, &argv, 0);
658
659 /*
660 * Initialize IPRT and create the test.
661 */
662 RTTEST hTest;
663 int rc = RTTestInitAndCreate("tstAudioMixBuffer", &hTest);
664 if (rc)
665 return rc;
666 RTTestBanner(hTest);
667
668 tstBasics(hTest);
669 tstSingle(hTest);
670 tstParentChild(hTest);
671 tstConversion8(hTest);
672 tstConversion16(hTest);
673 tstVolume(hTest);
674
675 /*
676 * Summary
677 */
678 return RTTestSummaryAndDestroy(hTest);
679}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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