blob: f5a46e025198bb79c57963398615e79b810d869c [file] [log] [blame]
Benny Prijono69d9d192006-05-21 19:00:28 +00001/* $Id$ */
2/*
Benny Prijono32177c02008-06-20 22:44:47 +00003 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
Benny Prijono69d9d192006-05-21 19:00:28 +00004 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
Benny Prijono1ec70b32006-06-20 15:39:07 +000020/**
21 * \page page_pjmedia_samples_sndtest_c Samples: Sound Card Benchmark
22 *
23 * This example can be used to benchmark the quality of the sound card
24 * installed in the system. At the end of the test, it will report
25 * the jitter and clock drifts of the device.
26 *
27 * This file is pjsip-apps/src/samples/sndtest.c
28 *
29 * Screenshots on WinXP: \image html sndtest.jpg
30 *
31 * \includelineno sndtest.c
32 */
33
34
Benny Prijono69d9d192006-05-21 19:00:28 +000035#include <pjmedia.h>
36#include <pjlib.h>
37#include <pjlib-util.h>
38
39#include <stdlib.h> /* atoi() */
40#include <stdio.h>
41
42
43
44#define THIS_FILE "sndtest.c"
45
46/* Warn (print log with yellow color) if frame jitter is larger than
47 * this value (in usec).
48 */
49#define WARN_JITTER_USEC 1000
50
51/* Test duration in msec */
52#define DURATION 10000
53
Benny Prijono6a61c222006-05-22 10:28:44 +000054/* Skip the first msec from the calculation */
55#define SKIP_DURATION 1000
56
57/* Max frames per sec (to calculate number of delays to keep). */
Benny Prijono69d9d192006-05-21 19:00:28 +000058#define MAX_FRAMES_PER_SEC 100
59
60/* Number of frame durations to keep */
61#define MAX_DELAY_COUNTER (((DURATION/1000)+1)*MAX_FRAMES_PER_SEC)
62
63
64struct stream_data
65{
66 pj_uint32_t first_timestamp;
67 pj_uint32_t last_timestamp;
68 pj_timestamp last_called;
69 unsigned counter;
70 unsigned min_delay;
71 unsigned max_delay;
72 unsigned delay[MAX_DELAY_COUNTER];
73};
74
75struct test_data {
76 pjmedia_dir dir;
77 unsigned clock_rate;
78 unsigned samples_per_frame;
79 unsigned channel_count;
80 pj_bool_t running;
81 pj_bool_t has_error;
Benny Prijonod7443932008-01-04 18:00:11 +000082 pj_mutex_t *mutex;
Benny Prijono69d9d192006-05-21 19:00:28 +000083
84 struct stream_data capture_data;
85 struct stream_data playback_data;
86};
87
88
89
90static const char *desc =
91 " sndtest.c \n"
92 " \n"
93 " PURPOSE: \n"
94 " Test the performance of sound device. \n"
95 " \n"
96 " USAGE: \n"
97 " sndtest --help \n"
98 " sndtest [options] \n"
99 " \n"
100 " where options: \n"
101 " --id=ID -i Use device ID (default is -1) \n"
102 " --rate=HZ -r Set test clock rate (default=8000)\n"
103 " --frame=SAMPLES -f Set number of samples per frame\n"
104 " --channel=CH -n Set number of channels (default=1)\n"
105 " --verbose -v Show verbose result \n"
106 " --help -h Show this screen \n"
107;
108
109
110
111static void enum_devices(void)
112{
113 int i, count;
114
115 count = pjmedia_snd_get_dev_count();
116 if (count == 0) {
117 PJ_LOG(3,(THIS_FILE, "No devices found"));
118 return;
119 }
120
121 PJ_LOG(3,(THIS_FILE, "Found %d devices:", count));
122 for (i=0; i<count; ++i) {
123 const pjmedia_snd_dev_info *info;
124
125 info = pjmedia_snd_get_dev_info(i);
126 pj_assert(info != NULL);
127
128 PJ_LOG(3,(THIS_FILE," %d: %s (capture=%d, playback=%d)",
129 i, info->name, info->input_count, info->output_count));
130 }
131}
132
133
Benny Prijono69d9d192006-05-21 19:00:28 +0000134static pj_status_t play_cb(void *user_data, pj_uint32_t timestamp,
135 void *output, unsigned size)
136{
137 struct test_data *test_data = user_data;
138 struct stream_data *strm_data = &test_data->playback_data;
139
Benny Prijonod7443932008-01-04 18:00:11 +0000140 pj_mutex_lock(test_data->mutex);
141
Benny Prijono6a61c222006-05-22 10:28:44 +0000142 /* Skip frames when test is not started or test has finished */
Benny Prijono69d9d192006-05-21 19:00:28 +0000143 if (!test_data->running) {
Benny Prijonoac623b32006-07-03 15:19:31 +0000144 pj_bzero(output, size);
Benny Prijonod7443932008-01-04 18:00:11 +0000145
146 pj_mutex_unlock(test_data->mutex);
Benny Prijono69d9d192006-05-21 19:00:28 +0000147 return PJ_SUCCESS;
148 }
149
Benny Prijono6a61c222006-05-22 10:28:44 +0000150 /* Save last timestamp seen (to calculate drift) */
Benny Prijono69d9d192006-05-21 19:00:28 +0000151 strm_data->last_timestamp = timestamp;
152
153 if (strm_data->last_called.u64 == 0) {
154 pj_get_timestamp(&strm_data->last_called);
Benny Prijono6a61c222006-05-22 10:28:44 +0000155 /* Init min_delay to one frame */
Benny Prijono69d9d192006-05-21 19:00:28 +0000156 strm_data->min_delay = test_data->samples_per_frame * 1000000 /
157 test_data->clock_rate;
158 strm_data->first_timestamp = timestamp;
159
160 } else if (strm_data->counter <= MAX_DELAY_COUNTER) {
161 pj_timestamp now;
162 unsigned delay;
163
164 pj_get_timestamp(&now);
165
Benny Prijono6a61c222006-05-22 10:28:44 +0000166 /* Calculate frame interval */
Benny Prijono69d9d192006-05-21 19:00:28 +0000167 delay = pj_elapsed_usec(&strm_data->last_called, &now);
168 if (delay < strm_data->min_delay)
169 strm_data->min_delay = delay;
170 if (delay > strm_data->max_delay)
171 strm_data->max_delay = delay;
172
173 strm_data->last_called = now;
174
Benny Prijono6a61c222006-05-22 10:28:44 +0000175 /* Save the frame interval for later calculation */
Benny Prijono69d9d192006-05-21 19:00:28 +0000176 strm_data->delay[strm_data->counter] = delay;
177 ++strm_data->counter;
Benny Prijono6a61c222006-05-22 10:28:44 +0000178
179 } else {
180
181 /* No space, can't take anymore frames */
182 test_data->running = 0;
183
Benny Prijono69d9d192006-05-21 19:00:28 +0000184 }
185
Benny Prijonoac623b32006-07-03 15:19:31 +0000186 pj_bzero(output, size);
Benny Prijonod7443932008-01-04 18:00:11 +0000187
188 pj_mutex_unlock(test_data->mutex);
189
Benny Prijono69d9d192006-05-21 19:00:28 +0000190 return PJ_SUCCESS;
191}
192
193static pj_status_t rec_cb(void *user_data, pj_uint32_t timestamp,
Benny Prijonof521eb02006-08-06 23:07:25 +0000194 void *input, unsigned size)
Benny Prijono69d9d192006-05-21 19:00:28 +0000195{
196
197 struct test_data *test_data = user_data;
198 struct stream_data *strm_data = &test_data->capture_data;
199
Benny Prijonod7443932008-01-04 18:00:11 +0000200 pj_mutex_lock(test_data->mutex);
201
Benny Prijono69d9d192006-05-21 19:00:28 +0000202 PJ_UNUSED_ARG(input);
203 PJ_UNUSED_ARG(size);
204
Benny Prijono6a61c222006-05-22 10:28:44 +0000205 /* Skip frames when test is not started or test has finished */
Benny Prijono69d9d192006-05-21 19:00:28 +0000206 if (!test_data->running) {
Benny Prijonod7443932008-01-04 18:00:11 +0000207 pj_mutex_unlock(test_data->mutex);
Benny Prijono69d9d192006-05-21 19:00:28 +0000208 return PJ_SUCCESS;
209 }
210
Benny Prijono6a61c222006-05-22 10:28:44 +0000211 /* Save last timestamp seen (to calculate drift) */
Benny Prijono69d9d192006-05-21 19:00:28 +0000212 strm_data->last_timestamp = timestamp;
213
214 if (strm_data->last_called.u64 == 0) {
215 pj_get_timestamp(&strm_data->last_called);
Benny Prijono6a61c222006-05-22 10:28:44 +0000216 /* Init min_delay to one frame */
Benny Prijono69d9d192006-05-21 19:00:28 +0000217 strm_data->min_delay = test_data->samples_per_frame * 1000000 /
218 test_data->clock_rate;
219 strm_data->first_timestamp = timestamp;
220
221 } else if (strm_data->counter <= MAX_DELAY_COUNTER) {
222 pj_timestamp now;
223 unsigned delay;
224
225 pj_get_timestamp(&now);
Benny Prijono6a61c222006-05-22 10:28:44 +0000226
227 /* Calculate frame interval */
Benny Prijono69d9d192006-05-21 19:00:28 +0000228 delay = pj_elapsed_usec(&strm_data->last_called, &now);
229 if (delay < strm_data->min_delay)
230 strm_data->min_delay = delay;
231 if (delay > strm_data->max_delay)
232 strm_data->max_delay = delay;
233
234 strm_data->last_called = now;
235
Benny Prijono6a61c222006-05-22 10:28:44 +0000236 /* Save the frame interval for later calculation */
Benny Prijono69d9d192006-05-21 19:00:28 +0000237 strm_data->delay[strm_data->counter] = delay;
238 ++strm_data->counter;
Benny Prijono6a61c222006-05-22 10:28:44 +0000239
240 } else {
241
242 /* No space, can't take anymore frames */
243 test_data->running = 0;
244
Benny Prijono69d9d192006-05-21 19:00:28 +0000245 }
246
Benny Prijonod7443932008-01-04 18:00:11 +0000247 pj_mutex_unlock(test_data->mutex);
Benny Prijono69d9d192006-05-21 19:00:28 +0000248 return PJ_SUCCESS;
249}
250
251static void app_perror(const char *title, pj_status_t status)
252{
253 char errmsg[PJ_ERR_MSG_SIZE];
254
255 pj_strerror(status, errmsg, sizeof(errmsg));
256 printf( "%s: %s (err=%d)\n",
257 title, errmsg, status);
258}
259
260
261static void print_stream_data(const char *title,
262 struct test_data *test_data,
263 struct stream_data *strm_data,
264 int verbose)
265{
266 unsigned i, dur;
Benny Prijono959df2a2006-05-22 10:48:11 +0000267 int ptime;
Benny Prijono6a61c222006-05-22 10:28:44 +0000268 unsigned min_jitter, max_jitter, sum_jitter, avg_jitter=0;
Benny Prijono69d9d192006-05-21 19:00:28 +0000269
270 PJ_LOG(3,(THIS_FILE, " %s stream report:", title));
271
272 /* Check that frames are captured/played */
273 if (strm_data->counter == 0) {
274 PJ_LOG(1,(THIS_FILE, " Error: no frames are captured/played!"));
275 test_data->has_error = 1;
276 return;
277 }
278
279 /* Duration */
280 dur = (strm_data->counter+1) * test_data->samples_per_frame * 1000 /
281 test_data->clock_rate;
282 PJ_LOG(3,(THIS_FILE, " Duration: %ds.%03d",
283 dur/1000, dur%1000));
284
285 /* Frame interval */
286 if (strm_data->max_delay - strm_data->min_delay < WARN_JITTER_USEC) {
287 PJ_LOG(3,(THIS_FILE,
288 " Frame interval: min=%d.%03dms, max=%d.%03dms",
289 strm_data->min_delay/1000, strm_data->min_delay%1000,
290 strm_data->max_delay/1000, strm_data->max_delay%1000));
291 } else {
292 test_data->has_error = 1;
293 PJ_LOG(2,(THIS_FILE,
294 " Frame interval: min=%d.%03dms, max=%d.%03dms",
295 strm_data->min_delay/1000, strm_data->min_delay%1000,
296 strm_data->max_delay/1000, strm_data->max_delay%1000));
297 }
298
299 if (verbose) {
300 unsigned i;
301 unsigned decor = pj_log_get_decor();
302
303 PJ_LOG(3,(THIS_FILE, " Dumping frame delays:"));
304
305 pj_log_set_decor(0);
306 for (i=0; i<strm_data->counter; ++i)
307 PJ_LOG(3,(THIS_FILE, " %d.%03d", strm_data->delay[i]/1000,
308 strm_data->delay[i]%1000));
309 PJ_LOG(3,(THIS_FILE, "\r\n"));
310 pj_log_set_decor(decor);
311 }
312
Benny Prijono959df2a2006-05-22 10:48:11 +0000313 /* Calculate frame ptime in usec */
314 ptime = test_data->samples_per_frame * 1000000 /
315 test_data->clock_rate;
316
Benny Prijono69d9d192006-05-21 19:00:28 +0000317 /* Calculate jitter */
318 min_jitter = 0xFFFFF;
319 max_jitter = 0;
Benny Prijono6a61c222006-05-22 10:28:44 +0000320 sum_jitter = 0;
Benny Prijono69d9d192006-05-21 19:00:28 +0000321
322 for (i=1; i<strm_data->counter; ++i) {
Benny Prijono959df2a2006-05-22 10:48:11 +0000323 int jitter1, jitter2, jitter;
324
325 /* jitter1 is interarrival difference */
326 jitter1 = strm_data->delay[i] - strm_data->delay[i-1];
327 if (jitter1 < 0) jitter1 = -jitter1;
Benny Prijono69d9d192006-05-21 19:00:28 +0000328
Benny Prijono959df2a2006-05-22 10:48:11 +0000329 /* jitter2 is difference between actual and scheduled arrival.
330 * This is intended to capture situation when frames are coming
331 * instantaneously, which will calculate as zero jitter with
332 * jitter1 calculation.
333 */
334 jitter2 = ptime - strm_data->delay[i];
335 if (jitter2 < 0) jitter2 = -jitter2;
336
337 /* Set jitter as the maximum of the two jitter calculations.
338 * This is intended to show the worst result.
339 */
340 jitter = (jitter1>jitter2) ? jitter1 : jitter2;
341
342 /* Calculate min, max, avg jitter */
Benny Prijono69d9d192006-05-21 19:00:28 +0000343 if (jitter < (int)min_jitter) min_jitter = jitter;
344 if (jitter > (int)max_jitter) max_jitter = jitter;
345
Benny Prijono6a61c222006-05-22 10:28:44 +0000346 sum_jitter += jitter;
Benny Prijono69d9d192006-05-21 19:00:28 +0000347 }
Benny Prijono6a61c222006-05-22 10:28:44 +0000348
349 avg_jitter = (sum_jitter) / (strm_data->counter - 1);
350
Benny Prijono69d9d192006-05-21 19:00:28 +0000351 if (max_jitter < WARN_JITTER_USEC) {
352 PJ_LOG(3,(THIS_FILE,
353 " Jitter: min=%d.%03dms, avg=%d.%03dms, max=%d.%03dms",
354 min_jitter/1000, min_jitter%1000,
355 avg_jitter/1000, avg_jitter%1000,
356 max_jitter/1000, max_jitter%1000));
357 } else {
358 test_data->has_error = 1;
359 PJ_LOG(2,(THIS_FILE,
360 " Jitter: min=%d.%03dms, avg=%d.%03dms, max=%d.%03dms",
361 min_jitter/1000, min_jitter%1000,
362 avg_jitter/1000, avg_jitter%1000,
363 max_jitter/1000, max_jitter%1000));
364 }
365}
366
367
Benny Prijonod7443932008-01-04 18:00:11 +0000368static int perform_test(pj_pool_t *pool, int dev_id, pjmedia_dir dir,
Benny Prijono69d9d192006-05-21 19:00:28 +0000369 unsigned clock_rate, unsigned samples_per_frame,
370 unsigned nchannel, int verbose)
371{
372 pj_status_t status = PJ_SUCCESS;
373 pjmedia_snd_stream *strm;
374 struct test_data test_data;
Benny Prijono5807f2c2006-11-29 23:12:26 +0000375 pjmedia_snd_stream_info si;
Benny Prijonod7443932008-01-04 18:00:11 +0000376
Benny Prijono69d9d192006-05-21 19:00:28 +0000377 /*
378 * Init test parameters
379 */
Benny Prijonoac623b32006-07-03 15:19:31 +0000380 pj_bzero(&test_data, sizeof(test_data));
Benny Prijono69d9d192006-05-21 19:00:28 +0000381 test_data.dir = dir;
382 test_data.clock_rate = clock_rate;
383 test_data.samples_per_frame = samples_per_frame;
384 test_data.channel_count = nchannel;
385
Benny Prijonod7443932008-01-04 18:00:11 +0000386 pj_mutex_create_simple(pool, "sndtest", &test_data.mutex);
387
Benny Prijono69d9d192006-05-21 19:00:28 +0000388 /*
389 * Open device.
390 */
Benny Prijono69d9d192006-05-21 19:00:28 +0000391 if (dir == PJMEDIA_DIR_CAPTURE) {
392 status = pjmedia_snd_open_rec( dev_id, clock_rate, nchannel,
393 samples_per_frame, 16, &rec_cb,
394 &test_data, &strm);
395 } else if (dir == PJMEDIA_DIR_PLAYBACK) {
396 status = pjmedia_snd_open_player( dev_id, clock_rate, nchannel,
397 samples_per_frame, 16, &play_cb,
398 &test_data, &strm);
399 } else {
400 status = pjmedia_snd_open( dev_id, dev_id, clock_rate, nchannel,
401 samples_per_frame, 16, &rec_cb, &play_cb,
402 &test_data, &strm);
403 }
404
405 if (status != PJ_SUCCESS) {
406 app_perror("Unable to open device for capture", status);
407 return status;
408 }
409
Benny Prijono5807f2c2006-11-29 23:12:26 +0000410 pjmedia_snd_stream_get_info(strm, &si);
411 if (si.play_id >= 0) {
412 PJ_LOG(3,(THIS_FILE, "Testing playback device %s",
413 pjmedia_snd_get_dev_info(si.play_id)->name));
414 }
415 if (si.rec_id >= 0) {
416 PJ_LOG(3,(THIS_FILE, "Testing capture device %s",
417 pjmedia_snd_get_dev_info(si.rec_id)->name));
418 }
419
Benny Prijono69d9d192006-05-21 19:00:28 +0000420 /* Sleep for a while to let sound device "settles" */
Benny Prijono6a61c222006-05-22 10:28:44 +0000421 pj_thread_sleep(200);
Benny Prijono69d9d192006-05-21 19:00:28 +0000422
423
424 /*
425 * Start the stream.
426 */
427 status = pjmedia_snd_stream_start(strm);
428 if (status != PJ_SUCCESS) {
429 app_perror("Unable to start capture stream", status);
430 return status;
431 }
432
Benny Prijono6a61c222006-05-22 10:28:44 +0000433 PJ_LOG(3,(THIS_FILE,
434 " Please wait while test is in progress (~%d secs)..",
435 (DURATION+SKIP_DURATION)/1000));
436
437 /* Let the stream runs for few msec/sec to get stable result.
Benny Prijono69d9d192006-05-21 19:00:28 +0000438 * (capture normally begins with frames available simultaneously).
439 */
Benny Prijono6a61c222006-05-22 10:28:44 +0000440 pj_thread_sleep(SKIP_DURATION);
Benny Prijono69d9d192006-05-21 19:00:28 +0000441
442
443 /* Begin gather data */
444 test_data.running = 1;
445
446 /*
447 * Let the test runs for a while.
448 */
Benny Prijono69d9d192006-05-21 19:00:28 +0000449 pj_thread_sleep(DURATION);
450
451
452 /*
453 * Close stream.
454 */
455 test_data.running = 0;
456 pjmedia_snd_stream_close(strm);
457
458
459 /*
460 * Print results.
461 */
462 PJ_LOG(3,(THIS_FILE, " Dumping results:"));
463
464 PJ_LOG(3,(THIS_FILE, " Parameters: clock rate=%dHz, %d samples/frame",
465 clock_rate, samples_per_frame));
466
467 if (dir & PJMEDIA_DIR_PLAYBACK)
468 print_stream_data("Playback", &test_data, &test_data.playback_data,
469 verbose);
470 if (dir & PJMEDIA_DIR_CAPTURE)
471 print_stream_data("Capture", &test_data, &test_data.capture_data,
472 verbose);
473
474 /* Check drifting */
475 if (dir == PJMEDIA_DIR_CAPTURE_PLAYBACK) {
476 int end_diff, start_diff, drift;
477
478 end_diff = test_data.capture_data.last_timestamp -
479 test_data.playback_data.last_timestamp;
480 start_diff = test_data.capture_data.first_timestamp-
481 test_data.playback_data.first_timestamp;
Benny Prijonod7443932008-01-04 18:00:11 +0000482 drift = end_diff > start_diff? end_diff - start_diff :
483 start_diff - end_diff;
Benny Prijono69d9d192006-05-21 19:00:28 +0000484
485 PJ_LOG(3,(THIS_FILE, " Checking for clock drifts:"));
486
487 /* Allow one frame tolerance for clock drift detection */
488 if (drift < (int)samples_per_frame) {
489 PJ_LOG(3,(THIS_FILE, " No clock drifts is detected"));
490 } else {
491 const char *which = (drift<0 ? "slower" : "faster");
492 unsigned msec_dur;
493
494 if (drift < 0) drift = -drift;
495
496
497 msec_dur = (test_data.capture_data.last_timestamp -
498 test_data.capture_data.first_timestamp) * 1000 /
499 test_data.clock_rate;
500
501 PJ_LOG(2,(THIS_FILE,
502 " Sound capture is %d samples %s than playback "
Benny Prijono6a61c222006-05-22 10:28:44 +0000503 "at the end of the test (average is %d samples"
Benny Prijono69d9d192006-05-21 19:00:28 +0000504 " per second)",
505 drift, which,
506 drift * 1000 / msec_dur));
507
508 }
509 }
510
511 if (test_data.has_error == 0) {
512 PJ_LOG(3,(THIS_FILE, " Test completed, sound device looks okay."));
513 return 0;
514 } else {
515 PJ_LOG(2,(THIS_FILE, " Test completed with some warnings"));
516 return 1;
517 }
518}
519
520
521int main(int argc, char *argv[])
522{
523 pj_caching_pool cp;
Benny Prijonod7443932008-01-04 18:00:11 +0000524 pj_pool_t *pool;
Benny Prijono69d9d192006-05-21 19:00:28 +0000525 pjmedia_endpt *med_endpt;
526 int id = -1, verbose = 0;
527 int clock_rate = 8000;
528 int frame = -1;
529 int channel = 1;
530 struct pj_getopt_option long_options[] = {
531 { "id", 1, 0, 'i' },
532 { "rate", 1, 0, 'r' },
533 { "frame", 1, 0, 'f' },
534 { "channel", 1, 0, 'n' },
535 { "verbose", 0, 0, 'v' },
536 { "help", 0, 0, 'h' },
537 { NULL, 0, 0, 0 }
538 };
539 int c, option_index;
540
541
542 pj_status_t status;
543
544 /* Init pjlib */
545 status = pj_init();
546 PJ_ASSERT_RETURN(status==PJ_SUCCESS, 1);
547
548 /* Must create a pool factory before we can allocate any memory. */
549 pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);
550
Benny Prijonod7443932008-01-04 18:00:11 +0000551 /* Also create pool for misc purposes */
552 pool = pj_pool_create(&cp.factory, "sndtest", 1000, 1000, NULL);
553
Benny Prijono69d9d192006-05-21 19:00:28 +0000554 /*
555 * Initialize media endpoint.
556 * This will implicitly initialize PJMEDIA too.
557 */
558 status = pjmedia_endpt_create(&cp.factory, NULL, 1, &med_endpt);
559 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
560
561 /* Print devices */
562 enum_devices();
563
564 /* Parse options */
565 pj_optind = 0;
566 while((c=pj_getopt_long(argc,argv, "i:r:f:n:vh",
567 long_options, &option_index))!=-1)
568 {
569 switch (c) {
570 case 'i':
571 id = atoi(pj_optarg);
572 break;
573 case 'r':
574 clock_rate = atoi(pj_optarg);
575 break;
576 case 'f':
577 frame = atoi(pj_optarg);
578 break;
579 case 'n':
580 channel = atoi(pj_optarg);
581 break;
582 case 'v':
583 verbose = 1;
584 break;
585 case 'h':
586 puts(desc);
587 return 0;
588 break;
589 default:
590 printf("Error: invalid options %s\n", argv[pj_optind-1]);
591 puts(desc);
592 return 1;
593 }
594 }
595
596 if (pj_optind != argc) {
597 printf("Error: invalid options\n");
598 puts(desc);
599 return 1;
600 }
601
602 if (!verbose)
603 pj_log_set_level(3);
604
605 if (frame == -1)
606 frame = 10 * clock_rate / 1000;
607
608
Benny Prijonod7443932008-01-04 18:00:11 +0000609 status = perform_test(pool, id, PJMEDIA_DIR_CAPTURE_PLAYBACK,
Benny Prijono69d9d192006-05-21 19:00:28 +0000610 clock_rate, frame, channel, verbose);
Benny Prijono69d9d192006-05-21 19:00:28 +0000611
Benny Prijonod7443932008-01-04 18:00:11 +0000612 pjmedia_endpt_destroy(med_endpt);
613 pj_pool_release(pool);
614 pj_caching_pool_destroy(&cp);
615 pj_shutdown();
Benny Prijono69d9d192006-05-21 19:00:28 +0000616
Benny Prijonod7443932008-01-04 18:00:11 +0000617 return status == PJ_SUCCESS ? 0 : 1;
Benny Prijono69d9d192006-05-21 19:00:28 +0000618}
619
620