blob: 18b8895134ec3252a18f6d73efbf14e2f479c61c [file] [log] [blame]
Benny Prijonoff64ccf2009-07-16 11:37:15 +00001/* $Id$ */
2/*
3 * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
4 *
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 */
Benny Prijono7b40c6c2009-07-16 10:36:48 +000019#include "systest.h"
20#include "gui.h"
21
22#define THIS_FILE "systest.c"
23
24unsigned test_item_count;
25test_item_t test_items[SYSTEST_MAX_TEST];
Sauw Minga7487622010-03-30 11:42:51 +000026char doc_path[PATH_LENGTH] = {0};
27char res_path[PATH_LENGTH] = {0};
28char fpath[PATH_LENGTH];
Benny Prijono7b40c6c2009-07-16 10:36:48 +000029
30#define USER_ERROR "User used said not okay"
31
32static void systest_wizard(void);
33static void systest_list_audio_devs(void);
34static void systest_display_settings(void);
35static void systest_play_tone(void);
36static void systest_play_wav1(void);
37static void systest_play_wav2(void);
38static void systest_rec_audio(void);
39static void systest_audio_test(void);
40static void systest_latency_test(void);
Nanang Izzuddin160a49c2010-09-07 10:00:49 +000041static void systest_aec_test(void);
Benny Prijono7b40c6c2009-07-16 10:36:48 +000042static void exit_app(void);
43
44/* Menus */
45static gui_menu menu_exit = { "Exit", &exit_app };
46
47static gui_menu menu_wizard = { "Run test wizard", &systest_wizard };
48static gui_menu menu_playtn = { "Play Tone", &systest_play_tone };
49static gui_menu menu_playwv1 = { "Play WAV File1", &systest_play_wav1 };
50static gui_menu menu_playwv2 = { "Play WAV File2", &systest_play_wav2 };
51static gui_menu menu_recaud = { "Record Audio", &systest_rec_audio };
52static gui_menu menu_audtest = { "Device Test", &systest_audio_test };
53static gui_menu menu_calclat = { "Latency Test", &systest_latency_test };
Nanang Izzuddin160a49c2010-09-07 10:00:49 +000054static gui_menu menu_sndaec = { "AEC/AES Test", &systest_aec_test };
Benny Prijono7b40c6c2009-07-16 10:36:48 +000055
56static gui_menu menu_listdev = { "View Devices", &systest_list_audio_devs };
57static gui_menu menu_getsets = { "View Settings", &systest_display_settings };
58
59static gui_menu menu_tests = {
60 "Tests", NULL,
Nanang Izzuddin160a49c2010-09-07 10:00:49 +000061 10,
Benny Prijono7b40c6c2009-07-16 10:36:48 +000062 {
63 &menu_wizard,
64 &menu_audtest,
65 &menu_playtn,
66 &menu_playwv1,
67 &menu_playwv2,
68 &menu_recaud,
69 &menu_calclat,
Nanang Izzuddin160a49c2010-09-07 10:00:49 +000070 &menu_sndaec,
Benny Prijono7b40c6c2009-07-16 10:36:48 +000071 NULL,
72 &menu_exit
73 }
74};
75
76static gui_menu menu_options = {
77 "Options", NULL,
78 2,
79 {
80 &menu_listdev,
81 &menu_getsets,
82 }
83};
84
85static gui_menu root_menu = {
86 "Root", NULL, 2, {&menu_tests, &menu_options}
87};
88
89/*****************************************************************/
90
Sauw Minga7487622010-03-30 11:42:51 +000091PJ_INLINE(char *) add_path(const char *path, const char *fname)
92{
93 strncpy(fpath, path, PATH_LENGTH);
94 strncat(fpath, fname, PATH_LENGTH);
95 return fpath;
96}
97
Benny Prijono7b40c6c2009-07-16 10:36:48 +000098static void exit_app(void)
99{
Sauw Minga7487622010-03-30 11:42:51 +0000100 systest_save_result(add_path(doc_path, RESULT_OUT_PATH));
Benny Prijono7b40c6c2009-07-16 10:36:48 +0000101 gui_destroy();
102}
103
104
105#include <pjsua-lib/pjsua.h>
106#include <pjmedia_audiodev.h>
107
108typedef struct systest_t
109{
110 pjsua_config ua_cfg;
111 pjsua_media_config media_cfg;
112 pjmedia_aud_dev_index rec_id;
113 pjmedia_aud_dev_index play_id;
114} systest_t;
115
116static systest_t systest;
117static char textbuf[600];
118
Benny Prijonoadca6fd2010-05-10 09:05:19 +0000119/* Device ID to test */
120int systest_cap_dev_id = PJMEDIA_AUD_DEFAULT_CAPTURE_DEV;
121int systest_play_dev_id = PJMEDIA_AUD_DEFAULT_PLAYBACK_DEV;
122
Benny Prijono7b40c6c2009-07-16 10:36:48 +0000123static void systest_perror(const char *title, pj_status_t status)
124{
125 char errmsg[PJ_ERR_MSG_SIZE];
126 char themsg[PJ_ERR_MSG_SIZE + 100];
127
128 if (status != PJ_SUCCESS)
129 pj_strerror(status, errmsg, sizeof(errmsg));
130 else
131 errmsg[0] = '\0';
132
133 strcpy(themsg, title);
Benny Prijonoc6f0e1a2009-11-08 03:35:41 +0000134 strncat(themsg, errmsg, sizeof(themsg)-1);
Benny Prijono7b40c6c2009-07-16 10:36:48 +0000135 themsg[sizeof(themsg)-1] = '\0';
136
137 gui_msgbox("Error", themsg, WITH_OK);
138}
139
140test_item_t *systest_alloc_test_item(const char *title)
141{
142 test_item_t *ti;
143
144 if (test_item_count == SYSTEST_MAX_TEST) {
145 gui_msgbox("Error", "You have done too many tests", WITH_OK);
146 return NULL;
147 }
148
149 ti = &test_items[test_item_count++];
150 pj_bzero(ti, sizeof(*ti));
151 pj_ansi_strcpy(ti->title, title);
152
153 return ti;
154}
155
156/*****************************************************************************
157 * test: play simple ringback tone and hear it
158 */
159static void systest_play_tone(void)
160{
161 /* Ringtones */
162 #define RINGBACK_FREQ1 440 /* 400 */
163 #define RINGBACK_FREQ2 480 /* 450 */
164 #define RINGBACK_ON 3000 /* 400 */
165 #define RINGBACK_OFF 4000 /* 200 */
166 #define RINGBACK_CNT 1 /* 2 */
167 #define RINGBACK_INTERVAL 4000 /* 2000 */
168
169 unsigned i, samples_per_frame;
170 pjmedia_tone_desc tone[RINGBACK_CNT];
171 pj_pool_t *pool = NULL;
172 pjmedia_port *ringback_port = NULL;
173 enum gui_key key;
174 int ringback_slot = -1;
175 test_item_t *ti;
176 pj_str_t name;
177 const char *title = "Audio Tone Playback Test";
178 pj_status_t status;
179
180 ti = systest_alloc_test_item(title);
181 if (!ti)
182 return;
183
184 key = gui_msgbox(title,
185 "This test will play simple ringback tone to "
186 "the speaker. Please listen carefully for audio "
187 "impairments such as stutter. You may need "
188 "to let this test running for a while to "
189 "make sure that everything is okay. Press "
190 "OK to start, CANCEL to skip",
191 WITH_OKCANCEL);
192 if (key != KEY_OK) {
193 ti->skipped = PJ_TRUE;
194 return;
195 }
196
197 PJ_LOG(3,(THIS_FILE, "Running %s", title));
198
199 pool = pjsua_pool_create("ringback", 512, 512);
200 samples_per_frame = systest.media_cfg.audio_frame_ptime *
201 systest.media_cfg.clock_rate *
202 systest.media_cfg.channel_count / 1000;
203
204 /* Ringback tone (call is ringing) */
205 name = pj_str("ringback");
206 status = pjmedia_tonegen_create2(pool, &name,
207 systest.media_cfg.clock_rate,
208 systest.media_cfg.channel_count,
209 samples_per_frame,
210 16, PJMEDIA_TONEGEN_LOOP,
211 &ringback_port);
212 if (status != PJ_SUCCESS)
213 goto on_return;
214
215 pj_bzero(&tone, sizeof(tone));
216 for (i=0; i<RINGBACK_CNT; ++i) {
217 tone[i].freq1 = RINGBACK_FREQ1;
218 tone[i].freq2 = RINGBACK_FREQ2;
219 tone[i].on_msec = RINGBACK_ON;
220 tone[i].off_msec = RINGBACK_OFF;
221 }
222 tone[RINGBACK_CNT-1].off_msec = RINGBACK_INTERVAL;
223
224 status = pjmedia_tonegen_play(ringback_port, RINGBACK_CNT, tone,
225 PJMEDIA_TONEGEN_LOOP);
226 if (status != PJ_SUCCESS)
227 goto on_return;
228
229 status = pjsua_conf_add_port(pool, ringback_port, &ringback_slot);
230 if (status != PJ_SUCCESS)
231 goto on_return;
232
233 status = pjsua_conf_connect(ringback_slot, 0);
234 if (status != PJ_SUCCESS)
235 goto on_return;
236
237 key = gui_msgbox(title,
238 "Ringback tone should be playing now in the "
239 "speaker. Press OK to stop. ", WITH_OK);
240
241 status = PJ_SUCCESS;
242
243on_return:
244 if (ringback_slot != -1)
245 pjsua_conf_remove_port(ringback_slot);
246 if (ringback_port)
247 pjmedia_port_destroy(ringback_port);
248 if (pool)
249 pj_pool_release(pool);
250
251 if (status != PJ_SUCCESS) {
252 systest_perror("Sorry we encounter error when initializing "
253 "the tone generator: ", status);
254 ti->success = PJ_FALSE;
255 pj_strerror(status, ti->reason, sizeof(ti->reason));
256 } else {
257 key = gui_msgbox(title, "Is the audio okay?", WITH_YESNO);
258 ti->success = (key == KEY_YES);
259 if (!ti->success)
260 pj_ansi_strcpy(ti->reason, USER_ERROR);
261 }
262 return;
263}
264
Benny Prijonoc6f0e1a2009-11-08 03:35:41 +0000265/* Util: create file player, each time trying different paths until we get
266 * the file.
267 */
268static pj_status_t create_player(unsigned path_cnt, const char *paths[],
269 pjsua_player_id *p_id)
270{
271 pj_str_t name;
272 pj_status_t status = PJ_ENOTFOUND;
273 unsigned i;
274
275 for (i=0; i<path_cnt; ++i) {
276 status = pjsua_player_create(pj_cstr(&name, paths[i]), 0, p_id);
277 if (status == PJ_SUCCESS)
278 return PJ_SUCCESS;
279 }
280 return status;
281}
Benny Prijono7b40c6c2009-07-16 10:36:48 +0000282
283/*****************************************************************************
284 * test: play WAV file
285 */
Benny Prijonoc6f0e1a2009-11-08 03:35:41 +0000286static void systest_play_wav(unsigned path_cnt, const char *paths[])
Benny Prijono7b40c6c2009-07-16 10:36:48 +0000287{
288 pjsua_player_id play_id = PJSUA_INVALID_ID;
289 enum gui_key key;
290 test_item_t *ti;
Benny Prijono7b40c6c2009-07-16 10:36:48 +0000291 const char *title = "WAV File Playback Test";
292 pj_status_t status;
293
294 ti = systest_alloc_test_item(title);
295 if (!ti)
296 return;
297
298 pj_ansi_snprintf(textbuf, sizeof(textbuf),
299 "This test will play %s file to "
300 "the speaker. Please listen carefully for audio "
301 "impairments such as stutter. Let this test run "
302 "for a while to make sure that everything is okay."
303 " Press OK to start, CANCEL to skip",
Benny Prijonoc6f0e1a2009-11-08 03:35:41 +0000304 paths[0]);
Benny Prijono7b40c6c2009-07-16 10:36:48 +0000305
306 key = gui_msgbox(title, textbuf,
307 WITH_OKCANCEL);
308 if (key != KEY_OK) {
309 ti->skipped = PJ_TRUE;
310 return;
311 }
312
313 PJ_LOG(3,(THIS_FILE, "Running %s", title));
314
315 /* WAV port */
Benny Prijonoc6f0e1a2009-11-08 03:35:41 +0000316 status = create_player(path_cnt, paths, &play_id);
Benny Prijono7b40c6c2009-07-16 10:36:48 +0000317 if (status != PJ_SUCCESS)
318 goto on_return;
319
320 status = pjsua_conf_connect(pjsua_player_get_conf_port(play_id), 0);
321 if (status != PJ_SUCCESS)
322 goto on_return;
323
324 key = gui_msgbox(title,
325 "WAV file should be playing now in the "
326 "speaker. Press OK to stop. ", WITH_OK);
327
328 status = PJ_SUCCESS;
329
330on_return:
331 if (play_id != -1)
332 pjsua_player_destroy(play_id);
333
334 if (status != PJ_SUCCESS) {
335 systest_perror("Sorry we've encountered error", status);
336 ti->success = PJ_FALSE;
337 pj_strerror(status, ti->reason, sizeof(ti->reason));
338 } else {
339 key = gui_msgbox(title, "Is the audio okay?", WITH_YESNO);
340 ti->success = (key == KEY_YES);
341 if (!ti->success)
342 pj_ansi_strcpy(ti->reason, USER_ERROR);
343 }
344 return;
345}
346
347static void systest_play_wav1(void)
348{
Sauw Minga7487622010-03-30 11:42:51 +0000349 const char *paths[] = { add_path(res_path, WAV_PLAYBACK_PATH),
Benny Prijonoc6f0e1a2009-11-08 03:35:41 +0000350 ALT_PATH1 WAV_PLAYBACK_PATH };
351 systest_play_wav(PJ_ARRAY_SIZE(paths), paths);
Benny Prijono7b40c6c2009-07-16 10:36:48 +0000352}
353
354static void systest_play_wav2(void)
355{
Sauw Minga7487622010-03-30 11:42:51 +0000356 const char *paths[] = { add_path(res_path, WAV_TOCK8_PATH),
Benny Prijonoc6f0e1a2009-11-08 03:35:41 +0000357 ALT_PATH1 WAV_TOCK8_PATH};
358 systest_play_wav(PJ_ARRAY_SIZE(paths), paths);
Benny Prijono7b40c6c2009-07-16 10:36:48 +0000359}
360
361
362/*****************************************************************************
363 * test: record audio
364 */
365static void systest_rec_audio(void)
366{
Sauw Minga7487622010-03-30 11:42:51 +0000367 const pj_str_t filename = pj_str(add_path(doc_path, WAV_REC_OUT_PATH));
Benny Prijono7b40c6c2009-07-16 10:36:48 +0000368 pj_pool_t *pool = NULL;
369 enum gui_key key;
370 pjsua_recorder_id rec_id = PJSUA_INVALID_ID;
371 pjsua_player_id play_id = PJSUA_INVALID_ID;
372 pjsua_conf_port_id rec_slot = PJSUA_INVALID_ID;
373 pjsua_conf_port_id play_slot = PJSUA_INVALID_ID;
374 pj_status_t status = PJ_SUCCESS;
375 const char *title = "Audio Recording";
376 test_item_t *ti;
377
378 ti = systest_alloc_test_item(title);
379 if (!ti)
380 return;
381
382 key = gui_msgbox(title,
383 "This test will allow you to record audio "
384 "from the microphone, and playback the "
385 "audio to the speaker. Press OK to start recording, "
386 "CANCEL to skip.",
387 WITH_OKCANCEL);
388 if (key != KEY_OK) {
389 ti->skipped = PJ_TRUE;
390 return;
391 }
392
393 PJ_LOG(3,(THIS_FILE, "Running %s", title));
394
395 pool = pjsua_pool_create("rectest", 512, 512);
396
397 status = pjsua_recorder_create(&filename, 0, NULL, -1, 0, &rec_id);
398 if (status != PJ_SUCCESS)
399 goto on_return;
400
401 rec_slot = pjsua_recorder_get_conf_port(rec_id);
402
403 status = pjsua_conf_connect(0, rec_slot);
404 if (status != PJ_SUCCESS)
405 goto on_return;
406
407 key = gui_msgbox(title,
408 "Recording is in progress now, please say "
409 "something in the microphone. Press OK "
410 "to stop recording", WITH_OK);
411
412 pjsua_conf_disconnect(0, rec_slot);
413 rec_slot = PJSUA_INVALID_ID;
414 pjsua_recorder_destroy(rec_id);
415 rec_id = PJSUA_INVALID_ID;
416
Benny Prijono7b40c6c2009-07-16 10:36:48 +0000417 status = pjsua_player_create(&filename, 0, &play_id);
418 if (status != PJ_SUCCESS)
419 goto on_return;
420
421 play_slot = pjsua_player_get_conf_port(play_id);
422
423 status = pjsua_conf_connect(play_slot, 0);
424 if (status != PJ_SUCCESS)
425 goto on_return;
426
427 key = gui_msgbox(title,
Benny Prijono258dc212009-07-17 11:37:42 +0000428 "Recording has been stopped. "
Benny Prijono7b40c6c2009-07-16 10:36:48 +0000429 "The recorded audio is being played now to "
430 "the speaker device, in a loop. Listen for "
431 "any audio impairments. Press OK to stop.",
432 WITH_OK);
433
434on_return:
435 if (rec_slot != PJSUA_INVALID_ID)
436 pjsua_conf_disconnect(0, rec_slot);
437 if (rec_id != PJSUA_INVALID_ID)
438 pjsua_recorder_destroy(rec_id);
439 if (play_slot != PJSUA_INVALID_ID)
440 pjsua_conf_disconnect(play_slot, 0);
441 if (play_id != PJSUA_INVALID_ID)
442 pjsua_player_destroy(play_id);
443 if (pool)
444 pj_pool_release(pool);
445
446 if (status != PJ_SUCCESS) {
447 systest_perror("Sorry we encountered an error: ", status);
448 ti->success = PJ_FALSE;
449 pj_strerror(status, ti->reason, sizeof(ti->reason));
450 } else {
451 key = gui_msgbox(title, "Is the audio okay?", WITH_YESNO);
452 ti->success = (key == KEY_YES);
453 if (!ti->success) {
454 pj_ansi_snprintf(textbuf, sizeof(textbuf),
455 "You will probably need to copy the recorded "
456 "WAV file %s to a desktop computer and analyze "
457 "it, to find out whether it's a recording "
458 "or playback problem.",
459 WAV_REC_OUT_PATH);
460 gui_msgbox(title, textbuf, WITH_OK);
461 pj_ansi_strcpy(ti->reason, USER_ERROR);
462 }
463 }
464}
465
466
467/****************************************************************************
468 * test: audio system test
469 */
470static void systest_audio_test(void)
471{
472 enum {
473 GOOD_MAX_INTERVAL = 5,
474 };
475 const pjmedia_dir dir = PJMEDIA_DIR_CAPTURE_PLAYBACK;
476 pjmedia_aud_param param;
477 pjmedia_aud_test_results result;
478 int textbufpos;
479 enum gui_key key;
480 unsigned problem_count = 0;
481 const char *problems[16];
482 char drifttext[120];
483 test_item_t *ti;
484 const char *title = "Audio Device Test";
485 pj_status_t status;
486
487 ti = systest_alloc_test_item(title);
488 if (!ti)
489 return;
490
491 key = gui_msgbox(title,
492 "This will run an automated test for about "
493 "ten seconds or so, and display some "
494 "statistics about your sound device. "
495 "Please don't do anything until the test completes. "
496 "Press OK to start, or CANCEL to skip this test.",
497 WITH_OKCANCEL);
498 if (key != KEY_OK) {
499 ti->skipped = PJ_TRUE;
500 return;
501 }
502
503 PJ_LOG(3,(THIS_FILE, "Running %s", title));
504
505 /* Disable sound device in pjsua first */
506 pjsua_set_no_snd_dev();
507
508 /* Setup parameters */
509 status = pjmedia_aud_dev_default_param(systest.play_id, &param);
510 if (status != PJ_SUCCESS) {
511 systest_perror("Sorry we had error in pjmedia_aud_dev_default_param()", status);
512 pjsua_set_snd_dev(systest.rec_id, systest.play_id);
513 ti->success = PJ_FALSE;
514 pj_strerror(status, ti->reason, sizeof(ti->reason));
515 ti->reason[sizeof(ti->reason)-1] = '\0';
516 return;
517 }
518
519 param.dir = dir;
520 param.rec_id = systest.rec_id;
521 param.play_id = systest.play_id;
Benny Prijono258dc212009-07-17 11:37:42 +0000522 param.clock_rate = systest.media_cfg.snd_clock_rate;
Benny Prijono7b40c6c2009-07-16 10:36:48 +0000523 param.channel_count = systest.media_cfg.channel_count;
524 param.samples_per_frame = param.clock_rate * param.channel_count *
525 systest.media_cfg.audio_frame_ptime / 1000;
526
527 /* Latency settings */
528 param.flags |= (PJMEDIA_AUD_DEV_CAP_INPUT_LATENCY |
529 PJMEDIA_AUD_DEV_CAP_OUTPUT_LATENCY);
530 param.input_latency_ms = systest.media_cfg.snd_rec_latency;
531 param.output_latency_ms = systest.media_cfg.snd_play_latency;
532
533 /* Run the test */
534 status = pjmedia_aud_test(&param, &result);
535 if (status != PJ_SUCCESS) {
536 systest_perror("Sorry we encountered error with the test", status);
537 pjsua_set_snd_dev(systest.rec_id, systest.play_id);
538 ti->success = PJ_FALSE;
539 pj_strerror(status, ti->reason, sizeof(ti->reason));
540 ti->reason[sizeof(ti->reason)-1] = '\0';
541 return;
542 }
543
544 /* Restore pjsua sound device */
545 pjsua_set_snd_dev(systest.rec_id, systest.play_id);
546
547 /* Analyze the result! */
548 strcpy(textbuf, "Here are the audio statistics:\r\n");
549 textbufpos = strlen(textbuf);
550
551 if (result.rec.frame_cnt==0) {
552 problems[problem_count++] =
553 "No audio frames were captured from the microphone. "
554 "This means the audio device is not working properly.";
555 } else {
556 pj_ansi_snprintf(textbuf+textbufpos,
557 sizeof(textbuf)-textbufpos,
558 "Rec : interval (min/max/avg/dev)=\r\n"
559 " %u/%u/%u/%u (ms)\r\n"
560 " max burst=%u\r\n",
561 result.rec.min_interval,
562 result.rec.max_interval,
563 result.rec.avg_interval,
564 result.rec.dev_interval,
565 result.rec.max_burst);
566 textbufpos = strlen(textbuf);
567
568 if (result.rec.max_burst > GOOD_MAX_INTERVAL) {
569 problems[problem_count++] =
570 "Recording max burst is quite high";
571 }
572 }
573
574 if (result.play.frame_cnt==0) {
575 problems[problem_count++] =
576 "No audio frames were played to the speaker. "
577 "This means the audio device is not working properly.";
578 } else {
579 pj_ansi_snprintf(textbuf+textbufpos,
580 sizeof(textbuf)-textbufpos,
581 "Play: interval (min/max/avg/dev)=\r\n"
582 " %u/%u/%u/%u (ms)\r\n"
583 " burst=%u\r\n",
584 result.play.min_interval,
585 result.play.max_interval,
586 result.play.avg_interval,
587 result.play.dev_interval,
588 result.play.max_burst);
589 textbufpos = strlen(textbuf);
590
591 if (result.play.max_burst > GOOD_MAX_INTERVAL) {
592 problems[problem_count++] =
593 "Playback max burst is quite high";
594 }
595 }
596
597 if (result.rec_drift_per_sec) {
598 const char *which = result.rec_drift_per_sec>=0 ? "faster" : "slower";
599 unsigned drift = result.rec_drift_per_sec>=0 ?
600 result.rec_drift_per_sec :
601 -result.rec_drift_per_sec;
602
603 pj_ansi_snprintf(drifttext, sizeof(drifttext),
Benny Prijono258dc212009-07-17 11:37:42 +0000604 "Clock drifts detected. Capture "
605 "is %d samples/sec %s "
Benny Prijono7b40c6c2009-07-16 10:36:48 +0000606 "than the playback device",
607 drift, which);
608 problems[problem_count++] = drifttext;
609 }
610
611 if (problem_count == 0) {
612 pj_ansi_snprintf(textbuf+textbufpos,
613 sizeof(textbuf)-textbufpos,
614 "\r\nThe sound device seems to be okay!");
615 textbufpos = strlen(textbuf);
616
617 key = gui_msgbox("Audio Device Test", textbuf, WITH_OK);
618 } else {
619 unsigned i;
620
621 pj_ansi_snprintf(textbuf+textbufpos,
622 sizeof(textbuf)-textbufpos,
623 "There could be %d problem(s) with the "
624 "sound device:\r\n",
625 problem_count);
626 textbufpos = strlen(textbuf);
627
628 for (i=0; i<problem_count; ++i) {
629 pj_ansi_snprintf(textbuf+textbufpos,
630 sizeof(textbuf)-textbufpos,
631 " %d: %s\r\n", i+1, problems[i]);
632 textbufpos = strlen(textbuf);
633 }
634
635 key = gui_msgbox(title, textbuf, WITH_OK);
636 }
637
638 ti->success = PJ_TRUE;
639 pj_ansi_strncpy(ti->reason, textbuf, sizeof(ti->reason));
640 ti->reason[sizeof(ti->reason)-1] = '\0';
641}
642
643
644/****************************************************************************
645 * sound latency test
646 */
647static int calculate_latency(pj_pool_t *pool, pjmedia_port *wav,
648 unsigned *lat_sum, unsigned *lat_cnt,
649 unsigned *lat_min, unsigned *lat_max)
650{
651 pjmedia_frame frm;
652 short *buf;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000653 unsigned i, clock_rate, samples_per_frame, read, len;
Benny Prijono7b40c6c2009-07-16 10:36:48 +0000654 unsigned start_pos;
Benny Prijonodbf4cb92009-07-18 09:18:26 +0000655 pj_bool_t first;
Benny Prijono7b40c6c2009-07-16 10:36:48 +0000656 pj_status_t status;
657
658 *lat_sum = 0;
659 *lat_cnt = 0;
660 *lat_min = 10000;
661 *lat_max = 0;
662
Benny Prijonoc45d9512010-12-10 11:04:30 +0000663 samples_per_frame = PJMEDIA_PIA_SPF(&wav->info);
664 clock_rate = PJMEDIA_PIA_SRATE(&wav->info);
Benny Prijono7b40c6c2009-07-16 10:36:48 +0000665 frm.buf = pj_pool_alloc(pool, samples_per_frame * 2);
666 frm.size = samples_per_frame * 2;
667 len = pjmedia_wav_player_get_len(wav);
668 buf = pj_pool_alloc(pool, len + samples_per_frame);
669
670 /* Read the whole file */
671 read = 0;
672 while (read < len/2) {
673 status = pjmedia_port_get_frame(wav, &frm);
674 if (status != PJ_SUCCESS)
675 break;
676
677 pjmedia_copy_samples(buf+read, (short*)frm.buf, samples_per_frame);
678 read += samples_per_frame;
679 }
680
Benny Prijonoc45d9512010-12-10 11:04:30 +0000681 if (read < 2 * clock_rate) {
Benny Prijono7b40c6c2009-07-16 10:36:48 +0000682 systest_perror("The WAV file is too short", PJ_SUCCESS);
683 return -1;
684 }
685
Benny Prijonodbf4cb92009-07-18 09:18:26 +0000686 /* Zero the first 500ms to remove loud click noises
687 * (keypad press, etc.)
688 */
Benny Prijonoc45d9512010-12-10 11:04:30 +0000689 pjmedia_zero_samples(buf, clock_rate / 2);
Benny Prijonodbf4cb92009-07-18 09:18:26 +0000690
Benny Prijono7b40c6c2009-07-16 10:36:48 +0000691 /* Loop to calculate latency */
692 start_pos = 0;
Benny Prijonodbf4cb92009-07-18 09:18:26 +0000693 first = PJ_TRUE;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000694 while (start_pos < len/2 - clock_rate) {
Benny Prijono7b40c6c2009-07-16 10:36:48 +0000695 int max_signal = 0;
696 unsigned max_signal_pos = start_pos;
697 unsigned max_echo_pos = 0;
698 unsigned pos;
699 unsigned lat;
700
701 /* Get the largest signal in the next 0.7s */
Benny Prijonoc45d9512010-12-10 11:04:30 +0000702 for (i=start_pos; i<start_pos + clock_rate * 700 / 1000; ++i) {
Benny Prijono7b40c6c2009-07-16 10:36:48 +0000703 if (abs(buf[i]) > max_signal) {
704 max_signal = abs(buf[i]);
705 max_signal_pos = i;
706 }
707 }
708
709 /* Advance 10ms from max_signal_pos */
Benny Prijonoc45d9512010-12-10 11:04:30 +0000710 pos = max_signal_pos + 10 * clock_rate / 1000;
Benny Prijono7b40c6c2009-07-16 10:36:48 +0000711
712 /* Get the largest signal in the next 800ms */
713 max_signal = 0;
714 max_echo_pos = pos;
Benny Prijonoc45d9512010-12-10 11:04:30 +0000715 for (i=pos; i<pos+clock_rate * 8 / 10; ++i) {
Benny Prijono7b40c6c2009-07-16 10:36:48 +0000716 if (abs(buf[i]) > max_signal) {
717 max_signal = abs(buf[i]);
718 max_echo_pos = i;
719 }
720 }
721
Benny Prijonoc45d9512010-12-10 11:04:30 +0000722 lat = (max_echo_pos - max_signal_pos) * 1000 / clock_rate;
Benny Prijono7b40c6c2009-07-16 10:36:48 +0000723
Benny Prijono258dc212009-07-17 11:37:42 +0000724#if 0
Benny Prijono7b40c6c2009-07-16 10:36:48 +0000725 PJ_LOG(4,(THIS_FILE, "Signal at %dms, echo at %d ms, latency %d ms",
Benny Prijonoc45d9512010-12-10 11:04:30 +0000726 max_signal_pos * 1000 / clock_rate,
727 max_echo_pos * 1000 / clock_rate,
Benny Prijono7b40c6c2009-07-16 10:36:48 +0000728 lat));
729#endif
730
731 *lat_sum += lat;
732 (*lat_cnt)++;
733 if (lat < *lat_min)
734 *lat_min = lat;
735 if (lat > *lat_max)
736 *lat_max = lat;
737
738 /* Advance next loop */
Benny Prijonodbf4cb92009-07-18 09:18:26 +0000739 if (first) {
Benny Prijonoc45d9512010-12-10 11:04:30 +0000740 start_pos = max_signal_pos + clock_rate * 9 / 10;
Benny Prijonodbf4cb92009-07-18 09:18:26 +0000741 first = PJ_FALSE;
Benny Prijonoff64ccf2009-07-16 11:37:15 +0000742 } else {
Benny Prijonoc45d9512010-12-10 11:04:30 +0000743 start_pos += clock_rate;
Benny Prijonoff64ccf2009-07-16 11:37:15 +0000744 }
Benny Prijono7b40c6c2009-07-16 10:36:48 +0000745 }
746
747 return 0;
748}
749
750
751static void systest_latency_test(void)
752{
Sauw Minga7487622010-03-30 11:42:51 +0000753 const char *ref_wav_paths[] = { add_path(res_path, WAV_TOCK8_PATH), ALT_PATH1 WAV_TOCK8_PATH };
754 pj_str_t rec_wav_file;
Benny Prijono7b40c6c2009-07-16 10:36:48 +0000755 pjsua_player_id play_id = PJSUA_INVALID_ID;
756 pjsua_conf_port_id play_slot = PJSUA_INVALID_ID;
757 pjsua_recorder_id rec_id = PJSUA_INVALID_ID;
758 pjsua_conf_port_id rec_slot = PJSUA_INVALID_ID;
759 pj_pool_t *pool = NULL;
760 pjmedia_port *wav_port = NULL;
761 unsigned lat_sum=0, lat_cnt=0, lat_min=0, lat_max=0;
762 enum gui_key key;
763 test_item_t *ti;
764 const char *title = "Audio Latency Test";
765 pj_status_t status;
766
767 ti = systest_alloc_test_item(title);
768 if (!ti)
769 return;
770
771 key = gui_msgbox(title,
772 "This test will try to find the audio device's "
773 "latency. We will play a special WAV file to the "
774 "speaker for ten seconds, then at the end "
775 "calculate the latency. Please don't do anything "
776 "until the test is done.", WITH_OKCANCEL);
777 if (key != KEY_OK) {
778 ti->skipped = PJ_TRUE;
779 return;
780 }
781 key = gui_msgbox(title,
782 "For this test to work, we must be able to capture "
783 "the audio played in the speaker (the echo), and only"
784 " that audio (i.e. you must be in relatively quiet "
785 "place to run this test). "
786 "Press OK to start, or CANCEL to skip.",
787 WITH_OKCANCEL);
788 if (key != KEY_OK) {
789 ti->skipped = PJ_TRUE;
790 return;
791 }
792
793 PJ_LOG(3,(THIS_FILE, "Running %s", title));
794
Benny Prijonoc6f0e1a2009-11-08 03:35:41 +0000795 status = create_player(PJ_ARRAY_SIZE(ref_wav_paths), ref_wav_paths,
796 &play_id);
Benny Prijono7b40c6c2009-07-16 10:36:48 +0000797 if (status != PJ_SUCCESS)
798 goto on_return;
799
800 play_slot = pjsua_player_get_conf_port(play_id);
801
Sauw Minga7487622010-03-30 11:42:51 +0000802 rec_wav_file = pj_str(add_path(doc_path, WAV_LATENCY_OUT_PATH));
Benny Prijono7b40c6c2009-07-16 10:36:48 +0000803 status = pjsua_recorder_create(&rec_wav_file, 0, NULL, -1, 0, &rec_id);
804 if (status != PJ_SUCCESS)
805 goto on_return;
806
807 rec_slot = pjsua_recorder_get_conf_port(rec_id);
808
809 /* Setup the test */
810 //status = pjsua_conf_connect(0, 0);
Benny Prijono7b40c6c2009-07-16 10:36:48 +0000811 status = pjsua_conf_connect(play_slot, 0);
Benny Prijonoff64ccf2009-07-16 11:37:15 +0000812 status = pjsua_conf_connect(0, rec_slot);
Benny Prijono7b40c6c2009-07-16 10:36:48 +0000813 status = pjsua_conf_connect(play_slot, rec_slot);
814
815
816 /* We're running */
Benny Prijono258dc212009-07-17 11:37:42 +0000817 PJ_LOG(3,(THIS_FILE, "Please wait while test is running (~10 sec)"));
Benny Prijono7b40c6c2009-07-16 10:36:48 +0000818 gui_sleep(10);
819
820 /* Done with the test */
821 //status = pjsua_conf_disconnect(0, 0);
822 status = pjsua_conf_disconnect(play_slot, rec_slot);
Benny Prijono7b40c6c2009-07-16 10:36:48 +0000823 status = pjsua_conf_disconnect(0, rec_slot);
Benny Prijonoff64ccf2009-07-16 11:37:15 +0000824 status = pjsua_conf_disconnect(play_slot, 0);
Benny Prijono7b40c6c2009-07-16 10:36:48 +0000825
826 pjsua_recorder_destroy(rec_id);
827 rec_id = PJSUA_INVALID_ID;
828
829 pjsua_player_destroy(play_id);
830 play_id = PJSUA_INVALID_ID;
831
832 /* Confirm that echo is heard */
833 gui_msgbox(title,
834 "Test is done. Now we need to confirm that we indeed "
835 "captured the echo. We will play the captured audio "
836 "and please confirm that you can hear the 'tock' echo.",
837 WITH_OK);
838
839 status = pjsua_player_create(&rec_wav_file, 0, &play_id);
840 if (status != PJ_SUCCESS)
841 goto on_return;
842
Benny Prijonoff64ccf2009-07-16 11:37:15 +0000843 play_slot = pjsua_player_get_conf_port(play_id);
844
845 status = pjsua_conf_connect(play_slot, 0);
Benny Prijono7b40c6c2009-07-16 10:36:48 +0000846 if (status != PJ_SUCCESS)
847 goto on_return;
848
849 key = gui_msgbox(title,
850 "The captured audio is being played back now. "
851 "Can you hear the 'tock' echo?",
852 WITH_YESNO);
Benny Prijonoff64ccf2009-07-16 11:37:15 +0000853
854 pjsua_player_destroy(play_id);
855 play_id = PJSUA_INVALID_ID;
856
Benny Prijono7b40c6c2009-07-16 10:36:48 +0000857 if (key != KEY_YES)
858 goto on_return;
859
860 /* Now analyze the latency */
861 pool = pjsua_pool_create("latency", 512, 512);
862
863 status = pjmedia_wav_player_port_create(pool, rec_wav_file.ptr, 0, 0, 0, &wav_port);
864 if (status != PJ_SUCCESS)
865 goto on_return;
866
867 status = calculate_latency(pool, wav_port, &lat_sum, &lat_cnt,
868 &lat_min, &lat_max);
869 if (status != PJ_SUCCESS)
870 goto on_return;
871
872on_return:
873 if (wav_port)
874 pjmedia_port_destroy(wav_port);
875 if (pool)
876 pj_pool_release(pool);
877 if (play_id != PJSUA_INVALID_ID)
878 pjsua_player_destroy(play_id);
879 if (rec_id != PJSUA_INVALID_ID)
880 pjsua_recorder_destroy(rec_id);
881
882 if (status != PJ_SUCCESS) {
883 systest_perror("Sorry we encountered an error: ", status);
884 ti->success = PJ_FALSE;
885 pj_strerror(status, ti->reason, sizeof(ti->reason));
886 } else if (key != KEY_YES) {
887 ti->success = PJ_FALSE;
888 if (!ti->success) {
889 pj_ansi_strcpy(ti->reason, USER_ERROR);
890 }
891 } else {
892 char msg[200];
893 int msglen;
894
895 pj_ansi_snprintf(msg, sizeof(msg),
896 "The sound device latency:\r\n"
897 " Min=%u, Max=%u, Avg=%u\r\n",
898 lat_min, lat_max, lat_sum/lat_cnt);
899 msglen = strlen(msg);
900
901 if (lat_sum/lat_cnt > 500) {
902 pj_ansi_snprintf(msg+msglen, sizeof(msg)-msglen,
903 "The latency is huge!\r\n");
904 msglen = strlen(msg);
905 } else if (lat_sum/lat_cnt > 200) {
906 pj_ansi_snprintf(msg+msglen, sizeof(msg)-msglen,
907 "The latency is quite high\r\n");
908 msglen = strlen(msg);
909 }
910
911 key = gui_msgbox(title, msg, WITH_OK);
912
913 ti->success = PJ_TRUE;
914 pj_ansi_strncpy(ti->reason, msg, sizeof(ti->reason));
915 ti->reason[sizeof(ti->reason)-1] = '\0';
916 }
917}
918
919
Nanang Izzuddin160a49c2010-09-07 10:00:49 +0000920static void systest_aec_test(void)
921{
922 const char *ref_wav_paths[] = { add_path(res_path, WAV_PLAYBACK_PATH),
923 ALT_PATH1 WAV_PLAYBACK_PATH };
924 pjsua_player_id player_id = PJSUA_INVALID_ID;
925 pjsua_recorder_id writer_id = PJSUA_INVALID_ID;
926 enum gui_key key;
927 test_item_t *ti;
928 const char *title = "AEC/AES Test";
929 unsigned last_ec_tail = 0;
930 pj_status_t status;
931 pj_str_t tmp;
932
933 ti = systest_alloc_test_item(title);
934 if (!ti)
935 return;
936
937 key = gui_msgbox(title,
938 "This test will try to find whether the AEC/AES "
939 "works good on this system. Test will play a file "
940 "while recording from mic. The recording will be "
941 "played back later so you can check if echo is there. "
942 "Press OK to start.",
943 WITH_OKCANCEL);
944 if (key != KEY_OK) {
945 ti->skipped = PJ_TRUE;
946 return;
947 }
948
949 /* Save current EC tail */
950 status = pjsua_get_ec_tail(&last_ec_tail);
951 if (status != PJ_SUCCESS)
952 goto on_return;
953
954 /* Set EC tail setting to default */
955 status = pjsua_set_ec(PJSUA_DEFAULT_EC_TAIL_LEN, 0);
956 if (status != PJ_SUCCESS)
957 goto on_return;
958
959 /*
960 * Create player and recorder
961 */
962 status = create_player(PJ_ARRAY_SIZE(ref_wav_paths), ref_wav_paths,
963 &player_id);
964 if (status != PJ_SUCCESS) {
965 PJ_PERROR(1,(THIS_FILE, status, "Error opening WAV file %s",
966 WAV_PLAYBACK_PATH));
967 goto on_return;
968 }
969
970 status = pjsua_recorder_create(pj_cstr(&tmp, AEC_REC_PATH), 0, 0, -1,
971 0, &writer_id);
972 if (status != PJ_SUCCESS) {
973 PJ_PERROR(1,(THIS_FILE, status, "Error writing WAV file %s",
974 AEC_REC_PATH));
975 goto on_return;
976 }
977
978 /*
979 * Start playback and recording.
980 */
981 pjsua_conf_connect(pjsua_player_get_conf_port(player_id), 0);
982 pj_thread_sleep(100);
983 pjsua_conf_connect(0, pjsua_recorder_get_conf_port(writer_id));
984
985 /* Wait user signal */
986 gui_msgbox(title, "AEC/AES test is running. Press OK to stop this test.",
987 WITH_OK);
988
989 /*
990 * Stop and close playback and recorder
991 */
992 pjsua_conf_disconnect(0, pjsua_recorder_get_conf_port(writer_id));
993 pjsua_conf_disconnect(pjsua_player_get_conf_port(player_id), 0);
994 pjsua_recorder_destroy(writer_id);
995 pjsua_player_destroy(player_id);
996 player_id = PJSUA_INVALID_ID;
997 writer_id = PJSUA_INVALID_ID;
998
999 /*
1000 * Play the result.
1001 */
1002 status = pjsua_player_create(pj_cstr(&tmp, AEC_REC_PATH), 0, &player_id);
1003 if (status != PJ_SUCCESS) {
1004 PJ_PERROR(1,(THIS_FILE, status, "Error opening WAV file %s", AEC_REC_PATH));
1005 goto on_return;
1006 }
1007 pjsua_conf_connect(pjsua_player_get_conf_port(player_id), 0);
1008
1009 /* Wait user signal */
1010 gui_msgbox(title, "We are now playing the captured audio from the mic. "
1011 "Check if echo (of the audio played back previously) is "
1012 "present in the audio. The recording is stored in "
1013 AEC_REC_PATH " for offline analysis. "
1014 "Press OK to stop.",
1015 WITH_OK);
1016
1017 pjsua_conf_disconnect(pjsua_player_get_conf_port(player_id), 0);
1018
1019 key = gui_msgbox(title,
1020 "Did you notice any echo in the recording?",
1021 WITH_YESNO);
1022
1023
1024on_return:
1025 if (player_id != PJSUA_INVALID_ID)
1026 pjsua_player_destroy(player_id);
1027 if (writer_id != PJSUA_INVALID_ID)
1028 pjsua_recorder_destroy(writer_id);
1029
1030 /* Wait until sound device closed before restoring back EC tail setting */
1031 while (pjsua_snd_is_active())
1032 pj_thread_sleep(10);
1033 pjsua_set_ec(last_ec_tail, 0);
1034
1035
1036 if (status != PJ_SUCCESS) {
1037 systest_perror("Sorry we encountered an error: ", status);
1038 ti->success = PJ_FALSE;
1039 pj_strerror(status, ti->reason, sizeof(ti->reason));
1040 } else if (key == KEY_YES) {
1041 ti->success = PJ_FALSE;
1042 if (!ti->success) {
1043 pj_ansi_strcpy(ti->reason, USER_ERROR);
1044 }
1045 } else {
1046 char msg[200];
1047
1048 pj_ansi_snprintf(msg, sizeof(msg), "Test succeeded.\r\n");
1049
1050 ti->success = PJ_TRUE;
1051 pj_ansi_strncpy(ti->reason, msg, sizeof(ti->reason));
1052 ti->reason[sizeof(ti->reason)-1] = '\0';
1053 }
1054}
1055
Benny Prijono7b40c6c2009-07-16 10:36:48 +00001056
1057/****************************************************************************
1058 * configurations
1059 */
1060static void systest_list_audio_devs()
1061{
1062 unsigned i, dev_count, len=0;
1063 pj_status_t status;
1064 test_item_t *ti;
1065 enum gui_key key;
1066 const char *title = "Audio Device List";
1067
1068 ti = systest_alloc_test_item(title);
1069 if (!ti)
1070 return;
1071
1072 PJ_LOG(3,(THIS_FILE, "Running %s", title));
1073
1074 dev_count = pjmedia_aud_dev_count();
1075 if (dev_count == 0) {
1076 key = gui_msgbox(title,
1077 "No audio devices are found", WITH_OK);
1078 ti->success = PJ_FALSE;
1079 pj_ansi_strcpy(ti->reason, "No device found");
1080 return;
1081 }
1082
1083 pj_ansi_snprintf(ti->reason+len, sizeof(ti->reason)-len,
1084 "Found %u devices\r\n", dev_count);
1085 len = strlen(ti->reason);
1086
1087 for (i=0; i<dev_count; ++i) {
1088 pjmedia_aud_dev_info info;
1089
1090 status = pjmedia_aud_dev_get_info(i, &info);
1091 if (status != PJ_SUCCESS) {
1092 systest_perror("Error retrieving device info: ", status);
1093 ti->success = PJ_FALSE;
1094 pj_strerror(status, ti->reason, sizeof(ti->reason));
1095 return;
1096 }
1097
1098 pj_ansi_snprintf(ti->reason+len, sizeof(ti->reason)-len,
1099 " %2d: %s [%s] (%d/%d)\r\n",
1100 i, info.driver, info.name,
1101 info.input_count, info.output_count);
1102 len = strlen(ti->reason);
1103 }
1104
1105 ti->reason[len] = '\0';
1106 key = gui_msgbox(title, ti->reason, WITH_OK);
1107
1108 ti->success = PJ_TRUE;
1109}
1110
1111static void systest_display_settings(void)
1112{
1113 pjmedia_aud_dev_info di;
1114 int len = 0;
1115 enum gui_key key;
1116 test_item_t *ti;
1117 const char *title = "Audio Settings";
1118 pj_status_t status;
1119
1120 ti = systest_alloc_test_item(title);
1121 if (!ti)
1122 return;
1123
1124 PJ_LOG(3,(THIS_FILE, "Running %s", title));
1125
1126 pj_ansi_snprintf(textbuf+len, sizeof(textbuf)-len, "Version: %s\r\n",
1127 pj_get_version());
1128 len = strlen(textbuf);
1129
Benny Prijono258dc212009-07-17 11:37:42 +00001130 pj_ansi_snprintf(textbuf+len, sizeof(textbuf)-len, "Test clock rate: %d\r\n",
Benny Prijono7b40c6c2009-07-16 10:36:48 +00001131 systest.media_cfg.clock_rate);
1132 len = strlen(textbuf);
1133
Benny Prijono258dc212009-07-17 11:37:42 +00001134 pj_ansi_snprintf(textbuf+len, sizeof(textbuf)-len, "Device clock rate: %d\r\n",
1135 systest.media_cfg.snd_clock_rate);
1136 len = strlen(textbuf);
1137
Benny Prijono7b40c6c2009-07-16 10:36:48 +00001138 pj_ansi_snprintf(textbuf+len, sizeof(textbuf)-len, "Aud frame ptime: %d\r\n",
1139 systest.media_cfg.audio_frame_ptime);
1140 len = strlen(textbuf);
1141
1142 pj_ansi_snprintf(textbuf+len, sizeof(textbuf)-len, "Channel count: %d\r\n",
1143 systest.media_cfg.channel_count);
1144 len = strlen(textbuf);
1145
1146 pj_ansi_snprintf(textbuf+len, sizeof(textbuf)-len, "Audio switching: %s\r\n",
1147 (PJMEDIA_CONF_USE_SWITCH_BOARD ? "Switchboard" : "Conf bridge"));
1148 len = strlen(textbuf);
1149
1150 pj_ansi_snprintf(textbuf+len, sizeof(textbuf)-len, "Snd buff count: %d\r\n",
1151 PJMEDIA_SOUND_BUFFER_COUNT);
1152 len = strlen(textbuf);
1153
1154 /* Capture device */
1155 status = pjmedia_aud_dev_get_info(systest.rec_id, &di);
1156 if (status != PJ_SUCCESS) {
1157 systest_perror("Error querying device info", status);
1158 ti->success = PJ_FALSE;
1159 pj_strerror(status, ti->reason, sizeof(ti->reason));
1160 return;
1161 }
1162
1163 pj_ansi_snprintf(textbuf+len, sizeof(textbuf)-len,
1164 "Rec dev : %d (%s) [%s]\r\n",
1165 systest.rec_id,
1166 di.name,
1167 di.driver);
1168 len = strlen(textbuf);
1169
1170 pj_ansi_snprintf(textbuf+len, sizeof(textbuf)-len,
1171 "Rec buf : %d msec\r\n",
1172 systest.media_cfg.snd_rec_latency);
1173 len = strlen(textbuf);
1174
1175 /* Playback device */
1176 status = pjmedia_aud_dev_get_info(systest.play_id, &di);
1177 if (status != PJ_SUCCESS) {
1178 systest_perror("Error querying device info", status);
1179 return;
1180 }
1181
1182 pj_ansi_snprintf(textbuf+len, sizeof(textbuf)-len,
1183 "Play dev: %d (%s) [%s]\r\n",
1184 systest.play_id,
1185 di.name,
1186 di.driver);
1187 len = strlen(textbuf);
1188
1189 pj_ansi_snprintf(textbuf+len, sizeof(textbuf)-len,
1190 "Play buf: %d msec\r\n",
1191 systest.media_cfg.snd_play_latency);
1192 len = strlen(textbuf);
1193
1194 ti->success = PJ_TRUE;
1195 pj_ansi_strncpy(ti->reason, textbuf, sizeof(ti->reason));
1196 ti->reason[sizeof(ti->reason)-1] = '\0';
1197 key = gui_msgbox(title, textbuf, WITH_OK);
1198
1199}
1200
1201/*****************************************************************/
1202
1203int systest_init(void)
1204{
1205 pjsua_logging_config log_cfg;
1206 pj_status_t status = PJ_SUCCESS;
1207
1208 status = pjsua_create();
1209 if (status != PJ_SUCCESS) {
1210 systest_perror("Sorry we've had error in pjsua_create(): ", status);
1211 return status;
1212 }
1213
1214 pjsua_logging_config_default(&log_cfg);
Sauw Minga7487622010-03-30 11:42:51 +00001215 log_cfg.log_filename = pj_str(add_path(doc_path, LOG_OUT_PATH));
Benny Prijono7b40c6c2009-07-16 10:36:48 +00001216
1217 pjsua_config_default(&systest.ua_cfg);
1218 pjsua_media_config_default(&systest.media_cfg);
Benny Prijono258dc212009-07-17 11:37:42 +00001219 systest.media_cfg.clock_rate = TEST_CLOCK_RATE;
1220 systest.media_cfg.snd_clock_rate = DEV_CLOCK_RATE;
Benny Prijono7b40c6c2009-07-16 10:36:48 +00001221 if (OVERRIDE_AUD_FRAME_PTIME)
1222 systest.media_cfg.audio_frame_ptime = OVERRIDE_AUD_FRAME_PTIME;
1223 systest.media_cfg.channel_count = CHANNEL_COUNT;
Benny Prijono258dc212009-07-17 11:37:42 +00001224 systest.rec_id = REC_DEV_ID;
1225 systest.play_id = PLAY_DEV_ID;
Benny Prijono7b40c6c2009-07-16 10:36:48 +00001226 systest.media_cfg.ec_tail_len = 0;
Nanang Izzuddin160a49c2010-09-07 10:00:49 +00001227 systest.media_cfg.snd_auto_close_time = 0;
Benny Prijono7b40c6c2009-07-16 10:36:48 +00001228
1229#if defined(OVERRIDE_AUDDEV_PLAY_LAT) && OVERRIDE_AUDDEV_PLAY_LAT!=0
1230 systest.media_cfg.snd_play_latency = OVERRIDE_AUDDEV_PLAY_LAT;
1231#endif
1232
1233#if defined(OVERRIDE_AUDDEV_REC_LAT) && OVERRIDE_AUDDEV_REC_LAT!=0
1234 systest.media_cfg.snd_rec_latency = OVERRIDE_AUDDEV_REC_LAT;
1235#endif
1236
1237 status = pjsua_init(&systest.ua_cfg, &log_cfg, &systest.media_cfg);
1238 if (status != PJ_SUCCESS) {
1239 pjsua_destroy();
1240 systest_perror("Sorry we've had error in pjsua_init(): ", status);
1241 return status;
1242 }
1243
1244 status = pjsua_start();
1245 if (status != PJ_SUCCESS) {
1246 pjsua_destroy();
1247 systest_perror("Sorry we've had error in pjsua_start(): ", status);
1248 return status;
1249 }
1250
1251 status = gui_init(&root_menu);
1252 if (status != 0)
1253 goto on_return;
1254
1255 return 0;
1256
1257on_return:
1258 gui_destroy();
1259 return status;
1260}
1261
1262
Benny Prijonoc712c282010-05-10 09:51:02 +00001263int systest_set_dev(int cap_dev, int play_dev)
1264{
1265 systest.rec_id = systest_cap_dev_id = cap_dev;
1266 systest.play_id = systest_play_dev_id = play_dev;
1267 return pjsua_set_snd_dev(cap_dev, play_dev);
1268}
1269
Benny Prijono7b40c6c2009-07-16 10:36:48 +00001270static void systest_wizard(void)
1271{
1272 PJ_LOG(3,(THIS_FILE, "Running test wizard"));
1273 systest_list_audio_devs();
1274 systest_display_settings();
1275 systest_play_tone();
1276 systest_play_wav1();
1277 systest_rec_audio();
1278 systest_audio_test();
1279 systest_latency_test();
Nanang Izzuddin160a49c2010-09-07 10:00:49 +00001280 systest_aec_test();
Benny Prijono7b40c6c2009-07-16 10:36:48 +00001281 gui_msgbox("Test wizard", "Test wizard complete.", WITH_OK);
1282}
1283
1284
1285int systest_run(void)
1286{
1287 gui_start(&root_menu);
1288 return 0;
1289}
1290
1291void systest_save_result(const char *filename)
1292{
1293 unsigned i;
1294 pj_oshandle_t fd;
1295 pj_time_val tv;
1296 pj_parsed_time pt;
1297 pj_ssize_t size;
1298 const char *text;
1299 pj_status_t status;
1300
1301 status = pj_file_open(NULL, filename, PJ_O_WRONLY | PJ_O_APPEND, &fd);
1302 if (status != PJ_SUCCESS) {
1303 pj_ansi_snprintf(textbuf, sizeof(textbuf),
1304 "Error opening file %s",
1305 filename);
1306 systest_perror(textbuf, status);
1307 return;
1308 }
1309
1310 text = "\r\n\r\nPJSYSTEST Report\r\n";
1311 size = strlen(text);
1312 pj_file_write(fd, text, &size);
1313
1314 /* Put timestamp */
1315 pj_gettimeofday(&tv);
1316 if (pj_time_decode(&tv, &pt) == PJ_SUCCESS) {
1317 pj_ansi_snprintf(textbuf, sizeof(textbuf),
1318 "Time: %04d/%02d/%02d %02d:%02d:%02d\r\n",
1319 pt.year, pt.mon+1, pt.day,
1320 pt.hour, pt.min, pt.sec);
1321 size = strlen(textbuf);
1322 pj_file_write(fd, textbuf, &size);
1323 }
1324
1325 pj_ansi_snprintf(textbuf, sizeof(textbuf),
1326 "Tests invoked: %u\r\n"
1327 "-----------------------------------------------\r\n",
1328 test_item_count);
1329 size = strlen(textbuf);
1330 pj_file_write(fd, textbuf, &size);
1331
1332 for (i=0; i<test_item_count; ++i) {
1333 test_item_t *ti = &test_items[i];
1334 pj_ansi_snprintf(textbuf, sizeof(textbuf),
1335 "\r\nTEST %d: %s %s\r\n",
1336 i, ti->title,
1337 (ti->skipped? "Skipped" : (ti->success ? "Success" : "Failed")));
1338 size = strlen(textbuf);
1339 pj_file_write(fd, textbuf, &size);
1340
1341 size = strlen(ti->reason);
1342 pj_file_write(fd, ti->reason, &size);
1343
1344 size = 2;
1345 pj_file_write(fd, "\r\n", &size);
1346 }
1347
1348
1349 pj_file_close(fd);
1350
1351 pj_ansi_snprintf(textbuf, sizeof(textbuf),
1352 "Test result successfully appended to file %s",
1353 filename);
1354 gui_msgbox("Test result saved", textbuf, WITH_OK);
1355}
1356
1357void systest_deinit(void)
1358{
1359 gui_destroy();
1360 pjsua_destroy();
1361}
1362