~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/alsa/pcm-test.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 //
  3 // kselftest for the ALSA PCM API
  4 //
  5 // Original author: Jaroslav Kysela <perex@perex.cz>
  6 // Copyright (c) 2022 Red Hat Inc.
  7 
  8 // This test will iterate over all cards detected in the system, exercising
  9 // every PCM device it can find.  This may conflict with other system
 10 // software if there is audio activity so is best run on a system with a
 11 // minimal active userspace.
 12 
 13 #include <stdio.h>
 14 #include <stdlib.h>
 15 #include <stdbool.h>
 16 #include <errno.h>
 17 #include <assert.h>
 18 #include <pthread.h>
 19 
 20 #include "../kselftest.h"
 21 #include "alsa-local.h"
 22 
 23 typedef struct timespec timestamp_t;
 24 
 25 struct card_data {
 26         int card;
 27         snd_ctl_card_info_t *info;
 28         const char *name;
 29         pthread_t thread;
 30         struct card_data *next;
 31 };
 32 
 33 struct card_data *card_list = NULL;
 34 
 35 struct pcm_data {
 36         snd_pcm_t *handle;
 37         int card;
 38         int device;
 39         int subdevice;
 40         const char *card_name;
 41         snd_pcm_stream_t stream;
 42         snd_config_t *pcm_config;
 43         struct pcm_data *next;
 44 };
 45 
 46 struct pcm_data *pcm_list = NULL;
 47 
 48 int num_missing = 0;
 49 struct pcm_data *pcm_missing = NULL;
 50 
 51 snd_config_t *default_pcm_config;
 52 
 53 /* Lock while reporting results since kselftest doesn't */
 54 pthread_mutex_t results_lock = PTHREAD_MUTEX_INITIALIZER;
 55 
 56 enum test_class {
 57         TEST_CLASS_DEFAULT,
 58         TEST_CLASS_SYSTEM,
 59 };
 60 
 61 void timestamp_now(timestamp_t *tstamp)
 62 {
 63         if (clock_gettime(CLOCK_MONOTONIC_RAW, tstamp))
 64                 ksft_exit_fail_msg("clock_get_time\n");
 65 }
 66 
 67 long long timestamp_diff_ms(timestamp_t *tstamp)
 68 {
 69         timestamp_t now, diff;
 70         timestamp_now(&now);
 71         if (tstamp->tv_nsec > now.tv_nsec) {
 72                 diff.tv_sec = now.tv_sec - tstamp->tv_sec - 1;
 73                 diff.tv_nsec = (now.tv_nsec + 1000000000L) - tstamp->tv_nsec;
 74         } else {
 75                 diff.tv_sec = now.tv_sec - tstamp->tv_sec;
 76                 diff.tv_nsec = now.tv_nsec - tstamp->tv_nsec;
 77         }
 78         return (diff.tv_sec * 1000) + ((diff.tv_nsec + 500000L) / 1000000L);
 79 }
 80 
 81 static long device_from_id(snd_config_t *node)
 82 {
 83         const char *id;
 84         char *end;
 85         long v;
 86 
 87         if (snd_config_get_id(node, &id))
 88                 ksft_exit_fail_msg("snd_config_get_id\n");
 89         errno = 0;
 90         v = strtol(id, &end, 10);
 91         if (errno || *end)
 92                 return -1;
 93         return v;
 94 }
 95 
 96 static void missing_device(int card, int device, int subdevice, snd_pcm_stream_t stream)
 97 {
 98         struct pcm_data *pcm_data;
 99 
100         for (pcm_data = pcm_list; pcm_data != NULL; pcm_data = pcm_data->next) {
101                 if (pcm_data->card != card)
102                         continue;
103                 if (pcm_data->device != device)
104                         continue;
105                 if (pcm_data->subdevice != subdevice)
106                         continue;
107                 if (pcm_data->stream != stream)
108                         continue;
109                 return;
110         }
111         pcm_data = calloc(1, sizeof(*pcm_data));
112         if (!pcm_data)
113                 ksft_exit_fail_msg("Out of memory\n");
114         pcm_data->card = card;
115         pcm_data->device = device;
116         pcm_data->subdevice = subdevice;
117         pcm_data->stream = stream;
118         pcm_data->next = pcm_missing;
119         pcm_missing = pcm_data;
120         num_missing++;
121 }
122 
123 static void missing_devices(int card, snd_config_t *card_config)
124 {
125         snd_config_t *pcm_config, *node1, *node2;
126         snd_config_iterator_t i1, i2, next1, next2;
127         int device, subdevice;
128 
129         pcm_config = conf_get_subtree(card_config, "pcm", NULL);
130         if (!pcm_config)
131                 return;
132         snd_config_for_each(i1, next1, pcm_config) {
133                 node1 = snd_config_iterator_entry(i1);
134                 device = device_from_id(node1);
135                 if (device < 0)
136                         continue;
137                 if (snd_config_get_type(node1) != SND_CONFIG_TYPE_COMPOUND)
138                         continue;
139                 snd_config_for_each(i2, next2, node1) {
140                         node2 = snd_config_iterator_entry(i2);
141                         subdevice = device_from_id(node2);
142                         if (subdevice < 0)
143                                 continue;
144                         if (conf_get_subtree(node2, "PLAYBACK", NULL))
145                                 missing_device(card, device, subdevice, SND_PCM_STREAM_PLAYBACK);
146                         if (conf_get_subtree(node2, "CAPTURE", NULL))
147                                 missing_device(card, device, subdevice, SND_PCM_STREAM_CAPTURE);
148                 }
149         }
150 }
151 
152 static void find_pcms(void)
153 {
154         char name[32], key[64];
155         char *card_name, *card_longname;
156         int card, dev, subdev, count, direction, err;
157         snd_pcm_stream_t stream;
158         struct pcm_data *pcm_data;
159         snd_ctl_t *handle;
160         snd_pcm_info_t *pcm_info;
161         snd_config_t *config, *card_config, *pcm_config;
162         struct card_data *card_data;
163 
164         snd_pcm_info_alloca(&pcm_info);
165 
166         card = -1;
167         if (snd_card_next(&card) < 0 || card < 0)
168                 return;
169 
170         config = get_alsalib_config();
171 
172         while (card >= 0) {
173                 card_data = calloc(1, sizeof(*card_data));
174                 if (!card_data)
175                         ksft_exit_fail_msg("Out of memory\n");
176 
177                 sprintf(name, "hw:%d", card);
178 
179                 err = snd_ctl_open_lconf(&handle, name, 0, config);
180                 if (err < 0) {
181                         ksft_print_msg("Failed to get hctl for card %d: %s\n",
182                                        card, snd_strerror(err));
183                         goto next_card;
184                 }
185 
186                 err = snd_card_get_name(card, &card_name);
187                 if (err != 0)
188                         card_name = "Unknown";
189                 err = snd_card_get_longname(card, &card_longname);
190                 if (err != 0)
191                         card_longname = "Unknown";
192 
193                 err = snd_ctl_card_info_malloc(&card_data->info);
194                 if (err != 0)
195                         ksft_exit_fail_msg("Failed to allocate card info: %d\n",
196                                 err);
197 
198                 err = snd_ctl_card_info(handle, card_data->info);
199                 if (err == 0) {
200                         card_data->name = snd_ctl_card_info_get_id(card_data->info);
201                         if (!card_data->name)
202                                 ksft_print_msg("Failed to get card ID\n");
203                 } else {
204                         ksft_print_msg("Failed to get card info: %d\n", err);
205                 }
206 
207                 if (!card_data->name)
208                         card_data->name = "Unknown";
209 
210                 ksft_print_msg("Card %d/%s - %s (%s)\n", card,
211                                card_data->name, card_name, card_longname);
212 
213                 card_config = conf_by_card(card);
214 
215                 card_data->card = card;
216                 card_data->next = card_list;
217                 card_list = card_data;
218 
219                 dev = -1;
220                 while (1) {
221                         if (snd_ctl_pcm_next_device(handle, &dev) < 0)
222                                 ksft_exit_fail_msg("snd_ctl_pcm_next_device\n");
223                         if (dev < 0)
224                                 break;
225 
226                         for (direction = 0; direction < 2; direction++) {
227                                 stream = direction ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK;
228                                 sprintf(key, "pcm.%d.%s", dev, snd_pcm_stream_name(stream));
229                                 pcm_config = conf_get_subtree(card_config, key, NULL);
230                                 if (conf_get_bool(card_config, key, "skip", false)) {
231                                         ksft_print_msg("skipping pcm %d.%d.%s\n", card, dev, snd_pcm_stream_name(stream));
232                                         continue;
233                                 }
234                                 snd_pcm_info_set_device(pcm_info, dev);
235                                 snd_pcm_info_set_subdevice(pcm_info, 0);
236                                 snd_pcm_info_set_stream(pcm_info, stream);
237                                 err = snd_ctl_pcm_info(handle, pcm_info);
238                                 if (err == -ENOENT)
239                                         continue;
240                                 if (err < 0)
241                                         ksft_exit_fail_msg("snd_ctl_pcm_info: %d:%d:%d\n",
242                                                            dev, 0, stream);
243 
244                                 ksft_print_msg("%s.0 - %s\n", card_data->name,
245                                                snd_pcm_info_get_id(pcm_info));
246 
247                                 count = snd_pcm_info_get_subdevices_count(pcm_info);
248                                 for (subdev = 0; subdev < count; subdev++) {
249                                         sprintf(key, "pcm.%d.%d.%s", dev, subdev, snd_pcm_stream_name(stream));
250                                         if (conf_get_bool(card_config, key, "skip", false)) {
251                                                 ksft_print_msg("skipping pcm %d.%d.%d.%s\n", card, dev,
252                                                                subdev, snd_pcm_stream_name(stream));
253                                                 continue;
254                                         }
255                                         pcm_data = calloc(1, sizeof(*pcm_data));
256                                         if (!pcm_data)
257                                                 ksft_exit_fail_msg("Out of memory\n");
258                                         pcm_data->card = card;
259                                         pcm_data->device = dev;
260                                         pcm_data->subdevice = subdev;
261                                         pcm_data->card_name = card_data->name;
262                                         pcm_data->stream = stream;
263                                         pcm_data->pcm_config = conf_get_subtree(card_config, key, NULL);
264                                         pcm_data->next = pcm_list;
265                                         pcm_list = pcm_data;
266                                 }
267                         }
268                 }
269 
270                 /* check for missing devices */
271                 missing_devices(card, card_config);
272 
273         next_card:
274                 snd_ctl_close(handle);
275                 if (snd_card_next(&card) < 0) {
276                         ksft_print_msg("snd_card_next");
277                         break;
278                 }
279         }
280 
281         snd_config_delete(config);
282 }
283 
284 static void test_pcm_time(struct pcm_data *data, enum test_class class,
285                           const char *test_name, snd_config_t *pcm_cfg)
286 {
287         char name[64], msg[256];
288         const int duration_s = 2, margin_ms = 100;
289         const int duration_ms = duration_s * 1000;
290         const char *cs;
291         int i, err;
292         snd_pcm_t *handle = NULL;
293         snd_pcm_access_t access = SND_PCM_ACCESS_RW_INTERLEAVED;
294         snd_pcm_format_t format, old_format;
295         const char *alt_formats[8];
296         unsigned char *samples = NULL;
297         snd_pcm_sframes_t frames;
298         long long ms;
299         long rate, channels, period_size, buffer_size;
300         unsigned int rrate;
301         snd_pcm_uframes_t rperiod_size, rbuffer_size, start_threshold;
302         timestamp_t tstamp;
303         bool pass = false;
304         snd_pcm_hw_params_t *hw_params;
305         snd_pcm_sw_params_t *sw_params;
306         const char *test_class_name;
307         bool skip = true;
308         const char *desc;
309 
310         switch (class) {
311         case TEST_CLASS_DEFAULT:
312                 test_class_name = "default";
313                 break;
314         case TEST_CLASS_SYSTEM:
315                 test_class_name = "system";
316                 break;
317         default:
318                 ksft_exit_fail_msg("Unknown test class %d\n", class);
319                 break;
320         }
321 
322         desc = conf_get_string(pcm_cfg, "description", NULL, NULL);
323         if (desc)
324                 ksft_print_msg("%s.%s.%s.%d.%d.%s - %s\n",
325                                test_class_name, test_name,
326                                data->card_name, data->device, data->subdevice,
327                                snd_pcm_stream_name(data->stream),
328                                desc);
329 
330 
331         snd_pcm_hw_params_alloca(&hw_params);
332         snd_pcm_sw_params_alloca(&sw_params);
333 
334         cs = conf_get_string(pcm_cfg, "format", NULL, "S16_LE");
335         format = snd_pcm_format_value(cs);
336         if (format == SND_PCM_FORMAT_UNKNOWN)
337                 ksft_exit_fail_msg("Wrong format '%s'\n", cs);
338         conf_get_string_array(pcm_cfg, "alt_formats", NULL,
339                                 alt_formats, ARRAY_SIZE(alt_formats), NULL);
340         rate = conf_get_long(pcm_cfg, "rate", NULL, 48000);
341         channels = conf_get_long(pcm_cfg, "channels", NULL, 2);
342         period_size = conf_get_long(pcm_cfg, "period_size", NULL, 4096);
343         buffer_size = conf_get_long(pcm_cfg, "buffer_size", NULL, 16384);
344 
345         samples = malloc((rate * channels * snd_pcm_format_physical_width(format)) / 8);
346         if (!samples)
347                 ksft_exit_fail_msg("Out of memory\n");
348         snd_pcm_format_set_silence(format, samples, rate * channels);
349 
350         sprintf(name, "hw:%d,%d,%d", data->card, data->device, data->subdevice);
351         err = snd_pcm_open(&handle, name, data->stream, 0);
352         if (err < 0) {
353                 snprintf(msg, sizeof(msg), "Failed to get pcm handle: %s", snd_strerror(err));
354                 goto __close;
355         }
356 
357         err = snd_pcm_hw_params_any(handle, hw_params);
358         if (err < 0) {
359                 snprintf(msg, sizeof(msg), "snd_pcm_hw_params_any: %s", snd_strerror(err));
360                 goto __close;
361         }
362         err = snd_pcm_hw_params_set_rate_resample(handle, hw_params, 0);
363         if (err < 0) {
364                 snprintf(msg, sizeof(msg), "snd_pcm_hw_params_set_rate_resample: %s", snd_strerror(err));
365                 goto __close;
366         }
367         err = snd_pcm_hw_params_set_access(handle, hw_params, access);
368         if (err < 0) {
369                 snprintf(msg, sizeof(msg), "snd_pcm_hw_params_set_access %s: %s",
370                                            snd_pcm_access_name(access), snd_strerror(err));
371                 goto __close;
372         }
373         i = -1;
374 __format:
375         err = snd_pcm_hw_params_set_format(handle, hw_params, format);
376         if (err < 0) {
377                 i++;
378                 if (i < ARRAY_SIZE(alt_formats) && alt_formats[i]) {
379                         old_format = format;
380                         format = snd_pcm_format_value(alt_formats[i]);
381                         if (format != SND_PCM_FORMAT_UNKNOWN) {
382                                 ksft_print_msg("%s.%s.%d.%d.%s.%s format %s -> %s\n",
383                                                  test_name,
384                                                  data->card_name, data->device, data->subdevice,
385                                                  snd_pcm_stream_name(data->stream),
386                                                  snd_pcm_access_name(access),
387                                                  snd_pcm_format_name(old_format),
388                                                  snd_pcm_format_name(format));
389                                 samples = realloc(samples, (rate * channels *
390                                                             snd_pcm_format_physical_width(format)) / 8);
391                                 if (!samples)
392                                         ksft_exit_fail_msg("Out of memory\n");
393                                 snd_pcm_format_set_silence(format, samples, rate * channels);
394                                 goto __format;
395                         }
396                 }
397                 snprintf(msg, sizeof(msg), "snd_pcm_hw_params_set_format %s: %s",
398                                            snd_pcm_format_name(format), snd_strerror(err));
399                 goto __close;
400         }
401         err = snd_pcm_hw_params_set_channels(handle, hw_params, channels);
402         if (err < 0) {
403                 snprintf(msg, sizeof(msg), "snd_pcm_hw_params_set_channels %ld: %s", channels, snd_strerror(err));
404                 goto __close;
405         }
406         rrate = rate;
407         err = snd_pcm_hw_params_set_rate_near(handle, hw_params, &rrate, 0);
408         if (err < 0) {
409                 snprintf(msg, sizeof(msg), "snd_pcm_hw_params_set_rate %ld: %s", rate, snd_strerror(err));
410                 goto __close;
411         }
412         if (rrate != rate) {
413                 snprintf(msg, sizeof(msg), "rate mismatch %ld != %u", rate, rrate);
414                 goto __close;
415         }
416         rperiod_size = period_size;
417         err = snd_pcm_hw_params_set_period_size_near(handle, hw_params, &rperiod_size, 0);
418         if (err < 0) {
419                 snprintf(msg, sizeof(msg), "snd_pcm_hw_params_set_period_size %ld: %s", period_size, snd_strerror(err));
420                 goto __close;
421         }
422         rbuffer_size = buffer_size;
423         err = snd_pcm_hw_params_set_buffer_size_near(handle, hw_params, &rbuffer_size);
424         if (err < 0) {
425                 snprintf(msg, sizeof(msg), "snd_pcm_hw_params_set_buffer_size %ld: %s", buffer_size, snd_strerror(err));
426                 goto __close;
427         }
428         err = snd_pcm_hw_params(handle, hw_params);
429         if (err < 0) {
430                 snprintf(msg, sizeof(msg), "snd_pcm_hw_params: %s", snd_strerror(err));
431                 goto __close;
432         }
433 
434         err = snd_pcm_sw_params_current(handle, sw_params);
435         if (err < 0) {
436                 snprintf(msg, sizeof(msg), "snd_pcm_sw_params_current: %s", snd_strerror(err));
437                 goto __close;
438         }
439         if (data->stream == SND_PCM_STREAM_PLAYBACK) {
440                 start_threshold = (rbuffer_size / rperiod_size) * rperiod_size;
441         } else {
442                 start_threshold = rperiod_size;
443         }
444         err = snd_pcm_sw_params_set_start_threshold(handle, sw_params, start_threshold);
445         if (err < 0) {
446                 snprintf(msg, sizeof(msg), "snd_pcm_sw_params_set_start_threshold %ld: %s", (long)start_threshold, snd_strerror(err));
447                 goto __close;
448         }
449         err = snd_pcm_sw_params_set_avail_min(handle, sw_params, rperiod_size);
450         if (err < 0) {
451                 snprintf(msg, sizeof(msg), "snd_pcm_sw_params_set_avail_min %ld: %s", (long)rperiod_size, snd_strerror(err));
452                 goto __close;
453         }
454         err = snd_pcm_sw_params(handle, sw_params);
455         if (err < 0) {
456                 snprintf(msg, sizeof(msg), "snd_pcm_sw_params: %s", snd_strerror(err));
457                 goto __close;
458         }
459 
460         ksft_print_msg("%s.%s.%s.%d.%d.%s hw_params.%s.%s.%ld.%ld.%ld.%ld sw_params.%ld\n",
461                          test_class_name, test_name,
462                          data->card_name, data->device, data->subdevice,
463                          snd_pcm_stream_name(data->stream),
464                          snd_pcm_access_name(access),
465                          snd_pcm_format_name(format),
466                          (long)rate, (long)channels,
467                          (long)rperiod_size, (long)rbuffer_size,
468                          (long)start_threshold);
469 
470         /* Set all the params, actually run the test */
471         skip = false;
472 
473         timestamp_now(&tstamp);
474         for (i = 0; i < duration_s; i++) {
475                 if (data->stream == SND_PCM_STREAM_PLAYBACK) {
476                         frames = snd_pcm_writei(handle, samples, rate);
477                         if (frames < 0) {
478                                 snprintf(msg, sizeof(msg),
479                                          "Write failed: expected %ld, wrote %li", rate, frames);
480                                 goto __close;
481                         }
482                         if (frames < rate) {
483                                 snprintf(msg, sizeof(msg),
484                                          "expected %ld, wrote %li", rate, frames);
485                                 goto __close;
486                         }
487                 } else {
488                         frames = snd_pcm_readi(handle, samples, rate);
489                         if (frames < 0) {
490                                 snprintf(msg, sizeof(msg),
491                                          "expected %ld, wrote %li", rate, frames);
492                                 goto __close;
493                         }
494                         if (frames < rate) {
495                                 snprintf(msg, sizeof(msg),
496                                          "expected %ld, wrote %li", rate, frames);
497                                 goto __close;
498                         }
499                 }
500         }
501 
502         snd_pcm_drain(handle);
503         ms = timestamp_diff_ms(&tstamp);
504         if (ms < duration_ms - margin_ms || ms > duration_ms + margin_ms) {
505                 snprintf(msg, sizeof(msg), "time mismatch: expected %dms got %lld", duration_ms, ms);
506                 goto __close;
507         }
508 
509         msg[0] = '\0';
510         pass = true;
511 __close:
512         pthread_mutex_lock(&results_lock);
513 
514         switch (class) {
515         case TEST_CLASS_SYSTEM:
516                 test_class_name = "system";
517                 /*
518                  * Anything specified as specific to this system
519                  * should always be supported.
520                  */
521                 ksft_test_result(!skip, "%s.%s.%s.%d.%d.%s.params\n",
522                                  test_class_name, test_name,
523                                  data->card_name, data->device,
524                                  data->subdevice,
525                                  snd_pcm_stream_name(data->stream));
526                 break;
527         default:
528                 break;
529         }
530 
531         if (!skip)
532                 ksft_test_result(pass, "%s.%s.%s.%d.%d.%s\n",
533                                  test_class_name, test_name,
534                                  data->card_name, data->device,
535                                  data->subdevice,
536                                  snd_pcm_stream_name(data->stream));
537         else
538                 ksft_test_result_skip("%s.%s.%s.%d.%d.%s\n",
539                                  test_class_name, test_name,
540                                  data->card_name, data->device,
541                                  data->subdevice,
542                                  snd_pcm_stream_name(data->stream));
543 
544         if (msg[0])
545                 ksft_print_msg("%s\n", msg);
546 
547         pthread_mutex_unlock(&results_lock);
548 
549         free(samples);
550         if (handle)
551                 snd_pcm_close(handle);
552 }
553 
554 void run_time_tests(struct pcm_data *pcm, enum test_class class,
555                     snd_config_t *cfg)
556 {
557         const char *test_name, *test_type;
558         snd_config_t *pcm_cfg;
559         snd_config_iterator_t i, next;
560 
561         if (!cfg)
562                 return;
563 
564         cfg = conf_get_subtree(cfg, "test", NULL);
565         if (cfg == NULL)
566                 return;
567 
568         snd_config_for_each(i, next, cfg) {
569                 pcm_cfg = snd_config_iterator_entry(i);
570                 if (snd_config_get_id(pcm_cfg, &test_name) < 0)
571                         ksft_exit_fail_msg("snd_config_get_id\n");
572                 test_type = conf_get_string(pcm_cfg, "type", NULL, "time");
573                 if (strcmp(test_type, "time") == 0)
574                         test_pcm_time(pcm, class, test_name, pcm_cfg);
575                 else
576                         ksft_exit_fail_msg("unknown test type '%s'\n", test_type);
577         }
578 }
579 
580 void *card_thread(void *data)
581 {
582         struct card_data *card = data;
583         struct pcm_data *pcm;
584 
585         for (pcm = pcm_list; pcm != NULL; pcm = pcm->next) {
586                 if (pcm->card != card->card)
587                         continue;
588 
589                 run_time_tests(pcm, TEST_CLASS_DEFAULT, default_pcm_config);
590                 run_time_tests(pcm, TEST_CLASS_SYSTEM, pcm->pcm_config);
591         }
592 
593         return 0;
594 }
595 
596 int main(void)
597 {
598         struct card_data *card;
599         struct card_cfg_data *conf;
600         struct pcm_data *pcm;
601         snd_config_t *global_config, *cfg;
602         int num_pcm_tests = 0, num_tests, num_std_pcm_tests;
603         int ret;
604         void *thread_ret;
605 
606         ksft_print_header();
607 
608         global_config = conf_load_from_file("pcm-test.conf");
609         default_pcm_config = conf_get_subtree(global_config, "pcm", NULL);
610         if (default_pcm_config == NULL)
611                 ksft_exit_fail_msg("default pcm test configuration (pcm compound) is missing\n");
612 
613         conf_load();
614 
615         find_pcms();
616 
617         for (conf = conf_cards; conf; conf = conf->next)
618                 if (conf->card < 0)
619                         num_missing++;
620 
621         num_std_pcm_tests = conf_get_count(default_pcm_config, "test", NULL);
622 
623         for (pcm = pcm_list; pcm != NULL; pcm = pcm->next) {
624                 num_pcm_tests += num_std_pcm_tests;
625                 cfg = pcm->pcm_config;
626                 if (cfg == NULL)
627                         continue;
628                 /* Setting params is reported as a separate test */
629                 num_tests = conf_get_count(cfg, "test", NULL) * 2;
630                 if (num_tests > 0)
631                         num_pcm_tests += num_tests;
632         }
633 
634         ksft_set_plan(num_missing + num_pcm_tests);
635 
636         for (conf = conf_cards; conf; conf = conf->next)
637                 if (conf->card < 0)
638                         ksft_test_result_fail("test.missing.%s.%s\n",
639                                               conf->filename, conf->config_id);
640 
641         for (pcm = pcm_missing; pcm != NULL; pcm = pcm->next) {
642                 ksft_test_result(false, "test.missing.%s.%d.%d.%s\n",
643                                  pcm->card_name, pcm->device, pcm->subdevice,
644                                  snd_pcm_stream_name(pcm->stream));
645         }
646 
647         for (card = card_list; card != NULL; card = card->next) {
648                 ret = pthread_create(&card->thread, NULL, card_thread, card);
649                 if (ret != 0) {
650                         ksft_exit_fail_msg("Failed to create card %d thread: %d (%s)\n",
651                                            card->card, ret,
652                                            strerror(errno));
653                 }
654         }
655 
656         for (card = card_list; card != NULL; card = card->next) {
657                 ret = pthread_join(card->thread, &thread_ret);
658                 if (ret != 0) {
659                         ksft_exit_fail_msg("Failed to join card %d thread: %d (%s)\n",
660                                            card->card, ret,
661                                            strerror(errno));
662                 }
663         }
664 
665         snd_config_delete(global_config);
666         conf_free();
667 
668         ksft_exit_pass();
669 
670         return 0;
671 }
672 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php