blob: 2a32cdb156f45e4ae19922a945f9bf370f960376 [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>
Nanang Izzuddina940b362009-02-23 13:53:30 +000022//#include <pjmedia/symbian_sound_aps.h>
Benny Prijonoba5926a2007-05-02 11:29:37 +000023#include "ua.h"
24
25#define THIS_FILE "symbian_ua.cpp"
Nanang Izzuddinda37ea32009-03-06 16:24:43 +000026#define CON_LOG_LEVEL 3 // console log level
27#define FILE_LOG_LEVEL 4 // logfile log level
Benny Prijonoba5926a2007-05-02 11:29:37 +000028
Benny Prijono72a81aa2007-05-02 23:06:11 +000029//
Benny Prijonoc71ad432007-05-04 07:25:19 +000030// Basic config.
31//
32#define SIP_PORT 5060
33
34
35//
Benny Prijonob2c96822007-05-03 13:31:21 +000036// Destination URI (to make call, or to subscribe presence)
37//
Benny Prijono0e2c6462008-02-14 13:39:24 +000038#define SIP_DST_URI "sip:100@pjsip.lab"
Benny Prijonob2c96822007-05-03 13:31:21 +000039
40//
Benny Prijono72a81aa2007-05-02 23:06:11 +000041// Account
42//
Nanang Izzuddin82f7a412008-12-17 11:36:22 +000043#define HAS_SIP_ACCOUNT 0 // 1 to enable registration
Benny Prijono0e2c6462008-02-14 13:39:24 +000044#define SIP_DOMAIN "pjsip.lab"
45#define SIP_USER "400"
46#define SIP_PASSWD "400"
Benny Prijonoba5926a2007-05-02 11:29:37 +000047
Benny Prijono72a81aa2007-05-02 23:06:11 +000048//
49// Outbound proxy for all accounts
50//
51#define SIP_PROXY NULL
Benny Prijono4b55e0a2008-12-18 13:22:52 +000052//#define SIP_PROXY "<sip:192.168.0.8;lr>"
Benny Prijono897f9f82007-05-03 19:56:21 +000053
54
55//
56// Configure nameserver if DNS SRV is to be used with both SIP
57// or STUN (for STUN see other settings below)
58//
Nanang Izzuddin82f7a412008-12-17 11:36:22 +000059#define NAMESERVER NULL
60//#define NAMESERVER "192.168.0.2"
Benny Prijono897f9f82007-05-03 19:56:21 +000061
62//
63// STUN server
Benny Prijono684c0ad2008-01-03 18:50:27 +000064#if 0
Benny Prijono897f9f82007-05-03 19:56:21 +000065 // Use this to have the STUN server resolved normally
66# define STUN_DOMAIN NULL
Benny Prijono4b55e0a2008-12-18 13:22:52 +000067# define STUN_SERVER "stun.pjsip.org"
Benny Prijono897f9f82007-05-03 19:56:21 +000068#elif 0
69 // Use this to have the STUN server resolved with DNS SRV
Benny Prijono4b55e0a2008-12-18 13:22:52 +000070# define STUN_DOMAIN "pjsip.org"
Benny Prijono897f9f82007-05-03 19:56:21 +000071# define STUN_SERVER NULL
72#else
73 // Use this to disable STUN
74# define STUN_DOMAIN NULL
75# define STUN_SERVER NULL
76#endif
77
78//
79// Use ICE?
80//
Benny Prijono70c5ba02007-12-31 11:27:35 +000081#define USE_ICE 1
Benny Prijono72a81aa2007-05-02 23:06:11 +000082
Nanang Izzuddin6a6392f2008-06-02 18:30:15 +000083//
84// Use SRTP?
85//
86#define USE_SRTP PJSUA_DEFAULT_USE_SRTP
Benny Prijono72a81aa2007-05-02 23:06:11 +000087
Benny Prijonob2c96822007-05-03 13:31:21 +000088//
89// Globals
90//
91static pjsua_acc_id g_acc_id = PJSUA_INVALID_ID;
92static pjsua_call_id g_call_id = PJSUA_INVALID_ID;
93static pjsua_buddy_id g_buddy_id = PJSUA_INVALID_ID;
Benny Prijono72a81aa2007-05-02 23:06:11 +000094
Benny Prijonoba5926a2007-05-02 11:29:37 +000095
96/* Callback called by the library upon receiving incoming call */
97static void on_incoming_call(pjsua_acc_id acc_id, pjsua_call_id call_id,
98 pjsip_rx_data *rdata)
99{
100 pjsua_call_info ci;
101
102 PJ_UNUSED_ARG(acc_id);
103 PJ_UNUSED_ARG(rdata);
104
Benny Prijonob2c96822007-05-03 13:31:21 +0000105 if (g_call_id != PJSUA_INVALID_ID) {
106 pjsua_call_answer(call_id, PJSIP_SC_BUSY_HERE, NULL, NULL);
107 return;
108 }
109
Benny Prijonoba5926a2007-05-02 11:29:37 +0000110 pjsua_call_get_info(call_id, &ci);
111
112 PJ_LOG(3,(THIS_FILE, "Incoming call from %.*s!!",
113 (int)ci.remote_info.slen,
114 ci.remote_info.ptr));
115
Benny Prijonob2c96822007-05-03 13:31:21 +0000116 g_call_id = call_id;
117
Benny Prijono897f9f82007-05-03 19:56:21 +0000118 /* Automatically answer incoming calls with 180/Ringing */
119 pjsua_call_answer(call_id, 180, NULL, NULL);
Benny Prijonoba5926a2007-05-02 11:29:37 +0000120}
121
122/* Callback called by the library when call's state has changed */
123static void on_call_state(pjsua_call_id call_id, pjsip_event *e)
124{
125 pjsua_call_info ci;
126
127 PJ_UNUSED_ARG(e);
128
129 pjsua_call_get_info(call_id, &ci);
Benny Prijonob2c96822007-05-03 13:31:21 +0000130
131 if (ci.state == PJSIP_INV_STATE_DISCONNECTED) {
132 if (call_id == g_call_id)
133 g_call_id = PJSUA_INVALID_ID;
Benny Prijono897f9f82007-05-03 19:56:21 +0000134 } else if (ci.state != PJSIP_INV_STATE_INCOMING) {
Benny Prijonob2c96822007-05-03 13:31:21 +0000135 if (g_call_id == PJSUA_INVALID_ID)
136 g_call_id = call_id;
137 }
138
Benny Prijonoba5926a2007-05-02 11:29:37 +0000139 PJ_LOG(3,(THIS_FILE, "Call %d state=%.*s", call_id,
140 (int)ci.state_text.slen,
141 ci.state_text.ptr));
142}
143
144/* Callback called by the library when call's media state has changed */
145static void on_call_media_state(pjsua_call_id call_id)
146{
147 pjsua_call_info ci;
148
149 pjsua_call_get_info(call_id, &ci);
150
151 if (ci.media_status == PJSUA_CALL_MEDIA_ACTIVE) {
152 // When media is active, connect call to sound device.
153 pjsua_conf_connect(ci.conf_slot, 0);
154 pjsua_conf_connect(0, ci.conf_slot);
155 }
156}
157
158
Benny Prijonob2c96822007-05-03 13:31:21 +0000159/* Handler on buddy state changed. */
160static void on_buddy_state(pjsua_buddy_id buddy_id)
161{
162 pjsua_buddy_info info;
163 pjsua_buddy_get_info(buddy_id, &info);
164
165 PJ_LOG(3,(THIS_FILE, "%.*s status is %.*s",
166 (int)info.uri.slen,
167 info.uri.ptr,
168 (int)info.status_text.slen,
169 info.status_text.ptr));
170}
171
172
173/* Incoming IM message (i.e. MESSAGE request)! */
174static void on_pager(pjsua_call_id call_id, const pj_str_t *from,
175 const pj_str_t *to, const pj_str_t *contact,
176 const pj_str_t *mime_type, const pj_str_t *text)
177{
178 /* Note: call index may be -1 */
179 PJ_UNUSED_ARG(call_id);
180 PJ_UNUSED_ARG(to);
181 PJ_UNUSED_ARG(contact);
182 PJ_UNUSED_ARG(mime_type);
183
184 PJ_LOG(3,(THIS_FILE,"MESSAGE from %.*s: %.*s",
185 (int)from->slen, from->ptr,
186 (int)text->slen, text->ptr));
187}
188
189
190/* Received typing indication */
191static void on_typing(pjsua_call_id call_id, const pj_str_t *from,
192 const pj_str_t *to, const pj_str_t *contact,
193 pj_bool_t is_typing)
194{
195 PJ_UNUSED_ARG(call_id);
196 PJ_UNUSED_ARG(to);
197 PJ_UNUSED_ARG(contact);
198
199 PJ_LOG(3,(THIS_FILE, "IM indication: %.*s %s",
200 (int)from->slen, from->ptr,
201 (is_typing?"is typing..":"has stopped typing")));
202}
203
204
205/* Call transfer request status. */
206static void on_call_transfer_status(pjsua_call_id call_id,
207 int status_code,
208 const pj_str_t *status_text,
209 pj_bool_t final,
210 pj_bool_t *p_cont)
211{
212 PJ_LOG(3,(THIS_FILE, "Call %d: transfer status=%d (%.*s) %s",
213 call_id, status_code,
214 (int)status_text->slen, status_text->ptr,
215 (final ? "[final]" : "")));
216
217 if (status_code/100 == 2) {
218 PJ_LOG(3,(THIS_FILE,
219 "Call %d: call transfered successfully, disconnecting call",
220 call_id));
221 pjsua_call_hangup(call_id, PJSIP_SC_GONE, NULL, NULL);
222 *p_cont = PJ_FALSE;
223 }
224}
225
226
Benny Prijonoaecabfc2007-10-26 05:35:42 +0000227/* NAT detection result */
228static void on_nat_detect(const pj_stun_nat_detect_result *res)
229{
230 if (res->status != PJ_SUCCESS) {
231 pjsua_perror(THIS_FILE, "NAT detection failed", res->status);
232 } else {
233 PJ_LOG(3, (THIS_FILE, "NAT detected as %s", res->nat_type_name));
234 }
235}
236
Benny Prijonob2c96822007-05-03 13:31:21 +0000237/* Notification that call is being replaced. */
238static void on_call_replaced(pjsua_call_id old_call_id,
239 pjsua_call_id new_call_id)
240{
241 pjsua_call_info old_ci, new_ci;
242
243 pjsua_call_get_info(old_call_id, &old_ci);
244 pjsua_call_get_info(new_call_id, &new_ci);
245
246 PJ_LOG(3,(THIS_FILE, "Call %d with %.*s is being replaced by "
247 "call %d with %.*s",
248 old_call_id,
249 (int)old_ci.remote_info.slen, old_ci.remote_info.ptr,
250 new_call_id,
251 (int)new_ci.remote_info.slen, new_ci.remote_info.ptr));
252}
253
Nanang Izzuddin83457d52009-02-16 16:29:05 +0000254
Nanang Izzuddin82f7a412008-12-17 11:36:22 +0000255//#include<e32debug.h>
256
Benny Prijonoba5926a2007-05-02 11:29:37 +0000257/* Logging callback */
Benny Prijono797e3382007-12-01 09:10:07 +0000258static void log_writer(int level, const char *buf, int len)
Benny Prijonoba5926a2007-05-02 11:29:37 +0000259{
Benny Prijonoc71ad432007-05-04 07:25:19 +0000260 static wchar_t buf16[PJ_LOG_MAX_SIZE];
Benny Prijonoba5926a2007-05-02 11:29:37 +0000261
262 PJ_UNUSED_ARG(level);
263
264 pj_ansi_to_unicode(buf, len, buf16, PJ_ARRAY_SIZE(buf16));
265
266 TPtrC16 aBuf((const TUint16*)buf16, (TInt)len);
Nanang Izzuddin82f7a412008-12-17 11:36:22 +0000267 //RDebug::Print(aBuf);
Benny Prijonoba5926a2007-05-02 11:29:37 +0000268 console->Write(aBuf);
Benny Prijono797e3382007-12-01 09:10:07 +0000269
Benny Prijonoba5926a2007-05-02 11:29:37 +0000270}
271
272/*
273 * app_startup()
274 *
275 * url may contain URL to call.
276 */
Benny Prijonob2c96822007-05-03 13:31:21 +0000277static pj_status_t app_startup()
Benny Prijonoba5926a2007-05-02 11:29:37 +0000278{
Benny Prijonoba5926a2007-05-02 11:29:37 +0000279 pj_status_t status;
280
281 /* Redirect log before pjsua_init() */
Benny Prijono70c5ba02007-12-31 11:27:35 +0000282 pj_log_set_log_func(&log_writer);
283
284 /* Set log level */
Nanang Izzuddinda37ea32009-03-06 16:24:43 +0000285 pj_log_set_level(CON_LOG_LEVEL);
Benny Prijonoba5926a2007-05-02 11:29:37 +0000286
287 /* Create pjsua first! */
288 status = pjsua_create();
289 if (status != PJ_SUCCESS) {
290 pjsua_perror(THIS_FILE, "pjsua_create() error", status);
291 return status;
292 }
293
Benny Prijonoba5926a2007-05-02 11:29:37 +0000294 /* Init pjsua */
Benny Prijonoc71ad432007-05-04 07:25:19 +0000295 pjsua_config cfg;
296 pjsua_logging_config log_cfg;
297 pjsua_media_config med_cfg;
Benny Prijonoba5926a2007-05-02 11:29:37 +0000298
Benny Prijonoc71ad432007-05-04 07:25:19 +0000299 pjsua_config_default(&cfg);
300 cfg.max_calls = 2;
301 cfg.thread_cnt = 0; // Disable threading on Symbian
Nanang Izzuddin6a6392f2008-06-02 18:30:15 +0000302 cfg.use_srtp = USE_SRTP;
303 cfg.srtp_secure_signaling = 0;
304
Benny Prijonoc71ad432007-05-04 07:25:19 +0000305 cfg.cb.on_incoming_call = &on_incoming_call;
306 cfg.cb.on_call_media_state = &on_call_media_state;
307 cfg.cb.on_call_state = &on_call_state;
308 cfg.cb.on_buddy_state = &on_buddy_state;
309 cfg.cb.on_pager = &on_pager;
310 cfg.cb.on_typing = &on_typing;
311 cfg.cb.on_call_transfer_status = &on_call_transfer_status;
312 cfg.cb.on_call_replaced = &on_call_replaced;
Benny Prijonoaecabfc2007-10-26 05:35:42 +0000313 cfg.cb.on_nat_detect = &on_nat_detect;
314
Benny Prijonoc71ad432007-05-04 07:25:19 +0000315 if (SIP_PROXY) {
316 cfg.outbound_proxy_cnt = 1;
317 cfg.outbound_proxy[0] = pj_str(SIP_PROXY);
318 }
319
320 if (NAMESERVER) {
321 cfg.nameserver_count = 1;
322 cfg.nameserver[0] = pj_str(NAMESERVER);
323 }
324
325 if (NAMESERVER && STUN_DOMAIN) {
326 cfg.stun_domain = pj_str(STUN_DOMAIN);
327 } else if (STUN_SERVER) {
328 cfg.stun_host = pj_str(STUN_SERVER);
329 }
330
331
332 pjsua_logging_config_default(&log_cfg);
Nanang Izzuddinda37ea32009-03-06 16:24:43 +0000333 log_cfg.level = FILE_LOG_LEVEL;
334 log_cfg.console_level = CON_LOG_LEVEL;
Benny Prijonoc71ad432007-05-04 07:25:19 +0000335 log_cfg.cb = &log_writer;
Nanang Izzuddin83457d52009-02-16 16:29:05 +0000336 log_cfg.log_filename = pj_str("C:\\data\\symbian_ua.log");
Benny Prijonoba5926a2007-05-02 11:29:37 +0000337
Benny Prijonoc71ad432007-05-04 07:25:19 +0000338 pjsua_media_config_default(&med_cfg);
339 med_cfg.thread_cnt = 0; // Disable threading on Symbian
340 med_cfg.has_ioqueue = PJ_FALSE;
341 med_cfg.clock_rate = 8000;
Benny Prijono5df8bb62007-12-28 18:55:02 +0000342 med_cfg.audio_frame_ptime = 40;
Benny Prijonoc71ad432007-05-04 07:25:19 +0000343 med_cfg.ec_tail_len = 0;
344 med_cfg.enable_ice = USE_ICE;
Nanang Izzuddin81db8c72009-02-05 10:59:14 +0000345 med_cfg.snd_auto_close_time = 0; // wait for 0 seconds idle before sound dev get auto-closed
Nanang Izzuddina3775972009-03-03 18:25:55 +0000346 //med_cfg.no_vad = PJ_TRUE;
Benny Prijonoc71ad432007-05-04 07:25:19 +0000347
348 status = pjsua_init(&cfg, &log_cfg, &med_cfg);
349 if (status != PJ_SUCCESS) {
350 pjsua_perror(THIS_FILE, "pjsua_init() error", status);
351 pjsua_destroy();
352 return status;
Benny Prijonoba5926a2007-05-02 11:29:37 +0000353 }
Nanang Izzuddin829ac022008-05-27 00:24:26 +0000354
355 /* Adjust Speex priority and enable only the narrowband */
356 {
357 pj_str_t codec_id = pj_str("speex/8000");
358 pjmedia_codec_mgr_set_codec_priority(
359 pjmedia_endpt_get_codec_mgr(pjsua_var.med_endpt),
360 &codec_id, PJMEDIA_CODEC_PRIO_NORMAL+1);
Benny Prijonoba5926a2007-05-02 11:29:37 +0000361
Nanang Izzuddin829ac022008-05-27 00:24:26 +0000362 codec_id = pj_str("speex/16000");
363 pjmedia_codec_mgr_set_codec_priority(
364 pjmedia_endpt_get_codec_mgr(pjsua_var.med_endpt),
365 &codec_id, PJMEDIA_CODEC_PRIO_DISABLED);
366
367 codec_id = pj_str("speex/32000");
368 pjmedia_codec_mgr_set_codec_priority(
369 pjmedia_endpt_get_codec_mgr(pjsua_var.med_endpt),
370 &codec_id, PJMEDIA_CODEC_PRIO_DISABLED);
371 }
372
Benny Prijonoba5926a2007-05-02 11:29:37 +0000373 /* Add UDP transport. */
Benny Prijonoc71ad432007-05-04 07:25:19 +0000374 pjsua_transport_config tcfg;
375 pjsua_transport_id tid;
Benny Prijonoba5926a2007-05-02 11:29:37 +0000376
Benny Prijonoc71ad432007-05-04 07:25:19 +0000377 pjsua_transport_config_default(&tcfg);
378 tcfg.port = SIP_PORT;
379 status = pjsua_transport_create(PJSIP_TRANSPORT_UDP, &tcfg, &tid);
380 if (status != PJ_SUCCESS) {
381 pjsua_perror(THIS_FILE, "Error creating transport", status);
382 pjsua_destroy();
383 return status;
Benny Prijonoba5926a2007-05-02 11:29:37 +0000384 }
385
Benny Prijonoc71ad432007-05-04 07:25:19 +0000386 /* Add account for the transport */
387 pjsua_acc_add_local(tid, PJ_TRUE, &g_acc_id);
388
389
Benny Prijonoba5926a2007-05-02 11:29:37 +0000390 /* Initialization is done, now start pjsua */
391 status = pjsua_start();
392 if (status != PJ_SUCCESS) {
393 pjsua_perror(THIS_FILE, "Error starting pjsua", status);
394 pjsua_destroy();
395 return status;
396 }
397
398 /* Register to SIP server by creating SIP account. */
Benny Prijono72a81aa2007-05-02 23:06:11 +0000399 if (HAS_SIP_ACCOUNT) {
Benny Prijonoba5926a2007-05-02 11:29:37 +0000400 pjsua_acc_config cfg;
401
402 pjsua_acc_config_default(&cfg);
403 cfg.id = pj_str("sip:" SIP_USER "@" SIP_DOMAIN);
404 cfg.reg_uri = pj_str("sip:" SIP_DOMAIN);
405 cfg.cred_count = 1;
Benny Prijono0e2c6462008-02-14 13:39:24 +0000406 cfg.cred_info[0].realm = pj_str("*");
Benny Prijonoba5926a2007-05-02 11:29:37 +0000407 cfg.cred_info[0].scheme = pj_str("digest");
408 cfg.cred_info[0].username = pj_str(SIP_USER);
409 cfg.cred_info[0].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
410 cfg.cred_info[0].data = pj_str(SIP_PASSWD);
411
Benny Prijonob2c96822007-05-03 13:31:21 +0000412 status = pjsua_acc_add(&cfg, PJ_TRUE, &g_acc_id);
Benny Prijonoba5926a2007-05-02 11:29:37 +0000413 if (status != PJ_SUCCESS) {
414 pjsua_perror(THIS_FILE, "Error adding account", status);
415 pjsua_destroy();
416 return status;
417 }
418 }
419
Benny Prijonob2c96822007-05-03 13:31:21 +0000420 if (SIP_DST_URI) {
421 pjsua_buddy_config bcfg;
422
423 pjsua_buddy_config_default(&bcfg);
424 bcfg.uri = pj_str(SIP_DST_URI);
425 bcfg.subscribe = PJ_FALSE;
426
427 pjsua_buddy_add(&bcfg, &g_buddy_id);
Benny Prijonoba5926a2007-05-02 11:29:37 +0000428 }
Benny Prijonoba5926a2007-05-02 11:29:37 +0000429 return PJ_SUCCESS;
430}
431
432
433////////////////////////////////////////////////////////////////////////////
Benny Prijonoc71ad432007-05-04 07:25:19 +0000434/*
435 * The interractive console UI
436 */
Benny Prijonoba5926a2007-05-02 11:29:37 +0000437#include <e32base.h>
438
439class ConsoleUI : public CActive
440{
441public:
Nanang Izzuddin82f7a412008-12-17 11:36:22 +0000442 ConsoleUI(CConsoleBase *con);
Benny Prijonoba5926a2007-05-02 11:29:37 +0000443
Benny Prijonoc71ad432007-05-04 07:25:19 +0000444 // Run console UI
445 void Run();
446
447 // Stop
448 void Stop();
Benny Prijonoba5926a2007-05-02 11:29:37 +0000449
450protected:
Benny Prijonoc71ad432007-05-04 07:25:19 +0000451 // Cancel asynchronous read.
452 void DoCancel();
Benny Prijonoba5926a2007-05-02 11:29:37 +0000453
Benny Prijonoc71ad432007-05-04 07:25:19 +0000454 // Implementation: called when read has completed.
455 void RunL();
Benny Prijonoba5926a2007-05-02 11:29:37 +0000456
457private:
Benny Prijonoc71ad432007-05-04 07:25:19 +0000458 CConsoleBase *con_;
Benny Prijonoba5926a2007-05-02 11:29:37 +0000459};
460
461
Nanang Izzuddin82f7a412008-12-17 11:36:22 +0000462ConsoleUI::ConsoleUI(CConsoleBase *con)
463: CActive(EPriorityStandard), con_(con)
Benny Prijonoba5926a2007-05-02 11:29:37 +0000464{
Benny Prijonoc71ad432007-05-04 07:25:19 +0000465 CActiveScheduler::Add(this);
Benny Prijonoba5926a2007-05-02 11:29:37 +0000466}
467
468// Run console UI
469void ConsoleUI::Run()
470{
Benny Prijonoc71ad432007-05-04 07:25:19 +0000471 con_->Read(iStatus);
472 SetActive();
Benny Prijonoba5926a2007-05-02 11:29:37 +0000473}
474
475// Stop console UI
476void ConsoleUI::Stop()
477{
Benny Prijonoc71ad432007-05-04 07:25:19 +0000478 DoCancel();
Benny Prijonoba5926a2007-05-02 11:29:37 +0000479}
480
481// Cancel asynchronous read.
482void ConsoleUI::DoCancel()
483{
Benny Prijonoc71ad432007-05-04 07:25:19 +0000484 con_->ReadCancel();
Benny Prijonoba5926a2007-05-02 11:29:37 +0000485}
486
Nanang Izzuddin798bf452009-02-12 12:35:27 +0000487static void PrintMainMenu()
Benny Prijono72a81aa2007-05-02 23:06:11 +0000488{
Nanang Izzuddinda37ea32009-03-06 16:24:43 +0000489 const char *menu =
490 "\n\n"
Nanang Izzuddin798bf452009-02-12 12:35:27 +0000491 "Main Menu:\n"
492 " d Enable/disable codecs\n"
Benny Prijono70c5ba02007-12-31 11:27:35 +0000493 " m Call " SIP_DST_URI "\n"
494 " a Answer call\n"
495 " g Hangup all calls\n"
Nanang Izzuddin0cb3b022009-02-27 17:37:35 +0000496 " t Toggle audio route\n"
Nanang Izzuddin798bf452009-02-12 12:35:27 +0000497#if !defined(PJMEDIA_CONF_USE_SWITCH_BOARD) || PJMEDIA_CONF_USE_SWITCH_BOARD==0
Nanang Izzuddin0cb3b022009-02-27 17:37:35 +0000498 " j Toggle loopback audio\n"
Nanang Izzuddin798bf452009-02-12 12:35:27 +0000499#endif
Benny Prijono1f61a8f2007-08-16 10:11:44 +0000500 " s Subscribe " SIP_DST_URI "\n"
Benny Prijonoc71ad432007-05-04 07:25:19 +0000501 " S Unsubscribe presence\n"
502 " o Set account online\n"
503 " O Set account offline\n"
Nanang Izzuddinda37ea32009-03-06 16:24:43 +0000504 " w Quit\n";
505
506 PJ_LOG(3, (THIS_FILE, menu));
Benny Prijono72a81aa2007-05-02 23:06:11 +0000507}
508
Nanang Izzuddin798bf452009-02-12 12:35:27 +0000509static void PrintCodecMenu()
510{
Nanang Izzuddinda37ea32009-03-06 16:24:43 +0000511 const char *menu =
512 "\n\n"
Nanang Izzuddin798bf452009-02-12 12:35:27 +0000513 "Codec Menu:\n"
514 " a Enable all codecs\n"
Nanang Izzuddina3775972009-03-03 18:25:55 +0000515#if PJMEDIA_HAS_PASSTHROUGH_CODEC_AMR
Nanang Izzuddin798bf452009-02-12 12:35:27 +0000516 " d Enable only AMR\n"
Nanang Izzuddina3775972009-03-03 18:25:55 +0000517#endif
518#if PJMEDIA_HAS_PASSTHROUGH_CODEC_G729
Nanang Izzuddin798bf452009-02-12 12:35:27 +0000519 " g Enable only G.729\n"
Nanang Izzuddina3775972009-03-03 18:25:55 +0000520#endif
521#if PJMEDIA_HAS_PASSTHROUGH_CODEC_ILBC
Nanang Izzuddin798bf452009-02-12 12:35:27 +0000522 " j Enable only iLBC\n"
523#endif
524 " m Enable only Speex\n"
525 " p Enable only GSM\n"
526 " t Enable only PCMU\n"
Nanang Izzuddinda37ea32009-03-06 16:24:43 +0000527 " w Enable only PCMA\n";
528
529 PJ_LOG(3, (THIS_FILE, menu));
Nanang Izzuddin798bf452009-02-12 12:35:27 +0000530}
531
532static void HandleMainMenu(TKeyCode kc) {
533 switch (kc) {
534
Nanang Izzuddin798bf452009-02-12 12:35:27 +0000535 case 't':
Nanang Izzuddin0cb3b022009-02-27 17:37:35 +0000536 {
Nanang Izzuddinfcb92d02009-03-10 13:32:09 +0000537 pjmedia_aud_dev_route route;
538 pj_status_t status;
539
540 status = pjsua_snd_get_setting(PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE,
541 &route);
542
543 if (status == PJ_SUCCESS) {
544 if (route == PJMEDIA_AUD_DEV_ROUTE_LOUDSPEAKER)
545 route = PJMEDIA_AUD_DEV_ROUTE_EARPIECE;
546 else
547 route = PJMEDIA_AUD_DEV_ROUTE_LOUDSPEAKER;
Nanang Izzuddin452b66b2009-02-18 15:23:47 +0000548
Nanang Izzuddinfcb92d02009-03-10 13:32:09 +0000549 status = pjsua_snd_set_setting(
550 PJMEDIA_AUD_DEV_CAP_OUTPUT_ROUTE,
551 &route, PJ_TRUE);
Nanang Izzuddin0cb3b022009-02-27 17:37:35 +0000552 }
Nanang Izzuddinfcb92d02009-03-10 13:32:09 +0000553
554 if (status != PJ_SUCCESS)
555 pjsua_perror(THIS_FILE, "Error switch audio route", status);
Nanang Izzuddin0cb3b022009-02-27 17:37:35 +0000556 }
Nanang Izzuddin798bf452009-02-12 12:35:27 +0000557 break;
Nanang Izzuddin798bf452009-02-12 12:35:27 +0000558
559 case 'j':
Nanang Izzuddin0cb3b022009-02-27 17:37:35 +0000560 {
Nanang Izzuddin798bf452009-02-12 12:35:27 +0000561 static pj_bool_t loopback_active = PJ_FALSE;
562 if (!loopback_active)
563 pjsua_conf_connect(0, 0);
564 else
565 pjsua_conf_disconnect(0, 0);
566 loopback_active = !loopback_active;
Nanang Izzuddin0cb3b022009-02-27 17:37:35 +0000567 }
Nanang Izzuddin798bf452009-02-12 12:35:27 +0000568 break;
569
570 case 'm':
571 if (g_call_id != PJSUA_INVALID_ID) {
572 PJ_LOG(3,(THIS_FILE, "Another call is active"));
573 break;
574 }
575
576 if (pjsua_verify_sip_url(SIP_DST_URI) == PJ_SUCCESS) {
577 pj_str_t dst = pj_str(SIP_DST_URI);
578 pjsua_call_make_call(g_acc_id, &dst, 0, NULL,
579 NULL, &g_call_id);
580 } else {
581 PJ_LOG(3,(THIS_FILE, "Invalid SIP URI"));
582 }
583 break;
584 case 'a':
585 if (g_call_id != PJSUA_INVALID_ID)
586 pjsua_call_answer(g_call_id, 200, NULL, NULL);
587 break;
588 case 'g':
589 pjsua_call_hangup_all();
590 break;
591 case 's':
592 case 'S':
593 if (g_buddy_id != PJSUA_INVALID_ID)
594 pjsua_buddy_subscribe_pres(g_buddy_id, kc=='s');
595 break;
596 case 'o':
597 case 'O':
598 pjsua_acc_set_online_status(g_acc_id, kc=='o');
599 break;
600
601 default:
602 PJ_LOG(3,(THIS_FILE, "Keycode '%c' (%d) is pressed", kc, kc));
603 break;
604 }
605
606 PrintMainMenu();
607}
608
609static void HandleCodecMenu(TKeyCode kc) {
610 const pj_str_t ID_ALL = {"*", 1};
611 pj_str_t codec = {NULL, 0};
612
613 if (kc == 'a') {
614 pjsua_codec_set_priority(&ID_ALL, PJMEDIA_CODEC_PRIO_NORMAL);
615 PJ_LOG(3,(THIS_FILE, "All codecs activated"));
616 } else {
617 switch (kc) {
618 case 'd':
619 codec = pj_str("AMR");
620 break;
621 case 'g':
622 codec = pj_str("G729");
623 break;
624 case 'j':
625 codec = pj_str("ILBC");
626 break;
627 case 'm':
628 codec = pj_str("SPEEX/8000");
629 break;
630 case 'p':
631 codec = pj_str("GSM");
632 break;
633 case 't':
634 codec = pj_str("PCMU");
635 break;
636 case 'w':
637 codec = pj_str("PCMA");
638 break;
639 default:
640 PJ_LOG(3,(THIS_FILE, "Keycode '%c' (%d) is pressed", kc, kc));
641 break;
642 }
643
644 if (codec.slen) {
645 pj_status_t status;
646
647 pjsua_codec_set_priority(&ID_ALL, PJMEDIA_CODEC_PRIO_DISABLED);
648
649 status = pjsua_codec_set_priority(&codec,
650 PJMEDIA_CODEC_PRIO_NORMAL);
651 if (status == PJ_SUCCESS)
652 PJ_LOG(3,(THIS_FILE, "%s activated", codec.ptr));
653 else
654 PJ_LOG(3,(THIS_FILE, "Failed activating %s, err=%d",
655 codec.ptr, status));
656 }
657 }
658}
659
Benny Prijonoba5926a2007-05-02 11:29:37 +0000660// Implementation: called when read has completed.
661void ConsoleUI::RunL()
662{
Nanang Izzuddin798bf452009-02-12 12:35:27 +0000663 enum {
664 MENU_TYPE_MAIN = 0,
665 MENU_TYPE_CODEC = 1
666 };
667 static int menu_type = MENU_TYPE_MAIN;
Benny Prijonoc71ad432007-05-04 07:25:19 +0000668 TKeyCode kc = con_->KeyCode();
669 pj_bool_t reschedule = PJ_TRUE;
670
Nanang Izzuddin798bf452009-02-12 12:35:27 +0000671 if (menu_type == MENU_TYPE_MAIN) {
672 if (kc == 'w') {
Nanang Izzuddin82f7a412008-12-17 11:36:22 +0000673 CActiveScheduler::Stop();
Benny Prijonoc71ad432007-05-04 07:25:19 +0000674 reschedule = PJ_FALSE;
Nanang Izzuddin798bf452009-02-12 12:35:27 +0000675 } else if (kc == 'd') {
676 menu_type = MENU_TYPE_CODEC;
677 PrintCodecMenu();
678 } else {
679 HandleMainMenu(kc);
680 }
681 } else {
682 HandleCodecMenu(kc);
683
684 menu_type = MENU_TYPE_MAIN;
685 PrintMainMenu();
Benny Prijonoc71ad432007-05-04 07:25:19 +0000686 }
Benny Prijonoc71ad432007-05-04 07:25:19 +0000687
688 if (reschedule)
689 Run();
Benny Prijonoba5926a2007-05-02 11:29:37 +0000690}
691
Benny Prijono70c5ba02007-12-31 11:27:35 +0000692#if 0
693// IP networking related testing
694static pj_status_t test_addr(void)
695{
696 int af;
697 unsigned i, count;
698 pj_addrinfo ai[8];
699 pj_sockaddr ifs[8];
700 const pj_str_t *hostname;
701 pj_hostent he;
702 pj_status_t status;
703
704 pj_log_set_log_func(&log_writer);
705
706 status = pj_init();
707 if (status != PJ_SUCCESS) {
708 pjsua_perror(THIS_FILE, "pj_init() error", status);
709 return status;
710 }
711
712 af = pj_AF_INET();
713
Benny Prijono684c0ad2008-01-03 18:50:27 +0000714#if 0
715 pj_in_addr in_addr;
716 pj_str_t aa = pj_str("1.1.1.1");
717 in_addr = pj_inet_addr(&aa);
718 char *the_addr = pj_inet_ntoa(in_addr);
719 PJ_LOG(3,(THIS_FILE, "IP addr=%s", the_addr));
720
721 aa = pj_str("192.168.0.15");
722 in_addr = pj_inet_addr(&aa);
723 the_addr = pj_inet_ntoa(in_addr);
724 PJ_LOG(3,(THIS_FILE, "IP addr=%s", the_addr));
725
726 aa = pj_str("2.2.2.2");
727 in_addr = pj_inet_addr(&aa);
728 the_addr = pj_inet_ntoa(in_addr);
729 PJ_LOG(3,(THIS_FILE, "IP addr=%s", the_addr));
730
731 return -1;
732#endif
733
Benny Prijono70c5ba02007-12-31 11:27:35 +0000734 // Hostname
735 hostname = pj_gethostname();
736 if (hostname == NULL) {
737 status = PJ_ERESOLVE;
738 pjsua_perror(THIS_FILE, "pj_gethostname() error", status);
739 goto on_return;
740 }
741
742 PJ_LOG(3,(THIS_FILE, "Hostname: %.*s", hostname->slen, hostname->ptr));
743
744 // Gethostbyname
745 status = pj_gethostbyname(hostname, &he);
746 if (status != PJ_SUCCESS) {
747 pjsua_perror(THIS_FILE, "pj_gethostbyname() error", status);
748 } else {
749 PJ_LOG(3,(THIS_FILE, "gethostbyname: %s",
750 pj_inet_ntoa(*(pj_in_addr*)he.h_addr)));
751 }
752
753 // Getaddrinfo
754 count = PJ_ARRAY_SIZE(ai);
755 status = pj_getaddrinfo(af, hostname, &count, ai);
756 if (status != PJ_SUCCESS) {
757 pjsua_perror(THIS_FILE, "pj_getaddrinfo() error", status);
758 } else {
759 for (i=0; i<count; ++i) {
760 char ipaddr[PJ_INET6_ADDRSTRLEN+2];
761 PJ_LOG(3,(THIS_FILE, "Addrinfo: %s",
762 pj_sockaddr_print(&ai[i].ai_addr, ipaddr, sizeof(ipaddr), 2)));
763 }
764 }
765
766 // Enum interface
767 count = PJ_ARRAY_SIZE(ifs);
768 status = pj_enum_ip_interface(af, &count, ifs);
769 if (status != PJ_SUCCESS) {
770 pjsua_perror(THIS_FILE, "pj_enum_ip_interface() error", status);
771 } else {
772 for (i=0; i<count; ++i) {
773 char ipaddr[PJ_INET6_ADDRSTRLEN+2];
774 PJ_LOG(3,(THIS_FILE, "Interface: %s",
775 pj_sockaddr_print(&ifs[i], ipaddr, sizeof(ipaddr), 2)));
776 }
777 }
778
779 // Get default iinterface
780 status = pj_getdefaultipinterface(af, &ifs[0]);
781 if (status != PJ_SUCCESS) {
782 pjsua_perror(THIS_FILE, "pj_getdefaultipinterface() error", status);
783 } else {
784 char ipaddr[PJ_INET6_ADDRSTRLEN+2];
785 PJ_LOG(3,(THIS_FILE, "Default IP: %s",
786 pj_sockaddr_print(&ifs[0], ipaddr, sizeof(ipaddr), 2)));
787 }
788
789 // Get default IP address
790 status = pj_gethostip(af, &ifs[0]);
791 if (status != PJ_SUCCESS) {
792 pjsua_perror(THIS_FILE, "pj_gethostip() error", status);
793 } else {
794 char ipaddr[PJ_INET6_ADDRSTRLEN+2];
795 PJ_LOG(3,(THIS_FILE, "Host IP: %s",
796 pj_sockaddr_print(&ifs[0], ipaddr, sizeof(ipaddr), 2)));
797 }
798
799 status = -1;
800
801on_return:
802 pj_shutdown();
803 return status;
804}
805#endif
806
807
Benny Prijono6b3ccdf2008-01-14 11:54:21 +0000808#include <es_sock.h>
Benny Prijono897f9f82007-05-03 19:56:21 +0000809
Nanang Izzuddin82f7a412008-12-17 11:36:22 +0000810#if 0
811// Force network connection to use the first IAP,
812// this is useful for debugging on emulator without GUI.
813// Include commdb.lib & apengine.lib in symbian_ua.mmp file
814// if this is enabled.
815
816#include <apdatahandler.h>
817
818inline void ForceUseFirstIAP()
819{
820 TUint32 rank = 1;
821 TUint32 bearers;
822 TUint32 prompt;
823 TUint32 iap;
824
825 CCommsDatabase* commDb = CCommsDatabase::NewL(EDatabaseTypeIAP);
826 CleanupStack::PushL(commDb);
827
828 CApDataHandler* apDataHandler = CApDataHandler::NewLC(*commDb);
829
830 TCommDbConnectionDirection direction = ECommDbConnectionDirectionOutgoing;
831 apDataHandler->GetPreferredIfDbIapTypeL(rank, direction, bearers, prompt, iap);
832 prompt = ECommDbDialogPrefDoNotPrompt;
833 apDataHandler->SetPreferredIfDbIapTypeL(rank, direction, bearers, (TCommDbDialogPref)prompt, iap, ETrue);
834 CleanupStack::PopAndDestroy(2); // apDataHandler, commDb
835}
836
837static void SelectIAP()
838{
839 ForceUseFirstIAP();
840}
841
842#else
843
844static void SelectIAP()
845{
846}
847
848#endif
849
850
Benny Prijonoba5926a2007-05-02 11:29:37 +0000851////////////////////////////////////////////////////////////////////////////
852int ua_main()
853{
Nanang Izzuddin82f7a412008-12-17 11:36:22 +0000854 RSocketServ aSocketServer;
855 RConnection aConn;
856 TInt err;
857 pj_symbianos_params sym_params;
Benny Prijonoc71ad432007-05-04 07:25:19 +0000858 pj_status_t status;
Nanang Izzuddin82f7a412008-12-17 11:36:22 +0000859
860 SelectIAP();
Benny Prijonoc71ad432007-05-04 07:25:19 +0000861
Benny Prijono70c5ba02007-12-31 11:27:35 +0000862 // Initialize RSocketServ
863 if ((err=aSocketServer.Connect()) != KErrNone)
864 return PJ_STATUS_FROM_OS(err);
865
866 // Open up a connection
867 if ((err=aConn.Open(aSocketServer)) != KErrNone) {
Nanang Izzuddin82f7a412008-12-17 11:36:22 +0000868 aSocketServer.Close();
869 return PJ_STATUS_FROM_OS(err);
Benny Prijono70c5ba02007-12-31 11:27:35 +0000870 }
871
872 if ((err=aConn.Start()) != KErrNone) {
873 aSocketServer.Close();
874 return PJ_STATUS_FROM_OS(err);
875 }
876
877 // Set Symbian OS parameters in pjlib.
878 // This must be done before pj_init() is called.
879 pj_bzero(&sym_params, sizeof(sym_params));
880 sym_params.rsocketserv = &aSocketServer;
881 sym_params.rconnection = &aConn;
882 pj_symbianos_set_params(&sym_params);
883
Benny Prijonoc71ad432007-05-04 07:25:19 +0000884 // Initialize pjsua
885 status = app_startup();
Benny Prijono70c5ba02007-12-31 11:27:35 +0000886 //status = test_addr();
887 if (status != PJ_SUCCESS) {
888 aConn.Close();
889 aSocketServer.Close();
Nanang Izzuddin82f7a412008-12-17 11:36:22 +0000890 return status;
Benny Prijono70c5ba02007-12-31 11:27:35 +0000891 }
Benny Prijono897f9f82007-05-03 19:56:21 +0000892
Benny Prijonoc71ad432007-05-04 07:25:19 +0000893 // Run the UI
Nanang Izzuddin82f7a412008-12-17 11:36:22 +0000894 ConsoleUI *con = new ConsoleUI(console);
Benny Prijonoc71ad432007-05-04 07:25:19 +0000895
896 con->Run();
Nanang Izzuddin798bf452009-02-12 12:35:27 +0000897 PrintMainMenu();
Nanang Izzuddin82f7a412008-12-17 11:36:22 +0000898
899 CActiveScheduler::Start();
Benny Prijonoc71ad432007-05-04 07:25:19 +0000900
901 delete con;
Benny Prijono684c0ad2008-01-03 18:50:27 +0000902
903 // Dump memory statistics
904 PJ_LOG(3,(THIS_FILE, "Max heap usage: %u.%03uMB",
Nanang Izzuddin82f7a412008-12-17 11:36:22 +0000905 pjsua_var.cp.peak_used_size / 1000000,
906 (pjsua_var.cp.peak_used_size % 1000000)/1000));
Benny Prijonoc71ad432007-05-04 07:25:19 +0000907
Benny Prijono684c0ad2008-01-03 18:50:27 +0000908 // check max stack usage
909#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
910 pj_thread_t* this_thread = pj_thread_this();
911 if (!this_thread)
Nanang Izzuddin82f7a412008-12-17 11:36:22 +0000912 return status;
Benny Prijono684c0ad2008-01-03 18:50:27 +0000913
914 const char* max_stack_file;
915 int max_stack_line;
916 status = pj_thread_get_stack_info(this_thread, &max_stack_file, &max_stack_line);
917
918 PJ_LOG(3,(THIS_FILE, "Max stack usage: %u at %s:%d",
Nanang Izzuddin82f7a412008-12-17 11:36:22 +0000919 pj_thread_get_stack_max_usage(this_thread),
920 max_stack_file, max_stack_line));
Benny Prijono684c0ad2008-01-03 18:50:27 +0000921#endif
922
Benny Prijonoc71ad432007-05-04 07:25:19 +0000923 // Shutdown pjsua
924 pjsua_destroy();
925
Benny Prijono70c5ba02007-12-31 11:27:35 +0000926 // Close connection and socket server
927 aConn.Close();
Nanang Izzuddin82f7a412008-12-17 11:36:22 +0000928 aSocketServer.Close();
Nanang Izzuddina940b362009-02-23 13:53:30 +0000929
Benny Prijono797e3382007-12-01 09:10:07 +0000930 return status;
Benny Prijonoba5926a2007-05-02 11:29:37 +0000931}
932