blob: 7e4c9c3af950f1af5d015c9b745136d248464240 [file] [log] [blame]
Benny Prijonoba5926a2007-05-02 11:29:37 +00001/* $Id$ */
2/*
3 * Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org>
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 */
Benny Prijonoba5926a2007-05-02 11:29:37 +000019#include <pjsua-lib/pjsua.h>
Benny Prijono72a81aa2007-05-02 23:06:11 +000020#include <pjsua-lib/pjsua_internal.h>
Benny Prijonoba5926a2007-05-02 11:29:37 +000021#include "ua.h"
22
23#define THIS_FILE "symbian_ua.cpp"
Benny Prijono684c0ad2008-01-03 18:50:27 +000024#define LOG_LEVEL 3
Benny Prijonoba5926a2007-05-02 11:29:37 +000025
Benny Prijono72a81aa2007-05-02 23:06:11 +000026//
Benny Prijonoc71ad432007-05-04 07:25:19 +000027// Basic config.
28//
29#define SIP_PORT 5060
30
31
32//
Benny Prijonob2c96822007-05-03 13:31:21 +000033// Destination URI (to make call, or to subscribe presence)
34//
Benny Prijono0e2c6462008-02-14 13:39:24 +000035#define SIP_DST_URI "sip:100@pjsip.lab"
Benny Prijonob2c96822007-05-03 13:31:21 +000036
37//
Benny Prijono72a81aa2007-05-02 23:06:11 +000038// Account
39//
Benny Prijono0e2c6462008-02-14 13:39:24 +000040#define HAS_SIP_ACCOUNT 1 // 0 to disable registration
41#define SIP_DOMAIN "pjsip.lab"
42#define SIP_USER "400"
43#define SIP_PASSWD "400"
Benny Prijonoba5926a2007-05-02 11:29:37 +000044
Benny Prijono72a81aa2007-05-02 23:06:11 +000045//
46// Outbound proxy for all accounts
47//
48#define SIP_PROXY NULL
Benny Prijono897f9f82007-05-03 19:56:21 +000049//#define SIP_PROXY "sip:192.168.0.8"
50
51
52//
53// Configure nameserver if DNS SRV is to be used with both SIP
54// or STUN (for STUN see other settings below)
55//
Benny Prijono0e2c6462008-02-14 13:39:24 +000056//#define NAMESERVER NULL
57#define NAMESERVER "192.168.0.2"
Benny Prijono897f9f82007-05-03 19:56:21 +000058
59//
60// STUN server
Benny Prijono684c0ad2008-01-03 18:50:27 +000061#if 0
Benny Prijono897f9f82007-05-03 19:56:21 +000062 // Use this to have the STUN server resolved normally
63# define STUN_DOMAIN NULL
Benny Prijono684c0ad2008-01-03 18:50:27 +000064# define STUN_SERVER "stun.xten.com"
Benny Prijono897f9f82007-05-03 19:56:21 +000065#elif 0
66 // Use this to have the STUN server resolved with DNS SRV
67# define STUN_DOMAIN "iptel.org"
68# define STUN_SERVER NULL
69#else
70 // Use this to disable STUN
71# define STUN_DOMAIN NULL
72# define STUN_SERVER NULL
73#endif
74
75//
76// Use ICE?
77//
Benny Prijono70c5ba02007-12-31 11:27:35 +000078#define USE_ICE 1
Benny Prijono72a81aa2007-05-02 23:06:11 +000079
Nanang Izzuddin6a6392f2008-06-02 18:30:15 +000080//
81// Use SRTP?
82//
83#define USE_SRTP PJSUA_DEFAULT_USE_SRTP
Benny Prijono72a81aa2007-05-02 23:06:11 +000084
Benny Prijonob2c96822007-05-03 13:31:21 +000085//
86// Globals
87//
88static pjsua_acc_id g_acc_id = PJSUA_INVALID_ID;
89static pjsua_call_id g_call_id = PJSUA_INVALID_ID;
90static pjsua_buddy_id g_buddy_id = PJSUA_INVALID_ID;
Benny Prijono72a81aa2007-05-02 23:06:11 +000091
Benny Prijonoba5926a2007-05-02 11:29:37 +000092
93/* Callback called by the library upon receiving incoming call */
94static void on_incoming_call(pjsua_acc_id acc_id, pjsua_call_id call_id,
95 pjsip_rx_data *rdata)
96{
97 pjsua_call_info ci;
98
99 PJ_UNUSED_ARG(acc_id);
100 PJ_UNUSED_ARG(rdata);
101
Benny Prijonob2c96822007-05-03 13:31:21 +0000102 if (g_call_id != PJSUA_INVALID_ID) {
103 pjsua_call_answer(call_id, PJSIP_SC_BUSY_HERE, NULL, NULL);
104 return;
105 }
106
Benny Prijonoba5926a2007-05-02 11:29:37 +0000107 pjsua_call_get_info(call_id, &ci);
108
109 PJ_LOG(3,(THIS_FILE, "Incoming call from %.*s!!",
110 (int)ci.remote_info.slen,
111 ci.remote_info.ptr));
112
Benny Prijonob2c96822007-05-03 13:31:21 +0000113 g_call_id = call_id;
114
Benny Prijono897f9f82007-05-03 19:56:21 +0000115 /* Automatically answer incoming calls with 180/Ringing */
116 pjsua_call_answer(call_id, 180, NULL, NULL);
Benny Prijonoba5926a2007-05-02 11:29:37 +0000117}
118
119/* Callback called by the library when call's state has changed */
120static void on_call_state(pjsua_call_id call_id, pjsip_event *e)
121{
122 pjsua_call_info ci;
123
124 PJ_UNUSED_ARG(e);
125
126 pjsua_call_get_info(call_id, &ci);
Benny Prijonob2c96822007-05-03 13:31:21 +0000127
128 if (ci.state == PJSIP_INV_STATE_DISCONNECTED) {
129 if (call_id == g_call_id)
130 g_call_id = PJSUA_INVALID_ID;
Benny Prijono897f9f82007-05-03 19:56:21 +0000131 } else if (ci.state != PJSIP_INV_STATE_INCOMING) {
Benny Prijonob2c96822007-05-03 13:31:21 +0000132 if (g_call_id == PJSUA_INVALID_ID)
133 g_call_id = call_id;
134 }
135
Benny Prijonoba5926a2007-05-02 11:29:37 +0000136 PJ_LOG(3,(THIS_FILE, "Call %d state=%.*s", call_id,
137 (int)ci.state_text.slen,
138 ci.state_text.ptr));
139}
140
141/* Callback called by the library when call's media state has changed */
142static void on_call_media_state(pjsua_call_id call_id)
143{
144 pjsua_call_info ci;
145
146 pjsua_call_get_info(call_id, &ci);
147
148 if (ci.media_status == PJSUA_CALL_MEDIA_ACTIVE) {
149 // When media is active, connect call to sound device.
150 pjsua_conf_connect(ci.conf_slot, 0);
151 pjsua_conf_connect(0, ci.conf_slot);
152 }
153}
154
155
Benny Prijonob2c96822007-05-03 13:31:21 +0000156/* Handler on buddy state changed. */
157static void on_buddy_state(pjsua_buddy_id buddy_id)
158{
159 pjsua_buddy_info info;
160 pjsua_buddy_get_info(buddy_id, &info);
161
162 PJ_LOG(3,(THIS_FILE, "%.*s status is %.*s",
163 (int)info.uri.slen,
164 info.uri.ptr,
165 (int)info.status_text.slen,
166 info.status_text.ptr));
167}
168
169
170/* Incoming IM message (i.e. MESSAGE request)! */
171static void on_pager(pjsua_call_id call_id, const pj_str_t *from,
172 const pj_str_t *to, const pj_str_t *contact,
173 const pj_str_t *mime_type, const pj_str_t *text)
174{
175 /* Note: call index may be -1 */
176 PJ_UNUSED_ARG(call_id);
177 PJ_UNUSED_ARG(to);
178 PJ_UNUSED_ARG(contact);
179 PJ_UNUSED_ARG(mime_type);
180
181 PJ_LOG(3,(THIS_FILE,"MESSAGE from %.*s: %.*s",
182 (int)from->slen, from->ptr,
183 (int)text->slen, text->ptr));
184}
185
186
187/* Received typing indication */
188static void on_typing(pjsua_call_id call_id, const pj_str_t *from,
189 const pj_str_t *to, const pj_str_t *contact,
190 pj_bool_t is_typing)
191{
192 PJ_UNUSED_ARG(call_id);
193 PJ_UNUSED_ARG(to);
194 PJ_UNUSED_ARG(contact);
195
196 PJ_LOG(3,(THIS_FILE, "IM indication: %.*s %s",
197 (int)from->slen, from->ptr,
198 (is_typing?"is typing..":"has stopped typing")));
199}
200
201
202/* Call transfer request status. */
203static void on_call_transfer_status(pjsua_call_id call_id,
204 int status_code,
205 const pj_str_t *status_text,
206 pj_bool_t final,
207 pj_bool_t *p_cont)
208{
209 PJ_LOG(3,(THIS_FILE, "Call %d: transfer status=%d (%.*s) %s",
210 call_id, status_code,
211 (int)status_text->slen, status_text->ptr,
212 (final ? "[final]" : "")));
213
214 if (status_code/100 == 2) {
215 PJ_LOG(3,(THIS_FILE,
216 "Call %d: call transfered successfully, disconnecting call",
217 call_id));
218 pjsua_call_hangup(call_id, PJSIP_SC_GONE, NULL, NULL);
219 *p_cont = PJ_FALSE;
220 }
221}
222
223
Benny Prijonoaecabfc2007-10-26 05:35:42 +0000224/* NAT detection result */
225static void on_nat_detect(const pj_stun_nat_detect_result *res)
226{
227 if (res->status != PJ_SUCCESS) {
228 pjsua_perror(THIS_FILE, "NAT detection failed", res->status);
229 } else {
230 PJ_LOG(3, (THIS_FILE, "NAT detected as %s", res->nat_type_name));
231 }
232}
233
Benny Prijonob2c96822007-05-03 13:31:21 +0000234/* Notification that call is being replaced. */
235static void on_call_replaced(pjsua_call_id old_call_id,
236 pjsua_call_id new_call_id)
237{
238 pjsua_call_info old_ci, new_ci;
239
240 pjsua_call_get_info(old_call_id, &old_ci);
241 pjsua_call_get_info(new_call_id, &new_ci);
242
243 PJ_LOG(3,(THIS_FILE, "Call %d with %.*s is being replaced by "
244 "call %d with %.*s",
245 old_call_id,
246 (int)old_ci.remote_info.slen, old_ci.remote_info.ptr,
247 new_call_id,
248 (int)new_ci.remote_info.slen, new_ci.remote_info.ptr));
249}
250
251
Benny Prijonoba5926a2007-05-02 11:29:37 +0000252/* Logging callback */
Benny Prijono797e3382007-12-01 09:10:07 +0000253static void log_writer(int level, const char *buf, int len)
Benny Prijonoba5926a2007-05-02 11:29:37 +0000254{
Benny Prijonoc71ad432007-05-04 07:25:19 +0000255 static wchar_t buf16[PJ_LOG_MAX_SIZE];
Benny Prijonoba5926a2007-05-02 11:29:37 +0000256
257 PJ_UNUSED_ARG(level);
258
259 pj_ansi_to_unicode(buf, len, buf16, PJ_ARRAY_SIZE(buf16));
260
261 TPtrC16 aBuf((const TUint16*)buf16, (TInt)len);
262 console->Write(aBuf);
Benny Prijono797e3382007-12-01 09:10:07 +0000263
Benny Prijonoba5926a2007-05-02 11:29:37 +0000264}
265
266/*
267 * app_startup()
268 *
269 * url may contain URL to call.
270 */
Benny Prijonob2c96822007-05-03 13:31:21 +0000271static pj_status_t app_startup()
Benny Prijonoba5926a2007-05-02 11:29:37 +0000272{
Benny Prijonoba5926a2007-05-02 11:29:37 +0000273 pj_status_t status;
274
275 /* Redirect log before pjsua_init() */
Benny Prijono70c5ba02007-12-31 11:27:35 +0000276 pj_log_set_log_func(&log_writer);
277
278 /* Set log level */
279 pj_log_set_level(LOG_LEVEL);
Benny Prijonoba5926a2007-05-02 11:29:37 +0000280
281 /* Create pjsua first! */
282 status = pjsua_create();
283 if (status != PJ_SUCCESS) {
284 pjsua_perror(THIS_FILE, "pjsua_create() error", status);
285 return status;
286 }
287
Benny Prijonoba5926a2007-05-02 11:29:37 +0000288 /* Init pjsua */
Benny Prijonoc71ad432007-05-04 07:25:19 +0000289 pjsua_config cfg;
290 pjsua_logging_config log_cfg;
291 pjsua_media_config med_cfg;
Benny Prijonoba5926a2007-05-02 11:29:37 +0000292
Benny Prijonoc71ad432007-05-04 07:25:19 +0000293 pjsua_config_default(&cfg);
294 cfg.max_calls = 2;
295 cfg.thread_cnt = 0; // Disable threading on Symbian
Nanang Izzuddin6a6392f2008-06-02 18:30:15 +0000296 cfg.use_srtp = USE_SRTP;
297 cfg.srtp_secure_signaling = 0;
298
Benny Prijonoc71ad432007-05-04 07:25:19 +0000299 cfg.cb.on_incoming_call = &on_incoming_call;
300 cfg.cb.on_call_media_state = &on_call_media_state;
301 cfg.cb.on_call_state = &on_call_state;
302 cfg.cb.on_buddy_state = &on_buddy_state;
303 cfg.cb.on_pager = &on_pager;
304 cfg.cb.on_typing = &on_typing;
305 cfg.cb.on_call_transfer_status = &on_call_transfer_status;
306 cfg.cb.on_call_replaced = &on_call_replaced;
Benny Prijonoaecabfc2007-10-26 05:35:42 +0000307 cfg.cb.on_nat_detect = &on_nat_detect;
308
Benny Prijonoc71ad432007-05-04 07:25:19 +0000309 if (SIP_PROXY) {
310 cfg.outbound_proxy_cnt = 1;
311 cfg.outbound_proxy[0] = pj_str(SIP_PROXY);
312 }
313
314 if (NAMESERVER) {
315 cfg.nameserver_count = 1;
316 cfg.nameserver[0] = pj_str(NAMESERVER);
317 }
318
319 if (NAMESERVER && STUN_DOMAIN) {
320 cfg.stun_domain = pj_str(STUN_DOMAIN);
321 } else if (STUN_SERVER) {
322 cfg.stun_host = pj_str(STUN_SERVER);
323 }
324
325
326 pjsua_logging_config_default(&log_cfg);
327 log_cfg.console_level = 4;
328 log_cfg.cb = &log_writer;
Nanang Izzuddincb2789a2008-07-24 15:30:44 +0000329 //log_cfg.log_filename = pj_str("C:\\data\\symbian_ua.log");
Benny Prijonoba5926a2007-05-02 11:29:37 +0000330
Benny Prijonoc71ad432007-05-04 07:25:19 +0000331 pjsua_media_config_default(&med_cfg);
332 med_cfg.thread_cnt = 0; // Disable threading on Symbian
333 med_cfg.has_ioqueue = PJ_FALSE;
334 med_cfg.clock_rate = 8000;
Nanang Izzuddincb2789a2008-07-24 15:30:44 +0000335#if defined(PJMEDIA_SYM_SND_USE_APS) && (PJMEDIA_SYM_SND_USE_APS==1)
336 med_cfg.audio_frame_ptime = 20;
337#else
Benny Prijono5df8bb62007-12-28 18:55:02 +0000338 med_cfg.audio_frame_ptime = 40;
Nanang Izzuddincb2789a2008-07-24 15:30:44 +0000339#endif
Benny Prijonoc71ad432007-05-04 07:25:19 +0000340 med_cfg.ec_tail_len = 0;
341 med_cfg.enable_ice = USE_ICE;
Nanang Izzuddin68559c32008-06-13 17:01:46 +0000342 med_cfg.snd_auto_close_time = 5; // wait for 5 seconds idle before sound dev get auto-closed
Benny Prijonoc71ad432007-05-04 07:25:19 +0000343
344 status = pjsua_init(&cfg, &log_cfg, &med_cfg);
345 if (status != PJ_SUCCESS) {
346 pjsua_perror(THIS_FILE, "pjsua_init() error", status);
347 pjsua_destroy();
348 return status;
Benny Prijonoba5926a2007-05-02 11:29:37 +0000349 }
Nanang Izzuddin829ac022008-05-27 00:24:26 +0000350
351 /* Adjust Speex priority and enable only the narrowband */
352 {
353 pj_str_t codec_id = pj_str("speex/8000");
354 pjmedia_codec_mgr_set_codec_priority(
355 pjmedia_endpt_get_codec_mgr(pjsua_var.med_endpt),
356 &codec_id, PJMEDIA_CODEC_PRIO_NORMAL+1);
Benny Prijonoba5926a2007-05-02 11:29:37 +0000357
Nanang Izzuddin829ac022008-05-27 00:24:26 +0000358 codec_id = pj_str("speex/16000");
359 pjmedia_codec_mgr_set_codec_priority(
360 pjmedia_endpt_get_codec_mgr(pjsua_var.med_endpt),
361 &codec_id, PJMEDIA_CODEC_PRIO_DISABLED);
362
363 codec_id = pj_str("speex/32000");
364 pjmedia_codec_mgr_set_codec_priority(
365 pjmedia_endpt_get_codec_mgr(pjsua_var.med_endpt),
366 &codec_id, PJMEDIA_CODEC_PRIO_DISABLED);
367 }
368
Benny Prijonoba5926a2007-05-02 11:29:37 +0000369 /* Add UDP transport. */
Benny Prijonoc71ad432007-05-04 07:25:19 +0000370 pjsua_transport_config tcfg;
371 pjsua_transport_id tid;
Benny Prijonoba5926a2007-05-02 11:29:37 +0000372
Benny Prijonoc71ad432007-05-04 07:25:19 +0000373 pjsua_transport_config_default(&tcfg);
374 tcfg.port = SIP_PORT;
375 status = pjsua_transport_create(PJSIP_TRANSPORT_UDP, &tcfg, &tid);
376 if (status != PJ_SUCCESS) {
377 pjsua_perror(THIS_FILE, "Error creating transport", status);
378 pjsua_destroy();
379 return status;
Benny Prijonoba5926a2007-05-02 11:29:37 +0000380 }
381
Benny Prijonoc71ad432007-05-04 07:25:19 +0000382 /* Add account for the transport */
383 pjsua_acc_add_local(tid, PJ_TRUE, &g_acc_id);
384
385
Benny Prijonoba5926a2007-05-02 11:29:37 +0000386 /* Initialization is done, now start pjsua */
387 status = pjsua_start();
388 if (status != PJ_SUCCESS) {
389 pjsua_perror(THIS_FILE, "Error starting pjsua", status);
390 pjsua_destroy();
391 return status;
392 }
393
394 /* Register to SIP server by creating SIP account. */
Benny Prijono72a81aa2007-05-02 23:06:11 +0000395 if (HAS_SIP_ACCOUNT) {
Benny Prijonoba5926a2007-05-02 11:29:37 +0000396 pjsua_acc_config cfg;
397
398 pjsua_acc_config_default(&cfg);
399 cfg.id = pj_str("sip:" SIP_USER "@" SIP_DOMAIN);
400 cfg.reg_uri = pj_str("sip:" SIP_DOMAIN);
401 cfg.cred_count = 1;
Benny Prijono0e2c6462008-02-14 13:39:24 +0000402 cfg.cred_info[0].realm = pj_str("*");
Benny Prijonoba5926a2007-05-02 11:29:37 +0000403 cfg.cred_info[0].scheme = pj_str("digest");
404 cfg.cred_info[0].username = pj_str(SIP_USER);
405 cfg.cred_info[0].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
406 cfg.cred_info[0].data = pj_str(SIP_PASSWD);
407
Benny Prijonob2c96822007-05-03 13:31:21 +0000408 status = pjsua_acc_add(&cfg, PJ_TRUE, &g_acc_id);
Benny Prijonoba5926a2007-05-02 11:29:37 +0000409 if (status != PJ_SUCCESS) {
410 pjsua_perror(THIS_FILE, "Error adding account", status);
411 pjsua_destroy();
412 return status;
413 }
414 }
415
Benny Prijonob2c96822007-05-03 13:31:21 +0000416 if (SIP_DST_URI) {
417 pjsua_buddy_config bcfg;
418
419 pjsua_buddy_config_default(&bcfg);
420 bcfg.uri = pj_str(SIP_DST_URI);
421 bcfg.subscribe = PJ_FALSE;
422
423 pjsua_buddy_add(&bcfg, &g_buddy_id);
Benny Prijonoba5926a2007-05-02 11:29:37 +0000424 }
Benny Prijonoba5926a2007-05-02 11:29:37 +0000425 return PJ_SUCCESS;
426}
427
428
429////////////////////////////////////////////////////////////////////////////
Benny Prijonoc71ad432007-05-04 07:25:19 +0000430/*
431 * The interractive console UI
432 */
Benny Prijonoba5926a2007-05-02 11:29:37 +0000433#include <e32base.h>
434
435class ConsoleUI : public CActive
436{
437public:
Benny Prijonoc71ad432007-05-04 07:25:19 +0000438 ConsoleUI(CActiveSchedulerWait *asw, CConsoleBase *con);
Benny Prijonoba5926a2007-05-02 11:29:37 +0000439
Benny Prijonoc71ad432007-05-04 07:25:19 +0000440 // Run console UI
441 void Run();
442
443 // Stop
444 void Stop();
Benny Prijonoba5926a2007-05-02 11:29:37 +0000445
446protected:
Benny Prijonoc71ad432007-05-04 07:25:19 +0000447 // Cancel asynchronous read.
448 void DoCancel();
Benny Prijonoba5926a2007-05-02 11:29:37 +0000449
Benny Prijonoc71ad432007-05-04 07:25:19 +0000450 // Implementation: called when read has completed.
451 void RunL();
Benny Prijonoba5926a2007-05-02 11:29:37 +0000452
453private:
Benny Prijonoc71ad432007-05-04 07:25:19 +0000454 CActiveSchedulerWait *asw_;
455 CConsoleBase *con_;
Benny Prijonoba5926a2007-05-02 11:29:37 +0000456};
457
458
459ConsoleUI::ConsoleUI(CActiveSchedulerWait *asw, CConsoleBase *con)
460: CActive(EPriorityStandard), asw_(asw), con_(con)
461{
Benny Prijonoc71ad432007-05-04 07:25:19 +0000462 CActiveScheduler::Add(this);
Benny Prijonoba5926a2007-05-02 11:29:37 +0000463}
464
465// Run console UI
466void ConsoleUI::Run()
467{
Benny Prijonoc71ad432007-05-04 07:25:19 +0000468 con_->Read(iStatus);
469 SetActive();
Benny Prijonoba5926a2007-05-02 11:29:37 +0000470}
471
472// Stop console UI
473void ConsoleUI::Stop()
474{
Benny Prijonoc71ad432007-05-04 07:25:19 +0000475 DoCancel();
Benny Prijonoba5926a2007-05-02 11:29:37 +0000476}
477
478// Cancel asynchronous read.
479void ConsoleUI::DoCancel()
480{
Benny Prijonoc71ad432007-05-04 07:25:19 +0000481 con_->ReadCancel();
Benny Prijonoba5926a2007-05-02 11:29:37 +0000482}
483
Benny Prijono72a81aa2007-05-02 23:06:11 +0000484static void PrintMenu()
485{
Benny Prijonoc71ad432007-05-04 07:25:19 +0000486 PJ_LOG(3, (THIS_FILE, "\n\n"
487 "Menu:\n"
488 " d Dump states\n"
Benny Prijono1f61a8f2007-08-16 10:11:44 +0000489 " D Dump states detail\n"
Benny Prijonoc71ad432007-05-04 07:25:19 +0000490 " P Dump pool factory\n"
Benny Prijono5df8bb62007-12-28 18:55:02 +0000491 " l Start loopback audio device\n"
492 " L Stop loopback audio device\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"
Benny Prijono1f61a8f2007-08-16 10:11:44 +0000496 " s Subscribe " SIP_DST_URI "\n"
Benny Prijonoc71ad432007-05-04 07:25:19 +0000497 " S Unsubscribe presence\n"
498 " o Set account online\n"
499 " O Set account offline\n"
Benny Prijono70c5ba02007-12-31 11:27:35 +0000500 " w Quit\n"));
Benny Prijono72a81aa2007-05-02 23:06:11 +0000501}
502
Benny Prijonoba5926a2007-05-02 11:29:37 +0000503// Implementation: called when read has completed.
504void ConsoleUI::RunL()
505{
Benny Prijonoc71ad432007-05-04 07:25:19 +0000506 TKeyCode kc = con_->KeyCode();
507 pj_bool_t reschedule = PJ_TRUE;
508
509 switch (kc) {
Benny Prijono70c5ba02007-12-31 11:27:35 +0000510 case 'w':
Benny Prijonoc71ad432007-05-04 07:25:19 +0000511 asw_->AsyncStop();
512 reschedule = PJ_FALSE;
513 break;
514 case 'D':
515 case 'd':
516 pjsua_dump(kc == 'D');
517 break;
518 case 'p':
519 case 'P':
Benny Prijono1f61a8f2007-08-16 10:11:44 +0000520 pj_pool_factory_dump(pjsua_get_pool_factory(), PJ_TRUE);
Benny Prijonoc71ad432007-05-04 07:25:19 +0000521 break;
Benny Prijono5df8bb62007-12-28 18:55:02 +0000522 case 'l':
523 pjsua_conf_connect(0, 0);
524 break;
525 case 'L':
526 pjsua_conf_disconnect(0, 0);
527 break;
Benny Prijono70c5ba02007-12-31 11:27:35 +0000528 case 'm':
Benny Prijonoc71ad432007-05-04 07:25:19 +0000529 if (g_call_id != PJSUA_INVALID_ID) {
530 PJ_LOG(3,(THIS_FILE, "Another call is active"));
531 break;
532 }
533
534 if (pjsua_verify_sip_url(SIP_DST_URI) == PJ_SUCCESS) {
535 pj_str_t dst = pj_str(SIP_DST_URI);
536 pjsua_call_make_call(g_acc_id, &dst, 0, NULL,
537 NULL, &g_call_id);
538 } else {
539 PJ_LOG(3,(THIS_FILE, "Invalid SIP URI"));
540 }
541 break;
Benny Prijono70c5ba02007-12-31 11:27:35 +0000542 case 'a':
Benny Prijonoc71ad432007-05-04 07:25:19 +0000543 if (g_call_id != PJSUA_INVALID_ID)
544 pjsua_call_answer(g_call_id, 200, NULL, NULL);
545 break;
Benny Prijono70c5ba02007-12-31 11:27:35 +0000546 case 'g':
Benny Prijonoc71ad432007-05-04 07:25:19 +0000547 pjsua_call_hangup_all();
548 break;
549 case 's':
550 case 'S':
551 if (g_buddy_id != PJSUA_INVALID_ID)
552 pjsua_buddy_subscribe_pres(g_buddy_id, kc=='s');
553 break;
554 case 'o':
555 case 'O':
556 pjsua_acc_set_online_status(g_acc_id, kc=='o');
557 break;
558 default:
559 PJ_LOG(3,(THIS_FILE, "Keycode '%c' (%d) is pressed",
560 kc, kc));
561 break;
562 }
Benny Prijono72a81aa2007-05-02 23:06:11 +0000563
Benny Prijonoc71ad432007-05-04 07:25:19 +0000564 PrintMenu();
565
566 if (reschedule)
567 Run();
Benny Prijonoba5926a2007-05-02 11:29:37 +0000568}
569
Benny Prijono70c5ba02007-12-31 11:27:35 +0000570#if 0
571// IP networking related testing
572static pj_status_t test_addr(void)
573{
574 int af;
575 unsigned i, count;
576 pj_addrinfo ai[8];
577 pj_sockaddr ifs[8];
578 const pj_str_t *hostname;
579 pj_hostent he;
580 pj_status_t status;
581
582 pj_log_set_log_func(&log_writer);
583
584 status = pj_init();
585 if (status != PJ_SUCCESS) {
586 pjsua_perror(THIS_FILE, "pj_init() error", status);
587 return status;
588 }
589
590 af = pj_AF_INET();
591
Benny Prijono684c0ad2008-01-03 18:50:27 +0000592#if 0
593 pj_in_addr in_addr;
594 pj_str_t aa = pj_str("1.1.1.1");
595 in_addr = pj_inet_addr(&aa);
596 char *the_addr = pj_inet_ntoa(in_addr);
597 PJ_LOG(3,(THIS_FILE, "IP addr=%s", the_addr));
598
599 aa = pj_str("192.168.0.15");
600 in_addr = pj_inet_addr(&aa);
601 the_addr = pj_inet_ntoa(in_addr);
602 PJ_LOG(3,(THIS_FILE, "IP addr=%s", the_addr));
603
604 aa = pj_str("2.2.2.2");
605 in_addr = pj_inet_addr(&aa);
606 the_addr = pj_inet_ntoa(in_addr);
607 PJ_LOG(3,(THIS_FILE, "IP addr=%s", the_addr));
608
609 return -1;
610#endif
611
Benny Prijono70c5ba02007-12-31 11:27:35 +0000612 // Hostname
613 hostname = pj_gethostname();
614 if (hostname == NULL) {
615 status = PJ_ERESOLVE;
616 pjsua_perror(THIS_FILE, "pj_gethostname() error", status);
617 goto on_return;
618 }
619
620 PJ_LOG(3,(THIS_FILE, "Hostname: %.*s", hostname->slen, hostname->ptr));
621
622 // Gethostbyname
623 status = pj_gethostbyname(hostname, &he);
624 if (status != PJ_SUCCESS) {
625 pjsua_perror(THIS_FILE, "pj_gethostbyname() error", status);
626 } else {
627 PJ_LOG(3,(THIS_FILE, "gethostbyname: %s",
628 pj_inet_ntoa(*(pj_in_addr*)he.h_addr)));
629 }
630
631 // Getaddrinfo
632 count = PJ_ARRAY_SIZE(ai);
633 status = pj_getaddrinfo(af, hostname, &count, ai);
634 if (status != PJ_SUCCESS) {
635 pjsua_perror(THIS_FILE, "pj_getaddrinfo() error", status);
636 } else {
637 for (i=0; i<count; ++i) {
638 char ipaddr[PJ_INET6_ADDRSTRLEN+2];
639 PJ_LOG(3,(THIS_FILE, "Addrinfo: %s",
640 pj_sockaddr_print(&ai[i].ai_addr, ipaddr, sizeof(ipaddr), 2)));
641 }
642 }
643
644 // Enum interface
645 count = PJ_ARRAY_SIZE(ifs);
646 status = pj_enum_ip_interface(af, &count, ifs);
647 if (status != PJ_SUCCESS) {
648 pjsua_perror(THIS_FILE, "pj_enum_ip_interface() error", status);
649 } else {
650 for (i=0; i<count; ++i) {
651 char ipaddr[PJ_INET6_ADDRSTRLEN+2];
652 PJ_LOG(3,(THIS_FILE, "Interface: %s",
653 pj_sockaddr_print(&ifs[i], ipaddr, sizeof(ipaddr), 2)));
654 }
655 }
656
657 // Get default iinterface
658 status = pj_getdefaultipinterface(af, &ifs[0]);
659 if (status != PJ_SUCCESS) {
660 pjsua_perror(THIS_FILE, "pj_getdefaultipinterface() error", status);
661 } else {
662 char ipaddr[PJ_INET6_ADDRSTRLEN+2];
663 PJ_LOG(3,(THIS_FILE, "Default IP: %s",
664 pj_sockaddr_print(&ifs[0], ipaddr, sizeof(ipaddr), 2)));
665 }
666
667 // Get default IP address
668 status = pj_gethostip(af, &ifs[0]);
669 if (status != PJ_SUCCESS) {
670 pjsua_perror(THIS_FILE, "pj_gethostip() error", status);
671 } else {
672 char ipaddr[PJ_INET6_ADDRSTRLEN+2];
673 PJ_LOG(3,(THIS_FILE, "Host IP: %s",
674 pj_sockaddr_print(&ifs[0], ipaddr, sizeof(ipaddr), 2)));
675 }
676
677 status = -1;
678
679on_return:
680 pj_shutdown();
681 return status;
682}
683#endif
684
685
Benny Prijono6b3ccdf2008-01-14 11:54:21 +0000686#include <es_sock.h>
Benny Prijono897f9f82007-05-03 19:56:21 +0000687
Benny Prijonoba5926a2007-05-02 11:29:37 +0000688////////////////////////////////////////////////////////////////////////////
689int ua_main()
690{
Benny Prijono70c5ba02007-12-31 11:27:35 +0000691 RSocketServ aSocketServer;
692 RConnection aConn;
693 TInt err;
694 pj_symbianos_params sym_params;
Benny Prijonoc71ad432007-05-04 07:25:19 +0000695 pj_status_t status;
696
Benny Prijono70c5ba02007-12-31 11:27:35 +0000697 // Initialize RSocketServ
698 if ((err=aSocketServer.Connect()) != KErrNone)
699 return PJ_STATUS_FROM_OS(err);
700
701 // Open up a connection
702 if ((err=aConn.Open(aSocketServer)) != KErrNone) {
703 aSocketServer.Close();
704 return PJ_STATUS_FROM_OS(err);
705 }
706
707 if ((err=aConn.Start()) != KErrNone) {
708 aSocketServer.Close();
709 return PJ_STATUS_FROM_OS(err);
710 }
711
712 // Set Symbian OS parameters in pjlib.
713 // This must be done before pj_init() is called.
714 pj_bzero(&sym_params, sizeof(sym_params));
715 sym_params.rsocketserv = &aSocketServer;
716 sym_params.rconnection = &aConn;
717 pj_symbianos_set_params(&sym_params);
718
Benny Prijonoc71ad432007-05-04 07:25:19 +0000719 // Initialize pjsua
720 status = app_startup();
Benny Prijono70c5ba02007-12-31 11:27:35 +0000721 //status = test_addr();
722 if (status != PJ_SUCCESS) {
723 aConn.Close();
724 aSocketServer.Close();
Benny Prijonoc71ad432007-05-04 07:25:19 +0000725 return status;
Benny Prijono70c5ba02007-12-31 11:27:35 +0000726 }
Benny Prijono897f9f82007-05-03 19:56:21 +0000727
Benny Prijonoc71ad432007-05-04 07:25:19 +0000728 // Run the UI
729 CActiveSchedulerWait *asw = new CActiveSchedulerWait;
730 ConsoleUI *con = new ConsoleUI(asw, console);
731
732 con->Run();
733
734 PrintMenu();
735 asw->Start();
736
737 delete con;
738 delete asw;
Benny Prijono684c0ad2008-01-03 18:50:27 +0000739
740 // Dump memory statistics
741 PJ_LOG(3,(THIS_FILE, "Max heap usage: %u.%03uMB",
742 pjsua_var.cp.peak_used_size / 1000000,
743 (pjsua_var.cp.peak_used_size % 1000000)/1000));
Benny Prijonoc71ad432007-05-04 07:25:19 +0000744
Benny Prijono684c0ad2008-01-03 18:50:27 +0000745 // check max stack usage
746#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
747 pj_thread_t* this_thread = pj_thread_this();
748 if (!this_thread)
749 return status;
750
751 const char* max_stack_file;
752 int max_stack_line;
753 status = pj_thread_get_stack_info(this_thread, &max_stack_file, &max_stack_line);
754
755 PJ_LOG(3,(THIS_FILE, "Max stack usage: %u at %s:%d",
756 pj_thread_get_stack_max_usage(this_thread),
757 max_stack_file, max_stack_line));
758#endif
759
Benny Prijonoc71ad432007-05-04 07:25:19 +0000760 // Shutdown pjsua
761 pjsua_destroy();
762
Benny Prijono70c5ba02007-12-31 11:27:35 +0000763 // Close connection and socket server
764 aConn.Close();
765 aSocketServer.Close();
766
Benny Prijono797e3382007-12-01 09:10:07 +0000767 return status;
Benny Prijonoba5926a2007-05-02 11:29:37 +0000768}
769