1d5ac70f0Sopenharmony_ci/* 2d5ac70f0Sopenharmony_ci * simple multi-thread stress test for PCM 3d5ac70f0Sopenharmony_ci * 4d5ac70f0Sopenharmony_ci * The main thread simply feeds or reads the sample data with the 5d5ac70f0Sopenharmony_ci * random size continuously. Meanwhile, the worker threads call some 6d5ac70f0Sopenharmony_ci * update function depending on the given mode, and show the thread 7d5ac70f0Sopenharmony_ci * number of the read value. 8d5ac70f0Sopenharmony_ci * 9d5ac70f0Sopenharmony_ci * The function for the worker thread is specified via -m option. 10d5ac70f0Sopenharmony_ci * When the random mode ('r') is set, the update function is chosen 11d5ac70f0Sopenharmony_ci * randomly in the loop. 12d5ac70f0Sopenharmony_ci * 13d5ac70f0Sopenharmony_ci * When the -v option is passed, this tries to show some obtained value 14d5ac70f0Sopenharmony_ci * from the function. Without -v, as default, it shows the thread number 15d5ac70f0Sopenharmony_ci * (0-9). In addition, it puts the mode suffix ('a' for avail, 'd' for 16d5ac70f0Sopenharmony_ci * delay, etc) for the random mode, as well as the suffix '!' indicating 17d5ac70f0Sopenharmony_ci * the error from the called function. 18d5ac70f0Sopenharmony_ci */ 19d5ac70f0Sopenharmony_ci 20d5ac70f0Sopenharmony_ci#include <stdio.h> 21d5ac70f0Sopenharmony_ci#include <pthread.h> 22d5ac70f0Sopenharmony_ci#include <getopt.h> 23d5ac70f0Sopenharmony_ci#include "../include/asoundlib.h" 24d5ac70f0Sopenharmony_ci 25d5ac70f0Sopenharmony_ci#define MAX_THREADS 10 26d5ac70f0Sopenharmony_ci 27d5ac70f0Sopenharmony_cienum { 28d5ac70f0Sopenharmony_ci MODE_AVAIL_UPDATE, 29d5ac70f0Sopenharmony_ci MODE_STATUS, 30d5ac70f0Sopenharmony_ci MODE_HWSYNC, 31d5ac70f0Sopenharmony_ci MODE_TIMESTAMP, 32d5ac70f0Sopenharmony_ci MODE_DELAY, 33d5ac70f0Sopenharmony_ci MODE_RANDOM 34d5ac70f0Sopenharmony_ci}; 35d5ac70f0Sopenharmony_ci 36d5ac70f0Sopenharmony_cistatic char mode_suffix[] = { 37d5ac70f0Sopenharmony_ci 'a', 's', 'h', 't', 'd', 'r' 38d5ac70f0Sopenharmony_ci}; 39d5ac70f0Sopenharmony_ci 40d5ac70f0Sopenharmony_cistatic const char *pcmdev = "default"; 41d5ac70f0Sopenharmony_cistatic int stream = SND_PCM_STREAM_PLAYBACK; 42d5ac70f0Sopenharmony_cistatic int num_threads = 1; 43d5ac70f0Sopenharmony_cistatic int periodsize = 16 * 1024; 44d5ac70f0Sopenharmony_cistatic int bufsize = 16 * 1024 * 4; 45d5ac70f0Sopenharmony_cistatic int channels = 2; 46d5ac70f0Sopenharmony_cistatic int rate = 48000; 47d5ac70f0Sopenharmony_cistatic snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE; 48d5ac70f0Sopenharmony_ci 49d5ac70f0Sopenharmony_cistatic int running_mode = MODE_AVAIL_UPDATE; 50d5ac70f0Sopenharmony_cistatic int show_value = 0; 51d5ac70f0Sopenharmony_cistatic int quiet = 0; 52d5ac70f0Sopenharmony_ci 53d5ac70f0Sopenharmony_cistatic pthread_t peeper_threads[MAX_THREADS]; 54d5ac70f0Sopenharmony_cistatic int running = 1; 55d5ac70f0Sopenharmony_cistatic snd_pcm_t *pcm; 56d5ac70f0Sopenharmony_ci 57d5ac70f0Sopenharmony_cistatic void *peeper(void *data) 58d5ac70f0Sopenharmony_ci{ 59d5ac70f0Sopenharmony_ci int thread_no = (long)data; 60d5ac70f0Sopenharmony_ci snd_pcm_sframes_t val; 61d5ac70f0Sopenharmony_ci snd_pcm_status_t *stat; 62d5ac70f0Sopenharmony_ci snd_htimestamp_t tstamp; 63d5ac70f0Sopenharmony_ci int mode = running_mode, err; 64d5ac70f0Sopenharmony_ci 65d5ac70f0Sopenharmony_ci snd_pcm_status_alloca(&stat); 66d5ac70f0Sopenharmony_ci 67d5ac70f0Sopenharmony_ci while (running) { 68d5ac70f0Sopenharmony_ci if (running_mode == MODE_RANDOM) 69d5ac70f0Sopenharmony_ci mode = rand() % MODE_RANDOM; 70d5ac70f0Sopenharmony_ci switch (mode) { 71d5ac70f0Sopenharmony_ci case MODE_AVAIL_UPDATE: 72d5ac70f0Sopenharmony_ci val = snd_pcm_avail_update(pcm); 73d5ac70f0Sopenharmony_ci err = 0; 74d5ac70f0Sopenharmony_ci break; 75d5ac70f0Sopenharmony_ci case MODE_STATUS: 76d5ac70f0Sopenharmony_ci err = snd_pcm_status(pcm, stat); 77d5ac70f0Sopenharmony_ci val = snd_pcm_status_get_avail(stat); 78d5ac70f0Sopenharmony_ci break; 79d5ac70f0Sopenharmony_ci case MODE_HWSYNC: 80d5ac70f0Sopenharmony_ci err = snd_pcm_hwsync(pcm); 81d5ac70f0Sopenharmony_ci break; 82d5ac70f0Sopenharmony_ci case MODE_TIMESTAMP: 83d5ac70f0Sopenharmony_ci err = snd_pcm_htimestamp(pcm, (snd_pcm_uframes_t *)&val, 84d5ac70f0Sopenharmony_ci &tstamp); 85d5ac70f0Sopenharmony_ci break; 86d5ac70f0Sopenharmony_ci default: 87d5ac70f0Sopenharmony_ci err = snd_pcm_delay(pcm, &val); 88d5ac70f0Sopenharmony_ci break; 89d5ac70f0Sopenharmony_ci } 90d5ac70f0Sopenharmony_ci 91d5ac70f0Sopenharmony_ci if (quiet) 92d5ac70f0Sopenharmony_ci continue; 93d5ac70f0Sopenharmony_ci if (running_mode == MODE_RANDOM) { 94d5ac70f0Sopenharmony_ci fprintf(stderr, "%d%c%s", thread_no, mode_suffix[mode], 95d5ac70f0Sopenharmony_ci err ? "!" : ""); 96d5ac70f0Sopenharmony_ci } else { 97d5ac70f0Sopenharmony_ci if (show_value && mode != MODE_HWSYNC) 98d5ac70f0Sopenharmony_ci fprintf(stderr, "\r%d ", (int)val); 99d5ac70f0Sopenharmony_ci else 100d5ac70f0Sopenharmony_ci fprintf(stderr, "%d%s", thread_no, 101d5ac70f0Sopenharmony_ci err ? "!" : ""); 102d5ac70f0Sopenharmony_ci } 103d5ac70f0Sopenharmony_ci } 104d5ac70f0Sopenharmony_ci return NULL; 105d5ac70f0Sopenharmony_ci} 106d5ac70f0Sopenharmony_ci 107d5ac70f0Sopenharmony_cistatic void usage(void) 108d5ac70f0Sopenharmony_ci{ 109d5ac70f0Sopenharmony_ci fprintf(stderr, "usage: multi-thread [-options]\n"); 110d5ac70f0Sopenharmony_ci fprintf(stderr, " -D str Set device name\n"); 111d5ac70f0Sopenharmony_ci fprintf(stderr, " -r val Set sample rate\n"); 112d5ac70f0Sopenharmony_ci fprintf(stderr, " -p val Set period size (in frame)\n"); 113d5ac70f0Sopenharmony_ci fprintf(stderr, " -b val Set buffer size (in frame)\n"); 114d5ac70f0Sopenharmony_ci fprintf(stderr, " -c val Set number of channels\n"); 115d5ac70f0Sopenharmony_ci fprintf(stderr, " -f str Set PCM format\n"); 116d5ac70f0Sopenharmony_ci fprintf(stderr, " -s str Set stream direction (playback or capture)\n"); 117d5ac70f0Sopenharmony_ci fprintf(stderr, " -t val Set number of threads\n"); 118d5ac70f0Sopenharmony_ci fprintf(stderr, " -m str Running mode (avail, status, hwsync, timestamp, delay, random)\n"); 119d5ac70f0Sopenharmony_ci fprintf(stderr, " -v Show value\n"); 120d5ac70f0Sopenharmony_ci fprintf(stderr, " -q Quiet mode\n"); 121d5ac70f0Sopenharmony_ci} 122d5ac70f0Sopenharmony_ci 123d5ac70f0Sopenharmony_cistatic int parse_options(int argc, char **argv) 124d5ac70f0Sopenharmony_ci{ 125d5ac70f0Sopenharmony_ci int c, i; 126d5ac70f0Sopenharmony_ci 127d5ac70f0Sopenharmony_ci while ((c = getopt(argc, argv, "D:r:f:p:b:s:t:m:vq")) >= 0) { 128d5ac70f0Sopenharmony_ci switch (c) { 129d5ac70f0Sopenharmony_ci case 'D': 130d5ac70f0Sopenharmony_ci pcmdev = optarg; 131d5ac70f0Sopenharmony_ci break; 132d5ac70f0Sopenharmony_ci case 'r': 133d5ac70f0Sopenharmony_ci rate = atoi(optarg); 134d5ac70f0Sopenharmony_ci break; 135d5ac70f0Sopenharmony_ci case 'p': 136d5ac70f0Sopenharmony_ci periodsize = atoi(optarg); 137d5ac70f0Sopenharmony_ci break; 138d5ac70f0Sopenharmony_ci case 'b': 139d5ac70f0Sopenharmony_ci bufsize = atoi(optarg); 140d5ac70f0Sopenharmony_ci break; 141d5ac70f0Sopenharmony_ci case 'c': 142d5ac70f0Sopenharmony_ci channels = atoi(optarg); 143d5ac70f0Sopenharmony_ci break; 144d5ac70f0Sopenharmony_ci case 'f': 145d5ac70f0Sopenharmony_ci format = snd_pcm_format_value(optarg); 146d5ac70f0Sopenharmony_ci break; 147d5ac70f0Sopenharmony_ci case 's': 148d5ac70f0Sopenharmony_ci if (*optarg == 'p' || *optarg == 'P') 149d5ac70f0Sopenharmony_ci stream = SND_PCM_STREAM_PLAYBACK; 150d5ac70f0Sopenharmony_ci else if (*optarg == 'c' || *optarg == 'C') 151d5ac70f0Sopenharmony_ci stream = SND_PCM_STREAM_CAPTURE; 152d5ac70f0Sopenharmony_ci else { 153d5ac70f0Sopenharmony_ci fprintf(stderr, "invalid stream direction\n"); 154d5ac70f0Sopenharmony_ci return 1; 155d5ac70f0Sopenharmony_ci } 156d5ac70f0Sopenharmony_ci break; 157d5ac70f0Sopenharmony_ci case 't': 158d5ac70f0Sopenharmony_ci num_threads = atoi(optarg); 159d5ac70f0Sopenharmony_ci if (num_threads < 1 || num_threads > MAX_THREADS) { 160d5ac70f0Sopenharmony_ci fprintf(stderr, "invalid number of threads\n"); 161d5ac70f0Sopenharmony_ci return 1; 162d5ac70f0Sopenharmony_ci } 163d5ac70f0Sopenharmony_ci break; 164d5ac70f0Sopenharmony_ci case 'm': 165d5ac70f0Sopenharmony_ci for (i = 0; i <= MODE_RANDOM; i++) 166d5ac70f0Sopenharmony_ci if (mode_suffix[i] == *optarg) 167d5ac70f0Sopenharmony_ci break; 168d5ac70f0Sopenharmony_ci if (i > MODE_RANDOM) { 169d5ac70f0Sopenharmony_ci fprintf(stderr, "invalid mode type\n"); 170d5ac70f0Sopenharmony_ci return 1; 171d5ac70f0Sopenharmony_ci } 172d5ac70f0Sopenharmony_ci running_mode = i; 173d5ac70f0Sopenharmony_ci break; 174d5ac70f0Sopenharmony_ci case 'v': 175d5ac70f0Sopenharmony_ci show_value = 1; 176d5ac70f0Sopenharmony_ci break; 177d5ac70f0Sopenharmony_ci case 'q': 178d5ac70f0Sopenharmony_ci quiet = 1; 179d5ac70f0Sopenharmony_ci break; 180d5ac70f0Sopenharmony_ci default: 181d5ac70f0Sopenharmony_ci usage(); 182d5ac70f0Sopenharmony_ci return 1; 183d5ac70f0Sopenharmony_ci } 184d5ac70f0Sopenharmony_ci } 185d5ac70f0Sopenharmony_ci return 0; 186d5ac70f0Sopenharmony_ci} 187d5ac70f0Sopenharmony_ci 188d5ac70f0Sopenharmony_cistatic int setup_params(void) 189d5ac70f0Sopenharmony_ci{ 190d5ac70f0Sopenharmony_ci snd_pcm_hw_params_t *hw; 191d5ac70f0Sopenharmony_ci 192d5ac70f0Sopenharmony_ci /* FIXME: more finer error checks */ 193d5ac70f0Sopenharmony_ci snd_pcm_hw_params_alloca(&hw); 194d5ac70f0Sopenharmony_ci snd_pcm_hw_params_any(pcm, hw); 195d5ac70f0Sopenharmony_ci snd_pcm_hw_params_set_access(pcm, hw, SND_PCM_ACCESS_RW_INTERLEAVED); 196d5ac70f0Sopenharmony_ci snd_pcm_hw_params_set_format(pcm, hw, format); 197d5ac70f0Sopenharmony_ci snd_pcm_hw_params_set_channels(pcm, hw, channels); 198d5ac70f0Sopenharmony_ci snd_pcm_hw_params_set_rate(pcm, hw, rate, 0); 199d5ac70f0Sopenharmony_ci snd_pcm_hw_params_set_period_size(pcm, hw, periodsize, 0); 200d5ac70f0Sopenharmony_ci snd_pcm_hw_params_set_buffer_size(pcm, hw, bufsize); 201d5ac70f0Sopenharmony_ci if (snd_pcm_hw_params(pcm, hw) < 0) { 202d5ac70f0Sopenharmony_ci fprintf(stderr, "snd_pcm_hw_params error\n"); 203d5ac70f0Sopenharmony_ci return 1; 204d5ac70f0Sopenharmony_ci } 205d5ac70f0Sopenharmony_ci return 0; 206d5ac70f0Sopenharmony_ci} 207d5ac70f0Sopenharmony_ci 208d5ac70f0Sopenharmony_ciint main(int argc, char **argv) 209d5ac70f0Sopenharmony_ci{ 210d5ac70f0Sopenharmony_ci char *buf; 211d5ac70f0Sopenharmony_ci int i, err; 212d5ac70f0Sopenharmony_ci 213d5ac70f0Sopenharmony_ci if (parse_options(argc, argv)) 214d5ac70f0Sopenharmony_ci return 1; 215d5ac70f0Sopenharmony_ci 216d5ac70f0Sopenharmony_ci err = snd_pcm_open(&pcm, pcmdev, stream, 0); 217d5ac70f0Sopenharmony_ci if (err < 0) { 218d5ac70f0Sopenharmony_ci fprintf(stderr, "cannot open pcm %s\n", pcmdev); 219d5ac70f0Sopenharmony_ci return 1; 220d5ac70f0Sopenharmony_ci } 221d5ac70f0Sopenharmony_ci 222d5ac70f0Sopenharmony_ci if (setup_params()) 223d5ac70f0Sopenharmony_ci return 1; 224d5ac70f0Sopenharmony_ci 225d5ac70f0Sopenharmony_ci buf = calloc(1, snd_pcm_format_size(format, bufsize) * channels); 226d5ac70f0Sopenharmony_ci if (!buf) { 227d5ac70f0Sopenharmony_ci fprintf(stderr, "cannot alloc buffer\n"); 228d5ac70f0Sopenharmony_ci return 1; 229d5ac70f0Sopenharmony_ci } 230d5ac70f0Sopenharmony_ci 231d5ac70f0Sopenharmony_ci for (i = 0; i < num_threads; i++) { 232d5ac70f0Sopenharmony_ci if (pthread_create(&peeper_threads[i], NULL, peeper, (void *)(long)i)) { 233d5ac70f0Sopenharmony_ci fprintf(stderr, "pthread_create error\n"); 234d5ac70f0Sopenharmony_ci return 1; 235d5ac70f0Sopenharmony_ci } 236d5ac70f0Sopenharmony_ci } 237d5ac70f0Sopenharmony_ci 238d5ac70f0Sopenharmony_ci if (stream == SND_PCM_STREAM_CAPTURE) 239d5ac70f0Sopenharmony_ci snd_pcm_start(pcm); 240d5ac70f0Sopenharmony_ci for (;;) { 241d5ac70f0Sopenharmony_ci int size = rand() % (bufsize / 2); 242d5ac70f0Sopenharmony_ci if (stream == SND_PCM_STREAM_PLAYBACK) 243d5ac70f0Sopenharmony_ci err = snd_pcm_writei(pcm, buf, size); 244d5ac70f0Sopenharmony_ci else 245d5ac70f0Sopenharmony_ci err = snd_pcm_readi(pcm, buf, size); 246d5ac70f0Sopenharmony_ci if (err < 0) { 247d5ac70f0Sopenharmony_ci fprintf(stderr, "read/write error %d\n", err); 248d5ac70f0Sopenharmony_ci err = snd_pcm_recover(pcm, err, 0); 249d5ac70f0Sopenharmony_ci if (err < 0) 250d5ac70f0Sopenharmony_ci break; 251d5ac70f0Sopenharmony_ci if (stream == SND_PCM_STREAM_CAPTURE) 252d5ac70f0Sopenharmony_ci snd_pcm_start(pcm); 253d5ac70f0Sopenharmony_ci } 254d5ac70f0Sopenharmony_ci } 255d5ac70f0Sopenharmony_ci 256d5ac70f0Sopenharmony_ci running = 0; 257d5ac70f0Sopenharmony_ci for (i = 0; i < num_threads; i++) 258d5ac70f0Sopenharmony_ci pthread_cancel(peeper_threads[i]); 259d5ac70f0Sopenharmony_ci for (i = 0; i < num_threads; i++) 260d5ac70f0Sopenharmony_ci pthread_join(peeper_threads[i], NULL); 261d5ac70f0Sopenharmony_ci 262d5ac70f0Sopenharmony_ci return 1; 263d5ac70f0Sopenharmony_ci} 264