#include <sys/types.h>
#include <sys/soundcard.h>
#include <atf-c.h>
#include <stdio.h>
#include <string.h>
#include <dev/sound/pcm/sound.h>
#include <dev/sound/pcm/pcm.h>
#include <dev/sound/pcm/g711.h>
static struct afmt_test_data {
const char *label;
uint8_t buffer[4];
size_t size;
int format;
intpcm_t value;
_Static_assert((sizeof(intpcm_t) == 4),
"Test data assumes 32bit, adjust negative values to new size.");
} const afmt_tests[] = {
{"s8_1", {0x01, 0x00, 0x00, 0x00}, 1, AFMT_S8, 0x00000001},
{"s8_2", {0x81, 0x00, 0x00, 0x00}, 1, AFMT_S8, 0xffffff81},
{"u8_1", {0x01, 0x00, 0x00, 0x00}, 1, AFMT_U8, 0xffffff81},
{"u8_2", {0x81, 0x00, 0x00, 0x00}, 1, AFMT_U8, 0x00000001},
{"s16le_1", {0x01, 0x02, 0x00, 0x00}, 2, AFMT_S16_LE, 0x00000201},
{"s16le_2", {0x81, 0x82, 0x00, 0x00}, 2, AFMT_S16_LE, 0xffff8281},
{"s16be_1", {0x01, 0x02, 0x00, 0x00}, 2, AFMT_S16_BE, 0x00000102},
{"s16be_2", {0x81, 0x82, 0x00, 0x00}, 2, AFMT_S16_BE, 0xffff8182},
{"u16le_1", {0x01, 0x02, 0x00, 0x00}, 2, AFMT_U16_LE, 0xffff8201},
{"u16le_2", {0x81, 0x82, 0x00, 0x00}, 2, AFMT_U16_LE, 0x00000281},
{"u16be_1", {0x01, 0x02, 0x00, 0x00}, 2, AFMT_U16_BE, 0xffff8102},
{"u16be_2", {0x81, 0x82, 0x00, 0x00}, 2, AFMT_U16_BE, 0x00000182},
{"s24le_1", {0x01, 0x02, 0x03, 0x00}, 3, AFMT_S24_LE, 0x00030201},
{"s24le_2", {0x81, 0x82, 0x83, 0x00}, 3, AFMT_S24_LE, 0xff838281},
{"s24be_1", {0x01, 0x02, 0x03, 0x00}, 3, AFMT_S24_BE, 0x00010203},
{"s24be_2", {0x81, 0x82, 0x83, 0x00}, 3, AFMT_S24_BE, 0xff818283},
{"u24le_1", {0x01, 0x02, 0x03, 0x00}, 3, AFMT_U24_LE, 0xff830201},
{"u24le_2", {0x81, 0x82, 0x83, 0x00}, 3, AFMT_U24_LE, 0x00038281},
{"u24be_1", {0x01, 0x02, 0x03, 0x00}, 3, AFMT_U24_BE, 0xff810203},
{"u24be_2", {0x81, 0x82, 0x83, 0x00}, 3, AFMT_U24_BE, 0x00018283},
{"s32le_1", {0x01, 0x02, 0x03, 0x04}, 4, AFMT_S32_LE, 0x04030201},
{"s32le_2", {0x81, 0x82, 0x83, 0x84}, 4, AFMT_S32_LE, 0x84838281},
{"s32be_1", {0x01, 0x02, 0x03, 0x04}, 4, AFMT_S32_BE, 0x01020304},
{"s32be_2", {0x81, 0x82, 0x83, 0x84}, 4, AFMT_S32_BE, 0x81828384},
{"u32le_1", {0x01, 0x02, 0x03, 0x04}, 4, AFMT_U32_LE, 0x84030201},
{"u32le_2", {0x81, 0x82, 0x83, 0x84}, 4, AFMT_U32_LE, 0x04838281},
{"u32be_1", {0x01, 0x02, 0x03, 0x04}, 4, AFMT_U32_BE, 0x81020304},
{"u32be_2", {0x81, 0x82, 0x83, 0x84}, 4, AFMT_U32_BE, 0x01828384},
{"f32le_1", {0x00, 0x00, 0x00, 0x3f}, 4, AFMT_F32_LE, 0x40000000},
{"f32le_2", {0x00, 0x00, 0x00, 0xbf}, 4, AFMT_F32_LE, 0xc0000000},
{"f32be_1", {0x3f, 0x00, 0x00, 0x00}, 4, AFMT_F32_BE, 0x40000000},
{"f32be_2", {0xbf, 0x00, 0x00, 0x00}, 4, AFMT_F32_BE, 0xc0000000},
{"mulaw_1", {0x01, 0x00, 0x00, 0x00}, 1, AFMT_MU_LAW, 0xffffff87},
{"mulaw_2", {0x81, 0x00, 0x00, 0x00}, 1, AFMT_MU_LAW, 0x00000079},
{"alaw_1", {0x2a, 0x00, 0x00, 0x00}, 1, AFMT_A_LAW, 0xffffff83},
{"alaw_2", {0xab, 0x00, 0x00, 0x00}, 1, AFMT_A_LAW, 0x00000079}
};
static intpcm_t
local_normalize(intpcm_t value, int val_bits, int norm_bits)
{
int32_t divisor;
intpcm_t remainder;
if (val_bits < norm_bits)
return (value * (1 << (norm_bits - val_bits)));
else if (val_bits > norm_bits) {
divisor = (1 << (val_bits - norm_bits));
remainder = value % divisor;
remainder = (remainder + divisor) % divisor;
return ((value - remainder) / divisor);
}
return value;
}
static intpcm_t
local_calc_limit(intpcm_t value, int val_bits)
{
if (sizeof(intpcm32_t) == (32 / 8) && val_bits == 32)
return (local_normalize(value, 32, 24));
return value;
}
ATF_TC(pcm_read);
ATF_TC_HEAD(pcm_read, tc)
{
atf_tc_set_md_var(tc, "descr",
"Read and verify different pcm sample formats.");
}
ATF_TC_BODY(pcm_read, tc)
{
const struct afmt_test_data *test;
uint8_t src[4];
intpcm_t expected, result;
size_t i;
for (i = 0; i < nitems(afmt_tests); i++) {
test = &afmt_tests[i];
memset(src, 0x66, sizeof(src));
memcpy(src, test->buffer, test->size);
expected = test->value;
result = pcm_sample_read(src, test->format);
ATF_CHECK_MSG(result == expected,
"pcm_read[\"%s\"].value: expected=0x%08x, result=0x%08x",
test->label, expected, result);
expected = local_calc_limit(test->value, test->size * 8);
result = pcm_sample_read_calc(src, test->format);
ATF_CHECK_MSG(result == expected,
"pcm_read[\"%s\"].calc: expected=0x%08x, result=0x%08x",
test->label, expected, result);
expected = local_normalize(test->value, test->size * 8, 32);
result = pcm_sample_read_norm(src, test->format);
ATF_CHECK_MSG(result == expected,
"pcm_read[\"%s\"].norm: expected=0x%08x, result=0x%08x",
test->label, expected, result);
}
}
ATF_TC(pcm_write);
ATF_TC_HEAD(pcm_write, tc)
{
atf_tc_set_md_var(tc, "descr",
"Write and verify different pcm sample formats.");
}
ATF_TC_BODY(pcm_write, tc)
{
const struct afmt_test_data *test;
uint8_t expected[4];
uint8_t dst[4];
intpcm_t value;
size_t i;
for (i = 0; i < nitems(afmt_tests); i++) {
test = &afmt_tests[i];
memcpy(expected, test->buffer, sizeof(expected));
memset(dst, 0x00, sizeof(dst));
value = test->value;
pcm_sample_write(dst, value, test->format);
ATF_CHECK_MSG(memcmp(dst, expected, sizeof(dst)) == 0,
"pcm_write[\"%s\"].value: "
"expected={0x%02x, 0x%02x, 0x%02x, 0x%02x}, "
"result={0x%02x, 0x%02x, 0x%02x, 0x%02x}, ", test->label,
expected[0], expected[1], expected[2], expected[3],
dst[0], dst[1], dst[2], dst[3]);
memcpy(expected, test->buffer, sizeof(expected));
memset(dst, 0x00, sizeof(dst));
value = local_calc_limit(test->value, test->size * 8);
if (value != test->value) {
if (test->format & AFMT_BIGENDIAN)
expected[3] = 0x00;
else
expected[0] = 0x00;
}
pcm_sample_write_calc(dst, value, test->format);
ATF_CHECK_MSG(memcmp(dst, expected, sizeof(dst)) == 0,
"pcm_write[\"%s\"].calc: "
"expected={0x%02x, 0x%02x, 0x%02x, 0x%02x}, "
"result={0x%02x, 0x%02x, 0x%02x, 0x%02x}, ", test->label,
expected[0], expected[1], expected[2], expected[3],
dst[0], dst[1], dst[2], dst[3]);
memcpy(expected, test->buffer, sizeof(expected));
memset(dst, 0x00, sizeof(dst));
value = local_normalize(test->value, test->size * 8, 32);
pcm_sample_write_norm(dst, value, test->format);
ATF_CHECK_MSG(memcmp(dst, expected, sizeof(dst)) == 0,
"pcm_write[\"%s\"].norm: "
"expected={0x%02x, 0x%02x, 0x%02x, 0x%02x}, "
"result={0x%02x, 0x%02x, 0x%02x, 0x%02x}, ", test->label,
expected[0], expected[1], expected[2], expected[3],
dst[0], dst[1], dst[2], dst[3]);
}
}
ATF_TC(pcm_format_bits);
ATF_TC_HEAD(pcm_format_bits, tc)
{
atf_tc_set_md_var(tc, "descr",
"Verify bit width of different pcm sample formats.");
}
ATF_TC_BODY(pcm_format_bits, tc)
{
const struct afmt_test_data *test;
size_t bits;
size_t i;
for (i = 0; i < nitems(afmt_tests); i++) {
test = &afmt_tests[i];
bits = AFMT_BIT(test->format);
ATF_CHECK_MSG(bits == test->size * 8,
"format_bits[%zu].size: expected=%zu, result=%zu",
i, test->size * 8, bits);
}
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, pcm_read);
ATF_TP_ADD_TC(tp, pcm_write);
ATF_TP_ADD_TC(tp, pcm_format_bits);
return atf_no_error();
}