kselftest/alsa: pcm - move more configuration to configuration files
authorJaroslav Kysela <perex@perex.cz>
Tue, 27 Dec 2022 17:06:47 +0000 (17:06 +0000)
committerTakashi Iwai <tiwai@suse.de>
Mon, 2 Jan 2023 14:07:35 +0000 (15:07 +0100)
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>
tools/testing/selftests/alsa/Makefile
tools/testing/selftests/alsa/alsa-local.h
tools/testing/selftests/alsa/conf.c
tools/testing/selftests/alsa/conf.d/Lenovo_ThinkPad_P1_Gen2.conf
tools/testing/selftests/alsa/pcm-test.c
tools/testing/selftests/alsa/pcm-test.conf [new file with mode: 0644]

index a8c0383878d3e60955c3f446ca465f22a1d38bbd..77fba3e498cc9d9370ecaa55e486ef8065cb6d2c 100644 (file)
@@ -14,7 +14,7 @@ TEST_GEN_PROGS := mixer-test pcm-test
 
 TEST_GEN_PROGS_EXTENDED := libatest.so
 
-TEST_FILES := conf.d
+TEST_FILES := conf.d pcm-test.conf
 
 include ../lib.mk
 
index 65f197ea9773ab699a59fb9d26444e689e0c941d..de030dc23bd19f37ee5e790cb636a7f1443dc458 100644 (file)
@@ -12,6 +12,7 @@
 
 snd_config_t *get_alsalib_config(void);
 
+snd_config_t *conf_load_from_file(const char *filename);
 void conf_load(void);
 void conf_free(void);
 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);
 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);
+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 */
index c7ffc8f04195511d6da33a630fedfd40ba2b6a03..d7aafe5a1993aaf45aa1c7b237db72a15a27f224 100644 (file)
@@ -125,7 +125,7 @@ static int dump_config_tree(snd_config_t *top)
        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_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_iterator_t i, next;
 
-       config = load(filename);
+       config = conf_load_from_file(filename);
        if (snd_config_search(config, "sysfs", &sysfs_config) ||
            snd_config_get_type(sysfs_config) != SND_CONFIG_TYPE_COMPOUND)
                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);
        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);
+               }
+       }
+}
index 0a83f35d43eb7d6fd1b38a097f72ef84aaa4b873..5b40a916295ddef400bc3cbf97f326483b8e24fd 100644 (file)
@@ -55,6 +55,14 @@ card.hda {
                                period_size 24000
                                buffer_size 192000
                        }
+                       test.time3 {
+                               access RW_INTERLEAVED
+                               format S16_LE
+                               rate 44100
+                               channels 2
+                               period_size 24000
+                               buffer_size 192000
+                       }
                }
                CAPTURE {
                        # use default tests, check for the presence
index 6e7dfc395b987e8137da670240fb50bebab4a533..e973b03ae1fd56b8f246703358e779e46dda8216 100644 (file)
@@ -31,7 +31,6 @@ struct pcm_data {
        struct pcm_data *next;
 };
 
-int num_pcms = 0;
 struct pcm_data *pcm_list = NULL;
 
 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->next = pcm_list;
                                        pcm_list = pcm_data;
-                                       num_pcms++;
                                }
                        }
                }
@@ -219,17 +217,15 @@ static void find_pcms(void)
        snd_config_delete(config);
 }
 
-static void test_pcm_time1(struct pcm_data *data,
-                          const char *cfg_prefix, const char *sformat,
-                          long srate, long schannels,
-                          long speriod_size, long sbuffer_size)
+static void test_pcm_time(struct pcm_data *data, const char *test_name, snd_config_t *pcm_cfg)
 {
        char name[64], key[128], msg[256];
        const char *cs;
        int i, err;
        snd_pcm_t *handle = NULL;
        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;
        snd_pcm_sframes_t frames;
        long long ms;
@@ -237,27 +233,23 @@ static void test_pcm_time1(struct pcm_data *data,
        unsigned int rrate;
        snd_pcm_uframes_t rperiod_size, rbuffer_size, start_threshold;
        timestamp_t tstamp;
-       bool pass = false, automatic = true;
+       bool pass = false;
        snd_pcm_hw_params_t *hw_params;
        snd_pcm_sw_params_t *sw_params;
 
        snd_pcm_hw_params_alloca(&hw_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);
        if (format == SND_PCM_FORMAT_UNKNOWN)
                ksft_exit_fail_msg("Wrong format '%s'\n", cs);
-       rate = conf_get_long(data->pcm_config, cfg_prefix, "rate", srate);
-       channels = conf_get_long(data->pcm_config, cfg_prefix, "channels", schannels);
-       period_size = conf_get_long(data->pcm_config, cfg_prefix, "period_size", speriod_size);
-       buffer_size = conf_get_long(data->pcm_config, cfg_prefix, "buffer_size", sbuffer_size);
-
-       automatic = strcmp(sformat, snd_pcm_format_name(format)) == 0 &&
-                       srate == rate &&
-                       schannels == channels &&
-                       speriod_size == period_size &&
-                       sbuffer_size == buffer_size;
+       conf_get_string_array(pcm_cfg, "alt_formats", NULL,
+                               alt_formats, ARRAY_SIZE(alt_formats), NULL);
+       rate = conf_get_long(pcm_cfg, "rate", NULL, 48000);
+       channels = conf_get_long(pcm_cfg, "channels", NULL, 2);
+       period_size = conf_get_long(pcm_cfg, "period_size", NULL, 4096);
+       buffer_size = conf_get_long(pcm_cfg, "buffer_size", NULL, 16384);
 
        samples = malloc((rate * channels * snd_pcm_format_physical_width(format)) / 8);
        if (!samples)
@@ -287,16 +279,29 @@ static void test_pcm_time1(struct pcm_data *data,
                                           snd_pcm_access_name(access), snd_strerror(err));
                goto __close;
        }
+       i = -1;
 __format:
        err = snd_pcm_hw_params_set_format(handle, hw_params, format);
        if (err < 0) {
-               if (automatic && format == SND_PCM_FORMAT_S16_LE) {
-                       format = SND_PCM_FORMAT_S32_LE;
-                       ksft_print_msg("%s.%d.%d.%d.%s.%s format S16_LE -> S32_LE\n",
-                                        cfg_prefix,
-                                        data->card, data->device, data->subdevice,
-                                        snd_pcm_stream_name(data->stream),
-                                        snd_pcm_access_name(access));
+               i++;
+               if (i < ARRAY_SIZE(alt_formats) && alt_formats[i]) {
+                       old_format = format;
+                       format = snd_pcm_format_value(alt_formats[i]);
+                       if (format != SND_PCM_FORMAT_UNKNOWN) {
+                               ksft_print_msg("%s.%d.%d.%d.%s.%s format %s -> %s\n",
+                                                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",
                                           snd_pcm_format_name(format), snd_strerror(err));
@@ -362,7 +367,7 @@ __format:
        }
 
        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,
                         snd_pcm_stream_name(data->stream),
                         snd_pcm_access_name(access),
@@ -411,7 +416,7 @@ __format:
        pass = true;
 __close:
        ksft_test_result(pass, "%s.%d.%d.%d.%s%s%s\n",
-                        cfg_prefix,
+                        test_name,
                         data->card, data->device, data->subdevice,
                         snd_pcm_stream_name(data->stream),
                         msg[0] ? " " : "", msg);
@@ -420,19 +425,35 @@ __close:
                snd_pcm_close(handle);
 }
 
-#define TESTS_PER_PCM 2
-
 int main(void)
 {
        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();
 
+       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();
 
        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) {
                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) {
-               test_pcm_time1(pcm, "test.time1", "S16_LE", 48000, 2, 512, 4096);
-               test_pcm_time1(pcm, "test.time2", "S16_LE", 48000, 2, 24000, 192000);
+               cfg = pcm->pcm_config;
+               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();
 
        ksft_exit_pass();
diff --git a/tools/testing/selftests/alsa/pcm-test.conf b/tools/testing/selftests/alsa/pcm-test.conf
new file mode 100644 (file)
index 0000000..473a192
--- /dev/null
@@ -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
+}