VirtualBox

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

Last change on this file since 63214 was 62981, checked in by vboxsync, 8 years ago

more descriptive variable names.

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