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 /* 32 bit floating point sample formats. */ 74 {"f32le_1", {0x00, 0x00, 0x00, 0x3f}, 4, AFMT_F32_LE, 0x40000000}, 75 {"f32le_2", {0x00, 0x00, 0x00, 0xbf}, 4, AFMT_F32_LE, 0xc0000000}, 76 {"f32be_1", {0x3f, 0x00, 0x00, 0x00}, 4, AFMT_F32_BE, 0x40000000}, 77 {"f32be_2", {0xbf, 0x00, 0x00, 0x00}, 4, AFMT_F32_BE, 0xc0000000}, 78 79 /* u-law and A-law sample formats. */ 80 {"mulaw_1", {0x01, 0x00, 0x00, 0x00}, 1, AFMT_MU_LAW, 0xffffff87}, 81 {"mulaw_2", {0x81, 0x00, 0x00, 0x00}, 1, AFMT_MU_LAW, 0x00000079}, 82 {"alaw_1", {0x2a, 0x00, 0x00, 0x00}, 1, AFMT_A_LAW, 0xffffff83}, 83 {"alaw_2", {0xab, 0x00, 0x00, 0x00}, 1, AFMT_A_LAW, 0x00000079} 84 }; 85 86 /* Normalize sample values in strictly correct (but slow) c. */ 87 static intpcm_t 88 local_normalize(intpcm_t value, int val_bits, int norm_bits) 89 { 90 int32_t divisor; 91 intpcm_t remainder; 92 93 /* Avoid undefined or implementation defined behavior. */ 94 if (val_bits < norm_bits) 95 /* Multiply instead of left shift (value may be negative). */ 96 return (value * (1 << (norm_bits - val_bits))); 97 else if (val_bits > norm_bits) { 98 divisor = (1 << (val_bits - norm_bits)); 99 /* Positive remainder, to discard lowest bits from value. */ 100 remainder = value % divisor; 101 remainder = (remainder + divisor) % divisor; 102 /* Divide instead of right shift (value may be negative). */ 103 return ((value - remainder) / divisor); 104 } 105 return value; 106 } 107 108 /* Restrict magnitude of sample value to 24bit for 32bit calculations. */ 109 static intpcm_t 110 local_calc_limit(intpcm_t value, int val_bits) 111 { 112 /* 113 * When intpcm32_t is defined to be 32bit, calculations for mixing and 114 * volume changes use 32bit integers instead of 64bit. To get some 115 * headroom for calculations, 32bit sample values are restricted to 116 * 24bit magnitude in that case. Also avoid implementation defined 117 * behavior here. 118 */ 119 if (sizeof(intpcm32_t) == (32 / 8) && val_bits == 32) 120 return (local_normalize(value, 32, 24)); 121 return value; 122 } 123 124 ATF_TC(pcm_read); 125 ATF_TC_HEAD(pcm_read, tc) 126 { 127 atf_tc_set_md_var(tc, "descr", 128 "Read and verify different pcm sample formats."); 129 } 130 ATF_TC_BODY(pcm_read, tc) 131 { 132 const struct afmt_test_data *test; 133 uint8_t src[4]; 134 intpcm_t expected, result; 135 size_t i; 136 137 for (i = 0; i < nitems(afmt_tests); i++) { 138 test = &afmt_tests[i]; 139 140 /* Copy byte representation, fill with distinctive pattern. */ 141 memset(src, 0x66, sizeof(src)); 142 memcpy(src, test->buffer, test->size); 143 144 /* Read sample at format magnitude. */ 145 expected = test->value; 146 result = pcm_sample_read(src, test->format); 147 ATF_CHECK_MSG(result == expected, 148 "pcm_read[\"%s\"].value: expected=0x%08x, result=0x%08x", 149 test->label, expected, result); 150 151 /* Read sample at format magnitude, for calculations. */ 152 expected = local_calc_limit(test->value, test->size * 8); 153 result = pcm_sample_read_calc(src, test->format); 154 ATF_CHECK_MSG(result == expected, 155 "pcm_read[\"%s\"].calc: expected=0x%08x, result=0x%08x", 156 test->label, expected, result); 157 158 /* Read sample at full 32 bit magnitude. */ 159 expected = local_normalize(test->value, test->size * 8, 32); 160 result = pcm_sample_read_norm(src, test->format); 161 ATF_CHECK_MSG(result == expected, 162 "pcm_read[\"%s\"].norm: expected=0x%08x, result=0x%08x", 163 test->label, expected, result); 164 } 165 } 166 167 ATF_TC(pcm_write); 168 ATF_TC_HEAD(pcm_write, tc) 169 { 170 atf_tc_set_md_var(tc, "descr", 171 "Write and verify different pcm sample formats."); 172 } 173 ATF_TC_BODY(pcm_write, tc) 174 { 175 const struct afmt_test_data *test; 176 uint8_t expected[4]; 177 uint8_t dst[4]; 178 intpcm_t value; 179 size_t i; 180 181 for (i = 0; i < nitems(afmt_tests); i++) { 182 test = &afmt_tests[i]; 183 184 /* Write sample of format specific magnitude. */ 185 memcpy(expected, test->buffer, sizeof(expected)); 186 memset(dst, 0x00, sizeof(dst)); 187 value = test->value; 188 pcm_sample_write(dst, value, test->format); 189 ATF_CHECK_MSG(memcmp(dst, expected, sizeof(dst)) == 0, 190 "pcm_write[\"%s\"].value: " 191 "expected={0x%02x, 0x%02x, 0x%02x, 0x%02x}, " 192 "result={0x%02x, 0x%02x, 0x%02x, 0x%02x}, ", test->label, 193 expected[0], expected[1], expected[2], expected[3], 194 dst[0], dst[1], dst[2], dst[3]); 195 196 /* Write sample of format specific, calculation magnitude. */ 197 memcpy(expected, test->buffer, sizeof(expected)); 198 memset(dst, 0x00, sizeof(dst)); 199 value = local_calc_limit(test->value, test->size * 8); 200 if (value != test->value) { 201 /* 202 * 32 bit sample was reduced to 24 bit resolution 203 * for calculation, least significant byte is lost. 204 */ 205 if (test->format & AFMT_BIGENDIAN) 206 expected[3] = 0x00; 207 else 208 expected[0] = 0x00; 209 } 210 pcm_sample_write_calc(dst, value, test->format); 211 ATF_CHECK_MSG(memcmp(dst, expected, sizeof(dst)) == 0, 212 "pcm_write[\"%s\"].calc: " 213 "expected={0x%02x, 0x%02x, 0x%02x, 0x%02x}, " 214 "result={0x%02x, 0x%02x, 0x%02x, 0x%02x}, ", test->label, 215 expected[0], expected[1], expected[2], expected[3], 216 dst[0], dst[1], dst[2], dst[3]); 217 218 /* Write normalized sample of full 32 bit magnitude. */ 219 memcpy(expected, test->buffer, sizeof(expected)); 220 memset(dst, 0x00, sizeof(dst)); 221 value = local_normalize(test->value, test->size * 8, 32); 222 pcm_sample_write_norm(dst, value, test->format); 223 ATF_CHECK_MSG(memcmp(dst, expected, sizeof(dst)) == 0, 224 "pcm_write[\"%s\"].norm: " 225 "expected={0x%02x, 0x%02x, 0x%02x, 0x%02x}, " 226 "result={0x%02x, 0x%02x, 0x%02x, 0x%02x}, ", test->label, 227 expected[0], expected[1], expected[2], expected[3], 228 dst[0], dst[1], dst[2], dst[3]); 229 } 230 } 231 232 ATF_TC(pcm_format_bits); 233 ATF_TC_HEAD(pcm_format_bits, tc) 234 { 235 atf_tc_set_md_var(tc, "descr", 236 "Verify bit width of different pcm sample formats."); 237 } 238 ATF_TC_BODY(pcm_format_bits, tc) 239 { 240 const struct afmt_test_data *test; 241 size_t bits; 242 size_t i; 243 244 for (i = 0; i < nitems(afmt_tests); i++) { 245 test = &afmt_tests[i]; 246 247 /* Check bit width determined for given sample format. */ 248 bits = AFMT_BIT(test->format); 249 ATF_CHECK_MSG(bits == test->size * 8, 250 "format_bits[%zu].size: expected=%zu, result=%zu", 251 i, test->size * 8, bits); 252 } 253 } 254 255 ATF_TP_ADD_TCS(tp) 256 { 257 ATF_TP_ADD_TC(tp, pcm_read); 258 ATF_TP_ADD_TC(tp, pcm_write); 259 ATF_TP_ADD_TC(tp, pcm_format_bits); 260 261 return atf_no_error(); 262 } 263