mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-11-01 17:08:10 +00:00
kselftest/alsa: pcm - move more configuration to configuration files
Obtain all test parameters from the configuration files. The defaults are defined in the pcm-test.conf file. The test count and parameters may be variable per specific hardware. Also, handle alt_formats field now (with the fixes in the format loop). It replaces the original "automatic" logic which is not so universal. The code may be further extended to skip various tests based on the configuration hints, if the exact PCM hardware parameters are not available for the given hardware. Signed-off-by: Jaroslav Kysela <perex@perex.cz> Signed-off-by: Mark Brown <broonie@kernel.org> Link: https://lore.kernel.org/r/20221208-alsa-pcm-test-hacks-v4-2-5a152e65b1e1@kernel.org Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
c48cafc241
commit
348d09fcd1
6 changed files with 121 additions and 36 deletions
|
@ -14,7 +14,7 @@ TEST_GEN_PROGS := mixer-test pcm-test
|
||||||
|
|
||||||
TEST_GEN_PROGS_EXTENDED := libatest.so
|
TEST_GEN_PROGS_EXTENDED := libatest.so
|
||||||
|
|
||||||
TEST_FILES := conf.d
|
TEST_FILES := conf.d pcm-test.conf
|
||||||
|
|
||||||
include ../lib.mk
|
include ../lib.mk
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
snd_config_t *get_alsalib_config(void);
|
snd_config_t *get_alsalib_config(void);
|
||||||
|
|
||||||
|
snd_config_t *conf_load_from_file(const char *filename);
|
||||||
void conf_load(void);
|
void conf_load(void);
|
||||||
void conf_free(void);
|
void conf_free(void);
|
||||||
snd_config_t *conf_by_card(int card);
|
snd_config_t *conf_by_card(int card);
|
||||||
|
@ -20,5 +21,7 @@ int conf_get_count(snd_config_t *root, const char *key1, const char *key2);
|
||||||
const char *conf_get_string(snd_config_t *root, const char *key1, const char *key2, const char *def);
|
const char *conf_get_string(snd_config_t *root, const char *key1, const char *key2, const char *def);
|
||||||
long conf_get_long(snd_config_t *root, const char *key1, const char *key2, long def);
|
long conf_get_long(snd_config_t *root, const char *key1, const char *key2, long def);
|
||||||
int conf_get_bool(snd_config_t *root, const char *key1, const char *key2, int def);
|
int conf_get_bool(snd_config_t *root, const char *key1, const char *key2, int def);
|
||||||
|
void conf_get_string_array(snd_config_t *root, const char *key1, const char *key2,
|
||||||
|
const char **array, int array_size, const char *def);
|
||||||
|
|
||||||
#endif /* __ALSA_LOCAL_H */
|
#endif /* __ALSA_LOCAL_H */
|
||||||
|
|
|
@ -125,7 +125,7 @@ static int dump_config_tree(snd_config_t *top)
|
||||||
snd_output_close(out);
|
snd_output_close(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
static snd_config_t *load(const char *filename)
|
snd_config_t *conf_load_from_file(const char *filename)
|
||||||
{
|
{
|
||||||
snd_config_t *dst;
|
snd_config_t *dst;
|
||||||
snd_input_t *input;
|
snd_input_t *input;
|
||||||
|
@ -235,7 +235,7 @@ static bool test_filename1(int card, const char *filename, const char *sysfs_car
|
||||||
snd_config_t *config, *sysfs_config, *card_config, *sysfs_card_config, *node;
|
snd_config_t *config, *sysfs_config, *card_config, *sysfs_card_config, *node;
|
||||||
snd_config_iterator_t i, next;
|
snd_config_iterator_t i, next;
|
||||||
|
|
||||||
config = load(filename);
|
config = conf_load_from_file(filename);
|
||||||
if (snd_config_search(config, "sysfs", &sysfs_config) ||
|
if (snd_config_search(config, "sysfs", &sysfs_config) ||
|
||||||
snd_config_get_type(sysfs_config) != SND_CONFIG_TYPE_COMPOUND)
|
snd_config_get_type(sysfs_config) != SND_CONFIG_TYPE_COMPOUND)
|
||||||
ksft_exit_fail_msg("Missing global sysfs block in filename %s\n", filename);
|
ksft_exit_fail_msg("Missing global sysfs block in filename %s\n", filename);
|
||||||
|
@ -446,3 +446,25 @@ int conf_get_bool(snd_config_t *root, const char *key1, const char *key2, int de
|
||||||
ksft_exit_fail_msg("key '%s'.'%s' is not an bool\n", key1, key2);
|
ksft_exit_fail_msg("key '%s'.'%s' is not an bool\n", key1, key2);
|
||||||
return !!ret;
|
return !!ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void conf_get_string_array(snd_config_t *root, const char *key1, const char *key2,
|
||||||
|
const char **array, int array_size, const char *def)
|
||||||
|
{
|
||||||
|
snd_config_t *cfg;
|
||||||
|
char buf[16];
|
||||||
|
int ret, index;
|
||||||
|
|
||||||
|
ret = conf_get_by_keys(root, key1, key2, &cfg);
|
||||||
|
if (ret == -ENOENT)
|
||||||
|
cfg = NULL;
|
||||||
|
else if (ret < 0)
|
||||||
|
ksft_exit_fail_msg("key '%s'.'%s' search error: %s\n", key1, key2, snd_strerror(ret));
|
||||||
|
for (index = 0; index < array_size; index++) {
|
||||||
|
if (cfg == NULL) {
|
||||||
|
array[index] = def;
|
||||||
|
} else {
|
||||||
|
sprintf(buf, "%i", index);
|
||||||
|
array[index] = conf_get_string(cfg, buf, NULL, def);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -55,6 +55,14 @@ card.hda {
|
||||||
period_size 24000
|
period_size 24000
|
||||||
buffer_size 192000
|
buffer_size 192000
|
||||||
}
|
}
|
||||||
|
test.time3 {
|
||||||
|
access RW_INTERLEAVED
|
||||||
|
format S16_LE
|
||||||
|
rate 44100
|
||||||
|
channels 2
|
||||||
|
period_size 24000
|
||||||
|
buffer_size 192000
|
||||||
|
}
|
||||||
}
|
}
|
||||||
CAPTURE {
|
CAPTURE {
|
||||||
# use default tests, check for the presence
|
# use default tests, check for the presence
|
||||||
|
|
|
@ -31,7 +31,6 @@ struct pcm_data {
|
||||||
struct pcm_data *next;
|
struct pcm_data *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
int num_pcms = 0;
|
|
||||||
struct pcm_data *pcm_list = NULL;
|
struct pcm_data *pcm_list = NULL;
|
||||||
|
|
||||||
int num_missing = 0;
|
int num_missing = 0;
|
||||||
|
@ -200,7 +199,6 @@ static void find_pcms(void)
|
||||||
pcm_data->pcm_config = conf_get_subtree(card_config, key, NULL);
|
pcm_data->pcm_config = conf_get_subtree(card_config, key, NULL);
|
||||||
pcm_data->next = pcm_list;
|
pcm_data->next = pcm_list;
|
||||||
pcm_list = pcm_data;
|
pcm_list = pcm_data;
|
||||||
num_pcms++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -219,17 +217,15 @@ static void find_pcms(void)
|
||||||
snd_config_delete(config);
|
snd_config_delete(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_pcm_time1(struct pcm_data *data,
|
static void test_pcm_time(struct pcm_data *data, const char *test_name, snd_config_t *pcm_cfg)
|
||||||
const char *cfg_prefix, const char *sformat,
|
|
||||||
long srate, long schannels,
|
|
||||||
long speriod_size, long sbuffer_size)
|
|
||||||
{
|
{
|
||||||
char name[64], key[128], msg[256];
|
char name[64], key[128], msg[256];
|
||||||
const char *cs;
|
const char *cs;
|
||||||
int i, err;
|
int i, err;
|
||||||
snd_pcm_t *handle = NULL;
|
snd_pcm_t *handle = NULL;
|
||||||
snd_pcm_access_t access = SND_PCM_ACCESS_RW_INTERLEAVED;
|
snd_pcm_access_t access = SND_PCM_ACCESS_RW_INTERLEAVED;
|
||||||
snd_pcm_format_t format;
|
snd_pcm_format_t format, old_format;
|
||||||
|
const char *alt_formats[8];
|
||||||
unsigned char *samples = NULL;
|
unsigned char *samples = NULL;
|
||||||
snd_pcm_sframes_t frames;
|
snd_pcm_sframes_t frames;
|
||||||
long long ms;
|
long long ms;
|
||||||
|
@ -237,27 +233,23 @@ static void test_pcm_time1(struct pcm_data *data,
|
||||||
unsigned int rrate;
|
unsigned int rrate;
|
||||||
snd_pcm_uframes_t rperiod_size, rbuffer_size, start_threshold;
|
snd_pcm_uframes_t rperiod_size, rbuffer_size, start_threshold;
|
||||||
timestamp_t tstamp;
|
timestamp_t tstamp;
|
||||||
bool pass = false, automatic = true;
|
bool pass = false;
|
||||||
snd_pcm_hw_params_t *hw_params;
|
snd_pcm_hw_params_t *hw_params;
|
||||||
snd_pcm_sw_params_t *sw_params;
|
snd_pcm_sw_params_t *sw_params;
|
||||||
|
|
||||||
snd_pcm_hw_params_alloca(&hw_params);
|
snd_pcm_hw_params_alloca(&hw_params);
|
||||||
snd_pcm_sw_params_alloca(&sw_params);
|
snd_pcm_sw_params_alloca(&sw_params);
|
||||||
|
|
||||||
cs = conf_get_string(data->pcm_config, cfg_prefix, "format", sformat);
|
cs = conf_get_string(pcm_cfg, "format", NULL, "S16_LE");
|
||||||
format = snd_pcm_format_value(cs);
|
format = snd_pcm_format_value(cs);
|
||||||
if (format == SND_PCM_FORMAT_UNKNOWN)
|
if (format == SND_PCM_FORMAT_UNKNOWN)
|
||||||
ksft_exit_fail_msg("Wrong format '%s'\n", cs);
|
ksft_exit_fail_msg("Wrong format '%s'\n", cs);
|
||||||
rate = conf_get_long(data->pcm_config, cfg_prefix, "rate", srate);
|
conf_get_string_array(pcm_cfg, "alt_formats", NULL,
|
||||||
channels = conf_get_long(data->pcm_config, cfg_prefix, "channels", schannels);
|
alt_formats, ARRAY_SIZE(alt_formats), NULL);
|
||||||
period_size = conf_get_long(data->pcm_config, cfg_prefix, "period_size", speriod_size);
|
rate = conf_get_long(pcm_cfg, "rate", NULL, 48000);
|
||||||
buffer_size = conf_get_long(data->pcm_config, cfg_prefix, "buffer_size", sbuffer_size);
|
channels = conf_get_long(pcm_cfg, "channels", NULL, 2);
|
||||||
|
period_size = conf_get_long(pcm_cfg, "period_size", NULL, 4096);
|
||||||
automatic = strcmp(sformat, snd_pcm_format_name(format)) == 0 &&
|
buffer_size = conf_get_long(pcm_cfg, "buffer_size", NULL, 16384);
|
||||||
srate == rate &&
|
|
||||||
schannels == channels &&
|
|
||||||
speriod_size == period_size &&
|
|
||||||
sbuffer_size == buffer_size;
|
|
||||||
|
|
||||||
samples = malloc((rate * channels * snd_pcm_format_physical_width(format)) / 8);
|
samples = malloc((rate * channels * snd_pcm_format_physical_width(format)) / 8);
|
||||||
if (!samples)
|
if (!samples)
|
||||||
|
@ -287,16 +279,29 @@ static void test_pcm_time1(struct pcm_data *data,
|
||||||
snd_pcm_access_name(access), snd_strerror(err));
|
snd_pcm_access_name(access), snd_strerror(err));
|
||||||
goto __close;
|
goto __close;
|
||||||
}
|
}
|
||||||
|
i = -1;
|
||||||
__format:
|
__format:
|
||||||
err = snd_pcm_hw_params_set_format(handle, hw_params, format);
|
err = snd_pcm_hw_params_set_format(handle, hw_params, format);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
if (automatic && format == SND_PCM_FORMAT_S16_LE) {
|
i++;
|
||||||
format = SND_PCM_FORMAT_S32_LE;
|
if (i < ARRAY_SIZE(alt_formats) && alt_formats[i]) {
|
||||||
ksft_print_msg("%s.%d.%d.%d.%s.%s format S16_LE -> S32_LE\n",
|
old_format = format;
|
||||||
cfg_prefix,
|
format = snd_pcm_format_value(alt_formats[i]);
|
||||||
data->card, data->device, data->subdevice,
|
if (format != SND_PCM_FORMAT_UNKNOWN) {
|
||||||
snd_pcm_stream_name(data->stream),
|
ksft_print_msg("%s.%d.%d.%d.%s.%s format %s -> %s\n",
|
||||||
snd_pcm_access_name(access));
|
test_name,
|
||||||
|
data->card, data->device, data->subdevice,
|
||||||
|
snd_pcm_stream_name(data->stream),
|
||||||
|
snd_pcm_access_name(access),
|
||||||
|
snd_pcm_format_name(old_format),
|
||||||
|
snd_pcm_format_name(format));
|
||||||
|
samples = realloc(samples, (rate * channels *
|
||||||
|
snd_pcm_format_physical_width(format)) / 8);
|
||||||
|
if (!samples)
|
||||||
|
ksft_exit_fail_msg("Out of memory\n");
|
||||||
|
snd_pcm_format_set_silence(format, samples, rate * channels);
|
||||||
|
goto __format;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
snprintf(msg, sizeof(msg), "snd_pcm_hw_params_set_format %s: %s",
|
snprintf(msg, sizeof(msg), "snd_pcm_hw_params_set_format %s: %s",
|
||||||
snd_pcm_format_name(format), snd_strerror(err));
|
snd_pcm_format_name(format), snd_strerror(err));
|
||||||
|
@ -362,7 +367,7 @@ static void test_pcm_time1(struct pcm_data *data,
|
||||||
}
|
}
|
||||||
|
|
||||||
ksft_print_msg("%s.%d.%d.%d.%s hw_params.%s.%s.%ld.%ld.%ld.%ld sw_params.%ld\n",
|
ksft_print_msg("%s.%d.%d.%d.%s hw_params.%s.%s.%ld.%ld.%ld.%ld sw_params.%ld\n",
|
||||||
cfg_prefix,
|
test_name,
|
||||||
data->card, data->device, data->subdevice,
|
data->card, data->device, data->subdevice,
|
||||||
snd_pcm_stream_name(data->stream),
|
snd_pcm_stream_name(data->stream),
|
||||||
snd_pcm_access_name(access),
|
snd_pcm_access_name(access),
|
||||||
|
@ -411,7 +416,7 @@ static void test_pcm_time1(struct pcm_data *data,
|
||||||
pass = true;
|
pass = true;
|
||||||
__close:
|
__close:
|
||||||
ksft_test_result(pass, "%s.%d.%d.%d.%s%s%s\n",
|
ksft_test_result(pass, "%s.%d.%d.%d.%s%s%s\n",
|
||||||
cfg_prefix,
|
test_name,
|
||||||
data->card, data->device, data->subdevice,
|
data->card, data->device, data->subdevice,
|
||||||
snd_pcm_stream_name(data->stream),
|
snd_pcm_stream_name(data->stream),
|
||||||
msg[0] ? " " : "", msg);
|
msg[0] ? " " : "", msg);
|
||||||
|
@ -420,19 +425,35 @@ static void test_pcm_time1(struct pcm_data *data,
|
||||||
snd_pcm_close(handle);
|
snd_pcm_close(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define TESTS_PER_PCM 2
|
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
struct pcm_data *pcm;
|
struct pcm_data *pcm;
|
||||||
|
snd_config_t *global_config, *default_pcm_config, *cfg, *pcm_cfg;
|
||||||
|
snd_config_iterator_t i, next;
|
||||||
|
int num_pcm_tests = 0, num_tests;
|
||||||
|
const char *test_name, *test_type;
|
||||||
|
|
||||||
ksft_print_header();
|
ksft_print_header();
|
||||||
|
|
||||||
|
global_config = conf_load_from_file("pcm-test.conf");
|
||||||
|
default_pcm_config = conf_get_subtree(global_config, "pcm", NULL);
|
||||||
|
if (default_pcm_config == NULL)
|
||||||
|
ksft_exit_fail_msg("default pcm test configuration (pcm compound) is missing\n");
|
||||||
|
|
||||||
conf_load();
|
conf_load();
|
||||||
|
|
||||||
find_pcms();
|
find_pcms();
|
||||||
|
|
||||||
ksft_set_plan(num_missing + num_pcms * TESTS_PER_PCM);
|
for (pcm = pcm_list; pcm != NULL; pcm = pcm->next) {
|
||||||
|
cfg = pcm->pcm_config;
|
||||||
|
if (cfg == NULL)
|
||||||
|
cfg = default_pcm_config;
|
||||||
|
num_tests = conf_get_count(cfg, "test", NULL);
|
||||||
|
if (num_tests > 0)
|
||||||
|
num_pcm_tests += num_tests;
|
||||||
|
}
|
||||||
|
|
||||||
|
ksft_set_plan(num_missing + num_pcm_tests);
|
||||||
|
|
||||||
for (pcm = pcm_missing; pcm != NULL; pcm = pcm->next) {
|
for (pcm = pcm_missing; pcm != NULL; pcm = pcm->next) {
|
||||||
ksft_test_result(false, "test.missing.%d.%d.%d.%s\n",
|
ksft_test_result(false, "test.missing.%d.%d.%d.%s\n",
|
||||||
|
@ -441,10 +462,25 @@ int main(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (pcm = pcm_list; pcm != NULL; pcm = pcm->next) {
|
for (pcm = pcm_list; pcm != NULL; pcm = pcm->next) {
|
||||||
test_pcm_time1(pcm, "test.time1", "S16_LE", 48000, 2, 512, 4096);
|
cfg = pcm->pcm_config;
|
||||||
test_pcm_time1(pcm, "test.time2", "S16_LE", 48000, 2, 24000, 192000);
|
if (cfg == NULL)
|
||||||
|
cfg = default_pcm_config;
|
||||||
|
cfg = conf_get_subtree(cfg, "test", NULL);
|
||||||
|
if (cfg == NULL)
|
||||||
|
continue;
|
||||||
|
snd_config_for_each(i, next, cfg) {
|
||||||
|
pcm_cfg = snd_config_iterator_entry(i);
|
||||||
|
if (snd_config_get_id(pcm_cfg, &test_name) < 0)
|
||||||
|
ksft_exit_fail_msg("snd_config_get_id\n");
|
||||||
|
test_type = conf_get_string(pcm_cfg, "type", NULL, "time");
|
||||||
|
if (strcmp(test_type, "time") == 0)
|
||||||
|
test_pcm_time(pcm, test_name, pcm_cfg);
|
||||||
|
else
|
||||||
|
ksft_exit_fail_msg("unknown test type '%s'\n", test_type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
snd_config_delete(global_config);
|
||||||
conf_free();
|
conf_free();
|
||||||
|
|
||||||
ksft_exit_pass();
|
ksft_exit_pass();
|
||||||
|
|
16
tools/testing/selftests/alsa/pcm-test.conf
Normal file
16
tools/testing/selftests/alsa/pcm-test.conf
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
pcm.test.time1 {
|
||||||
|
format S16_LE
|
||||||
|
alt_formats [ S32_LE ]
|
||||||
|
rate 48000
|
||||||
|
channels 2
|
||||||
|
period_size 512
|
||||||
|
buffer_size 4096
|
||||||
|
}
|
||||||
|
pcm.test.time2 {
|
||||||
|
format S16_LE
|
||||||
|
alt_formats [ S32_LE ]
|
||||||
|
rate 48000
|
||||||
|
channels 2
|
||||||
|
period_size 24000
|
||||||
|
buffer_size 192000
|
||||||
|
}
|
Loading…
Reference in a new issue