blob: 531e55285707fb23df74a1c5b4df349040beec19 [file] [log] [blame]
Benny Prijonoba5926a2007-05-02 11:29:37 +00001/* $Id$ */
2/*
Benny Prijono844653c2008-12-23 17:27:53 +00003 * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
Benny Prijonoba5926a2007-05-02 11:29:37 +00005 *
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 */
Benny Prijonoba5926a2007-05-02 11:29:37 +000020#include <pjsua-lib/pjsua.h>
Benny Prijono72a81aa2007-05-02 23:06:11 +000021#include <pjsua-lib/pjsua_internal.h>
Benny Prijonoba5926a2007-05-02 11:29:37 +000022#include "ua.h"
23
24#define THIS_FILE "symbian_ua.cpp"
Benny Prijono684c0ad2008-01-03 18:50:27 +000025#define LOG_LEVEL 3
Benny Prijonoba5926a2007-05-02 11:29:37 +000026
Benny Prijono72a81aa2007-05-02 23:06:11 +000027//
Benny Prijonoc71ad432007-05-04 07:25:19 +000028// Basic config.
29//
30#define SIP_PORT 5060
31
32
33//
Benny Prijonob2c96822007-05-03 13:31:21 +000034// Destination URI (to make call, or to subscribe presence)
35//
Benny Prijono0e2c6462008-02-14 13:39:24 +000036#define SIP_DST_URI "sip:100@pjsip.lab"
Benny Prijonob2c96822007-05-03 13:31:21 +000037
38//
Benny Prijono72a81aa2007-05-02 23:06:11 +000039// Account
40//
Nanang Izzuddin82f7a412008-12-17 11:36:22 +000041#define HAS_SIP_ACCOUNT 0 // 1 to enable registration
Benny Prijono0e2c6462008-02-14 13:39:24 +000042#define SIP_DOMAIN "pjsip.lab"
43#define SIP_USER "400"
44#define SIP_PASSWD "400"
Benny Prijonoba5926a2007-05-02 11:29:37 +000045
Benny Prijono72a81aa2007-05-02 23:06:11 +000046//
47// Outbound proxy for all accounts
48//
49#define SIP_PROXY NULL
Benny Prijono4b55e0a2008-12-18 13:22:52 +000050//#define SIP_PROXY "<sip:192.168.0.8;lr>"
Benny Prijono897f9f82007-05-03 19:56:21 +000051
52
53//
54// Configure nameserver if DNS SRV is to be used with both SIP
55// or STUN (for STUN see other settings below)
56//
Nanang Izzuddin82f7a412008-12-17 11:36:22 +000057#define NAMESERVER NULL
58//#define NAMESERVER "192.168.0.2"
Benny Prijono897f9f82007-05-03 19:56:21 +000059
60//
61// STUN server
Benny Prijono684c0ad2008-01-03 18:50:27 +000062#if 0
Benny Prijono897f9f82007-05-03 19:56:21 +000063 // Use this to have the STUN server resolved normally
64# define STUN_DOMAIN NULL
Benny Prijono4b55e0a2008-12-18 13:22:52 +000065# define STUN_SERVER "stun.pjsip.org"
Benny Prijono897f9f82007-05-03 19:56:21 +000066#elif 0
67 // Use this to have the STUN server resolved with DNS SRV
Benny Prijono4b55e0a2008-12-18 13:22:52 +000068# define STUN_DOMAIN "pjsip.org"
Benny Prijono897f9f82007-05-03 19:56:21 +000069# define STUN_SERVER NULL
70#else
71 // Use this to disable STUN
72# define STUN_DOMAIN NULL
73# define STUN_SERVER NULL
74#endif
75
76//
77// Use ICE?
78//
Benny Prijono70c5ba02007-12-31 11:27:35 +000079#define USE_ICE 1
Benny Prijono72a81aa2007-05-02 23:06:11 +000080
Nanang Izzuddin6a6392f2008-06-02 18:30:15 +000081//
82// Use SRTP?
83//
84#define USE_SRTP PJSUA_DEFAULT_USE_SRTP
Benny Prijono72a81aa2007-05-02 23:06:11 +000085
Benny Prijonob2c96822007-05-03 13:31:21 +000086//
87// Globals
88//
89static pjsua_acc_id g_acc_id = PJSUA_INVALID_ID;
90static pjsua_call_id g_call_id = PJSUA_INVALID_ID;
91static pjsua_buddy_id g_buddy_id = PJSUA_INVALID_ID;
Benny Prijono72a81aa2007-05-02 23:06:11 +000092
Nanang Izzuddin81db8c72009-02-05 10:59:14 +000093static pj_pool_t *app_pool;
94static pjmedia_snd_port *snd_port;
95
Benny Prijonoba5926a2007-05-02 11:29:37 +000096
97/* Callback called by the library upon receiving incoming call */
98static void on_incoming_call(pjsua_acc_id acc_id, pjsua_call_id call_id,
99 pjsip_rx_data *rdata)
100{
101 pjsua_call_info ci;
102
103 PJ_UNUSED_ARG(acc_id);
104 PJ_UNUSED_ARG(rdata);
105
Benny Prijonob2c96822007-05-03 13:31:21 +0000106 if (g_call_id != PJSUA_INVALID_ID) {
107 pjsua_call_answer(call_id, PJSIP_SC_BUSY_HERE, NULL, NULL);
108 return;
109 }
110
Benny Prijonoba5926a2007-05-02 11:29:37 +0000111 pjsua_call_get_info(call_id, &ci);
112
113 PJ_LOG(3,(THIS_FILE, "Incoming call from %.*s!!",
114 (int)ci.remote_info.slen,
115 ci.remote_info.ptr));
116
Benny Prijonob2c96822007-05-03 13:31:21 +0000117 g_call_id = call_id;
118
Benny Prijono897f9f82007-05-03 19:56:21 +0000119 /* Automatically answer incoming calls with 180/Ringing */
120 pjsua_call_answer(call_id, 180, NULL, NULL);
Benny Prijonoba5926a2007-05-02 11:29:37 +0000121}
122
123/* Callback called by the library when call's state has changed */
124static void on_call_state(pjsua_call_id call_id, pjsip_event *e)
125{
126 pjsua_call_info ci;
127
128 PJ_UNUSED_ARG(e);
129
130 pjsua_call_get_info(call_id, &ci);
Benny Prijonob2c96822007-05-03 13:31:21 +0000131
132 if (ci.state == PJSIP_INV_STATE_DISCONNECTED) {
133 if (call_id == g_call_id)
134 g_call_id = PJSUA_INVALID_ID;
Nanang Izzuddin81db8c72009-02-05 10:59:14 +0000135 if (snd_port) {
136 pjmedia_snd_port_destroy(snd_port);
137 snd_port = NULL;
138 }
Benny Prijono897f9f82007-05-03 19:56:21 +0000139 } else if (ci.state != PJSIP_INV_STATE_INCOMING) {
Benny Prijonob2c96822007-05-03 13:31:21 +0000140 if (g_call_id == PJSUA_INVALID_ID)
141 g_call_id = call_id;
142 }
143
Benny Prijonoba5926a2007-05-02 11:29:37 +0000144 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 */
150static 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
Benny Prijonob2c96822007-05-03 13:31:21 +0000164/* Handler on buddy state changed. */
165static 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)! */
179static 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 */
196static 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. */
211static 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
Benny Prijonoaecabfc2007-10-26 05:35:42 +0000232/* NAT detection result */
233static 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
Benny Prijonob2c96822007-05-03 13:31:21 +0000242/* Notification that call is being replaced. */
243static 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
Nanang Izzuddin81db8c72009-02-05 10:59:14 +0000259/* Notification that stream is created. */
260static void on_stream_created(pjsua_call_id call_id,
261 pjmedia_session *sess,
262 unsigned stream_idx,
263 pjmedia_port **p_port)
264{
265 pjmedia_port *conf;
266 pjmedia_session_info sess_info;
267 pjmedia_stream_info *strm_info;
268 pjmedia_snd_setting setting;
269 unsigned samples_per_frame;
270 pj_status_t status;
271
272 status = pjmedia_session_get_info(sess, &sess_info);
273 if (status != PJ_SUCCESS) {
274 PJ_LOG(1,(THIS_FILE, "on_stream_created() failed to get session info, "
275 "status=%d", status));
276 return;
277 }
278
279 strm_info = &sess_info.stream_info[stream_idx];
280 if (strm_info->type != PJMEDIA_TYPE_AUDIO)
281 return;
282
283 /* Don't need to reopen sound device when the session doesn't use
284 * PCM format.
285 */
286 if (strm_info->param->info.format.u32 == 0 ||
287 strm_info->param->info.format.u32 == PJMEDIA_FOURCC_L16)
288 {
289 return;
290 }
291
292 pj_bzero(&setting, sizeof(setting));
293 setting.format = strm_info->param->info.format;
294 setting.bitrate = strm_info->param->info.avg_bps;
295 setting.cng = strm_info->param->setting.cng;
296 setting.vad = strm_info->param->setting.vad;
297 setting.plc = strm_info->param->setting.plc;
298
299 /* Reopen sound device. */
300 conf = pjsua_set_no_snd_dev();
301
302 samples_per_frame = conf->info.samples_per_frame;
303
304 status = pjmedia_snd_port_create2(app_pool,
305 PJMEDIA_DIR_CAPTURE_PLAYBACK,
306 0,
307 0,
308 8000,
309 1,
310 samples_per_frame,
311 16,
312 &setting,
313 &snd_port);
314 if (status != PJ_SUCCESS) {
315 PJ_LOG(1,(THIS_FILE, "on_stream_created() failed to reopen sound "
316 "device, status=%d", status));
317 return;
318 }
319
320 status = pjmedia_snd_port_connect(snd_port, conf);
321 if (status != PJ_SUCCESS) {
322 PJ_LOG(1,(THIS_FILE, "on_stream_created() failed to connect sound "
323 "device to conference, status=%d", status));
324 return;
325 }
326}
Benny Prijonob2c96822007-05-03 13:31:21 +0000327
Nanang Izzuddin82f7a412008-12-17 11:36:22 +0000328//#include<e32debug.h>
329
Benny Prijonoba5926a2007-05-02 11:29:37 +0000330/* Logging callback */
Benny Prijono797e3382007-12-01 09:10:07 +0000331static void log_writer(int level, const char *buf, int len)
Benny Prijonoba5926a2007-05-02 11:29:37 +0000332{
Benny Prijonoc71ad432007-05-04 07:25:19 +0000333 static wchar_t buf16[PJ_LOG_MAX_SIZE];
Benny Prijonoba5926a2007-05-02 11:29:37 +0000334
335 PJ_UNUSED_ARG(level);
336
337 pj_ansi_to_unicode(buf, len, buf16, PJ_ARRAY_SIZE(buf16));
338
339 TPtrC16 aBuf((const TUint16*)buf16, (TInt)len);
Nanang Izzuddin82f7a412008-12-17 11:36:22 +0000340 //RDebug::Print(aBuf);
Benny Prijonoba5926a2007-05-02 11:29:37 +0000341 console->Write(aBuf);
Benny Prijono797e3382007-12-01 09:10:07 +0000342
Benny Prijonoba5926a2007-05-02 11:29:37 +0000343}
344
345/*
346 * app_startup()
347 *
348 * url may contain URL to call.
349 */
Benny Prijonob2c96822007-05-03 13:31:21 +0000350static pj_status_t app_startup()
Benny Prijonoba5926a2007-05-02 11:29:37 +0000351{
Benny Prijonoba5926a2007-05-02 11:29:37 +0000352 pj_status_t status;
353
354 /* Redirect log before pjsua_init() */
Benny Prijono70c5ba02007-12-31 11:27:35 +0000355 pj_log_set_log_func(&log_writer);
356
357 /* Set log level */
358 pj_log_set_level(LOG_LEVEL);
Benny Prijonoba5926a2007-05-02 11:29:37 +0000359
360 /* Create pjsua first! */
361 status = pjsua_create();
362 if (status != PJ_SUCCESS) {
363 pjsua_perror(THIS_FILE, "pjsua_create() error", status);
364 return status;
365 }
366
Nanang Izzuddin81db8c72009-02-05 10:59:14 +0000367 /* Create pool for application */
368 app_pool = pjsua_pool_create("pjsua-app", 1000, 1000);
369
Benny Prijonoba5926a2007-05-02 11:29:37 +0000370 /* Init pjsua */
Benny Prijonoc71ad432007-05-04 07:25:19 +0000371 pjsua_config cfg;
372 pjsua_logging_config log_cfg;
373 pjsua_media_config med_cfg;
Benny Prijonoba5926a2007-05-02 11:29:37 +0000374
Benny Prijonoc71ad432007-05-04 07:25:19 +0000375 pjsua_config_default(&cfg);
376 cfg.max_calls = 2;
377 cfg.thread_cnt = 0; // Disable threading on Symbian
Nanang Izzuddin6a6392f2008-06-02 18:30:15 +0000378 cfg.use_srtp = USE_SRTP;
379 cfg.srtp_secure_signaling = 0;
380
Benny Prijonoc71ad432007-05-04 07:25:19 +0000381 cfg.cb.on_incoming_call = &on_incoming_call;
382 cfg.cb.on_call_media_state = &on_call_media_state;
383 cfg.cb.on_call_state = &on_call_state;
384 cfg.cb.on_buddy_state = &on_buddy_state;
385 cfg.cb.on_pager = &on_pager;
386 cfg.cb.on_typing = &on_typing;
387 cfg.cb.on_call_transfer_status = &on_call_transfer_status;
388 cfg.cb.on_call_replaced = &on_call_replaced;
Benny Prijonoaecabfc2007-10-26 05:35:42 +0000389 cfg.cb.on_nat_detect = &on_nat_detect;
Nanang Izzuddin81db8c72009-02-05 10:59:14 +0000390 cfg.cb.on_stream_created = &on_stream_created;
Benny Prijonoaecabfc2007-10-26 05:35:42 +0000391
Benny Prijonoc71ad432007-05-04 07:25:19 +0000392 if (SIP_PROXY) {
393 cfg.outbound_proxy_cnt = 1;
394 cfg.outbound_proxy[0] = pj_str(SIP_PROXY);
395 }
396
397 if (NAMESERVER) {
398 cfg.nameserver_count = 1;
399 cfg.nameserver[0] = pj_str(NAMESERVER);
400 }
401
402 if (NAMESERVER && STUN_DOMAIN) {
403 cfg.stun_domain = pj_str(STUN_DOMAIN);
404 } else if (STUN_SERVER) {
405 cfg.stun_host = pj_str(STUN_SERVER);
406 }
407
408
409 pjsua_logging_config_default(&log_cfg);
Benny Prijono4b55e0a2008-12-18 13:22:52 +0000410 log_cfg.level = LOG_LEVEL;
411 log_cfg.console_level = LOG_LEVEL;
Benny Prijonoc71ad432007-05-04 07:25:19 +0000412 log_cfg.cb = &log_writer;
Nanang Izzuddincb2789a2008-07-24 15:30:44 +0000413 //log_cfg.log_filename = pj_str("C:\\data\\symbian_ua.log");
Benny Prijonoba5926a2007-05-02 11:29:37 +0000414
Benny Prijonoc71ad432007-05-04 07:25:19 +0000415 pjsua_media_config_default(&med_cfg);
416 med_cfg.thread_cnt = 0; // Disable threading on Symbian
417 med_cfg.has_ioqueue = PJ_FALSE;
418 med_cfg.clock_rate = 8000;
Benny Prijono5df8bb62007-12-28 18:55:02 +0000419 med_cfg.audio_frame_ptime = 40;
Benny Prijonoc71ad432007-05-04 07:25:19 +0000420 med_cfg.ec_tail_len = 0;
421 med_cfg.enable_ice = USE_ICE;
Nanang Izzuddin81db8c72009-02-05 10:59:14 +0000422 med_cfg.snd_auto_close_time = 0; // wait for 0 seconds idle before sound dev get auto-closed
Benny Prijonoc71ad432007-05-04 07:25:19 +0000423
424 status = pjsua_init(&cfg, &log_cfg, &med_cfg);
425 if (status != PJ_SUCCESS) {
426 pjsua_perror(THIS_FILE, "pjsua_init() error", status);
427 pjsua_destroy();
428 return status;
Benny Prijonoba5926a2007-05-02 11:29:37 +0000429 }
Nanang Izzuddin829ac022008-05-27 00:24:26 +0000430
431 /* Adjust Speex priority and enable only the narrowband */
432 {
433 pj_str_t codec_id = pj_str("speex/8000");
434 pjmedia_codec_mgr_set_codec_priority(
435 pjmedia_endpt_get_codec_mgr(pjsua_var.med_endpt),
436 &codec_id, PJMEDIA_CODEC_PRIO_NORMAL+1);
Benny Prijonoba5926a2007-05-02 11:29:37 +0000437
Nanang Izzuddin829ac022008-05-27 00:24:26 +0000438 codec_id = pj_str("speex/16000");
439 pjmedia_codec_mgr_set_codec_priority(
440 pjmedia_endpt_get_codec_mgr(pjsua_var.med_endpt),
441 &codec_id, PJMEDIA_CODEC_PRIO_DISABLED);
442
443 codec_id = pj_str("speex/32000");
444 pjmedia_codec_mgr_set_codec_priority(
445 pjmedia_endpt_get_codec_mgr(pjsua_var.med_endpt),
446 &codec_id, PJMEDIA_CODEC_PRIO_DISABLED);
447 }
448
Benny Prijonoba5926a2007-05-02 11:29:37 +0000449 /* Add UDP transport. */
Benny Prijonoc71ad432007-05-04 07:25:19 +0000450 pjsua_transport_config tcfg;
451 pjsua_transport_id tid;
Benny Prijonoba5926a2007-05-02 11:29:37 +0000452
Benny Prijonoc71ad432007-05-04 07:25:19 +0000453 pjsua_transport_config_default(&tcfg);
454 tcfg.port = SIP_PORT;
455 status = pjsua_transport_create(PJSIP_TRANSPORT_UDP, &tcfg, &tid);
456 if (status != PJ_SUCCESS) {
457 pjsua_perror(THIS_FILE, "Error creating transport", status);
458 pjsua_destroy();
459 return status;
Benny Prijonoba5926a2007-05-02 11:29:37 +0000460 }
461
Benny Prijonoc71ad432007-05-04 07:25:19 +0000462 /* Add account for the transport */
463 pjsua_acc_add_local(tid, PJ_TRUE, &g_acc_id);
464
465
Benny Prijonoba5926a2007-05-02 11:29:37 +0000466 /* Initialization is done, now start pjsua */
467 status = pjsua_start();
468 if (status != PJ_SUCCESS) {
469 pjsua_perror(THIS_FILE, "Error starting pjsua", status);
470 pjsua_destroy();
471 return status;
472 }
473
474 /* Register to SIP server by creating SIP account. */
Benny Prijono72a81aa2007-05-02 23:06:11 +0000475 if (HAS_SIP_ACCOUNT) {
Benny Prijonoba5926a2007-05-02 11:29:37 +0000476 pjsua_acc_config cfg;
477
478 pjsua_acc_config_default(&cfg);
479 cfg.id = pj_str("sip:" SIP_USER "@" SIP_DOMAIN);
480 cfg.reg_uri = pj_str("sip:" SIP_DOMAIN);
481 cfg.cred_count = 1;
Benny Prijono0e2c6462008-02-14 13:39:24 +0000482 cfg.cred_info[0].realm = pj_str("*");
Benny Prijonoba5926a2007-05-02 11:29:37 +0000483 cfg.cred_info[0].scheme = pj_str("digest");
484 cfg.cred_info[0].username = pj_str(SIP_USER);
485 cfg.cred_info[0].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
486 cfg.cred_info[0].data = pj_str(SIP_PASSWD);
487
Benny Prijonob2c96822007-05-03 13:31:21 +0000488 status = pjsua_acc_add(&cfg, PJ_TRUE, &g_acc_id);
Benny Prijonoba5926a2007-05-02 11:29:37 +0000489 if (status != PJ_SUCCESS) {
490 pjsua_perror(THIS_FILE, "Error adding account", status);
491 pjsua_destroy();
492 return status;
493 }
494 }
495
Benny Prijonob2c96822007-05-03 13:31:21 +0000496 if (SIP_DST_URI) {
497 pjsua_buddy_config bcfg;
498
499 pjsua_buddy_config_default(&bcfg);
500 bcfg.uri = pj_str(SIP_DST_URI);
501 bcfg.subscribe = PJ_FALSE;
502
503 pjsua_buddy_add(&bcfg, &g_buddy_id);
Benny Prijonoba5926a2007-05-02 11:29:37 +0000504 }
Benny Prijonoba5926a2007-05-02 11:29:37 +0000505 return PJ_SUCCESS;
506}
507
508
509////////////////////////////////////////////////////////////////////////////
Benny Prijonoc71ad432007-05-04 07:25:19 +0000510/*
511 * The interractive console UI
512 */
Benny Prijonoba5926a2007-05-02 11:29:37 +0000513#include <e32base.h>
514
515class ConsoleUI : public CActive
516{
517public:
Nanang Izzuddin82f7a412008-12-17 11:36:22 +0000518 ConsoleUI(CConsoleBase *con);
Benny Prijonoba5926a2007-05-02 11:29:37 +0000519
Benny Prijonoc71ad432007-05-04 07:25:19 +0000520 // Run console UI
521 void Run();
522
523 // Stop
524 void Stop();
Benny Prijonoba5926a2007-05-02 11:29:37 +0000525
526protected:
Benny Prijonoc71ad432007-05-04 07:25:19 +0000527 // Cancel asynchronous read.
528 void DoCancel();
Benny Prijonoba5926a2007-05-02 11:29:37 +0000529
Benny Prijonoc71ad432007-05-04 07:25:19 +0000530 // Implementation: called when read has completed.
531 void RunL();
Benny Prijonoba5926a2007-05-02 11:29:37 +0000532
533private:
Benny Prijonoc71ad432007-05-04 07:25:19 +0000534 CConsoleBase *con_;
Benny Prijonoba5926a2007-05-02 11:29:37 +0000535};
536
537
Nanang Izzuddin82f7a412008-12-17 11:36:22 +0000538ConsoleUI::ConsoleUI(CConsoleBase *con)
539: CActive(EPriorityStandard), con_(con)
Benny Prijonoba5926a2007-05-02 11:29:37 +0000540{
Benny Prijonoc71ad432007-05-04 07:25:19 +0000541 CActiveScheduler::Add(this);
Benny Prijonoba5926a2007-05-02 11:29:37 +0000542}
543
544// Run console UI
545void ConsoleUI::Run()
546{
Benny Prijonoc71ad432007-05-04 07:25:19 +0000547 con_->Read(iStatus);
548 SetActive();
Benny Prijonoba5926a2007-05-02 11:29:37 +0000549}
550
551// Stop console UI
552void ConsoleUI::Stop()
553{
Benny Prijonoc71ad432007-05-04 07:25:19 +0000554 DoCancel();
Benny Prijonoba5926a2007-05-02 11:29:37 +0000555}
556
557// Cancel asynchronous read.
558void ConsoleUI::DoCancel()
559{
Benny Prijonoc71ad432007-05-04 07:25:19 +0000560 con_->ReadCancel();
Benny Prijonoba5926a2007-05-02 11:29:37 +0000561}
562
Benny Prijono72a81aa2007-05-02 23:06:11 +0000563static void PrintMenu()
564{
Benny Prijonoc71ad432007-05-04 07:25:19 +0000565 PJ_LOG(3, (THIS_FILE, "\n\n"
566 "Menu:\n"
567 " d Dump states\n"
Benny Prijono1f61a8f2007-08-16 10:11:44 +0000568 " D Dump states detail\n"
Benny Prijonoc71ad432007-05-04 07:25:19 +0000569 " P Dump pool factory\n"
Benny Prijono5df8bb62007-12-28 18:55:02 +0000570 " l Start loopback audio device\n"
571 " L Stop loopback audio device\n"
Benny Prijono70c5ba02007-12-31 11:27:35 +0000572 " m Call " SIP_DST_URI "\n"
573 " a Answer call\n"
574 " g Hangup all calls\n"
Benny Prijono1f61a8f2007-08-16 10:11:44 +0000575 " s Subscribe " SIP_DST_URI "\n"
Benny Prijonoc71ad432007-05-04 07:25:19 +0000576 " S Unsubscribe presence\n"
577 " o Set account online\n"
578 " O Set account offline\n"
Benny Prijono70c5ba02007-12-31 11:27:35 +0000579 " w Quit\n"));
Benny Prijono72a81aa2007-05-02 23:06:11 +0000580}
581
Benny Prijonoba5926a2007-05-02 11:29:37 +0000582// Implementation: called when read has completed.
583void ConsoleUI::RunL()
584{
Benny Prijonoc71ad432007-05-04 07:25:19 +0000585 TKeyCode kc = con_->KeyCode();
586 pj_bool_t reschedule = PJ_TRUE;
587
588 switch (kc) {
Benny Prijono70c5ba02007-12-31 11:27:35 +0000589 case 'w':
Nanang Izzuddin82f7a412008-12-17 11:36:22 +0000590 CActiveScheduler::Stop();
Benny Prijonoc71ad432007-05-04 07:25:19 +0000591 reschedule = PJ_FALSE;
592 break;
593 case 'D':
594 case 'd':
595 pjsua_dump(kc == 'D');
596 break;
597 case 'p':
598 case 'P':
Benny Prijono1f61a8f2007-08-16 10:11:44 +0000599 pj_pool_factory_dump(pjsua_get_pool_factory(), PJ_TRUE);
Benny Prijonoc71ad432007-05-04 07:25:19 +0000600 break;
Benny Prijono5df8bb62007-12-28 18:55:02 +0000601 case 'l':
602 pjsua_conf_connect(0, 0);
603 break;
604 case 'L':
605 pjsua_conf_disconnect(0, 0);
606 break;
Benny Prijono70c5ba02007-12-31 11:27:35 +0000607 case 'm':
Benny Prijonoc71ad432007-05-04 07:25:19 +0000608 if (g_call_id != PJSUA_INVALID_ID) {
609 PJ_LOG(3,(THIS_FILE, "Another call is active"));
610 break;
611 }
612
613 if (pjsua_verify_sip_url(SIP_DST_URI) == PJ_SUCCESS) {
614 pj_str_t dst = pj_str(SIP_DST_URI);
615 pjsua_call_make_call(g_acc_id, &dst, 0, NULL,
616 NULL, &g_call_id);
617 } else {
618 PJ_LOG(3,(THIS_FILE, "Invalid SIP URI"));
619 }
620 break;
Benny Prijono70c5ba02007-12-31 11:27:35 +0000621 case 'a':
Benny Prijonoc71ad432007-05-04 07:25:19 +0000622 if (g_call_id != PJSUA_INVALID_ID)
623 pjsua_call_answer(g_call_id, 200, NULL, NULL);
624 break;
Benny Prijono70c5ba02007-12-31 11:27:35 +0000625 case 'g':
Benny Prijonoc71ad432007-05-04 07:25:19 +0000626 pjsua_call_hangup_all();
627 break;
628 case 's':
629 case 'S':
630 if (g_buddy_id != PJSUA_INVALID_ID)
631 pjsua_buddy_subscribe_pres(g_buddy_id, kc=='s');
632 break;
633 case 'o':
634 case 'O':
635 pjsua_acc_set_online_status(g_acc_id, kc=='o');
636 break;
637 default:
638 PJ_LOG(3,(THIS_FILE, "Keycode '%c' (%d) is pressed",
639 kc, kc));
640 break;
641 }
Benny Prijono72a81aa2007-05-02 23:06:11 +0000642
Benny Prijonoc71ad432007-05-04 07:25:19 +0000643 PrintMenu();
644
645 if (reschedule)
646 Run();
Benny Prijonoba5926a2007-05-02 11:29:37 +0000647}
648
Benny Prijono70c5ba02007-12-31 11:27:35 +0000649#if 0
650// IP networking related testing
651static pj_status_t test_addr(void)
652{
653 int af;
654 unsigned i, count;
655 pj_addrinfo ai[8];
656 pj_sockaddr ifs[8];
657 const pj_str_t *hostname;
658 pj_hostent he;
659 pj_status_t status;
660
661 pj_log_set_log_func(&log_writer);
662
663 status = pj_init();
664 if (status != PJ_SUCCESS) {
665 pjsua_perror(THIS_FILE, "pj_init() error", status);
666 return status;
667 }
668
669 af = pj_AF_INET();
670
Benny Prijono684c0ad2008-01-03 18:50:27 +0000671#if 0
672 pj_in_addr in_addr;
673 pj_str_t aa = pj_str("1.1.1.1");
674 in_addr = pj_inet_addr(&aa);
675 char *the_addr = pj_inet_ntoa(in_addr);
676 PJ_LOG(3,(THIS_FILE, "IP addr=%s", the_addr));
677
678 aa = pj_str("192.168.0.15");
679 in_addr = pj_inet_addr(&aa);
680 the_addr = pj_inet_ntoa(in_addr);
681 PJ_LOG(3,(THIS_FILE, "IP addr=%s", the_addr));
682
683 aa = pj_str("2.2.2.2");
684 in_addr = pj_inet_addr(&aa);
685 the_addr = pj_inet_ntoa(in_addr);
686 PJ_LOG(3,(THIS_FILE, "IP addr=%s", the_addr));
687
688 return -1;
689#endif
690
Benny Prijono70c5ba02007-12-31 11:27:35 +0000691 // Hostname
692 hostname = pj_gethostname();
693 if (hostname == NULL) {
694 status = PJ_ERESOLVE;
695 pjsua_perror(THIS_FILE, "pj_gethostname() error", status);
696 goto on_return;
697 }
698
699 PJ_LOG(3,(THIS_FILE, "Hostname: %.*s", hostname->slen, hostname->ptr));
700
701 // Gethostbyname
702 status = pj_gethostbyname(hostname, &he);
703 if (status != PJ_SUCCESS) {
704 pjsua_perror(THIS_FILE, "pj_gethostbyname() error", status);
705 } else {
706 PJ_LOG(3,(THIS_FILE, "gethostbyname: %s",
707 pj_inet_ntoa(*(pj_in_addr*)he.h_addr)));
708 }
709
710 // Getaddrinfo
711 count = PJ_ARRAY_SIZE(ai);
712 status = pj_getaddrinfo(af, hostname, &count, ai);
713 if (status != PJ_SUCCESS) {
714 pjsua_perror(THIS_FILE, "pj_getaddrinfo() error", status);
715 } else {
716 for (i=0; i<count; ++i) {
717 char ipaddr[PJ_INET6_ADDRSTRLEN+2];
718 PJ_LOG(3,(THIS_FILE, "Addrinfo: %s",
719 pj_sockaddr_print(&ai[i].ai_addr, ipaddr, sizeof(ipaddr), 2)));
720 }
721 }
722
723 // Enum interface
724 count = PJ_ARRAY_SIZE(ifs);
725 status = pj_enum_ip_interface(af, &count, ifs);
726 if (status != PJ_SUCCESS) {
727 pjsua_perror(THIS_FILE, "pj_enum_ip_interface() error", status);
728 } else {
729 for (i=0; i<count; ++i) {
730 char ipaddr[PJ_INET6_ADDRSTRLEN+2];
731 PJ_LOG(3,(THIS_FILE, "Interface: %s",
732 pj_sockaddr_print(&ifs[i], ipaddr, sizeof(ipaddr), 2)));
733 }
734 }
735
736 // Get default iinterface
737 status = pj_getdefaultipinterface(af, &ifs[0]);
738 if (status != PJ_SUCCESS) {
739 pjsua_perror(THIS_FILE, "pj_getdefaultipinterface() error", status);
740 } else {
741 char ipaddr[PJ_INET6_ADDRSTRLEN+2];
742 PJ_LOG(3,(THIS_FILE, "Default IP: %s",
743 pj_sockaddr_print(&ifs[0], ipaddr, sizeof(ipaddr), 2)));
744 }
745
746 // Get default IP address
747 status = pj_gethostip(af, &ifs[0]);
748 if (status != PJ_SUCCESS) {
749 pjsua_perror(THIS_FILE, "pj_gethostip() error", status);
750 } else {
751 char ipaddr[PJ_INET6_ADDRSTRLEN+2];
752 PJ_LOG(3,(THIS_FILE, "Host IP: %s",
753 pj_sockaddr_print(&ifs[0], ipaddr, sizeof(ipaddr), 2)));
754 }
755
756 status = -1;
757
758on_return:
759 pj_shutdown();
760 return status;
761}
762#endif
763
764
Benny Prijono6b3ccdf2008-01-14 11:54:21 +0000765#include <es_sock.h>
Benny Prijono897f9f82007-05-03 19:56:21 +0000766
Nanang Izzuddin82f7a412008-12-17 11:36:22 +0000767#if 0
768// Force network connection to use the first IAP,
769// this is useful for debugging on emulator without GUI.
770// Include commdb.lib & apengine.lib in symbian_ua.mmp file
771// if this is enabled.
772
773#include <apdatahandler.h>
774
775inline void ForceUseFirstIAP()
776{
777 TUint32 rank = 1;
778 TUint32 bearers;
779 TUint32 prompt;
780 TUint32 iap;
781
782 CCommsDatabase* commDb = CCommsDatabase::NewL(EDatabaseTypeIAP);
783 CleanupStack::PushL(commDb);
784
785 CApDataHandler* apDataHandler = CApDataHandler::NewLC(*commDb);
786
787 TCommDbConnectionDirection direction = ECommDbConnectionDirectionOutgoing;
788 apDataHandler->GetPreferredIfDbIapTypeL(rank, direction, bearers, prompt, iap);
789 prompt = ECommDbDialogPrefDoNotPrompt;
790 apDataHandler->SetPreferredIfDbIapTypeL(rank, direction, bearers, (TCommDbDialogPref)prompt, iap, ETrue);
791 CleanupStack::PopAndDestroy(2); // apDataHandler, commDb
792}
793
794static void SelectIAP()
795{
796 ForceUseFirstIAP();
797}
798
799#else
800
801static void SelectIAP()
802{
803}
804
805#endif
806
807
Benny Prijonoba5926a2007-05-02 11:29:37 +0000808////////////////////////////////////////////////////////////////////////////
809int ua_main()
810{
Nanang Izzuddin82f7a412008-12-17 11:36:22 +0000811 RSocketServ aSocketServer;
812 RConnection aConn;
813 TInt err;
814 pj_symbianos_params sym_params;
Benny Prijonoc71ad432007-05-04 07:25:19 +0000815 pj_status_t status;
Nanang Izzuddin82f7a412008-12-17 11:36:22 +0000816
817 SelectIAP();
Benny Prijonoc71ad432007-05-04 07:25:19 +0000818
Benny Prijono70c5ba02007-12-31 11:27:35 +0000819 // Initialize RSocketServ
820 if ((err=aSocketServer.Connect()) != KErrNone)
821 return PJ_STATUS_FROM_OS(err);
822
823 // Open up a connection
824 if ((err=aConn.Open(aSocketServer)) != KErrNone) {
Nanang Izzuddin82f7a412008-12-17 11:36:22 +0000825 aSocketServer.Close();
826 return PJ_STATUS_FROM_OS(err);
Benny Prijono70c5ba02007-12-31 11:27:35 +0000827 }
828
829 if ((err=aConn.Start()) != KErrNone) {
830 aSocketServer.Close();
831 return PJ_STATUS_FROM_OS(err);
832 }
833
834 // Set Symbian OS parameters in pjlib.
835 // This must be done before pj_init() is called.
836 pj_bzero(&sym_params, sizeof(sym_params));
837 sym_params.rsocketserv = &aSocketServer;
838 sym_params.rconnection = &aConn;
839 pj_symbianos_set_params(&sym_params);
840
Benny Prijonoc71ad432007-05-04 07:25:19 +0000841 // Initialize pjsua
842 status = app_startup();
Benny Prijono70c5ba02007-12-31 11:27:35 +0000843 //status = test_addr();
844 if (status != PJ_SUCCESS) {
845 aConn.Close();
846 aSocketServer.Close();
Nanang Izzuddin82f7a412008-12-17 11:36:22 +0000847 return status;
Benny Prijono70c5ba02007-12-31 11:27:35 +0000848 }
Benny Prijono897f9f82007-05-03 19:56:21 +0000849
Benny Prijonoc71ad432007-05-04 07:25:19 +0000850 // Run the UI
Nanang Izzuddin82f7a412008-12-17 11:36:22 +0000851 ConsoleUI *con = new ConsoleUI(console);
Benny Prijonoc71ad432007-05-04 07:25:19 +0000852
853 con->Run();
Benny Prijonoc71ad432007-05-04 07:25:19 +0000854 PrintMenu();
Nanang Izzuddin82f7a412008-12-17 11:36:22 +0000855
856 CActiveScheduler::Start();
Benny Prijonoc71ad432007-05-04 07:25:19 +0000857
858 delete con;
Benny Prijono684c0ad2008-01-03 18:50:27 +0000859
860 // Dump memory statistics
861 PJ_LOG(3,(THIS_FILE, "Max heap usage: %u.%03uMB",
Nanang Izzuddin82f7a412008-12-17 11:36:22 +0000862 pjsua_var.cp.peak_used_size / 1000000,
863 (pjsua_var.cp.peak_used_size % 1000000)/1000));
Benny Prijonoc71ad432007-05-04 07:25:19 +0000864
Benny Prijono684c0ad2008-01-03 18:50:27 +0000865 // check max stack usage
866#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
867 pj_thread_t* this_thread = pj_thread_this();
868 if (!this_thread)
Nanang Izzuddin82f7a412008-12-17 11:36:22 +0000869 return status;
Benny Prijono684c0ad2008-01-03 18:50:27 +0000870
871 const char* max_stack_file;
872 int max_stack_line;
873 status = pj_thread_get_stack_info(this_thread, &max_stack_file, &max_stack_line);
874
875 PJ_LOG(3,(THIS_FILE, "Max stack usage: %u at %s:%d",
Nanang Izzuddin82f7a412008-12-17 11:36:22 +0000876 pj_thread_get_stack_max_usage(this_thread),
877 max_stack_file, max_stack_line));
Benny Prijono684c0ad2008-01-03 18:50:27 +0000878#endif
879
Nanang Izzuddin81db8c72009-02-05 10:59:14 +0000880 // Let pjsua destroys app pool, since the pool may still be used by app
881 // until pjsua_destroy() finished.
882 // e.g: quitting app when there is an active call may cause sound port
883 // memory destroyed before sound port itself gets closed/destroyed.
884 /*
885 // Release application pool
886 if (app_pool) {
887 pj_pool_release(app_pool);
888 app_pool = NULL;
889 }
890 */
891
Benny Prijonoc71ad432007-05-04 07:25:19 +0000892 // Shutdown pjsua
893 pjsua_destroy();
894
Benny Prijono70c5ba02007-12-31 11:27:35 +0000895 // Close connection and socket server
896 aConn.Close();
Nanang Izzuddin82f7a412008-12-17 11:36:22 +0000897 aSocketServer.Close();
Benny Prijono70c5ba02007-12-31 11:27:35 +0000898
Benny Prijono797e3382007-12-01 09:10:07 +0000899 return status;
Benny Prijonoba5926a2007-05-02 11:29:37 +0000900}
901