1aba51cd0SJaroslav Kysela // SPDX-License-Identifier: GPL-2.0 2aba51cd0SJaroslav Kysela // 3aba51cd0SJaroslav Kysela // kselftest for the ALSA PCM API 4aba51cd0SJaroslav Kysela // 5aba51cd0SJaroslav Kysela // Original author: Jaroslav Kysela <perex@perex.cz> 6aba51cd0SJaroslav Kysela // Copyright (c) 2022 Red Hat Inc. 7aba51cd0SJaroslav Kysela 8aba51cd0SJaroslav Kysela // This test will iterate over all cards detected in the system, exercising 9aba51cd0SJaroslav Kysela // every PCM device it can find. This may conflict with other system 10aba51cd0SJaroslav Kysela // software if there is audio activity so is best run on a system with a 11aba51cd0SJaroslav Kysela // minimal active userspace. 12aba51cd0SJaroslav Kysela 13aba51cd0SJaroslav Kysela #include <stdio.h> 14aba51cd0SJaroslav Kysela #include <stdlib.h> 15aba51cd0SJaroslav Kysela #include <stdbool.h> 16aba51cd0SJaroslav Kysela #include <errno.h> 17aba51cd0SJaroslav Kysela #include <assert.h> 18aba51cd0SJaroslav Kysela 19aba51cd0SJaroslav Kysela #include "../kselftest.h" 20aba51cd0SJaroslav Kysela #include "alsa-local.h" 21aba51cd0SJaroslav Kysela 22aba51cd0SJaroslav Kysela typedef struct timespec timestamp_t; 23aba51cd0SJaroslav Kysela 24aba51cd0SJaroslav Kysela struct pcm_data { 25aba51cd0SJaroslav Kysela snd_pcm_t *handle; 26aba51cd0SJaroslav Kysela int card; 27aba51cd0SJaroslav Kysela int device; 28aba51cd0SJaroslav Kysela int subdevice; 29aba51cd0SJaroslav Kysela snd_pcm_stream_t stream; 30aba51cd0SJaroslav Kysela snd_config_t *pcm_config; 31aba51cd0SJaroslav Kysela struct pcm_data *next; 32aba51cd0SJaroslav Kysela }; 33aba51cd0SJaroslav Kysela 34aba51cd0SJaroslav Kysela int num_pcms = 0; 35aba51cd0SJaroslav Kysela struct pcm_data *pcm_list = NULL; 36aba51cd0SJaroslav Kysela 37aba51cd0SJaroslav Kysela int num_missing = 0; 38aba51cd0SJaroslav Kysela struct pcm_data *pcm_missing = NULL; 39aba51cd0SJaroslav Kysela 40aba51cd0SJaroslav Kysela void timestamp_now(timestamp_t *tstamp) 41aba51cd0SJaroslav Kysela { 42aba51cd0SJaroslav Kysela if (clock_gettime(CLOCK_MONOTONIC_RAW, tstamp)) 43aba51cd0SJaroslav Kysela ksft_exit_fail_msg("clock_get_time\n"); 44aba51cd0SJaroslav Kysela } 45aba51cd0SJaroslav Kysela 46aba51cd0SJaroslav Kysela long long timestamp_diff_ms(timestamp_t *tstamp) 47aba51cd0SJaroslav Kysela { 48aba51cd0SJaroslav Kysela timestamp_t now, diff; 49aba51cd0SJaroslav Kysela timestamp_now(&now); 50aba51cd0SJaroslav Kysela if (tstamp->tv_nsec > now.tv_nsec) { 51aba51cd0SJaroslav Kysela diff.tv_sec = now.tv_sec - tstamp->tv_sec - 1; 52aba51cd0SJaroslav Kysela diff.tv_nsec = (now.tv_nsec + 1000000000L) - tstamp->tv_nsec; 53aba51cd0SJaroslav Kysela } else { 54aba51cd0SJaroslav Kysela diff.tv_sec = now.tv_sec - tstamp->tv_sec; 55aba51cd0SJaroslav Kysela diff.tv_nsec = now.tv_nsec - tstamp->tv_nsec; 56aba51cd0SJaroslav Kysela } 57aba51cd0SJaroslav Kysela return (diff.tv_sec * 1000) + ((diff.tv_nsec + 500000L) / 1000000L); 58aba51cd0SJaroslav Kysela } 59aba51cd0SJaroslav Kysela 60aba51cd0SJaroslav Kysela static long device_from_id(snd_config_t *node) 61aba51cd0SJaroslav Kysela { 62aba51cd0SJaroslav Kysela const char *id; 63aba51cd0SJaroslav Kysela char *end; 64aba51cd0SJaroslav Kysela long v; 65aba51cd0SJaroslav Kysela 66aba51cd0SJaroslav Kysela if (snd_config_get_id(node, &id)) 67aba51cd0SJaroslav Kysela ksft_exit_fail_msg("snd_config_get_id\n"); 68aba51cd0SJaroslav Kysela errno = 0; 69aba51cd0SJaroslav Kysela v = strtol(id, &end, 10); 70aba51cd0SJaroslav Kysela if (errno || *end) 71aba51cd0SJaroslav Kysela return -1; 72aba51cd0SJaroslav Kysela return v; 73aba51cd0SJaroslav Kysela } 74aba51cd0SJaroslav Kysela 75aba51cd0SJaroslav Kysela static void missing_device(int card, int device, int subdevice, snd_pcm_stream_t stream) 76aba51cd0SJaroslav Kysela { 77aba51cd0SJaroslav Kysela struct pcm_data *pcm_data; 78aba51cd0SJaroslav Kysela 79aba51cd0SJaroslav Kysela for (pcm_data = pcm_list; pcm_data != NULL; pcm_data = pcm_data->next) { 80aba51cd0SJaroslav Kysela if (pcm_data->card != card) 81aba51cd0SJaroslav Kysela continue; 82aba51cd0SJaroslav Kysela if (pcm_data->device != device) 83aba51cd0SJaroslav Kysela continue; 84aba51cd0SJaroslav Kysela if (pcm_data->subdevice != subdevice) 85aba51cd0SJaroslav Kysela continue; 86aba51cd0SJaroslav Kysela if (pcm_data->stream != stream) 87aba51cd0SJaroslav Kysela continue; 88aba51cd0SJaroslav Kysela return; 89aba51cd0SJaroslav Kysela } 90aba51cd0SJaroslav Kysela pcm_data = calloc(1, sizeof(*pcm_data)); 91aba51cd0SJaroslav Kysela if (!pcm_data) 92aba51cd0SJaroslav Kysela ksft_exit_fail_msg("Out of memory\n"); 93aba51cd0SJaroslav Kysela pcm_data->card = card; 94aba51cd0SJaroslav Kysela pcm_data->device = device; 95aba51cd0SJaroslav Kysela pcm_data->subdevice = subdevice; 96aba51cd0SJaroslav Kysela pcm_data->stream = stream; 97aba51cd0SJaroslav Kysela pcm_data->next = pcm_missing; 98aba51cd0SJaroslav Kysela pcm_missing = pcm_data; 99aba51cd0SJaroslav Kysela num_missing++; 100aba51cd0SJaroslav Kysela } 101aba51cd0SJaroslav Kysela 102aba51cd0SJaroslav Kysela static void missing_devices(int card, snd_config_t *card_config) 103aba51cd0SJaroslav Kysela { 104aba51cd0SJaroslav Kysela snd_config_t *pcm_config, *node1, *node2; 105aba51cd0SJaroslav Kysela snd_config_iterator_t i1, i2, next1, next2; 106aba51cd0SJaroslav Kysela int device, subdevice; 107aba51cd0SJaroslav Kysela 108aba51cd0SJaroslav Kysela pcm_config = conf_get_subtree(card_config, "pcm", NULL); 109aba51cd0SJaroslav Kysela if (!pcm_config) 110aba51cd0SJaroslav Kysela return; 111aba51cd0SJaroslav Kysela snd_config_for_each(i1, next1, pcm_config) { 112aba51cd0SJaroslav Kysela node1 = snd_config_iterator_entry(i1); 113aba51cd0SJaroslav Kysela device = device_from_id(node1); 114aba51cd0SJaroslav Kysela if (device < 0) 115aba51cd0SJaroslav Kysela continue; 116aba51cd0SJaroslav Kysela if (snd_config_get_type(node1) != SND_CONFIG_TYPE_COMPOUND) 117aba51cd0SJaroslav Kysela continue; 118aba51cd0SJaroslav Kysela snd_config_for_each(i2, next2, node1) { 119aba51cd0SJaroslav Kysela node2 = snd_config_iterator_entry(i2); 120aba51cd0SJaroslav Kysela subdevice = device_from_id(node2); 121aba51cd0SJaroslav Kysela if (subdevice < 0) 122aba51cd0SJaroslav Kysela continue; 123aba51cd0SJaroslav Kysela if (conf_get_subtree(node2, "PLAYBACK", NULL)) 124aba51cd0SJaroslav Kysela missing_device(card, device, subdevice, SND_PCM_STREAM_PLAYBACK); 125aba51cd0SJaroslav Kysela if (conf_get_subtree(node2, "CAPTURE", NULL)) 126aba51cd0SJaroslav Kysela missing_device(card, device, subdevice, SND_PCM_STREAM_CAPTURE); 127aba51cd0SJaroslav Kysela } 128aba51cd0SJaroslav Kysela } 129aba51cd0SJaroslav Kysela } 130aba51cd0SJaroslav Kysela 131aba51cd0SJaroslav Kysela static void find_pcms(void) 132aba51cd0SJaroslav Kysela { 133aba51cd0SJaroslav Kysela char name[32], key[64]; 134aba51cd0SJaroslav Kysela int card, dev, subdev, count, direction, err; 135aba51cd0SJaroslav Kysela snd_pcm_stream_t stream; 136aba51cd0SJaroslav Kysela struct pcm_data *pcm_data; 137aba51cd0SJaroslav Kysela snd_ctl_t *handle; 138aba51cd0SJaroslav Kysela snd_pcm_info_t *pcm_info; 139aba51cd0SJaroslav Kysela snd_config_t *config, *card_config, *pcm_config; 140aba51cd0SJaroslav Kysela 141aba51cd0SJaroslav Kysela snd_pcm_info_alloca(&pcm_info); 142aba51cd0SJaroslav Kysela 143aba51cd0SJaroslav Kysela card = -1; 144aba51cd0SJaroslav Kysela if (snd_card_next(&card) < 0 || card < 0) 145aba51cd0SJaroslav Kysela return; 146aba51cd0SJaroslav Kysela 147aba51cd0SJaroslav Kysela config = get_alsalib_config(); 148aba51cd0SJaroslav Kysela 149aba51cd0SJaroslav Kysela while (card >= 0) { 150aba51cd0SJaroslav Kysela sprintf(name, "hw:%d", card); 151aba51cd0SJaroslav Kysela 152aba51cd0SJaroslav Kysela err = snd_ctl_open_lconf(&handle, name, 0, config); 153aba51cd0SJaroslav Kysela if (err < 0) { 154aba51cd0SJaroslav Kysela ksft_print_msg("Failed to get hctl for card %d: %s\n", 155aba51cd0SJaroslav Kysela card, snd_strerror(err)); 156aba51cd0SJaroslav Kysela goto next_card; 157aba51cd0SJaroslav Kysela } 158aba51cd0SJaroslav Kysela 159aba51cd0SJaroslav Kysela card_config = conf_by_card(card); 160aba51cd0SJaroslav Kysela 161aba51cd0SJaroslav Kysela dev = -1; 162aba51cd0SJaroslav Kysela while (1) { 163aba51cd0SJaroslav Kysela if (snd_ctl_pcm_next_device(handle, &dev) < 0) 164aba51cd0SJaroslav Kysela ksft_exit_fail_msg("snd_ctl_pcm_next_device\n"); 165aba51cd0SJaroslav Kysela if (dev < 0) 166aba51cd0SJaroslav Kysela break; 167aba51cd0SJaroslav Kysela 168aba51cd0SJaroslav Kysela for (direction = 0; direction < 2; direction++) { 169aba51cd0SJaroslav Kysela stream = direction ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK; 170aba51cd0SJaroslav Kysela sprintf(key, "pcm.%d.%s", dev, snd_pcm_stream_name(stream)); 171aba51cd0SJaroslav Kysela pcm_config = conf_get_subtree(card_config, key, NULL); 172aba51cd0SJaroslav Kysela if (conf_get_bool(card_config, key, "skip", false)) { 173aba51cd0SJaroslav Kysela ksft_print_msg("skipping pcm %d.%d.%s\n", card, dev, snd_pcm_stream_name(stream)); 174aba51cd0SJaroslav Kysela continue; 175aba51cd0SJaroslav Kysela } 176aba51cd0SJaroslav Kysela snd_pcm_info_set_device(pcm_info, dev); 177aba51cd0SJaroslav Kysela snd_pcm_info_set_subdevice(pcm_info, 0); 178aba51cd0SJaroslav Kysela snd_pcm_info_set_stream(pcm_info, stream); 179aba51cd0SJaroslav Kysela err = snd_ctl_pcm_info(handle, pcm_info); 180aba51cd0SJaroslav Kysela if (err == -ENOENT) 181aba51cd0SJaroslav Kysela continue; 182aba51cd0SJaroslav Kysela if (err < 0) 183aba51cd0SJaroslav Kysela ksft_exit_fail_msg("snd_ctl_pcm_info: %d:%d:%d\n", 184aba51cd0SJaroslav Kysela dev, 0, stream); 185aba51cd0SJaroslav Kysela count = snd_pcm_info_get_subdevices_count(pcm_info); 186aba51cd0SJaroslav Kysela for (subdev = 0; subdev < count; subdev++) { 187aba51cd0SJaroslav Kysela sprintf(key, "pcm.%d.%d.%s", dev, subdev, snd_pcm_stream_name(stream)); 188aba51cd0SJaroslav Kysela if (conf_get_bool(card_config, key, "skip", false)) { 189aba51cd0SJaroslav Kysela ksft_print_msg("skipping pcm %d.%d.%d.%s\n", card, dev, 190aba51cd0SJaroslav Kysela subdev, snd_pcm_stream_name(stream)); 191aba51cd0SJaroslav Kysela continue; 192aba51cd0SJaroslav Kysela } 193aba51cd0SJaroslav Kysela pcm_data = calloc(1, sizeof(*pcm_data)); 194aba51cd0SJaroslav Kysela if (!pcm_data) 195aba51cd0SJaroslav Kysela ksft_exit_fail_msg("Out of memory\n"); 196aba51cd0SJaroslav Kysela pcm_data->card = card; 197aba51cd0SJaroslav Kysela pcm_data->device = dev; 198aba51cd0SJaroslav Kysela pcm_data->subdevice = subdev; 199aba51cd0SJaroslav Kysela pcm_data->stream = stream; 200aba51cd0SJaroslav Kysela pcm_data->pcm_config = conf_get_subtree(card_config, key, NULL); 201aba51cd0SJaroslav Kysela pcm_data->next = pcm_list; 202aba51cd0SJaroslav Kysela pcm_list = pcm_data; 203aba51cd0SJaroslav Kysela num_pcms++; 204aba51cd0SJaroslav Kysela } 205aba51cd0SJaroslav Kysela } 206aba51cd0SJaroslav Kysela } 207aba51cd0SJaroslav Kysela 208aba51cd0SJaroslav Kysela /* check for missing devices */ 209aba51cd0SJaroslav Kysela missing_devices(card, card_config); 210aba51cd0SJaroslav Kysela 211aba51cd0SJaroslav Kysela next_card: 212aba51cd0SJaroslav Kysela snd_ctl_close(handle); 213aba51cd0SJaroslav Kysela if (snd_card_next(&card) < 0) { 214aba51cd0SJaroslav Kysela ksft_print_msg("snd_card_next"); 215aba51cd0SJaroslav Kysela break; 216aba51cd0SJaroslav Kysela } 217aba51cd0SJaroslav Kysela } 218aba51cd0SJaroslav Kysela 219aba51cd0SJaroslav Kysela snd_config_delete(config); 220aba51cd0SJaroslav Kysela } 221aba51cd0SJaroslav Kysela 222aba51cd0SJaroslav Kysela static void test_pcm_time1(struct pcm_data *data, 223*c48cafc2SMark Brown const char *cfg_prefix, const char *sformat, 224*c48cafc2SMark Brown long srate, long schannels, 225*c48cafc2SMark Brown long speriod_size, long sbuffer_size) 226aba51cd0SJaroslav Kysela { 227aba51cd0SJaroslav Kysela char name[64], key[128], msg[256]; 228aba51cd0SJaroslav Kysela const char *cs; 229aba51cd0SJaroslav Kysela int i, err; 230aba51cd0SJaroslav Kysela snd_pcm_t *handle = NULL; 231aba51cd0SJaroslav Kysela snd_pcm_access_t access = SND_PCM_ACCESS_RW_INTERLEAVED; 232aba51cd0SJaroslav Kysela snd_pcm_format_t format; 233aba51cd0SJaroslav Kysela unsigned char *samples = NULL; 234aba51cd0SJaroslav Kysela snd_pcm_sframes_t frames; 235aba51cd0SJaroslav Kysela long long ms; 236aba51cd0SJaroslav Kysela long rate, channels, period_size, buffer_size; 237aba51cd0SJaroslav Kysela unsigned int rrate; 238aba51cd0SJaroslav Kysela snd_pcm_uframes_t rperiod_size, rbuffer_size, start_threshold; 239aba51cd0SJaroslav Kysela timestamp_t tstamp; 240aba51cd0SJaroslav Kysela bool pass = false, automatic = true; 241aba51cd0SJaroslav Kysela snd_pcm_hw_params_t *hw_params; 242aba51cd0SJaroslav Kysela snd_pcm_sw_params_t *sw_params; 243aba51cd0SJaroslav Kysela 244aba51cd0SJaroslav Kysela snd_pcm_hw_params_alloca(&hw_params); 245aba51cd0SJaroslav Kysela snd_pcm_sw_params_alloca(&sw_params); 246aba51cd0SJaroslav Kysela 247*c48cafc2SMark Brown cs = conf_get_string(data->pcm_config, cfg_prefix, "format", sformat); 248aba51cd0SJaroslav Kysela format = snd_pcm_format_value(cs); 249aba51cd0SJaroslav Kysela if (format == SND_PCM_FORMAT_UNKNOWN) 250aba51cd0SJaroslav Kysela ksft_exit_fail_msg("Wrong format '%s'\n", cs); 251*c48cafc2SMark Brown rate = conf_get_long(data->pcm_config, cfg_prefix, "rate", srate); 252*c48cafc2SMark Brown channels = conf_get_long(data->pcm_config, cfg_prefix, "channels", schannels); 253*c48cafc2SMark Brown period_size = conf_get_long(data->pcm_config, cfg_prefix, "period_size", speriod_size); 254*c48cafc2SMark Brown buffer_size = conf_get_long(data->pcm_config, cfg_prefix, "buffer_size", sbuffer_size); 255aba51cd0SJaroslav Kysela 256*c48cafc2SMark Brown automatic = strcmp(sformat, snd_pcm_format_name(format)) == 0 && 257*c48cafc2SMark Brown srate == rate && 258*c48cafc2SMark Brown schannels == channels && 259*c48cafc2SMark Brown speriod_size == period_size && 260*c48cafc2SMark Brown sbuffer_size == buffer_size; 261aba51cd0SJaroslav Kysela 262aba51cd0SJaroslav Kysela samples = malloc((rate * channels * snd_pcm_format_physical_width(format)) / 8); 263aba51cd0SJaroslav Kysela if (!samples) 264aba51cd0SJaroslav Kysela ksft_exit_fail_msg("Out of memory\n"); 265aba51cd0SJaroslav Kysela snd_pcm_format_set_silence(format, samples, rate * channels); 266aba51cd0SJaroslav Kysela 267aba51cd0SJaroslav Kysela sprintf(name, "hw:%d,%d,%d", data->card, data->device, data->subdevice); 268aba51cd0SJaroslav Kysela err = snd_pcm_open(&handle, name, data->stream, 0); 269aba51cd0SJaroslav Kysela if (err < 0) { 270aba51cd0SJaroslav Kysela snprintf(msg, sizeof(msg), "Failed to get pcm handle: %s", snd_strerror(err)); 271aba51cd0SJaroslav Kysela goto __close; 272aba51cd0SJaroslav Kysela } 273aba51cd0SJaroslav Kysela 274aba51cd0SJaroslav Kysela err = snd_pcm_hw_params_any(handle, hw_params); 275aba51cd0SJaroslav Kysela if (err < 0) { 276aba51cd0SJaroslav Kysela snprintf(msg, sizeof(msg), "snd_pcm_hw_params_any: %s", snd_strerror(err)); 277aba51cd0SJaroslav Kysela goto __close; 278aba51cd0SJaroslav Kysela } 279aba51cd0SJaroslav Kysela err = snd_pcm_hw_params_set_rate_resample(handle, hw_params, 0); 280aba51cd0SJaroslav Kysela if (err < 0) { 281aba51cd0SJaroslav Kysela snprintf(msg, sizeof(msg), "snd_pcm_hw_params_set_rate_resample: %s", snd_strerror(err)); 282aba51cd0SJaroslav Kysela goto __close; 283aba51cd0SJaroslav Kysela } 284aba51cd0SJaroslav Kysela err = snd_pcm_hw_params_set_access(handle, hw_params, access); 285aba51cd0SJaroslav Kysela if (err < 0) { 286aba51cd0SJaroslav Kysela snprintf(msg, sizeof(msg), "snd_pcm_hw_params_set_access %s: %s", 287aba51cd0SJaroslav Kysela snd_pcm_access_name(access), snd_strerror(err)); 288aba51cd0SJaroslav Kysela goto __close; 289aba51cd0SJaroslav Kysela } 290aba51cd0SJaroslav Kysela __format: 291aba51cd0SJaroslav Kysela err = snd_pcm_hw_params_set_format(handle, hw_params, format); 292aba51cd0SJaroslav Kysela if (err < 0) { 293aba51cd0SJaroslav Kysela if (automatic && format == SND_PCM_FORMAT_S16_LE) { 294aba51cd0SJaroslav Kysela format = SND_PCM_FORMAT_S32_LE; 295aba51cd0SJaroslav Kysela ksft_print_msg("%s.%d.%d.%d.%s.%s format S16_LE -> S32_LE\n", 296*c48cafc2SMark Brown cfg_prefix, 297aba51cd0SJaroslav Kysela data->card, data->device, data->subdevice, 298aba51cd0SJaroslav Kysela snd_pcm_stream_name(data->stream), 299aba51cd0SJaroslav Kysela snd_pcm_access_name(access)); 300aba51cd0SJaroslav Kysela } 301aba51cd0SJaroslav Kysela snprintf(msg, sizeof(msg), "snd_pcm_hw_params_set_format %s: %s", 302aba51cd0SJaroslav Kysela snd_pcm_format_name(format), snd_strerror(err)); 303aba51cd0SJaroslav Kysela goto __close; 304aba51cd0SJaroslav Kysela } 305*c48cafc2SMark Brown err = snd_pcm_hw_params_set_channels(handle, hw_params, channels); 306aba51cd0SJaroslav Kysela if (err < 0) { 307aba51cd0SJaroslav Kysela snprintf(msg, sizeof(msg), "snd_pcm_hw_params_set_channels %ld: %s", channels, snd_strerror(err)); 308aba51cd0SJaroslav Kysela goto __close; 309aba51cd0SJaroslav Kysela } 310aba51cd0SJaroslav Kysela rrate = rate; 311aba51cd0SJaroslav Kysela err = snd_pcm_hw_params_set_rate_near(handle, hw_params, &rrate, 0); 312aba51cd0SJaroslav Kysela if (err < 0) { 313aba51cd0SJaroslav Kysela snprintf(msg, sizeof(msg), "snd_pcm_hw_params_set_rate %ld: %s", rate, snd_strerror(err)); 314aba51cd0SJaroslav Kysela goto __close; 315aba51cd0SJaroslav Kysela } 316aba51cd0SJaroslav Kysela if (rrate != rate) { 317*c48cafc2SMark Brown snprintf(msg, sizeof(msg), "rate mismatch %ld != %ld", rate, rrate); 318aba51cd0SJaroslav Kysela goto __close; 319aba51cd0SJaroslav Kysela } 320aba51cd0SJaroslav Kysela rperiod_size = period_size; 321aba51cd0SJaroslav Kysela err = snd_pcm_hw_params_set_period_size_near(handle, hw_params, &rperiod_size, 0); 322aba51cd0SJaroslav Kysela if (err < 0) { 323aba51cd0SJaroslav Kysela snprintf(msg, sizeof(msg), "snd_pcm_hw_params_set_period_size %ld: %s", period_size, snd_strerror(err)); 324aba51cd0SJaroslav Kysela goto __close; 325aba51cd0SJaroslav Kysela } 326aba51cd0SJaroslav Kysela rbuffer_size = buffer_size; 327aba51cd0SJaroslav Kysela err = snd_pcm_hw_params_set_buffer_size_near(handle, hw_params, &rbuffer_size); 328aba51cd0SJaroslav Kysela if (err < 0) { 329aba51cd0SJaroslav Kysela snprintf(msg, sizeof(msg), "snd_pcm_hw_params_set_buffer_size %ld: %s", buffer_size, snd_strerror(err)); 330aba51cd0SJaroslav Kysela goto __close; 331aba51cd0SJaroslav Kysela } 332aba51cd0SJaroslav Kysela err = snd_pcm_hw_params(handle, hw_params); 333aba51cd0SJaroslav Kysela if (err < 0) { 334aba51cd0SJaroslav Kysela snprintf(msg, sizeof(msg), "snd_pcm_hw_params: %s", snd_strerror(err)); 335aba51cd0SJaroslav Kysela goto __close; 336aba51cd0SJaroslav Kysela } 337aba51cd0SJaroslav Kysela 338aba51cd0SJaroslav Kysela err = snd_pcm_sw_params_current(handle, sw_params); 339aba51cd0SJaroslav Kysela if (err < 0) { 340aba51cd0SJaroslav Kysela snprintf(msg, sizeof(msg), "snd_pcm_sw_params_current: %s", snd_strerror(err)); 341aba51cd0SJaroslav Kysela goto __close; 342aba51cd0SJaroslav Kysela } 343aba51cd0SJaroslav Kysela if (data->stream == SND_PCM_STREAM_PLAYBACK) { 344aba51cd0SJaroslav Kysela start_threshold = (rbuffer_size / rperiod_size) * rperiod_size; 345aba51cd0SJaroslav Kysela } else { 346aba51cd0SJaroslav Kysela start_threshold = rperiod_size; 347aba51cd0SJaroslav Kysela } 348aba51cd0SJaroslav Kysela err = snd_pcm_sw_params_set_start_threshold(handle, sw_params, start_threshold); 349aba51cd0SJaroslav Kysela if (err < 0) { 350aba51cd0SJaroslav Kysela snprintf(msg, sizeof(msg), "snd_pcm_sw_params_set_start_threshold %ld: %s", (long)start_threshold, snd_strerror(err)); 351aba51cd0SJaroslav Kysela goto __close; 352aba51cd0SJaroslav Kysela } 353aba51cd0SJaroslav Kysela err = snd_pcm_sw_params_set_avail_min(handle, sw_params, rperiod_size); 354aba51cd0SJaroslav Kysela if (err < 0) { 355aba51cd0SJaroslav Kysela snprintf(msg, sizeof(msg), "snd_pcm_sw_params_set_avail_min %ld: %s", (long)rperiod_size, snd_strerror(err)); 356aba51cd0SJaroslav Kysela goto __close; 357aba51cd0SJaroslav Kysela } 358aba51cd0SJaroslav Kysela err = snd_pcm_sw_params(handle, sw_params); 359aba51cd0SJaroslav Kysela if (err < 0) { 360aba51cd0SJaroslav Kysela snprintf(msg, sizeof(msg), "snd_pcm_sw_params: %s", snd_strerror(err)); 361aba51cd0SJaroslav Kysela goto __close; 362aba51cd0SJaroslav Kysela } 363aba51cd0SJaroslav Kysela 364aba51cd0SJaroslav Kysela ksft_print_msg("%s.%d.%d.%d.%s hw_params.%s.%s.%ld.%ld.%ld.%ld sw_params.%ld\n", 365*c48cafc2SMark Brown cfg_prefix, 366aba51cd0SJaroslav Kysela data->card, data->device, data->subdevice, 367aba51cd0SJaroslav Kysela snd_pcm_stream_name(data->stream), 368aba51cd0SJaroslav Kysela snd_pcm_access_name(access), 369aba51cd0SJaroslav Kysela snd_pcm_format_name(format), 370aba51cd0SJaroslav Kysela (long)rate, (long)channels, 371aba51cd0SJaroslav Kysela (long)rperiod_size, (long)rbuffer_size, 372aba51cd0SJaroslav Kysela (long)start_threshold); 373aba51cd0SJaroslav Kysela 374aba51cd0SJaroslav Kysela timestamp_now(&tstamp); 375aba51cd0SJaroslav Kysela for (i = 0; i < 4; i++) { 376aba51cd0SJaroslav Kysela if (data->stream == SND_PCM_STREAM_PLAYBACK) { 377aba51cd0SJaroslav Kysela frames = snd_pcm_writei(handle, samples, rate); 378aba51cd0SJaroslav Kysela if (frames < 0) { 379aba51cd0SJaroslav Kysela snprintf(msg, sizeof(msg), 380aba51cd0SJaroslav Kysela "Write failed: expected %d, wrote %li", rate, frames); 381aba51cd0SJaroslav Kysela goto __close; 382aba51cd0SJaroslav Kysela } 383aba51cd0SJaroslav Kysela if (frames < rate) { 384aba51cd0SJaroslav Kysela snprintf(msg, sizeof(msg), 385aba51cd0SJaroslav Kysela "expected %d, wrote %li", rate, frames); 386aba51cd0SJaroslav Kysela goto __close; 387aba51cd0SJaroslav Kysela } 388aba51cd0SJaroslav Kysela } else { 389aba51cd0SJaroslav Kysela frames = snd_pcm_readi(handle, samples, rate); 390aba51cd0SJaroslav Kysela if (frames < 0) { 391aba51cd0SJaroslav Kysela snprintf(msg, sizeof(msg), 392aba51cd0SJaroslav Kysela "expected %d, wrote %li", rate, frames); 393aba51cd0SJaroslav Kysela goto __close; 394aba51cd0SJaroslav Kysela } 395aba51cd0SJaroslav Kysela if (frames < rate) { 396aba51cd0SJaroslav Kysela snprintf(msg, sizeof(msg), 397aba51cd0SJaroslav Kysela "expected %d, wrote %li", rate, frames); 398aba51cd0SJaroslav Kysela goto __close; 399aba51cd0SJaroslav Kysela } 400aba51cd0SJaroslav Kysela } 401aba51cd0SJaroslav Kysela } 402aba51cd0SJaroslav Kysela 403aba51cd0SJaroslav Kysela snd_pcm_drain(handle); 404aba51cd0SJaroslav Kysela ms = timestamp_diff_ms(&tstamp); 405aba51cd0SJaroslav Kysela if (ms < 3900 || ms > 4100) { 406aba51cd0SJaroslav Kysela snprintf(msg, sizeof(msg), "time mismatch: expected 4000ms got %lld", ms); 407aba51cd0SJaroslav Kysela goto __close; 408aba51cd0SJaroslav Kysela } 409aba51cd0SJaroslav Kysela 410aba51cd0SJaroslav Kysela msg[0] = '\0'; 411aba51cd0SJaroslav Kysela pass = true; 412aba51cd0SJaroslav Kysela __close: 413aba51cd0SJaroslav Kysela ksft_test_result(pass, "%s.%d.%d.%d.%s%s%s\n", 414*c48cafc2SMark Brown cfg_prefix, 415aba51cd0SJaroslav Kysela data->card, data->device, data->subdevice, 416aba51cd0SJaroslav Kysela snd_pcm_stream_name(data->stream), 417aba51cd0SJaroslav Kysela msg[0] ? " " : "", msg); 418aba51cd0SJaroslav Kysela free(samples); 419aba51cd0SJaroslav Kysela if (handle) 420aba51cd0SJaroslav Kysela snd_pcm_close(handle); 421aba51cd0SJaroslav Kysela } 422aba51cd0SJaroslav Kysela 423*c48cafc2SMark Brown #define TESTS_PER_PCM 2 424aba51cd0SJaroslav Kysela 425aba51cd0SJaroslav Kysela int main(void) 426aba51cd0SJaroslav Kysela { 427aba51cd0SJaroslav Kysela struct pcm_data *pcm; 428aba51cd0SJaroslav Kysela 429aba51cd0SJaroslav Kysela ksft_print_header(); 430aba51cd0SJaroslav Kysela 431aba51cd0SJaroslav Kysela conf_load(); 432aba51cd0SJaroslav Kysela 433aba51cd0SJaroslav Kysela find_pcms(); 434aba51cd0SJaroslav Kysela 435*c48cafc2SMark Brown ksft_set_plan(num_missing + num_pcms * TESTS_PER_PCM); 436aba51cd0SJaroslav Kysela 437aba51cd0SJaroslav Kysela for (pcm = pcm_missing; pcm != NULL; pcm = pcm->next) { 438aba51cd0SJaroslav Kysela ksft_test_result(false, "test.missing.%d.%d.%d.%s\n", 439aba51cd0SJaroslav Kysela pcm->card, pcm->device, pcm->subdevice, 440aba51cd0SJaroslav Kysela snd_pcm_stream_name(pcm->stream)); 441aba51cd0SJaroslav Kysela } 442aba51cd0SJaroslav Kysela 443aba51cd0SJaroslav Kysela for (pcm = pcm_list; pcm != NULL; pcm = pcm->next) { 444*c48cafc2SMark Brown test_pcm_time1(pcm, "test.time1", "S16_LE", 48000, 2, 512, 4096); 445*c48cafc2SMark Brown test_pcm_time1(pcm, "test.time2", "S16_LE", 48000, 2, 24000, 192000); 446aba51cd0SJaroslav Kysela } 447aba51cd0SJaroslav Kysela 448aba51cd0SJaroslav Kysela conf_free(); 449aba51cd0SJaroslav Kysela 450aba51cd0SJaroslav Kysela ksft_exit_pass(); 451aba51cd0SJaroslav Kysela 452aba51cd0SJaroslav Kysela return 0; 453aba51cd0SJaroslav Kysela } 454