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