VirtualBox

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

Last change on this file since 67446 was 67384, checked in by vboxsync, 8 years ago

Build fix.

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