~ubuntu-branches/ubuntu/trusty/sflphone/trusty

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.0.1/pjsip-apps/src/pjsystest/systest.c

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2014-01-28 18:23:36 UTC
  • mfrom: (4.3.4 sid)
  • Revision ID: package-import@ubuntu.com-20140128182336-jrsv0k9u6cawc068
Tags: 1.3.0-1
* New upstream release 
  - Fixes "New Upstream Release" (Closes: #735846)
  - Fixes "Ringtone does not stop" (Closes: #727164)
  - Fixes "[sflphone-kde] crash on startup" (Closes: #718178)
  - Fixes "sflphone GUI crashes when call is hung up" (Closes: #736583)
* Build-Depends: ensure GnuTLS 2.6
  - libucommon-dev (>= 6.0.7-1.1), libccrtp-dev (>= 2.0.6-3)
  - Fixes "FTBFS Build-Depends libgnutls{26,28}-dev" (Closes: #722040)
* Fix "boost 1.49 is going away" unversioned Build-Depends: (Closes: #736746)
* Add Build-Depends: libsndfile-dev, nepomuk-core-dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* $Id: systest.c 4087 2012-04-26 03:39:24Z ming $ */
2
 
/*
3
 
 * Copyright (C) 2008-2011 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
 
 */
19
 
#include "systest.h"
20
 
#include "gui.h"
21
 
 
22
 
#define THIS_FILE "systest.c"
23
 
 
24
 
unsigned    test_item_count;
25
 
test_item_t test_items[SYSTEST_MAX_TEST];
26
 
char        doc_path[PATH_LENGTH] = {0};
27
 
char        res_path[PATH_LENGTH] = {0};
28
 
char        fpath[PATH_LENGTH];
29
 
 
30
 
#define USER_ERROR  "User used said not okay"
31
 
 
32
 
static void systest_wizard(void);
33
 
static void systest_list_audio_devs(void);
34
 
static void systest_display_settings(void);
35
 
static void systest_play_tone(void);
36
 
static void systest_play_wav1(void);
37
 
static void systest_play_wav2(void);
38
 
static void systest_rec_audio(void);
39
 
static void systest_audio_test(void);
40
 
static void systest_latency_test(void);
41
 
static void systest_aec_test(void);
42
 
static void exit_app(void);
43
 
 
44
 
/* Menus */
45
 
static gui_menu menu_exit = { "Exit", &exit_app };
46
 
 
47
 
static gui_menu menu_wizard =  { "Run test wizard", &systest_wizard };
48
 
static gui_menu menu_playtn = { "Play Tone", &systest_play_tone };
49
 
static gui_menu menu_playwv1 = { "Play WAV File1", &systest_play_wav1 };
50
 
static gui_menu menu_playwv2 = { "Play WAV File2", &systest_play_wav2 };
51
 
static gui_menu menu_recaud  = { "Record Audio", &systest_rec_audio };
52
 
static gui_menu menu_audtest = { "Device Test", &systest_audio_test };
53
 
static gui_menu menu_calclat = { "Latency Test", &systest_latency_test };
54
 
static gui_menu menu_sndaec = { "AEC/AES Test", &systest_aec_test };
55
 
 
56
 
static gui_menu menu_listdev = { "View Devices", &systest_list_audio_devs };
57
 
static gui_menu menu_getsets = { "View Settings", &systest_display_settings };
58
 
 
59
 
static gui_menu menu_tests = {
60
 
    "Tests", NULL,
61
 
    10,
62
 
    {
63
 
        &menu_wizard,
64
 
        &menu_audtest,
65
 
        &menu_playtn,
66
 
        &menu_playwv1,
67
 
        &menu_playwv2,
68
 
        &menu_recaud,
69
 
        &menu_calclat,
70
 
        &menu_sndaec,
71
 
        NULL,
72
 
        &menu_exit
73
 
    }
74
 
};
75
 
 
76
 
static gui_menu menu_options = {
77
 
    "Options", NULL,
78
 
    2,
79
 
    {
80
 
        &menu_listdev,
81
 
        &menu_getsets,
82
 
    }
83
 
};
84
 
 
85
 
static gui_menu root_menu = {
86
 
    "Root", NULL, 2, {&menu_tests, &menu_options}
87
 
};
88
 
 
89
 
/*****************************************************************/
90
 
 
91
 
#if defined(PJ_DARWINOS) && PJ_DARWINOS!=0
92
 
PJ_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
 
}
98
 
#else
99
 
#   define add_path(path, fname) fname
100
 
#endif
101
 
 
102
 
static void exit_app(void)
103
 
{
104
 
    systest_save_result(add_path(doc_path, RESULT_OUT_PATH));
105
 
    gui_destroy();
106
 
}
107
 
 
108
 
 
109
 
#include <pjsua-lib/pjsua.h>
110
 
#include <pjmedia_audiodev.h>
111
 
 
112
 
typedef 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
 
 
120
 
static systest_t systest;
121
 
static char textbuf[600];
122
 
 
123
 
/* Device ID to test */
124
 
int systest_cap_dev_id = PJMEDIA_AUD_DEFAULT_CAPTURE_DEV;
125
 
int systest_play_dev_id = PJMEDIA_AUD_DEFAULT_PLAYBACK_DEV;
126
 
 
127
 
static 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);
138
 
    strncat(themsg, errmsg, sizeof(themsg)-1);
139
 
    themsg[sizeof(themsg)-1] = '\0';
140
 
 
141
 
    gui_msgbox("Error", themsg, WITH_OK);
142
 
}
143
 
 
144
 
test_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
 
 */
163
 
static 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
 
 
247
 
on_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
 
 
269
 
/* Util: create file player, each time trying different paths until we get
270
 
 * the file.
271
 
 */
272
 
static 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
 
}
286
 
 
287
 
/*****************************************************************************
288
 
 * test: play WAV file
289
 
 */
290
 
static void systest_play_wav(unsigned path_cnt, const char *paths[])
291
 
{
292
 
    pjsua_player_id play_id = PJSUA_INVALID_ID;
293
 
    enum gui_key key;
294
 
    test_item_t *ti;
295
 
    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",
308
 
                     paths[0]);
309
 
 
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 */
320
 
    status = create_player(path_cnt, paths, &play_id);
321
 
    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
 
 
334
 
on_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
 
 
351
 
static void systest_play_wav1(void)
352
 
{
353
 
    const char *paths[] = { add_path(res_path, WAV_PLAYBACK_PATH),
354
 
                            ALT_PATH1 WAV_PLAYBACK_PATH };
355
 
    systest_play_wav(PJ_ARRAY_SIZE(paths), paths);
356
 
}
357
 
 
358
 
static void systest_play_wav2(void)
359
 
{
360
 
    const char *paths[] = { add_path(res_path, WAV_TOCK8_PATH),
361
 
                            ALT_PATH1 WAV_TOCK8_PATH};
362
 
    systest_play_wav(PJ_ARRAY_SIZE(paths), paths);
363
 
}
364
 
 
365
 
 
366
 
/*****************************************************************************
367
 
 * test: record audio
368
 
 */
369
 
static void systest_rec_audio(void)
370
 
{
371
 
    const pj_str_t filename = pj_str(add_path(doc_path, WAV_REC_OUT_PATH));
372
 
    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
 
 
421
 
    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,
432
 
                     "Recording has been stopped. "
433
 
                     "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
 
 
438
 
on_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
 
 */
474
 
static 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;
526
 
    param.clock_rate = systest.media_cfg.snd_clock_rate;
527
 
    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),
608
 
                        "Clock drifts detected. Capture "
609
 
                        "is %d samples/sec %s "
610
 
                        "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
 
 */
651
 
static 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;
657
 
    unsigned i, clock_rate, samples_per_frame, read, len;
658
 
    unsigned start_pos;
659
 
    pj_bool_t first;
660
 
    pj_status_t status;
661
 
 
662
 
    *lat_sum = 0;
663
 
    *lat_cnt = 0;
664
 
    *lat_min = 10000;
665
 
    *lat_max = 0;
666
 
 
667
 
    samples_per_frame = PJMEDIA_PIA_SPF(&wav->info);
668
 
    clock_rate = PJMEDIA_PIA_SRATE(&wav->info);
669
 
    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
 
 
685
 
    if (read < 2 * clock_rate) {
686
 
        systest_perror("The WAV file is too short", PJ_SUCCESS);
687
 
        return -1;
688
 
    }
689
 
 
690
 
    /* Zero the first 500ms to remove loud click noises
691
 
     * (keypad press, etc.)
692
 
     */
693
 
    pjmedia_zero_samples(buf, clock_rate / 2);
694
 
 
695
 
    /* Loop to calculate latency */
696
 
    start_pos = 0;
697
 
    first = PJ_TRUE;
698
 
    while (start_pos < len/2 - clock_rate) {
699
 
        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 */
706
 
        for (i=start_pos; i<start_pos + clock_rate * 700 / 1000; ++i) {
707
 
            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 */
714
 
        pos = max_signal_pos + 10 * clock_rate / 1000;
715
 
 
716
 
        /* Get the largest signal in the next 800ms */
717
 
        max_signal = 0;
718
 
        max_echo_pos = pos;
719
 
        for (i=pos; i<pos+clock_rate * 8 / 10; ++i) {
720
 
            if (abs(buf[i]) > max_signal) {
721
 
                max_signal = abs(buf[i]);
722
 
                max_echo_pos = i;
723
 
            }
724
 
        }
725
 
 
726
 
        lat = (max_echo_pos - max_signal_pos) * 1000 / clock_rate;
727
 
 
728
 
#if 0
729
 
        PJ_LOG(4,(THIS_FILE, "Signal at %dms, echo at %d ms, latency %d ms",
730
 
                  max_signal_pos * 1000 / clock_rate,
731
 
                  max_echo_pos * 1000 / clock_rate,
732
 
                  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 */
743
 
        if (first) {
744
 
            start_pos = max_signal_pos + clock_rate * 9 / 10;
745
 
            first = PJ_FALSE;
746
 
        } else {
747
 
            start_pos += clock_rate;
748
 
        }
749
 
    }
750
 
 
751
 
    return 0;
752
 
}
753
 
 
754
 
 
755
 
static void systest_latency_test(void)
756
 
{
757
 
    const char *ref_wav_paths[] = { add_path(res_path, WAV_TOCK8_PATH), ALT_PATH1 WAV_TOCK8_PATH };
758
 
    pj_str_t rec_wav_file;
759
 
    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
 
 
799
 
    status = create_player(PJ_ARRAY_SIZE(ref_wav_paths), ref_wav_paths,
800
 
                           &play_id);
801
 
    if (status != PJ_SUCCESS)
802
 
        goto on_return;
803
 
 
804
 
    play_slot = pjsua_player_get_conf_port(play_id);
805
 
 
806
 
    rec_wav_file = pj_str(add_path(doc_path, WAV_LATENCY_OUT_PATH));
807
 
    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);
815
 
    status = pjsua_conf_connect(play_slot, 0);
816
 
    status = pjsua_conf_connect(0, rec_slot);
817
 
    status = pjsua_conf_connect(play_slot, rec_slot);
818
 
 
819
 
 
820
 
    /* We're running */
821
 
    PJ_LOG(3,(THIS_FILE, "Please wait while test is running (~10 sec)"));
822
 
    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);
827
 
    status = pjsua_conf_disconnect(0, rec_slot);
828
 
    status = pjsua_conf_disconnect(play_slot, 0);
829
 
 
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
 
 
847
 
    play_slot = pjsua_player_get_conf_port(play_id);
848
 
 
849
 
    status = pjsua_conf_connect(play_slot, 0);
850
 
    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);
857
 
 
858
 
    pjsua_player_destroy(play_id);
859
 
    play_id = PJSUA_INVALID_ID;
860
 
 
861
 
    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
 
 
876
 
on_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
 
 
924
 
static 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
 
 
974
 
    status = pjsua_recorder_create(
975
 
                 pj_cstr(&tmp, add_path(doc_path, AEC_REC_PATH)), 0, 0, -1,
976
 
                 0, &writer_id);
977
 
    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
 
     */
1007
 
    status = pjsua_player_create(
1008
 
                 pj_cstr(&tmp, add_path(doc_path, AEC_REC_PATH)),
1009
 
                 0, &player_id);
1010
 
    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
 
 
1031
 
on_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
 
 
1063
 
 
1064
 
/****************************************************************************
1065
 
 * configurations
1066
 
 */
1067
 
static 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
 
 
1118
 
static 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
 
 
1137
 
    pj_ansi_snprintf(textbuf+len, sizeof(textbuf)-len, "Test clock rate: %d\r\n",
1138
 
                     systest.media_cfg.clock_rate);
1139
 
    len = strlen(textbuf);
1140
 
 
1141
 
    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
 
 
1145
 
    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
 
 
1210
 
int 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);
1222
 
    log_cfg.log_filename = pj_str(add_path(doc_path, LOG_OUT_PATH));
1223
 
 
1224
 
    pjsua_config_default(&systest.ua_cfg);
1225
 
    pjsua_media_config_default(&systest.media_cfg);
1226
 
    systest.media_cfg.clock_rate = TEST_CLOCK_RATE;
1227
 
    systest.media_cfg.snd_clock_rate = DEV_CLOCK_RATE;
1228
 
    if (OVERRIDE_AUD_FRAME_PTIME)
1229
 
        systest.media_cfg.audio_frame_ptime = OVERRIDE_AUD_FRAME_PTIME;
1230
 
    systest.media_cfg.channel_count = CHANNEL_COUNT;
1231
 
    systest.rec_id = REC_DEV_ID;
1232
 
    systest.play_id = PLAY_DEV_ID;
1233
 
    systest.media_cfg.ec_tail_len = 0;
1234
 
    systest.media_cfg.snd_auto_close_time = 0;
1235
 
 
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
 
 
1264
 
on_return:
1265
 
    gui_destroy();
1266
 
    return status;
1267
 
}
1268
 
 
1269
 
 
1270
 
int 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
 
 
1277
 
static 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();
1287
 
    systest_aec_test();
1288
 
    gui_msgbox("Test wizard", "Test wizard complete.", WITH_OK);
1289
 
}
1290
 
 
1291
 
 
1292
 
int systest_run(void)
1293
 
{
1294
 
    gui_start(&root_menu);
1295
 
    return 0;
1296
 
}
1297
 
 
1298
 
void 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
 
 
1364
 
void systest_deinit(void)
1365
 
{
1366
 
    gui_destroy();
1367
 
    pjsua_destroy();
1368
 
}