~ubuntu-branches/ubuntu/wily/sflphone/wily

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.0.1/pjsip-apps/src/symbian_ua_gui/src/symbian_ua.cpp

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2014-01-28 18:23:36 UTC
  • mfrom: (1.1.11)
  • mto: This revision was merged to the branch mainline in revision 24.
  • Revision ID: package-import@ubuntu.com-20140128182336-3xenud1kbnwmf3mz
* 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: ua.cpp 1793 2008-02-14 13:39:24Z bennylp $ */
2
 
/*
3
 
 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4
 
 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5
 
 *
6
 
 * This program is free software; you can redistribute it and/or modify
7
 
 * it under the terms of the GNU General Public License as published by
8
 
 * the Free Software Foundation; either version 2 of the License, or
9
 
 * (at your option) any later version.
10
 
 *
11
 
 * This program is distributed in the hope that it will be useful,
12
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 
 * GNU General Public License for more details.
15
 
 *
16
 
 * You should have received a copy of the GNU General Public License
17
 
 * along with this program; if not, write to the Free Software
18
 
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
 
 */
20
 
#include <pjsua-lib/pjsua.h>
21
 
#include <pjsua-lib/pjsua_internal.h>
22
 
#include <es_sock.h>
23
 
#include "symbian_ua.h"
24
 
 
25
 
#define THIS_FILE       "symbian_ua.cpp"
26
 
#define LOG_LEVEL       3
27
 
 
28
 
#define SIP_PORT        5060
29
 
#define USE_ICE         0
30
 
#define USE_SRTP        PJSUA_DEFAULT_USE_SRTP
31
 
 
32
 
static RSocketServ aSocketServer;
33
 
static RConnection aConn;
34
 
 
35
 
static pjsua_acc_id g_acc_id = PJSUA_INVALID_ID;
36
 
static pjsua_call_id g_call_id = PJSUA_INVALID_ID;
37
 
static pjsua_buddy_id g_buddy_id = PJSUA_INVALID_ID;
38
 
 
39
 
static symbian_ua_info_cb_t g_cb =  {NULL, NULL, NULL, NULL, NULL};
40
 
 
41
 
static void log_writer(int level, const char *buf, int len)
42
 
{
43
 
    static wchar_t buf16[PJ_LOG_MAX_SIZE];
44
 
 
45
 
    PJ_UNUSED_ARG(level);
46
 
 
47
 
    if (!g_cb.on_info)
48
 
        return;
49
 
 
50
 
    pj_ansi_to_unicode(buf, len, buf16, PJ_ARRAY_SIZE(buf16));
51
 
    g_cb.on_info(buf16);
52
 
}
53
 
 
54
 
static void on_reg_state(pjsua_acc_id acc_id)
55
 
{
56
 
    pjsua_acc_info acc_info;
57
 
    pj_status_t status;
58
 
 
59
 
    status = pjsua_acc_get_info(acc_id, &acc_info);
60
 
    if (status != PJ_SUCCESS)
61
 
        return;
62
 
 
63
 
    if (acc_info.status == 200) {
64
 
        if (acc_info.expires) {
65
 
            PJ_LOG(3,(THIS_FILE, "Registration success!"));
66
 
            if (g_cb.on_reg_state) g_cb.on_reg_state(true);
67
 
        } else {
68
 
            PJ_LOG(3,(THIS_FILE, "Unregistration success!"));
69
 
            if (g_cb.on_unreg_state) g_cb.on_unreg_state(true);
70
 
        }
71
 
    } else {
72
 
        if (acc_info.expires) {
73
 
            PJ_LOG(3,(THIS_FILE, "Registration failed!"));
74
 
            if (g_cb.on_reg_state) g_cb.on_reg_state(false);
75
 
        } else {
76
 
            PJ_LOG(3,(THIS_FILE, "Unregistration failed!"));
77
 
            if (g_cb.on_unreg_state) g_cb.on_unreg_state(false);
78
 
        }
79
 
    }
80
 
}
81
 
 
82
 
/* Callback called by the library upon receiving incoming call */
83
 
static void on_incoming_call(pjsua_acc_id acc_id, pjsua_call_id call_id,
84
 
                             pjsip_rx_data *rdata)
85
 
{
86
 
    pjsua_call_info ci;
87
 
 
88
 
    PJ_UNUSED_ARG(acc_id);
89
 
    PJ_UNUSED_ARG(rdata);
90
 
 
91
 
    if (g_call_id != PJSUA_INVALID_ID) {
92
 
        pjsua_call_answer(call_id, PJSIP_SC_BUSY_HERE, NULL, NULL);
93
 
        return;
94
 
    }
95
 
 
96
 
    pjsua_call_get_info(call_id, &ci);
97
 
 
98
 
    PJ_LOG(3,(THIS_FILE, "Incoming call from %.*s!!",
99
 
                         (int)ci.remote_info.slen,
100
 
                         ci.remote_info.ptr));
101
 
 
102
 
    g_call_id = call_id;
103
 
 
104
 
    /* Automatically answer incoming calls with 180/Ringing */
105
 
    pjsua_call_answer(call_id, 180, NULL, NULL);
106
 
 
107
 
    if (g_cb.on_incoming_call) {
108
 
        static wchar_t disp[256];
109
 
        static wchar_t uri[PJSIP_MAX_URL_SIZE];
110
 
 
111
 
        pj_ansi_to_unicode(ci.remote_info.ptr, ci.remote_info.slen,
112
 
            disp, PJ_ARRAY_SIZE(disp));
113
 
        pj_ansi_to_unicode(ci.remote_contact.ptr, ci.remote_contact.slen,
114
 
            uri, PJ_ARRAY_SIZE(uri));
115
 
 
116
 
        g_cb.on_incoming_call(disp, uri);
117
 
    }
118
 
}
119
 
 
120
 
/* Callback called by the library when call's state has changed */
121
 
static void on_call_state(pjsua_call_id call_id, pjsip_event *e)
122
 
{
123
 
    pjsua_call_info ci;
124
 
 
125
 
    PJ_UNUSED_ARG(e);
126
 
 
127
 
    pjsua_call_get_info(call_id, &ci);
128
 
 
129
 
    if (ci.state == PJSIP_INV_STATE_DISCONNECTED) {
130
 
        if (call_id == g_call_id)
131
 
            g_call_id = PJSUA_INVALID_ID;
132
 
        if (g_cb.on_call_end) {
133
 
            static wchar_t reason[256];
134
 
            pj_ansi_to_unicode(ci.last_status_text.ptr, ci.last_status_text.slen,
135
 
                    reason, PJ_ARRAY_SIZE(reason));
136
 
            g_cb.on_call_end(reason);
137
 
        }
138
 
 
139
 
    } else if (ci.state != PJSIP_INV_STATE_INCOMING) {
140
 
        if (g_call_id == PJSUA_INVALID_ID)
141
 
            g_call_id = call_id;
142
 
    }
143
 
 
144
 
    PJ_LOG(3,(THIS_FILE, "Call %d state=%.*s", call_id,
145
 
                         (int)ci.state_text.slen,
146
 
                         ci.state_text.ptr));
147
 
}
148
 
 
149
 
/* Callback called by the library when call's media state has changed */
150
 
static void on_call_media_state(pjsua_call_id call_id)
151
 
{
152
 
    pjsua_call_info ci;
153
 
 
154
 
    pjsua_call_get_info(call_id, &ci);
155
 
 
156
 
    if (ci.media_status == PJSUA_CALL_MEDIA_ACTIVE) {
157
 
        // When media is active, connect call to sound device.
158
 
        pjsua_conf_connect(ci.conf_slot, 0);
159
 
        pjsua_conf_connect(0, ci.conf_slot);
160
 
    }
161
 
}
162
 
 
163
 
 
164
 
/* Handler on buddy state changed. */
165
 
static void on_buddy_state(pjsua_buddy_id buddy_id)
166
 
{
167
 
    pjsua_buddy_info info;
168
 
    pjsua_buddy_get_info(buddy_id, &info);
169
 
 
170
 
    PJ_LOG(3,(THIS_FILE, "%.*s status is %.*s",
171
 
              (int)info.uri.slen,
172
 
              info.uri.ptr,
173
 
              (int)info.status_text.slen,
174
 
              info.status_text.ptr));
175
 
}
176
 
 
177
 
 
178
 
/* Incoming IM message (i.e. MESSAGE request)!  */
179
 
static void on_pager(pjsua_call_id call_id, const pj_str_t *from,
180
 
                     const pj_str_t *to, const pj_str_t *contact,
181
 
                     const pj_str_t *mime_type, const pj_str_t *text)
182
 
{
183
 
    /* Note: call index may be -1 */
184
 
    PJ_UNUSED_ARG(call_id);
185
 
    PJ_UNUSED_ARG(to);
186
 
    PJ_UNUSED_ARG(contact);
187
 
    PJ_UNUSED_ARG(mime_type);
188
 
 
189
 
    PJ_LOG(3,(THIS_FILE,"MESSAGE from %.*s: %.*s",
190
 
              (int)from->slen, from->ptr,
191
 
              (int)text->slen, text->ptr));
192
 
}
193
 
 
194
 
 
195
 
/* Received typing indication  */
196
 
static void on_typing(pjsua_call_id call_id, const pj_str_t *from,
197
 
                      const pj_str_t *to, const pj_str_t *contact,
198
 
                      pj_bool_t is_typing)
199
 
{
200
 
    PJ_UNUSED_ARG(call_id);
201
 
    PJ_UNUSED_ARG(to);
202
 
    PJ_UNUSED_ARG(contact);
203
 
 
204
 
    PJ_LOG(3,(THIS_FILE, "IM indication: %.*s %s",
205
 
              (int)from->slen, from->ptr,
206
 
              (is_typing?"is typing..":"has stopped typing")));
207
 
}
208
 
 
209
 
 
210
 
/* Call transfer request status. */
211
 
static void on_call_transfer_status(pjsua_call_id call_id,
212
 
                                    int status_code,
213
 
                                    const pj_str_t *status_text,
214
 
                                    pj_bool_t final,
215
 
                                    pj_bool_t *p_cont)
216
 
{
217
 
    PJ_LOG(3,(THIS_FILE, "Call %d: transfer status=%d (%.*s) %s",
218
 
              call_id, status_code,
219
 
              (int)status_text->slen, status_text->ptr,
220
 
              (final ? "[final]" : "")));
221
 
 
222
 
    if (status_code/100 == 2) {
223
 
        PJ_LOG(3,(THIS_FILE,
224
 
                  "Call %d: call transfered successfully, disconnecting call",
225
 
                  call_id));
226
 
        pjsua_call_hangup(call_id, PJSIP_SC_GONE, NULL, NULL);
227
 
        *p_cont = PJ_FALSE;
228
 
    }
229
 
}
230
 
 
231
 
 
232
 
/* NAT detection result */
233
 
static void on_nat_detect(const pj_stun_nat_detect_result *res)
234
 
{
235
 
    if (res->status != PJ_SUCCESS) {
236
 
        pjsua_perror(THIS_FILE, "NAT detection failed", res->status);
237
 
    } else {
238
 
        PJ_LOG(3, (THIS_FILE, "NAT detected as %s", res->nat_type_name));
239
 
    }
240
 
}
241
 
 
242
 
/* Notification that call is being replaced. */
243
 
static void on_call_replaced(pjsua_call_id old_call_id,
244
 
                             pjsua_call_id new_call_id)
245
 
{
246
 
    pjsua_call_info old_ci, new_ci;
247
 
 
248
 
    pjsua_call_get_info(old_call_id, &old_ci);
249
 
    pjsua_call_get_info(new_call_id, &new_ci);
250
 
 
251
 
    PJ_LOG(3,(THIS_FILE, "Call %d with %.*s is being replaced by "
252
 
                         "call %d with %.*s",
253
 
                         old_call_id,
254
 
                         (int)old_ci.remote_info.slen, old_ci.remote_info.ptr,
255
 
                         new_call_id,
256
 
                         (int)new_ci.remote_info.slen, new_ci.remote_info.ptr));
257
 
}
258
 
 
259
 
int symbian_ua_init()
260
 
{
261
 
    TInt err;
262
 
    pj_symbianos_params sym_params;
263
 
    pj_status_t status;
264
 
 
265
 
    // Initialize RSocketServ
266
 
    if ((err=aSocketServer.Connect(32)) != KErrNone)
267
 
        return PJ_STATUS_FROM_OS(err);
268
 
 
269
 
    // Open up a connection
270
 
    if ((err=aConn.Open(aSocketServer)) != KErrNone) {
271
 
            aSocketServer.Close();
272
 
                return PJ_STATUS_FROM_OS(err);
273
 
    }
274
 
 
275
 
    if ((err=aConn.Start()) != KErrNone) {
276
 
        aConn.Close();
277
 
        aSocketServer.Close();
278
 
        return PJ_STATUS_FROM_OS(err);
279
 
    }
280
 
 
281
 
    // Set Symbian OS parameters in pjlib.
282
 
    // This must be done before pj_init() is called.
283
 
    pj_bzero(&sym_params, sizeof(sym_params));
284
 
    sym_params.rsocketserv = &aSocketServer;
285
 
    sym_params.rconnection = &aConn;
286
 
    pj_symbianos_set_params(&sym_params);
287
 
 
288
 
    /* Redirect log before pjsua_init() */
289
 
    pj_log_set_log_func(&log_writer);
290
 
 
291
 
    /* Set log level */
292
 
    pj_log_set_level(LOG_LEVEL);
293
 
 
294
 
    /* Create pjsua first! */
295
 
    status = pjsua_create();
296
 
    if (status != PJ_SUCCESS) {
297
 
        pjsua_perror(THIS_FILE, "pjsua_create() error", status);
298
 
        return status;
299
 
    }
300
 
 
301
 
    /* Init pjsua */
302
 
    pjsua_config cfg;
303
 
 
304
 
    pjsua_config_default(&cfg);
305
 
    cfg.max_calls = 2;
306
 
    cfg.thread_cnt = 0; // Disable threading on Symbian
307
 
    cfg.use_srtp = USE_SRTP;
308
 
    cfg.srtp_secure_signaling = 0;
309
 
 
310
 
    cfg.cb.on_incoming_call = &on_incoming_call;
311
 
    cfg.cb.on_call_media_state = &on_call_media_state;
312
 
    cfg.cb.on_call_state = &on_call_state;
313
 
    cfg.cb.on_buddy_state = &on_buddy_state;
314
 
    cfg.cb.on_pager = &on_pager;
315
 
    cfg.cb.on_typing = &on_typing;
316
 
    cfg.cb.on_call_transfer_status = &on_call_transfer_status;
317
 
    cfg.cb.on_call_replaced = &on_call_replaced;
318
 
    cfg.cb.on_nat_detect = &on_nat_detect;
319
 
    cfg.cb.on_reg_state = &on_reg_state;
320
 
 
321
 
    pjsua_media_config med_cfg;
322
 
 
323
 
    pjsua_media_config_default(&med_cfg);
324
 
    med_cfg.thread_cnt = 0; // Disable threading on Symbian
325
 
    med_cfg.has_ioqueue = PJ_FALSE;
326
 
    med_cfg.clock_rate = 8000;
327
 
#if defined(PJMEDIA_SYM_SND_USE_APS) && (PJMEDIA_SYM_SND_USE_APS==1)
328
 
    med_cfg.audio_frame_ptime = 20;
329
 
#else
330
 
    med_cfg.audio_frame_ptime = 40;
331
 
#endif
332
 
    med_cfg.ec_tail_len = 0;
333
 
    med_cfg.enable_ice = USE_ICE;
334
 
    med_cfg.snd_auto_close_time = 5; // wait for 5 seconds idle before sound dev get auto-closed
335
 
 
336
 
    pjsua_logging_config log_cfg;
337
 
 
338
 
    pjsua_logging_config_default(&log_cfg);
339
 
    log_cfg.console_level = LOG_LEVEL;
340
 
    log_cfg.cb = &log_writer;
341
 
    log_cfg.decor = 0;
342
 
 
343
 
    status = pjsua_init(&cfg, &log_cfg, &med_cfg);
344
 
    if (status != PJ_SUCCESS) {
345
 
            pjsua_perror(THIS_FILE, "pjsua_init() error", status);
346
 
            pjsua_destroy();
347
 
            return status;
348
 
    }
349
 
 
350
 
    /* Add UDP transport. */
351
 
    pjsua_transport_config tcfg;
352
 
    pjsua_transport_id tid;
353
 
 
354
 
    pjsua_transport_config_default(&tcfg);
355
 
    tcfg.port = SIP_PORT;
356
 
    status = pjsua_transport_create(PJSIP_TRANSPORT_UDP, &tcfg, &tid);
357
 
    if (status != PJ_SUCCESS) {
358
 
            pjsua_perror(THIS_FILE, "Error creating transport", status);
359
 
            pjsua_destroy();
360
 
            return status;
361
 
    }
362
 
 
363
 
    /* Add account for the transport */
364
 
    pjsua_acc_add_local(tid, PJ_TRUE, &g_acc_id);
365
 
 
366
 
    /* Initialization is done, now start pjsua */
367
 
    status = pjsua_start();
368
 
    if (status != PJ_SUCCESS) {
369
 
        pjsua_perror(THIS_FILE, "Error starting pjsua", status);
370
 
        pjsua_destroy();
371
 
        return status;
372
 
    }
373
 
 
374
 
    /* Adjust Speex priority and enable only the narrowband */
375
 
    {
376
 
        pj_str_t codec_id = pj_str("speex/8000");
377
 
        pjmedia_codec_mgr_set_codec_priority(
378
 
                pjmedia_endpt_get_codec_mgr(pjsua_var.med_endpt),
379
 
                &codec_id, PJMEDIA_CODEC_PRIO_NORMAL+1);
380
 
 
381
 
        codec_id = pj_str("speex/16000");
382
 
        pjmedia_codec_mgr_set_codec_priority(
383
 
                pjmedia_endpt_get_codec_mgr(pjsua_var.med_endpt),
384
 
                &codec_id, PJMEDIA_CODEC_PRIO_DISABLED);
385
 
 
386
 
        codec_id = pj_str("speex/32000");
387
 
        pjmedia_codec_mgr_set_codec_priority(
388
 
                pjmedia_endpt_get_codec_mgr(pjsua_var.med_endpt),
389
 
                &codec_id, PJMEDIA_CODEC_PRIO_DISABLED);
390
 
    }
391
 
 
392
 
    return PJ_SUCCESS;
393
 
}
394
 
 
395
 
 
396
 
int symbian_ua_destroy()
397
 
{
398
 
    // Shutdown pjsua
399
 
    pjsua_destroy();
400
 
 
401
 
    // Close connection and socket server
402
 
    aConn.Close();
403
 
    aSocketServer.Close();
404
 
 
405
 
    CloseSTDLIB();
406
 
 
407
 
    return PJ_SUCCESS;
408
 
}
409
 
 
410
 
void symbian_ua_set_info_callback(const symbian_ua_info_cb_t *cb)
411
 
{
412
 
    if (cb)
413
 
        g_cb = *cb;
414
 
    else
415
 
        pj_bzero(&g_cb, sizeof(g_cb));
416
 
}
417
 
 
418
 
int symbian_ua_set_account(const char *domain, const char *username,
419
 
                           const char *password,
420
 
                           bool use_srtp, bool use_ice)
421
 
{
422
 
    pj_status_t status;
423
 
 
424
 
    PJ_ASSERT_RETURN(username && password && domain, PJ_EINVAL);
425
 
    PJ_UNUSED_ARG(use_srtp);
426
 
    PJ_UNUSED_ARG(use_ice);
427
 
 
428
 
    if (domain[0] == 0) {
429
 
            pjsua_acc_info acc_info;
430
 
            pj_status_t status;
431
 
 
432
 
            status = pjsua_acc_get_info(g_acc_id, &acc_info);
433
 
            if (status != PJ_SUCCESS)
434
 
                return status;
435
 
 
436
 
            if (acc_info.status == 200) {
437
 
                        PJ_LOG(3,(THIS_FILE, "Unregistering.."));
438
 
                        pjsua_acc_set_registration(g_acc_id, PJ_FALSE);
439
 
                        g_acc_id = 0;
440
 
            }
441
 
            return PJ_SUCCESS;
442
 
    }
443
 
 
444
 
    if (pjsua_acc_get_count() > 1) {
445
 
        status = pjsua_acc_del(g_acc_id);
446
 
        if (status != PJ_SUCCESS) {
447
 
            pjsua_perror(THIS_FILE, "Error removing account", status);
448
 
            return status;
449
 
        }
450
 
        g_acc_id = 0;
451
 
    }
452
 
 
453
 
    pjsua_acc_config cfg;
454
 
    char tmp_id[PJSIP_MAX_URL_SIZE];
455
 
    char tmp_reg_uri[PJSIP_MAX_URL_SIZE];
456
 
 
457
 
    if (!pj_ansi_strnicmp(domain, "sip:", 4)) {
458
 
        domain += 4;
459
 
    }
460
 
 
461
 
    pjsua_acc_config_default(&cfg);
462
 
    pj_ansi_sprintf(tmp_id, "sip:%s@%s", username, domain);
463
 
    cfg.id = pj_str(tmp_id);
464
 
    pj_ansi_sprintf(tmp_reg_uri, "sip:%s", domain);
465
 
    cfg.reg_uri = pj_str(tmp_reg_uri);
466
 
    cfg.cred_count = 1;
467
 
    cfg.cred_info[0].realm = pj_str("*");
468
 
    cfg.cred_info[0].scheme = pj_str("digest");
469
 
    cfg.cred_info[0].username = pj_str((char*)username);
470
 
    cfg.cred_info[0].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
471
 
    cfg.cred_info[0].data = pj_str((char*)password);
472
 
 
473
 
    status = pjsua_acc_add(&cfg, PJ_TRUE, &g_acc_id);
474
 
    if (status != PJ_SUCCESS) {
475
 
            pjsua_perror(THIS_FILE, "Error setting account", status);
476
 
            pjsua_destroy();
477
 
            return status;
478
 
    }
479
 
 
480
 
    return PJ_SUCCESS;
481
 
}
482
 
 
483
 
int symbian_ua_makecall(const char* dest_url)
484
 
{
485
 
    if (pjsua_verify_url(dest_url) == PJ_SUCCESS) {
486
 
            pj_str_t dst = pj_str((char*)dest_url);
487
 
            pjsua_call_make_call(g_acc_id, &dst, 0, NULL,
488
 
                                 NULL, &g_call_id);
489
 
 
490
 
            return PJ_SUCCESS;
491
 
    }
492
 
 
493
 
    return PJ_EINVAL;
494
 
}
495
 
 
496
 
int symbian_ua_endcall()
497
 
{
498
 
    pjsua_call_hangup_all();
499
 
 
500
 
    return PJ_SUCCESS;
501
 
}
502
 
 
503
 
bool symbian_ua_anycall()
504
 
{
505
 
    return (pjsua_call_get_count()>0);
506
 
}
507
 
 
508
 
int symbian_ua_answercall()
509
 
{
510
 
    PJ_ASSERT_RETURN (g_call_id != PJSUA_INVALID_ID, PJ_EINVAL);
511
 
 
512
 
    return pjsua_call_answer(g_call_id, 200, NULL, NULL);
513
 
}