xref: /freebsd/tests/sys/sound/pcm_read_write.c (revision 17b7a0c595a51eaa7e83f16e99e1555bd13a445b)
1 /*-
2  * Copyright (c) 2025 Florian Walpen
3  *
4  * SPDX-License-Identifier: BSD-2-Clause
5  */
6 
7 /*
8  * These tests exercise conversion functions of the sound module, used to read
9  * pcm samples from a buffer, and write pcm samples to a buffer. The test cases
10  * are non-exhaustive, but should detect systematic errors in conversion of the
11  * various sample formats supported. In particular, the test cases establish
12  * correctness independent of the machine's endianness, making them suitable to
13  * check for architecture-specific problems.
14  */
15 
16 #include <sys/types.h>
17 #include <sys/soundcard.h>
18 
19 #include <atf-c.h>
20 #include <stdio.h>
21 #include <string.h>
22 
23 #include <dev/sound/pcm/sound.h>
24 #include <dev/sound/pcm/pcm.h>
25 #include <dev/sound/pcm/g711.h>
26 
27 /* Generic test data, with buffer content matching the sample values. */
28 static struct afmt_test_data {
29 	const char *label;
30 	uint8_t buffer[4];
31 	size_t size;
32 	int format;
33 	intpcm_t value;
34 	_Static_assert((sizeof(intpcm_t) == 4),
35 	    "Test data assumes 32bit, adjust negative values to new size.");
36 } const afmt_tests[] = {
37 	/* 8 bit sample formats. */
38 	{"s8_1", {0x01, 0x00, 0x00, 0x00}, 1, AFMT_S8, 0x00000001},
39 	{"s8_2", {0x81, 0x00, 0x00, 0x00}, 1, AFMT_S8, 0xffffff81},
40 	{"u8_1", {0x01, 0x00, 0x00, 0x00}, 1, AFMT_U8, 0xffffff81},
41 	{"u8_2", {0x81, 0x00, 0x00, 0x00}, 1, AFMT_U8, 0x00000001},
42 
43 	/* 16 bit sample formats. */
44 	{"s16le_1", {0x01, 0x02, 0x00, 0x00}, 2, AFMT_S16_LE, 0x00000201},
45 	{"s16le_2", {0x81, 0x82, 0x00, 0x00}, 2, AFMT_S16_LE, 0xffff8281},
46 	{"s16be_1", {0x01, 0x02, 0x00, 0x00}, 2, AFMT_S16_BE, 0x00000102},
47 	{"s16be_2", {0x81, 0x82, 0x00, 0x00}, 2, AFMT_S16_BE, 0xffff8182},
48 	{"u16le_1", {0x01, 0x02, 0x00, 0x00}, 2, AFMT_U16_LE, 0xffff8201},
49 	{"u16le_2", {0x81, 0x82, 0x00, 0x00}, 2, AFMT_U16_LE, 0x00000281},
50 	{"u16be_1", {0x01, 0x02, 0x00, 0x00}, 2, AFMT_U16_BE, 0xffff8102},
51 	{"u16be_2", {0x81, 0x82, 0x00, 0x00}, 2, AFMT_U16_BE, 0x00000182},
52 
53 	/* 24 bit sample formats. */
54 	{"s24le_1", {0x01, 0x02, 0x03, 0x00}, 3, AFMT_S24_LE, 0x00030201},
55 	{"s24le_2", {0x81, 0x82, 0x83, 0x00}, 3, AFMT_S24_LE, 0xff838281},
56 	{"s24be_1", {0x01, 0x02, 0x03, 0x00}, 3, AFMT_S24_BE, 0x00010203},
57 	{"s24be_2", {0x81, 0x82, 0x83, 0x00}, 3, AFMT_S24_BE, 0xff818283},
58 	{"u24le_1", {0x01, 0x02, 0x03, 0x00}, 3, AFMT_U24_LE, 0xff830201},
59 	{"u24le_2", {0x81, 0x82, 0x83, 0x00}, 3, AFMT_U24_LE, 0x00038281},
60 	{"u24be_1", {0x01, 0x02, 0x03, 0x00}, 3, AFMT_U24_BE, 0xff810203},
61 	{"u24be_2", {0x81, 0x82, 0x83, 0x00}, 3, AFMT_U24_BE, 0x00018283},
62 
63 	/* 32 bit sample formats. */
64 	{"s32le_1", {0x01, 0x02, 0x03, 0x04}, 4, AFMT_S32_LE, 0x04030201},
65 	{"s32le_2", {0x81, 0x82, 0x83, 0x84}, 4, AFMT_S32_LE, 0x84838281},
66 	{"s32be_1", {0x01, 0x02, 0x03, 0x04}, 4, AFMT_S32_BE, 0x01020304},
67 	{"s32be_2", {0x81, 0x82, 0x83, 0x84}, 4, AFMT_S32_BE, 0x81828384},
68 	{"u32le_1", {0x01, 0x02, 0x03, 0x04}, 4, AFMT_U32_LE, 0x84030201},
69 	{"u32le_2", {0x81, 0x82, 0x83, 0x84}, 4, AFMT_U32_LE, 0x04838281},
70 	{"u32be_1", {0x01, 0x02, 0x03, 0x04}, 4, AFMT_U32_BE, 0x81020304},
71 	{"u32be_2", {0x81, 0x82, 0x83, 0x84}, 4, AFMT_U32_BE, 0x01828384},
72 
73 	/* u-law and A-law sample formats. */
74 	{"mulaw_1", {0x01, 0x00, 0x00, 0x00}, 1, AFMT_MU_LAW, 0xffffff87},
75 	{"mulaw_2", {0x81, 0x00, 0x00, 0x00}, 1, AFMT_MU_LAW, 0x00000079},
76 	{"alaw_1", {0x2a, 0x00, 0x00, 0x00}, 1, AFMT_A_LAW, 0xffffff83},
77 	{"alaw_2", {0xab, 0x00, 0x00, 0x00}, 1, AFMT_A_LAW, 0x00000079}
78 };
79 
80 /* Normalize sample values in strictly correct (but slow) c. */
81 static intpcm_t
82 local_normalize(intpcm_t value, int val_bits, int norm_bits)
83 {
84 	/* Avoid undefined or implementation defined behavior. */
85 	if (val_bits < norm_bits)
86 		/* Multiply instead of left shift (value may be negative). */
87 		return (value * (1 << (norm_bits - val_bits)));
88 	else if (val_bits > norm_bits)
89 		/* Divide instead of right shift (value may be negative). */
90 		return (value / (1 << (val_bits - norm_bits)));
91 	return value;
92 }
93 
94 /* Restrict magnitude of sample value to 24bit for 32bit calculations. */
95 static intpcm_t
96 local_calc_limit(intpcm_t value, int val_bits)
97 {
98 	/*
99 	 * When intpcm32_t is defined to be 32bit, calculations for mixing and
100 	 * volume changes use 32bit integers instead of 64bit. To get some
101 	 * headroom for calculations, 32bit sample values are restricted to
102 	 * 24bit magnitude in that case. Also avoid implementation defined
103 	 * behavior here.
104 	 */
105 	if (sizeof(intpcm32_t) == (32 / 8) && val_bits == 32)
106 		/* Divide instead of right shift (value may be negative). */
107 		return (value / (1 << 8));
108 	return value;
109 }
110 
111 /* Lookup tables to read u-law and A-law sample formats. */
112 static const uint8_t ulaw_to_u8[G711_TABLE_SIZE] = ULAW_TO_U8;
113 static const uint8_t alaw_to_u8[G711_TABLE_SIZE] = ALAW_TO_U8;
114 
115 /* Helper function to read one sample value from a buffer. */
116 static intpcm_t
117 local_pcm_read(uint8_t *src, uint32_t format)
118 {
119 	intpcm_t value;
120 
121 	switch (format) {
122 	case AFMT_S8:
123 		value = _PCM_READ_S8_NE(src);
124 		break;
125 	case AFMT_U8:
126 		value = _PCM_READ_U8_NE(src);
127 		break;
128 	case AFMT_S16_LE:
129 		value = _PCM_READ_S16_LE(src);
130 		break;
131 	case AFMT_S16_BE:
132 		value = _PCM_READ_S16_BE(src);
133 		break;
134 	case AFMT_U16_LE:
135 		value = _PCM_READ_U16_LE(src);
136 		break;
137 	case AFMT_U16_BE:
138 		value = _PCM_READ_U16_BE(src);
139 		break;
140 	case AFMT_S24_LE:
141 		value = _PCM_READ_S24_LE(src);
142 		break;
143 	case AFMT_S24_BE:
144 		value = _PCM_READ_S24_BE(src);
145 		break;
146 	case AFMT_U24_LE:
147 		value = _PCM_READ_U24_LE(src);
148 		break;
149 	case AFMT_U24_BE:
150 		value = _PCM_READ_U24_BE(src);
151 		break;
152 	case AFMT_S32_LE:
153 		value = _PCM_READ_S32_LE(src);
154 		break;
155 	case AFMT_S32_BE:
156 		value = _PCM_READ_S32_BE(src);
157 		break;
158 	case AFMT_U32_LE:
159 		value = _PCM_READ_U32_LE(src);
160 		break;
161 	case AFMT_U32_BE:
162 		value = _PCM_READ_U32_BE(src);
163 		break;
164 	case AFMT_MU_LAW:
165 		value = _G711_TO_INTPCM(ulaw_to_u8, *src);
166 		break;
167 	case AFMT_A_LAW:
168 		value = _G711_TO_INTPCM(alaw_to_u8, *src);
169 		break;
170 	default:
171 		value = 0;
172 	}
173 
174 	return (value);
175 }
176 
177 /* Helper function to read one sample value from a buffer for calculations. */
178 static intpcm_t
179 local_pcm_read_calc(uint8_t *src, uint32_t format)
180 {
181 	intpcm_t value;
182 
183 	switch (format) {
184 	case AFMT_S8:
185 		value = PCM_READ_S8_NE(src);
186 		break;
187 	case AFMT_U8:
188 		value = PCM_READ_U8_NE(src);
189 		break;
190 	case AFMT_S16_LE:
191 		value = PCM_READ_S16_LE(src);
192 		break;
193 	case AFMT_S16_BE:
194 		value = PCM_READ_S16_BE(src);
195 		break;
196 	case AFMT_U16_LE:
197 		value = PCM_READ_U16_LE(src);
198 		break;
199 	case AFMT_U16_BE:
200 		value = PCM_READ_U16_BE(src);
201 		break;
202 	case AFMT_S24_LE:
203 		value = PCM_READ_S24_LE(src);
204 		break;
205 	case AFMT_S24_BE:
206 		value = PCM_READ_S24_BE(src);
207 		break;
208 	case AFMT_U24_LE:
209 		value = PCM_READ_U24_LE(src);
210 		break;
211 	case AFMT_U24_BE:
212 		value = PCM_READ_U24_BE(src);
213 		break;
214 	case AFMT_S32_LE:
215 		value = PCM_READ_S32_LE(src);
216 		break;
217 	case AFMT_S32_BE:
218 		value = PCM_READ_S32_BE(src);
219 		break;
220 	case AFMT_U32_LE:
221 		value = PCM_READ_U32_LE(src);
222 		break;
223 	case AFMT_U32_BE:
224 		value = PCM_READ_U32_BE(src);
225 		break;
226 	case AFMT_MU_LAW:
227 		value = _G711_TO_INTPCM(ulaw_to_u8, *src);
228 		break;
229 	case AFMT_A_LAW:
230 		value = _G711_TO_INTPCM(alaw_to_u8, *src);
231 		break;
232 	default:
233 		value = 0;
234 	}
235 
236 	return (value);
237 }
238 
239 /* Helper function to read one normalized sample from a buffer. */
240 static intpcm_t
241 local_pcm_read_norm(uint8_t *src, uint32_t format)
242 {
243 	intpcm_t value;
244 
245 	value = local_pcm_read(src, format);
246 	value <<= (32 - AFMT_BIT(format));
247 	return (value);
248 }
249 
250 /* Lookup tables to write u-law and A-law sample formats. */
251 static const uint8_t u8_to_ulaw[G711_TABLE_SIZE] = U8_TO_ULAW;
252 static const uint8_t u8_to_alaw[G711_TABLE_SIZE] = U8_TO_ALAW;
253 
254 /* Helper function to write one sample value to a buffer. */
255 static void
256 local_pcm_write(uint8_t *dst, intpcm_t value, uint32_t format)
257 {
258 	switch (format) {
259 	case AFMT_S8:
260 		_PCM_WRITE_S8_NE(dst, value);
261 		break;
262 	case AFMT_U8:
263 		_PCM_WRITE_U8_NE(dst, value);
264 		break;
265 	case AFMT_S16_LE:
266 		_PCM_WRITE_S16_LE(dst, value);
267 		break;
268 	case AFMT_S16_BE:
269 		_PCM_WRITE_S16_BE(dst, value);
270 		break;
271 	case AFMT_U16_LE:
272 		_PCM_WRITE_U16_LE(dst, value);
273 		break;
274 	case AFMT_U16_BE:
275 		_PCM_WRITE_U16_BE(dst, value);
276 		break;
277 	case AFMT_S24_LE:
278 		_PCM_WRITE_S24_LE(dst, value);
279 		break;
280 	case AFMT_S24_BE:
281 		_PCM_WRITE_S24_BE(dst, value);
282 		break;
283 	case AFMT_U24_LE:
284 		_PCM_WRITE_U24_LE(dst, value);
285 		break;
286 	case AFMT_U24_BE:
287 		_PCM_WRITE_U24_BE(dst, value);
288 		break;
289 	case AFMT_S32_LE:
290 		_PCM_WRITE_S32_LE(dst, value);
291 		break;
292 	case AFMT_S32_BE:
293 		_PCM_WRITE_S32_BE(dst, value);
294 		break;
295 	case AFMT_U32_LE:
296 		_PCM_WRITE_U32_LE(dst, value);
297 		break;
298 	case AFMT_U32_BE:
299 		_PCM_WRITE_U32_BE(dst, value);
300 		break;
301 	case AFMT_MU_LAW:
302 		*dst = _INTPCM_TO_G711(u8_to_ulaw, value);
303 		break;
304 	case AFMT_A_LAW:
305 		*dst = _INTPCM_TO_G711(u8_to_alaw, value);
306 		break;
307 	default:
308 		value = 0;
309 	}
310 }
311 
312 /* Helper function to write one calculation sample value to a buffer. */
313 static void
314 local_pcm_write_calc(uint8_t *dst, intpcm_t value, uint32_t format)
315 {
316 	switch (format) {
317 	case AFMT_S8:
318 		PCM_WRITE_S8_NE(dst, value);
319 		break;
320 	case AFMT_U8:
321 		PCM_WRITE_U8_NE(dst, value);
322 		break;
323 	case AFMT_S16_LE:
324 		PCM_WRITE_S16_LE(dst, value);
325 		break;
326 	case AFMT_S16_BE:
327 		PCM_WRITE_S16_BE(dst, value);
328 		break;
329 	case AFMT_U16_LE:
330 		PCM_WRITE_U16_LE(dst, value);
331 		break;
332 	case AFMT_U16_BE:
333 		PCM_WRITE_U16_BE(dst, value);
334 		break;
335 	case AFMT_S24_LE:
336 		PCM_WRITE_S24_LE(dst, value);
337 		break;
338 	case AFMT_S24_BE:
339 		PCM_WRITE_S24_BE(dst, value);
340 		break;
341 	case AFMT_U24_LE:
342 		PCM_WRITE_U24_LE(dst, value);
343 		break;
344 	case AFMT_U24_BE:
345 		PCM_WRITE_U24_BE(dst, value);
346 		break;
347 	case AFMT_S32_LE:
348 		PCM_WRITE_S32_LE(dst, value);
349 		break;
350 	case AFMT_S32_BE:
351 		PCM_WRITE_S32_BE(dst, value);
352 		break;
353 	case AFMT_U32_LE:
354 		PCM_WRITE_U32_LE(dst, value);
355 		break;
356 	case AFMT_U32_BE:
357 		PCM_WRITE_U32_BE(dst, value);
358 		break;
359 	case AFMT_MU_LAW:
360 		*dst = _INTPCM_TO_G711(u8_to_ulaw, value);
361 		break;
362 	case AFMT_A_LAW:
363 		*dst = _INTPCM_TO_G711(u8_to_alaw, value);
364 		break;
365 	default:
366 		value = 0;
367 	}
368 }
369 
370 /* Helper function to write one normalized sample to a buffer. */
371 static void
372 local_pcm_write_norm(uint8_t *dst, intpcm_t value, uint32_t format)
373 {
374 	local_pcm_write(dst, value >> (32 - AFMT_BIT(format)), format);
375 }
376 
377 ATF_TC(pcm_read);
378 ATF_TC_HEAD(pcm_read, tc)
379 {
380 	atf_tc_set_md_var(tc, "descr",
381 	    "Read and verify different pcm sample formats.");
382 }
383 ATF_TC_BODY(pcm_read, tc)
384 {
385 	const struct afmt_test_data *test;
386 	uint8_t src[4];
387 	intpcm_t expected, result;
388 	size_t i;
389 
390 	for (i = 0; i < nitems(afmt_tests); i++) {
391 		test = &afmt_tests[i];
392 
393 		/* Copy byte representation, fill with distinctive pattern. */
394 		memset(src, 0x66, sizeof(src));
395 		memcpy(src, test->buffer, test->size);
396 
397 		/* Read sample at format magnitude. */
398 		expected = test->value;
399 		result = local_pcm_read(src, test->format);
400 		ATF_CHECK_MSG(result == expected,
401 		    "pcm_read[\"%s\"].value: expected=0x%08x, result=0x%08x",
402 		    test->label, expected, result);
403 
404 		/* Read sample at format magnitude, for calculations. */
405 		expected = local_calc_limit(test->value, test->size * 8);
406 		result = local_pcm_read_calc(src, test->format);
407 		ATF_CHECK_MSG(result == expected,
408 		    "pcm_read[\"%s\"].calc: expected=0x%08x, result=0x%08x",
409 		    test->label, expected, result);
410 
411 		/* Read sample at full 32 bit magnitude. */
412 		expected = local_normalize(test->value, test->size * 8, 32);
413 		result = local_pcm_read_norm(src, test->format);
414 		ATF_CHECK_MSG(result == expected,
415 		    "pcm_read[\"%s\"].norm: expected=0x%08x, result=0x%08x",
416 		    test->label, expected, result);
417 	}
418 }
419 
420 ATF_TC(pcm_write);
421 ATF_TC_HEAD(pcm_write, tc)
422 {
423 	atf_tc_set_md_var(tc, "descr",
424 	    "Write and verify different pcm sample formats.");
425 }
426 ATF_TC_BODY(pcm_write, tc)
427 {
428 	const struct afmt_test_data *test;
429 	uint8_t expected[4];
430 	uint8_t dst[4];
431 	intpcm_t value;
432 	size_t i;
433 
434 	for (i = 0; i < nitems(afmt_tests); i++) {
435 		test = &afmt_tests[i];
436 
437 		/* Write sample of format specific magnitude. */
438 		memcpy(expected, test->buffer, sizeof(expected));
439 		memset(dst, 0x00, sizeof(dst));
440 		value = test->value;
441 		local_pcm_write(dst, value, test->format);
442 		ATF_CHECK_MSG(memcmp(dst, expected, sizeof(dst)) == 0,
443 		    "pcm_write[\"%s\"].value: "
444 		    "expected={0x%02x, 0x%02x, 0x%02x, 0x%02x}, "
445 		    "result={0x%02x, 0x%02x, 0x%02x, 0x%02x}, ", test->label,
446 		    expected[0], expected[1], expected[2], expected[3],
447 		    dst[0], dst[1], dst[2], dst[3]);
448 
449 		/* Write sample of format specific, calculation magnitude. */
450 		memcpy(expected, test->buffer, sizeof(expected));
451 		memset(dst, 0x00, sizeof(dst));
452 		value = local_calc_limit(test->value, test->size * 8);
453 		if (value != test->value) {
454 			/*
455 			 * 32 bit sample was reduced to 24 bit resolution
456 			 * for calculation, least significant byte is lost.
457 			 */
458 			if (test->format & AFMT_BIGENDIAN)
459 				expected[3] = 0x00;
460 			else
461 				expected[0] = 0x00;
462 		}
463 		local_pcm_write_calc(dst, value, test->format);
464 		ATF_CHECK_MSG(memcmp(dst, expected, sizeof(dst)) == 0,
465 		    "pcm_write[\"%s\"].calc: "
466 		    "expected={0x%02x, 0x%02x, 0x%02x, 0x%02x}, "
467 		    "result={0x%02x, 0x%02x, 0x%02x, 0x%02x}, ", test->label,
468 		    expected[0], expected[1], expected[2], expected[3],
469 		    dst[0], dst[1], dst[2], dst[3]);
470 
471 		/* Write normalized sample of full 32 bit magnitude. */
472 		memcpy(expected, test->buffer, sizeof(expected));
473 		memset(dst, 0x00, sizeof(dst));
474 		value = local_normalize(test->value, test->size * 8, 32);
475 		local_pcm_write_norm(dst, value, test->format);
476 		ATF_CHECK_MSG(memcmp(dst, expected, sizeof(dst)) == 0,
477 		    "pcm_write[\"%s\"].norm: "
478 		    "expected={0x%02x, 0x%02x, 0x%02x, 0x%02x}, "
479 		    "result={0x%02x, 0x%02x, 0x%02x, 0x%02x}, ", test->label,
480 		    expected[0], expected[1], expected[2], expected[3],
481 		    dst[0], dst[1], dst[2], dst[3]);
482 	}
483 }
484 
485 ATF_TC(pcm_format_bits);
486 ATF_TC_HEAD(pcm_format_bits, tc)
487 {
488 	atf_tc_set_md_var(tc, "descr",
489 	    "Verify bit width of different pcm sample formats.");
490 }
491 ATF_TC_BODY(pcm_format_bits, tc)
492 {
493 	const struct afmt_test_data *test;
494 	size_t bits;
495 	size_t i;
496 
497 	for (i = 0; i < nitems(afmt_tests); i++) {
498 		test = &afmt_tests[i];
499 
500 		/* Check bit width determined for given sample format. */
501 		bits = AFMT_BIT(test->format);
502 		ATF_CHECK_MSG(bits == test->size * 8,
503 		    "format_bits[%zu].size: expected=%zu, result=%zu",
504 		    i, test->size * 8, bits);
505 	}
506 }
507 
508 ATF_TP_ADD_TCS(tp)
509 {
510 	ATF_TP_ADD_TC(tp, pcm_read);
511 	ATF_TP_ADD_TC(tp, pcm_write);
512 	ATF_TP_ADD_TC(tp, pcm_format_bits);
513 
514 	return atf_no_error();
515 }
516