Blame test/pcm-multi-thread.c

Packit Service db8eaa
/*
Packit Service db8eaa
 * simple multi-thread stress test for PCM
Packit Service db8eaa
 *
Packit Service db8eaa
 * The main thread simply feeds or reads the sample data with the
Packit Service db8eaa
 * random size continuously.  Meanwhile, the worker threads call some
Packit Service db8eaa
 * update function depending on the given mode, and show the thread
Packit Service db8eaa
 * number of the read value.
Packit Service db8eaa
 *
Packit Service db8eaa
 * The function for the worker thread is specified via -m option.
Packit Service db8eaa
 * When the random mode ('r') is set, the update function is chosen
Packit Service db8eaa
 * randomly in the loop.
Packit Service db8eaa
 *
Packit Service db8eaa
 * When the -v option is passed, this tries to show some obtained value
Packit Service db8eaa
 * from the function.  Without -v, as default, it shows the thread number
Packit Service db8eaa
 * (0-9).  In addition, it puts the mode suffix ('a' for avail, 'd' for
Packit Service db8eaa
 * delay, etc) for the random mode, as well as the suffix '!' indicating
Packit Service db8eaa
 * the error from the called function.
Packit Service db8eaa
 */
Packit Service db8eaa
Packit Service db8eaa
#include <stdio.h>
Packit Service db8eaa
#include <pthread.h>
Packit Service db8eaa
#include <getopt.h>
Packit Service db8eaa
#include "../include/asoundlib.h"
Packit Service db8eaa
Packit Service db8eaa
#define MAX_THREADS	10
Packit Service db8eaa
Packit Service db8eaa
enum {
Packit Service db8eaa
	MODE_AVAIL_UPDATE,
Packit Service db8eaa
	MODE_STATUS,
Packit Service db8eaa
	MODE_HWSYNC,
Packit Service db8eaa
	MODE_TIMESTAMP,
Packit Service db8eaa
	MODE_DELAY,
Packit Service db8eaa
	MODE_RANDOM
Packit Service db8eaa
};
Packit Service db8eaa
Packit Service db8eaa
static char mode_suffix[] = {
Packit Service db8eaa
	'a', 's', 'h', 't', 'd', 'r'
Packit Service db8eaa
};
Packit Service db8eaa
Packit Service db8eaa
static const char *devname = "default";
Packit Service db8eaa
static int stream = SND_PCM_STREAM_PLAYBACK;
Packit Service db8eaa
static int num_threads = 1;
Packit Service db8eaa
static int periodsize = 16 * 1024;
Packit Service db8eaa
static int bufsize = 16 * 1024 * 4;
Packit Service db8eaa
static int channels = 2;
Packit Service db8eaa
static int rate = 48000;
Packit Service db8eaa
static snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE;
Packit Service db8eaa
Packit Service db8eaa
static int running_mode = MODE_AVAIL_UPDATE;
Packit Service db8eaa
static int show_value = 0;
Packit Service db8eaa
static int quiet = 0;
Packit Service db8eaa
Packit Service db8eaa
static pthread_t peeper_threads[MAX_THREADS];
Packit Service db8eaa
static int running = 1;
Packit Service db8eaa
static snd_pcm_t *pcm;
Packit Service db8eaa
Packit Service db8eaa
static void *peeper(void *data)
Packit Service db8eaa
{
Packit Service db8eaa
	int thread_no = (long)data;
Packit Service db8eaa
	snd_pcm_sframes_t val;
Packit Service db8eaa
	snd_pcm_status_t *stat;
Packit Service db8eaa
	snd_htimestamp_t tstamp;
Packit Service db8eaa
	int mode = running_mode, err;
Packit Service db8eaa
Packit Service db8eaa
	snd_pcm_status_alloca(&stat;;
Packit Service db8eaa
Packit Service db8eaa
	while (running) {
Packit Service db8eaa
		if (running_mode == MODE_RANDOM)
Packit Service db8eaa
			mode = rand() % MODE_RANDOM;
Packit Service db8eaa
		switch (mode) {
Packit Service db8eaa
		case MODE_AVAIL_UPDATE:
Packit Service db8eaa
			val = snd_pcm_avail_update(pcm);
Packit Service db8eaa
			err = 0;
Packit Service db8eaa
			break;
Packit Service db8eaa
		case MODE_STATUS:
Packit Service db8eaa
			err = snd_pcm_status(pcm, stat);
Packit Service db8eaa
			val = snd_pcm_status_get_avail(stat);
Packit Service db8eaa
			break;
Packit Service db8eaa
		case MODE_HWSYNC:
Packit Service db8eaa
			err = snd_pcm_hwsync(pcm);
Packit Service db8eaa
			break;
Packit Service db8eaa
		case MODE_TIMESTAMP:
Packit Service db8eaa
			err = snd_pcm_htimestamp(pcm, (snd_pcm_uframes_t *)&val,
Packit Service db8eaa
						 &tstamp);
Packit Service db8eaa
			break;
Packit Service db8eaa
		default:
Packit Service db8eaa
			err = snd_pcm_delay(pcm, &val;;
Packit Service db8eaa
			break;
Packit Service db8eaa
		}
Packit Service db8eaa
Packit Service db8eaa
		if (quiet)
Packit Service db8eaa
			continue;
Packit Service db8eaa
		if (running_mode == MODE_RANDOM) {
Packit Service db8eaa
			fprintf(stderr, "%d%c%s", thread_no, mode_suffix[mode],
Packit Service db8eaa
				err ? "!" : "");
Packit Service db8eaa
		} else {
Packit Service db8eaa
			if (show_value && mode != MODE_HWSYNC)
Packit Service db8eaa
				fprintf(stderr, "\r%d     ", (int)val);
Packit Service db8eaa
			else
Packit Service db8eaa
				fprintf(stderr, "%d%s", thread_no,
Packit Service db8eaa
					err ? "!" : "");
Packit Service db8eaa
		}
Packit Service db8eaa
	}
Packit Service db8eaa
	return NULL;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static void usage(void)
Packit Service db8eaa
{
Packit Service db8eaa
	fprintf(stderr, "usage: multi-thread [-options]\n");
Packit Service db8eaa
	fprintf(stderr, "  -D str  Set device name\n");
Packit Service db8eaa
	fprintf(stderr, "  -r val  Set sample rate\n");
Packit Service db8eaa
	fprintf(stderr, "  -p val  Set period size (in frame)\n");
Packit Service db8eaa
	fprintf(stderr, "  -b val  Set buffer size (in frame)\n");
Packit Service db8eaa
	fprintf(stderr, "  -c val  Set number of channels\n");
Packit Service db8eaa
	fprintf(stderr, "  -f str  Set PCM format\n");
Packit Service db8eaa
	fprintf(stderr, "  -s str  Set stream direction (playback or capture)\n");
Packit Service db8eaa
	fprintf(stderr, "  -t val  Set number of threads\n");
Packit Service db8eaa
	fprintf(stderr, "  -m str  Running mode (avail, status, hwsync, timestamp, delay, random)\n");
Packit Service db8eaa
	fprintf(stderr, "  -v      Show value\n");
Packit Service db8eaa
	fprintf(stderr, "  -q      Quiet mode\n");
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int parse_options(int argc, char **argv)
Packit Service db8eaa
{
Packit Service db8eaa
	int c, i;
Packit Service db8eaa
Packit Service db8eaa
	while ((c = getopt(argc, argv, "D:r:f:p:b:s:t:m:vq")) >= 0) {
Packit Service db8eaa
		switch (c) {
Packit Service db8eaa
		case 'D':
Packit Service db8eaa
			devname = optarg;
Packit Service db8eaa
			break;
Packit Service db8eaa
		case 'r':
Packit Service db8eaa
			rate = atoi(optarg);
Packit Service db8eaa
			break;
Packit Service db8eaa
		case 'p':
Packit Service db8eaa
			periodsize = atoi(optarg);
Packit Service db8eaa
			break;
Packit Service db8eaa
		case 'b':
Packit Service db8eaa
			bufsize = atoi(optarg);
Packit Service db8eaa
			break;
Packit Service db8eaa
		case 'c':
Packit Service db8eaa
			channels = atoi(optarg);
Packit Service db8eaa
			break;
Packit Service db8eaa
		case 'f':
Packit Service db8eaa
			format = snd_pcm_format_value(optarg);
Packit Service db8eaa
			break;
Packit Service db8eaa
		case 's':
Packit Service db8eaa
			if (*optarg == 'p' || *optarg == 'P')
Packit Service db8eaa
				stream = SND_PCM_STREAM_PLAYBACK;
Packit Service db8eaa
			else if (*optarg == 'c' || *optarg == 'C')
Packit Service db8eaa
				stream = SND_PCM_STREAM_CAPTURE;
Packit Service db8eaa
			else {
Packit Service db8eaa
				fprintf(stderr, "invalid stream direction\n");
Packit Service db8eaa
				return 1;
Packit Service db8eaa
			}
Packit Service db8eaa
			break;
Packit Service db8eaa
		case 't':
Packit Service db8eaa
			num_threads = atoi(optarg);
Packit Service db8eaa
			if (num_threads < 1 || num_threads > MAX_THREADS) {
Packit Service db8eaa
				fprintf(stderr, "invalid number of threads\n");
Packit Service db8eaa
				return 1;
Packit Service db8eaa
			}
Packit Service db8eaa
			break;
Packit Service db8eaa
		case 'm':
Packit Service db8eaa
			for (i = 0; i <= MODE_RANDOM; i++)
Packit Service db8eaa
				if (mode_suffix[i] == *optarg)
Packit Service db8eaa
					break;
Packit Service db8eaa
			if (i > MODE_RANDOM) {
Packit Service db8eaa
				fprintf(stderr, "invalid mode type\n");
Packit Service db8eaa
				return 1;
Packit Service db8eaa
			}
Packit Service db8eaa
			running_mode = i;
Packit Service db8eaa
			break;
Packit Service db8eaa
		case 'v':
Packit Service db8eaa
			show_value = 1;
Packit Service db8eaa
			break;
Packit Service db8eaa
		case 'q':
Packit Service db8eaa
			quiet = 1;
Packit Service db8eaa
			break;
Packit Service db8eaa
		default:
Packit Service db8eaa
			usage();
Packit Service db8eaa
			return 1;
Packit Service db8eaa
		}
Packit Service db8eaa
	}
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
static int setup_params(void)
Packit Service db8eaa
{
Packit Service db8eaa
	snd_pcm_hw_params_t *hw;
Packit Service db8eaa
Packit Service db8eaa
	/* FIXME: more finer error checks */
Packit Service db8eaa
	snd_pcm_hw_params_alloca(&hw;;
Packit Service db8eaa
	snd_pcm_hw_params_any(pcm, hw);
Packit Service db8eaa
	snd_pcm_hw_params_set_access(pcm, hw, SND_PCM_ACCESS_RW_INTERLEAVED);
Packit Service db8eaa
	snd_pcm_hw_params_set_format(pcm, hw, format);
Packit Service db8eaa
	snd_pcm_hw_params_set_channels(pcm, hw, channels);
Packit Service db8eaa
	snd_pcm_hw_params_set_rate(pcm, hw, rate, 0);
Packit Service db8eaa
	snd_pcm_hw_params_set_period_size(pcm, hw, periodsize, 0);
Packit Service db8eaa
	snd_pcm_hw_params_set_buffer_size(pcm, hw, bufsize);
Packit Service db8eaa
	if (snd_pcm_hw_params(pcm, hw) < 0) {
Packit Service db8eaa
		fprintf(stderr, "snd_pcm_hw_params error\n");
Packit Service db8eaa
		return 1;
Packit Service db8eaa
	}
Packit Service db8eaa
	return 0;
Packit Service db8eaa
}
Packit Service db8eaa
Packit Service db8eaa
int main(int argc, char **argv)
Packit Service db8eaa
{
Packit Service db8eaa
	char *buf;
Packit Service db8eaa
	int i, err;
Packit Service db8eaa
Packit Service db8eaa
	if (parse_options(argc, argv))
Packit Service db8eaa
		return 1;
Packit Service db8eaa
Packit Service db8eaa
	err = snd_pcm_open(&pcm, devname, stream, 0);
Packit Service db8eaa
	if (err < 0) {
Packit Service db8eaa
		fprintf(stderr, "cannot open pcm %s\n", devname);
Packit Service db8eaa
		return 1;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	if (setup_params())
Packit Service db8eaa
		return 1;
Packit Service db8eaa
Packit Service db8eaa
	buf = calloc(1, snd_pcm_format_size(format, bufsize) * channels);
Packit Service db8eaa
	if (!buf) {
Packit Service db8eaa
		fprintf(stderr, "cannot alloc buffer\n");
Packit Service db8eaa
		return 1;
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	for (i = 0; i < num_threads; i++) {
Packit Service db8eaa
		if (pthread_create(&peeper_threads[i], NULL, peeper, (void *)(long)i)) {
Packit Service db8eaa
			fprintf(stderr, "pthread_create error\n");
Packit Service db8eaa
			return 1;
Packit Service db8eaa
		}
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	if (stream == SND_PCM_STREAM_CAPTURE)
Packit Service db8eaa
		snd_pcm_start(pcm);
Packit Service db8eaa
	for (;;) {
Packit Service db8eaa
		int size = rand() % (bufsize / 2);
Packit Service db8eaa
		if (stream == SND_PCM_STREAM_PLAYBACK)
Packit Service db8eaa
			err = snd_pcm_writei(pcm, buf, size);
Packit Service db8eaa
		else
Packit Service db8eaa
			err = snd_pcm_readi(pcm, buf, size);
Packit Service db8eaa
		if (err < 0) {
Packit Service db8eaa
			fprintf(stderr, "read/write error %d\n", err);
Packit Service db8eaa
			err = snd_pcm_recover(pcm, err, 0);
Packit Service db8eaa
			if (err < 0)
Packit Service db8eaa
				break;
Packit Service db8eaa
			if (stream == SND_PCM_STREAM_CAPTURE)
Packit Service db8eaa
				snd_pcm_start(pcm);
Packit Service db8eaa
		}
Packit Service db8eaa
	}
Packit Service db8eaa
Packit Service db8eaa
	running = 0;
Packit Service db8eaa
	for (i = 0; i < num_threads; i++)
Packit Service db8eaa
		pthread_cancel(peeper_threads[i]);
Packit Service db8eaa
	for (i = 0; i < num_threads; i++)
Packit Service db8eaa
		pthread_join(peeper_threads[i], NULL);
Packit Service db8eaa
Packit Service db8eaa
	return 1;
Packit Service db8eaa
}