OSDN Git Service

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