blob: 58705979278b057414d1e526bc304f178c4af60e [file] [log] [blame]
Chinyue Chen2ff17232016-07-07 14:56:06 +08001/*
2 * Copyright 2016 The Chromium OS Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
7#include <pthread.h>
8#include <getopt.h>
9#include <stdio.h>
10#include <stdlib.h>
11
12#include "cras_client.h"
13
14#define CAPTURE_PERIOD_SIZE 256
15#define CAPTURE_PERIOD_COUNT 4
16
17int num_retries = 3;
18int wait_sec = 10;
19
20struct stream_in {
21 uint32_t sample_rate;
22 uint32_t channels;
23 uint32_t period_size;
24 struct cras_audio_format* cras_format;
25 struct cras_stream_params* cras_params;
26 cras_stream_id_t stream_id;
27
28 uint32_t frames_to_capture;
29 uint32_t frames_captured;
30 pthread_mutex_t lock;
31 pthread_cond_t cond;
32};
33
34static uint32_t get_input_period_size(uint32_t sample_rate)
35{
36 /*
37 * The supported capture sample rates range from 8000 to 48000.
38 * We need to use different buffer size when creating CRAS stream
39 * so that appropriate latency is maintained.
40 */
41 if (sample_rate <= 12000)
42 return (CAPTURE_PERIOD_SIZE) / 4;
43 else if (sample_rate <= 24000)
44 return (CAPTURE_PERIOD_SIZE) / 2;
45 else
46 return CAPTURE_PERIOD_SIZE;
47}
48
49void cras_server_error_cb(struct cras_client *client, void *user_arg);
50
51int cras_open(struct cras_client **client)
52{
53 int rc;
54
55 rc = cras_client_create(client);
56 if (rc < 0) {
57 fprintf(stderr, "%s: Failed to create CRAS client.\n", __func__);
58 return rc;
59 }
60
61 rc = cras_client_connect_timeout(*client, 3000);
62 if (rc) {
63 fprintf(stderr, "%s: Failed to connect to CRAS server, rc %d.\n",
64 __func__, rc);
65 goto fail;
66 }
67
68 rc = cras_client_run_thread(*client);
69 if (rc) {
70 fprintf(stderr, "%s: Failed to start CRAS client.\n", __func__);
71 goto fail;
72 }
73
74 rc = cras_client_connected_wait(*client);
75 if (rc) {
76 fprintf(stderr, "%s: Failed to wait for connected.\n", __func__);
77 goto fail;
78 }
79
80 cras_client_set_server_error_cb(*client, cras_server_error_cb, NULL);
81
82 return 0;
83
84fail:
85 cras_client_destroy(*client);
86 return rc;
87}
88
89int cras_close(struct cras_client *client)
90{
91 cras_client_stop(client);
92 cras_client_destroy(client);
93 return 0;
94}
95
96void cras_server_error_cb(struct cras_client *client, void *user_arg)
97{
98 fprintf(stderr, "Server error!\n");
99 cras_close(client);
100}
101
102static int in_read_cb(struct cras_client *client,
103 cras_stream_id_t stream_id,
104 uint8_t *captured_samples,
105 uint8_t *playback_samples,
106 unsigned int frames,
107 const struct timespec *captured_time,
108 const struct timespec *playback_time,
109 void *user_arg)
110{
111 struct stream_in *in = (struct stream_in *)user_arg;
112
113 pthread_mutex_lock(&in->lock);
114
115 in->frames_captured += frames;
116 if (in->frames_captured >= in->frames_to_capture)
117 pthread_cond_signal(&in->cond);
118
119 pthread_mutex_unlock(&in->lock);
120
121 return frames;
122}
123
124static int in_err_cb(struct cras_client *client,
125 cras_stream_id_t stream_id,
126 int error,
127 void *user_arg)
128{
129 fprintf(stderr, "%s: enter\n", __func__);
130 return 0;
131}
132
133struct stream_in *open_input_stream(struct cras_client *client,
134 uint32_t sample_rate, uint32_t channels)
135{
136 struct stream_in *in;
137
138 printf("%s: sample_rate %d channels %d\n", __func__, sample_rate, channels);
139
140 in = (struct stream_in *)calloc(1, sizeof(struct stream_in));
141
142 in->sample_rate = sample_rate;
143 in->channels = channels;
144 in->period_size = get_input_period_size(in->sample_rate);
145
146 in->cras_format = cras_audio_format_create(
147 SND_PCM_FORMAT_S16_LE,
148 in->sample_rate,
149 in->channels);
150 if (!in->cras_format) {
151 fprintf(stderr, "%s: Failed to create CRAS audio format.\n", __func__);
152 goto cleanup;
153 }
154
155 in->cras_params = cras_client_unified_params_create(
156 CRAS_STREAM_INPUT,
157 in->period_size,
158 CRAS_STREAM_TYPE_DEFAULT,
159 0,
160 (void *)in,
161 in_read_cb,
162 in_err_cb,
163 in->cras_format);
164 if (!in->cras_params) {
165 fprintf(stderr, "%s: Failed to create stream params.\n", __func__);
166 goto cleanup;
167 }
168
169 printf("%s: stream created.\n", __func__);
170 return in;
171
172cleanup:
173 if (in->cras_format)
174 cras_audio_format_destroy(in->cras_format);
175 if (in->cras_params)
176 cras_client_stream_params_destroy(in->cras_params);
177 free(in);
178 return NULL;
179}
180
181int start_input_stream(struct cras_client *client, struct stream_in *in)
182{
183 return cras_client_add_stream(client, &in->stream_id, in->cras_params);
184}
185
186void close_input_stream(struct cras_client *client, struct stream_in *in)
187{
188 if (in->stream_id)
189 cras_client_rm_stream(client, in->stream_id);
190 cras_audio_format_destroy(in->cras_format);
191 cras_client_stream_params_destroy(in->cras_params);
192 free(in);
193}
194
195int cras_test_capture(struct cras_client *client, uint32_t sample_rate,
196 uint32_t channels, uint32_t segment_ms, uint32_t segments)
197{
198 struct stream_in *in;
199 int i, ret = 0, fail_count = 0;
200 pthread_condattr_t attr;
201 struct timespec abs_ts, wait_ts;
202
203 in = open_input_stream(client, sample_rate, channels);
204 if (!in) {
205 fprintf(stderr, "%s: Failed to open input stream.\n", __func__);
206 return -1;
207 }
208
209 in->frames_to_capture = in->sample_rate * segment_ms / 1000;
210
211 pthread_mutex_init(&in->lock, (const pthread_mutexattr_t *)NULL);
212 pthread_condattr_init(&attr);
213 pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
214 pthread_cond_init(&in->cond, &attr);
215
216 pthread_mutex_lock(&in->lock);
217
218 ret = start_input_stream(client, in);
219 if (ret) {
220 pthread_mutex_unlock(&in->lock);
221 fprintf(stderr, "%s: Failed to start input stream.\n", __func__);
222 goto cleanup;
223 }
224
225 for (i = 0; i < segments; ++i) {
226 in->frames_captured = 0;
227
228 // Wait for captured data.
229 if (wait_sec > 0) {
230 clock_gettime(CLOCK_MONOTONIC, &abs_ts);
231 wait_ts.tv_sec = wait_sec;
232 wait_ts.tv_nsec = 0;
233 add_timespecs(&abs_ts, &wait_ts);
234 ret = pthread_cond_timedwait(&in->cond, &in->lock, &abs_ts);
235 } else {
236 ret = pthread_cond_wait(&in->cond, &in->lock);
237 }
238 if (ret) {
239 if (ret == ETIMEDOUT) {
240 fprintf(stderr, "%s: Failed to receive captured data.\n",
241 __func__);
242 } else {
243 fprintf(stderr, "%s: Failed to wait for data.\n", __func__);
244 }
245 if (++fail_count >= num_retries)
246 break;
247 else
248 continue;
249 }
250
251 printf("%s: Captured %d frames for segment %d.\n", __func__,
252 in->frames_captured, i);
253 }
254
255 pthread_mutex_unlock(&in->lock);
256
257cleanup:
258 close_input_stream(client, in);
259 return ret;
260}
261
262int cras_stress_capture(struct cras_client *client)
263{
264 uint32_t test_sample_rate[] = {
265 12345,
266 44100,
267 48000,
268 96000,
269 192000,
270 };
271 uint32_t test_channels[] = {
272 1,
273 2,
274 3,
275 4,
276 5,
277 6,
278 7,
279 8,
280 };
281 int i, j;
282 int ret;
283
284 for (i = 0; i < ARRAY_SIZE(test_sample_rate); ++i) {
285 for (j = 0; j < ARRAY_SIZE(test_channels); ++j) {
286 ret = cras_test_capture(client, test_sample_rate[i],
287 test_channels[j], 20, 10);
288 if (ret) {
289 fprintf(stderr,
290 "%s: Failed to capture sample_rate %d channels %d.\n",
291 __func__, test_sample_rate[i], test_channels[j]);
292 return ret;
293 }
294 }
295 }
296
297 return 0;
298}
299
300int main (int argc, char *argv[])
301{
302 struct cras_client *client;
303 int c, i, rc;
304 int num_tests = 1;
305 struct option long_opt[] =
306 {
307 { "help", no_argument, NULL, 'h' },
308 { "num_tests", required_argument, NULL, 'n' },
309 { "num_retries", required_argument, NULL, 'r' },
310 { "wait_sec", required_argument, NULL, 'w' },
311 { NULL, 0, NULL, 0 }
312 };
313
314 while (1) {
315 c = getopt_long(argc, argv, "hn:r:w:", long_opt, NULL);
316 if (c == -1)
317 break;
318 switch (c) {
319 case 'n':
320 num_tests = atoi(optarg);
321 break;
322
323 case 'r':
324 num_retries = atoi(optarg);
325 break;
326
327 case 'w':
328 wait_sec = atoi(optarg);
329 break;
330
331 case 'h':
332 printf("Usage: %s [OPTIONS]\n", argv[0]);
333 printf(" --num_tests <num> Number of test runs, "
334 "default: %d\n", num_tests);
335 printf(" --num_retries <num> Number of retries, "
336 "default: %d\n", num_retries);
337 printf(" --wait_sec <num> Wait seconds for captured data, "
338 "default: %d, use 0 to wait infinitely\n", wait_sec);
339 printf(" -h, --help Print this help and exit\n");
340 printf("\n");
341 exit(EXIT_SUCCESS);
342 }
343 }
344
345 rc = cras_open(&client);
346 if (rc) {
347 fprintf(stderr, "%s: Failed to open CRAS, rc %d.\n", __func__, rc);
348 exit(EXIT_FAILURE);
349 }
350
351 // Run tests.
352 for (i = 0; i < num_tests; ++i) {
353 printf("%s: ============\n", __func__);
354 printf("%s: TEST PASS %d\n", __func__, i);
355 printf("%s: ============\n", __func__);
356 rc = cras_stress_capture(client);
357 if (rc) {
358 fprintf(stderr, "%s: Failed in test pass %d.\n", __func__, i);
359 break;
360 }
361 }
362
363 if (client)
364 cras_close(client);
365
366 exit(EXIT_SUCCESS);
367}