Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Jaroslav Kysela and committed by
Takashi Iwai
348d09fc c48cafc2

+121 -36
+1 -1
tools/testing/selftests/alsa/Makefile
··· 14 14 15 15 TEST_GEN_PROGS_EXTENDED := libatest.so 16 16 17 - TEST_FILES := conf.d 17 + TEST_FILES := conf.d pcm-test.conf 18 18 19 19 include ../lib.mk 20 20
+3
tools/testing/selftests/alsa/alsa-local.h
··· 12 12 13 13 snd_config_t *get_alsalib_config(void); 14 14 15 + snd_config_t *conf_load_from_file(const char *filename); 15 16 void conf_load(void); 16 17 void conf_free(void); 17 18 snd_config_t *conf_by_card(int card); ··· 21 20 const char *conf_get_string(snd_config_t *root, const char *key1, const char *key2, const char *def); 22 21 long conf_get_long(snd_config_t *root, const char *key1, const char *key2, long def); 23 22 int conf_get_bool(snd_config_t *root, const char *key1, const char *key2, int def); 23 + void conf_get_string_array(snd_config_t *root, const char *key1, const char *key2, 24 + const char **array, int array_size, const char *def); 24 25 25 26 #endif /* __ALSA_LOCAL_H */
+24 -2
tools/testing/selftests/alsa/conf.c
··· 125 125 snd_output_close(out); 126 126 } 127 127 128 - static snd_config_t *load(const char *filename) 128 + snd_config_t *conf_load_from_file(const char *filename) 129 129 { 130 130 snd_config_t *dst; 131 131 snd_input_t *input; ··· 235 235 snd_config_t *config, *sysfs_config, *card_config, *sysfs_card_config, *node; 236 236 snd_config_iterator_t i, next; 237 237 238 - config = load(filename); 238 + config = conf_load_from_file(filename); 239 239 if (snd_config_search(config, "sysfs", &sysfs_config) || 240 240 snd_config_get_type(sysfs_config) != SND_CONFIG_TYPE_COMPOUND) 241 241 ksft_exit_fail_msg("Missing global sysfs block in filename %s\n", filename); ··· 445 445 if (ret < 0) 446 446 ksft_exit_fail_msg("key '%s'.'%s' is not an bool\n", key1, key2); 447 447 return !!ret; 448 + } 449 + 450 + void conf_get_string_array(snd_config_t *root, const char *key1, const char *key2, 451 + const char **array, int array_size, const char *def) 452 + { 453 + snd_config_t *cfg; 454 + char buf[16]; 455 + int ret, index; 456 + 457 + ret = conf_get_by_keys(root, key1, key2, &cfg); 458 + if (ret == -ENOENT) 459 + cfg = NULL; 460 + else if (ret < 0) 461 + ksft_exit_fail_msg("key '%s'.'%s' search error: %s\n", key1, key2, snd_strerror(ret)); 462 + for (index = 0; index < array_size; index++) { 463 + if (cfg == NULL) { 464 + array[index] = def; 465 + } else { 466 + sprintf(buf, "%i", index); 467 + array[index] = conf_get_string(cfg, buf, NULL, def); 468 + } 469 + } 448 470 }
+8
tools/testing/selftests/alsa/conf.d/Lenovo_ThinkPad_P1_Gen2.conf
··· 55 55 period_size 24000 56 56 buffer_size 192000 57 57 } 58 + test.time3 { 59 + access RW_INTERLEAVED 60 + format S16_LE 61 + rate 44100 62 + channels 2 63 + period_size 24000 64 + buffer_size 192000 65 + } 58 66 } 59 67 CAPTURE { 60 68 # use default tests, check for the presence
+69 -33
tools/testing/selftests/alsa/pcm-test.c
··· 31 31 struct pcm_data *next; 32 32 }; 33 33 34 - int num_pcms = 0; 35 34 struct pcm_data *pcm_list = NULL; 36 35 37 36 int num_missing = 0; ··· 199 200 pcm_data->pcm_config = conf_get_subtree(card_config, key, NULL); 200 201 pcm_data->next = pcm_list; 201 202 pcm_list = pcm_data; 202 - num_pcms++; 203 203 } 204 204 } 205 205 } ··· 217 219 snd_config_delete(config); 218 220 } 219 221 220 - static void test_pcm_time1(struct pcm_data *data, 221 - const char *cfg_prefix, const char *sformat, 222 - long srate, long schannels, 223 - long speriod_size, long sbuffer_size) 222 + static void test_pcm_time(struct pcm_data *data, const char *test_name, snd_config_t *pcm_cfg) 224 223 { 225 224 char name[64], key[128], msg[256]; 226 225 const char *cs; 227 226 int i, err; 228 227 snd_pcm_t *handle = NULL; 229 228 snd_pcm_access_t access = SND_PCM_ACCESS_RW_INTERLEAVED; 230 - snd_pcm_format_t format; 229 + snd_pcm_format_t format, old_format; 230 + const char *alt_formats[8]; 231 231 unsigned char *samples = NULL; 232 232 snd_pcm_sframes_t frames; 233 233 long long ms; ··· 233 237 unsigned int rrate; 234 238 snd_pcm_uframes_t rperiod_size, rbuffer_size, start_threshold; 235 239 timestamp_t tstamp; 236 - bool pass = false, automatic = true; 240 + bool pass = false; 237 241 snd_pcm_hw_params_t *hw_params; 238 242 snd_pcm_sw_params_t *sw_params; 239 243 240 244 snd_pcm_hw_params_alloca(&hw_params); 241 245 snd_pcm_sw_params_alloca(&sw_params); 242 246 243 - cs = conf_get_string(data->pcm_config, cfg_prefix, "format", sformat); 247 + cs = conf_get_string(pcm_cfg, "format", NULL, "S16_LE"); 244 248 format = snd_pcm_format_value(cs); 245 249 if (format == SND_PCM_FORMAT_UNKNOWN) 246 250 ksft_exit_fail_msg("Wrong format '%s'\n", cs); 247 - rate = conf_get_long(data->pcm_config, cfg_prefix, "rate", srate); 248 - channels = conf_get_long(data->pcm_config, cfg_prefix, "channels", schannels); 249 - period_size = conf_get_long(data->pcm_config, cfg_prefix, "period_size", speriod_size); 250 - buffer_size = conf_get_long(data->pcm_config, cfg_prefix, "buffer_size", sbuffer_size); 251 - 252 - automatic = strcmp(sformat, snd_pcm_format_name(format)) == 0 && 253 - srate == rate && 254 - schannels == channels && 255 - speriod_size == period_size && 256 - sbuffer_size == buffer_size; 251 + conf_get_string_array(pcm_cfg, "alt_formats", NULL, 252 + alt_formats, ARRAY_SIZE(alt_formats), NULL); 253 + rate = conf_get_long(pcm_cfg, "rate", NULL, 48000); 254 + channels = conf_get_long(pcm_cfg, "channels", NULL, 2); 255 + period_size = conf_get_long(pcm_cfg, "period_size", NULL, 4096); 256 + buffer_size = conf_get_long(pcm_cfg, "buffer_size", NULL, 16384); 257 257 258 258 samples = malloc((rate * channels * snd_pcm_format_physical_width(format)) / 8); 259 259 if (!samples) ··· 279 287 snd_pcm_access_name(access), snd_strerror(err)); 280 288 goto __close; 281 289 } 290 + i = -1; 282 291 __format: 283 292 err = snd_pcm_hw_params_set_format(handle, hw_params, format); 284 293 if (err < 0) { 285 - if (automatic && format == SND_PCM_FORMAT_S16_LE) { 286 - format = SND_PCM_FORMAT_S32_LE; 287 - ksft_print_msg("%s.%d.%d.%d.%s.%s format S16_LE -> S32_LE\n", 288 - cfg_prefix, 289 - data->card, data->device, data->subdevice, 290 - snd_pcm_stream_name(data->stream), 291 - snd_pcm_access_name(access)); 294 + i++; 295 + if (i < ARRAY_SIZE(alt_formats) && alt_formats[i]) { 296 + old_format = format; 297 + format = snd_pcm_format_value(alt_formats[i]); 298 + if (format != SND_PCM_FORMAT_UNKNOWN) { 299 + ksft_print_msg("%s.%d.%d.%d.%s.%s format %s -> %s\n", 300 + test_name, 301 + data->card, data->device, data->subdevice, 302 + snd_pcm_stream_name(data->stream), 303 + snd_pcm_access_name(access), 304 + snd_pcm_format_name(old_format), 305 + snd_pcm_format_name(format)); 306 + samples = realloc(samples, (rate * channels * 307 + snd_pcm_format_physical_width(format)) / 8); 308 + if (!samples) 309 + ksft_exit_fail_msg("Out of memory\n"); 310 + snd_pcm_format_set_silence(format, samples, rate * channels); 311 + goto __format; 312 + } 292 313 } 293 314 snprintf(msg, sizeof(msg), "snd_pcm_hw_params_set_format %s: %s", 294 315 snd_pcm_format_name(format), snd_strerror(err)); ··· 367 362 } 368 363 369 364 ksft_print_msg("%s.%d.%d.%d.%s hw_params.%s.%s.%ld.%ld.%ld.%ld sw_params.%ld\n", 370 - cfg_prefix, 365 + test_name, 371 366 data->card, data->device, data->subdevice, 372 367 snd_pcm_stream_name(data->stream), 373 368 snd_pcm_access_name(access), ··· 416 411 pass = true; 417 412 __close: 418 413 ksft_test_result(pass, "%s.%d.%d.%d.%s%s%s\n", 419 - cfg_prefix, 414 + test_name, 420 415 data->card, data->device, data->subdevice, 421 416 snd_pcm_stream_name(data->stream), 422 417 msg[0] ? " " : "", msg); ··· 425 420 snd_pcm_close(handle); 426 421 } 427 422 428 - #define TESTS_PER_PCM 2 429 - 430 423 int main(void) 431 424 { 432 425 struct pcm_data *pcm; 426 + snd_config_t *global_config, *default_pcm_config, *cfg, *pcm_cfg; 427 + snd_config_iterator_t i, next; 428 + int num_pcm_tests = 0, num_tests; 429 + const char *test_name, *test_type; 433 430 434 431 ksft_print_header(); 432 + 433 + global_config = conf_load_from_file("pcm-test.conf"); 434 + default_pcm_config = conf_get_subtree(global_config, "pcm", NULL); 435 + if (default_pcm_config == NULL) 436 + ksft_exit_fail_msg("default pcm test configuration (pcm compound) is missing\n"); 435 437 436 438 conf_load(); 437 439 438 440 find_pcms(); 439 441 440 - ksft_set_plan(num_missing + num_pcms * TESTS_PER_PCM); 442 + for (pcm = pcm_list; pcm != NULL; pcm = pcm->next) { 443 + cfg = pcm->pcm_config; 444 + if (cfg == NULL) 445 + cfg = default_pcm_config; 446 + num_tests = conf_get_count(cfg, "test", NULL); 447 + if (num_tests > 0) 448 + num_pcm_tests += num_tests; 449 + } 450 + 451 + ksft_set_plan(num_missing + num_pcm_tests); 441 452 442 453 for (pcm = pcm_missing; pcm != NULL; pcm = pcm->next) { 443 454 ksft_test_result(false, "test.missing.%d.%d.%d.%s\n", ··· 462 441 } 463 442 464 443 for (pcm = pcm_list; pcm != NULL; pcm = pcm->next) { 465 - test_pcm_time1(pcm, "test.time1", "S16_LE", 48000, 2, 512, 4096); 466 - test_pcm_time1(pcm, "test.time2", "S16_LE", 48000, 2, 24000, 192000); 444 + cfg = pcm->pcm_config; 445 + if (cfg == NULL) 446 + cfg = default_pcm_config; 447 + cfg = conf_get_subtree(cfg, "test", NULL); 448 + if (cfg == NULL) 449 + continue; 450 + snd_config_for_each(i, next, cfg) { 451 + pcm_cfg = snd_config_iterator_entry(i); 452 + if (snd_config_get_id(pcm_cfg, &test_name) < 0) 453 + ksft_exit_fail_msg("snd_config_get_id\n"); 454 + test_type = conf_get_string(pcm_cfg, "type", NULL, "time"); 455 + if (strcmp(test_type, "time") == 0) 456 + test_pcm_time(pcm, test_name, pcm_cfg); 457 + else 458 + ksft_exit_fail_msg("unknown test type '%s'\n", test_type); 459 + } 467 460 } 468 461 462 + snd_config_delete(global_config); 469 463 conf_free(); 470 464 471 465 ksft_exit_pass();
+16
tools/testing/selftests/alsa/pcm-test.conf
··· 1 + pcm.test.time1 { 2 + format S16_LE 3 + alt_formats [ S32_LE ] 4 + rate 48000 5 + channels 2 6 + period_size 512 7 + buffer_size 4096 8 + } 9 + pcm.test.time2 { 10 + format S16_LE 11 + alt_formats [ S32_LE ] 12 + rate 48000 13 + channels 2 14 + period_size 24000 15 + buffer_size 192000 16 + }