blob: b80055f9fde5d3cf1c2b48abdae3aad43ff78c10 [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
80
Benny Prijonob2c96822007-05-03 13:31:21 +000081//
82// Globals
83//
84static pjsua_acc_id g_acc_id = PJSUA_INVALID_ID;
85static pjsua_call_id g_call_id = PJSUA_INVALID_ID;
86static pjsua_buddy_id g_buddy_id = PJSUA_INVALID_ID;
Benny Prijono72a81aa2007-05-02 23:06:11 +000087
Benny Prijonoba5926a2007-05-02 11:29:37 +000088
89/* Callback called by the library upon receiving incoming call */
90static void on_incoming_call(pjsua_acc_id acc_id, pjsua_call_id call_id,
91 pjsip_rx_data *rdata)
92{
93 pjsua_call_info ci;
94
95 PJ_UNUSED_ARG(acc_id);
96 PJ_UNUSED_ARG(rdata);
97
Benny Prijonob2c96822007-05-03 13:31:21 +000098 if (g_call_id != PJSUA_INVALID_ID) {
99 pjsua_call_answer(call_id, PJSIP_SC_BUSY_HERE, NULL, NULL);
100 return;
101 }
102
Benny Prijonoba5926a2007-05-02 11:29:37 +0000103 pjsua_call_get_info(call_id, &ci);
104
105 PJ_LOG(3,(THIS_FILE, "Incoming call from %.*s!!",
106 (int)ci.remote_info.slen,
107 ci.remote_info.ptr));
108
Benny Prijonob2c96822007-05-03 13:31:21 +0000109 g_call_id = call_id;
110
Benny Prijono897f9f82007-05-03 19:56:21 +0000111 /* Automatically answer incoming calls with 180/Ringing */
112 pjsua_call_answer(call_id, 180, NULL, NULL);
Benny Prijonoba5926a2007-05-02 11:29:37 +0000113}
114
115/* Callback called by the library when call's state has changed */
116static void on_call_state(pjsua_call_id call_id, pjsip_event *e)
117{
118 pjsua_call_info ci;
119
120 PJ_UNUSED_ARG(e);
121
122 pjsua_call_get_info(call_id, &ci);
Benny Prijonob2c96822007-05-03 13:31:21 +0000123
124 if (ci.state == PJSIP_INV_STATE_DISCONNECTED) {
125 if (call_id == g_call_id)
126 g_call_id = PJSUA_INVALID_ID;
Benny Prijono897f9f82007-05-03 19:56:21 +0000127 } else if (ci.state != PJSIP_INV_STATE_INCOMING) {
Benny Prijonob2c96822007-05-03 13:31:21 +0000128 if (g_call_id == PJSUA_INVALID_ID)
129 g_call_id = call_id;
130 }
131
Benny Prijonoba5926a2007-05-02 11:29:37 +0000132 PJ_LOG(3,(THIS_FILE, "Call %d state=%.*s", call_id,
133 (int)ci.state_text.slen,
134 ci.state_text.ptr));
135}
136
137/* Callback called by the library when call's media state has changed */
138static void on_call_media_state(pjsua_call_id call_id)
139{
140 pjsua_call_info ci;
141
142 pjsua_call_get_info(call_id, &ci);
143
144 if (ci.media_status == PJSUA_CALL_MEDIA_ACTIVE) {
145 // When media is active, connect call to sound device.
146 pjsua_conf_connect(ci.conf_slot, 0);
147 pjsua_conf_connect(0, ci.conf_slot);
148 }
149}
150
151
Benny Prijonob2c96822007-05-03 13:31:21 +0000152/* Handler on buddy state changed. */
153static void on_buddy_state(pjsua_buddy_id buddy_id)
154{
155 pjsua_buddy_info info;
156 pjsua_buddy_get_info(buddy_id, &info);
157
158 PJ_LOG(3,(THIS_FILE, "%.*s status is %.*s",
159 (int)info.uri.slen,
160 info.uri.ptr,
161 (int)info.status_text.slen,
162 info.status_text.ptr));
163}
164
165
166/* Incoming IM message (i.e. MESSAGE request)! */
167static void on_pager(pjsua_call_id call_id, const pj_str_t *from,
168 const pj_str_t *to, const pj_str_t *contact,
169 const pj_str_t *mime_type, const pj_str_t *text)
170{
171 /* Note: call index may be -1 */
172 PJ_UNUSED_ARG(call_id);
173 PJ_UNUSED_ARG(to);
174 PJ_UNUSED_ARG(contact);
175 PJ_UNUSED_ARG(mime_type);
176
177 PJ_LOG(3,(THIS_FILE,"MESSAGE from %.*s: %.*s",
178 (int)from->slen, from->ptr,
179 (int)text->slen, text->ptr));
180}
181
182
183/* Received typing indication */
184static void on_typing(pjsua_call_id call_id, const pj_str_t *from,
185 const pj_str_t *to, const pj_str_t *contact,
186 pj_bool_t is_typing)
187{
188 PJ_UNUSED_ARG(call_id);
189 PJ_UNUSED_ARG(to);
190 PJ_UNUSED_ARG(contact);
191
192 PJ_LOG(3,(THIS_FILE, "IM indication: %.*s %s",
193 (int)from->slen, from->ptr,
194 (is_typing?"is typing..":"has stopped typing")));
195}
196
197
198/* Call transfer request status. */
199static void on_call_transfer_status(pjsua_call_id call_id,
200 int status_code,
201 const pj_str_t *status_text,
202 pj_bool_t final,
203 pj_bool_t *p_cont)
204{
205 PJ_LOG(3,(THIS_FILE, "Call %d: transfer status=%d (%.*s) %s",
206 call_id, status_code,
207 (int)status_text->slen, status_text->ptr,
208 (final ? "[final]" : "")));
209
210 if (status_code/100 == 2) {
211 PJ_LOG(3,(THIS_FILE,
212 "Call %d: call transfered successfully, disconnecting call",
213 call_id));
214 pjsua_call_hangup(call_id, PJSIP_SC_GONE, NULL, NULL);
215 *p_cont = PJ_FALSE;
216 }
217}
218
219
Benny Prijonoaecabfc2007-10-26 05:35:42 +0000220/* NAT detection result */
221static void on_nat_detect(const pj_stun_nat_detect_result *res)
222{
223 if (res->status != PJ_SUCCESS) {
224 pjsua_perror(THIS_FILE, "NAT detection failed", res->status);
225 } else {
226 PJ_LOG(3, (THIS_FILE, "NAT detected as %s", res->nat_type_name));
227 }
228}
229
Benny Prijonob2c96822007-05-03 13:31:21 +0000230/* Notification that call is being replaced. */
231static void on_call_replaced(pjsua_call_id old_call_id,
232 pjsua_call_id new_call_id)
233{
234 pjsua_call_info old_ci, new_ci;
235
236 pjsua_call_get_info(old_call_id, &old_ci);
237 pjsua_call_get_info(new_call_id, &new_ci);
238
239 PJ_LOG(3,(THIS_FILE, "Call %d with %.*s is being replaced by "
240 "call %d with %.*s",
241 old_call_id,
242 (int)old_ci.remote_info.slen, old_ci.remote_info.ptr,
243 new_call_id,
244 (int)new_ci.remote_info.slen, new_ci.remote_info.ptr));
245}
246
247
Benny Prijonoba5926a2007-05-02 11:29:37 +0000248/* Logging callback */
Benny Prijono797e3382007-12-01 09:10:07 +0000249static void log_writer(int level, const char *buf, int len)
Benny Prijonoba5926a2007-05-02 11:29:37 +0000250{
Benny Prijonoc71ad432007-05-04 07:25:19 +0000251 static wchar_t buf16[PJ_LOG_MAX_SIZE];
Benny Prijonoba5926a2007-05-02 11:29:37 +0000252
253 PJ_UNUSED_ARG(level);
254
255 pj_ansi_to_unicode(buf, len, buf16, PJ_ARRAY_SIZE(buf16));
256
257 TPtrC16 aBuf((const TUint16*)buf16, (TInt)len);
258 console->Write(aBuf);
Benny Prijono797e3382007-12-01 09:10:07 +0000259
Benny Prijonoba5926a2007-05-02 11:29:37 +0000260}
261
262/*
263 * app_startup()
264 *
265 * url may contain URL to call.
266 */
Benny Prijonob2c96822007-05-03 13:31:21 +0000267static pj_status_t app_startup()
Benny Prijonoba5926a2007-05-02 11:29:37 +0000268{
Benny Prijonoba5926a2007-05-02 11:29:37 +0000269 pj_status_t status;
270
271 /* Redirect log before pjsua_init() */
Benny Prijono70c5ba02007-12-31 11:27:35 +0000272 pj_log_set_log_func(&log_writer);
273
274 /* Set log level */
275 pj_log_set_level(LOG_LEVEL);
Benny Prijonoba5926a2007-05-02 11:29:37 +0000276
277 /* Create pjsua first! */
278 status = pjsua_create();
279 if (status != PJ_SUCCESS) {
280 pjsua_perror(THIS_FILE, "pjsua_create() error", status);
281 return status;
282 }
283
Benny Prijonoba5926a2007-05-02 11:29:37 +0000284 /* Init pjsua */
Benny Prijonoc71ad432007-05-04 07:25:19 +0000285 pjsua_config cfg;
286 pjsua_logging_config log_cfg;
287 pjsua_media_config med_cfg;
Benny Prijonoba5926a2007-05-02 11:29:37 +0000288
Benny Prijonoc71ad432007-05-04 07:25:19 +0000289 pjsua_config_default(&cfg);
290 cfg.max_calls = 2;
291 cfg.thread_cnt = 0; // Disable threading on Symbian
292 cfg.cb.on_incoming_call = &on_incoming_call;
293 cfg.cb.on_call_media_state = &on_call_media_state;
294 cfg.cb.on_call_state = &on_call_state;
295 cfg.cb.on_buddy_state = &on_buddy_state;
296 cfg.cb.on_pager = &on_pager;
297 cfg.cb.on_typing = &on_typing;
298 cfg.cb.on_call_transfer_status = &on_call_transfer_status;
299 cfg.cb.on_call_replaced = &on_call_replaced;
Benny Prijonoaecabfc2007-10-26 05:35:42 +0000300 cfg.cb.on_nat_detect = &on_nat_detect;
301
Benny Prijonoc71ad432007-05-04 07:25:19 +0000302 if (SIP_PROXY) {
303 cfg.outbound_proxy_cnt = 1;
304 cfg.outbound_proxy[0] = pj_str(SIP_PROXY);
305 }
306
307 if (NAMESERVER) {
308 cfg.nameserver_count = 1;
309 cfg.nameserver[0] = pj_str(NAMESERVER);
310 }
311
312 if (NAMESERVER && STUN_DOMAIN) {
313 cfg.stun_domain = pj_str(STUN_DOMAIN);
314 } else if (STUN_SERVER) {
315 cfg.stun_host = pj_str(STUN_SERVER);
316 }
317
318
319 pjsua_logging_config_default(&log_cfg);
320 log_cfg.console_level = 4;
321 log_cfg.cb = &log_writer;
Benny Prijonoba5926a2007-05-02 11:29:37 +0000322
Benny Prijonoc71ad432007-05-04 07:25:19 +0000323 pjsua_media_config_default(&med_cfg);
324 med_cfg.thread_cnt = 0; // Disable threading on Symbian
325 med_cfg.has_ioqueue = PJ_FALSE;
326 med_cfg.clock_rate = 8000;
Benny Prijono5df8bb62007-12-28 18:55:02 +0000327 med_cfg.audio_frame_ptime = 40;
Benny Prijonoc71ad432007-05-04 07:25:19 +0000328 med_cfg.ec_tail_len = 0;
329 med_cfg.enable_ice = USE_ICE;
330
331 status = pjsua_init(&cfg, &log_cfg, &med_cfg);
332 if (status != PJ_SUCCESS) {
333 pjsua_perror(THIS_FILE, "pjsua_init() error", status);
334 pjsua_destroy();
335 return status;
Benny Prijonoba5926a2007-05-02 11:29:37 +0000336 }
337
338 /* Add UDP transport. */
Benny Prijonoc71ad432007-05-04 07:25:19 +0000339 pjsua_transport_config tcfg;
340 pjsua_transport_id tid;
Benny Prijonoba5926a2007-05-02 11:29:37 +0000341
Benny Prijonoc71ad432007-05-04 07:25:19 +0000342 pjsua_transport_config_default(&tcfg);
343 tcfg.port = SIP_PORT;
344 status = pjsua_transport_create(PJSIP_TRANSPORT_UDP, &tcfg, &tid);
345 if (status != PJ_SUCCESS) {
346 pjsua_perror(THIS_FILE, "Error creating transport", status);
347 pjsua_destroy();
348 return status;
Benny Prijonoba5926a2007-05-02 11:29:37 +0000349 }
350
Benny Prijonoc71ad432007-05-04 07:25:19 +0000351 /* Add account for the transport */
352 pjsua_acc_add_local(tid, PJ_TRUE, &g_acc_id);
353
354
Benny Prijonoba5926a2007-05-02 11:29:37 +0000355 /* Initialization is done, now start pjsua */
356 status = pjsua_start();
357 if (status != PJ_SUCCESS) {
358 pjsua_perror(THIS_FILE, "Error starting pjsua", status);
359 pjsua_destroy();
360 return status;
361 }
362
363 /* Register to SIP server by creating SIP account. */
Benny Prijono72a81aa2007-05-02 23:06:11 +0000364 if (HAS_SIP_ACCOUNT) {
Benny Prijonoba5926a2007-05-02 11:29:37 +0000365 pjsua_acc_config cfg;
366
367 pjsua_acc_config_default(&cfg);
368 cfg.id = pj_str("sip:" SIP_USER "@" SIP_DOMAIN);
369 cfg.reg_uri = pj_str("sip:" SIP_DOMAIN);
370 cfg.cred_count = 1;
Benny Prijono0e2c6462008-02-14 13:39:24 +0000371 cfg.cred_info[0].realm = pj_str("*");
Benny Prijonoba5926a2007-05-02 11:29:37 +0000372 cfg.cred_info[0].scheme = pj_str("digest");
373 cfg.cred_info[0].username = pj_str(SIP_USER);
374 cfg.cred_info[0].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
375 cfg.cred_info[0].data = pj_str(SIP_PASSWD);
376
Benny Prijonob2c96822007-05-03 13:31:21 +0000377 status = pjsua_acc_add(&cfg, PJ_TRUE, &g_acc_id);
Benny Prijonoba5926a2007-05-02 11:29:37 +0000378 if (status != PJ_SUCCESS) {
379 pjsua_perror(THIS_FILE, "Error adding account", status);
380 pjsua_destroy();
381 return status;
382 }
383 }
384
Benny Prijonob2c96822007-05-03 13:31:21 +0000385 if (SIP_DST_URI) {
386 pjsua_buddy_config bcfg;
387
388 pjsua_buddy_config_default(&bcfg);
389 bcfg.uri = pj_str(SIP_DST_URI);
390 bcfg.subscribe = PJ_FALSE;
391
392 pjsua_buddy_add(&bcfg, &g_buddy_id);
Benny Prijonoba5926a2007-05-02 11:29:37 +0000393 }
Benny Prijonoba5926a2007-05-02 11:29:37 +0000394 return PJ_SUCCESS;
395}
396
397
398////////////////////////////////////////////////////////////////////////////
Benny Prijonoc71ad432007-05-04 07:25:19 +0000399/*
400 * The interractive console UI
401 */
Benny Prijonoba5926a2007-05-02 11:29:37 +0000402#include <e32base.h>
403
404class ConsoleUI : public CActive
405{
406public:
Benny Prijonoc71ad432007-05-04 07:25:19 +0000407 ConsoleUI(CActiveSchedulerWait *asw, CConsoleBase *con);
Benny Prijonoba5926a2007-05-02 11:29:37 +0000408
Benny Prijonoc71ad432007-05-04 07:25:19 +0000409 // Run console UI
410 void Run();
411
412 // Stop
413 void Stop();
Benny Prijonoba5926a2007-05-02 11:29:37 +0000414
415protected:
Benny Prijonoc71ad432007-05-04 07:25:19 +0000416 // Cancel asynchronous read.
417 void DoCancel();
Benny Prijonoba5926a2007-05-02 11:29:37 +0000418
Benny Prijonoc71ad432007-05-04 07:25:19 +0000419 // Implementation: called when read has completed.
420 void RunL();
Benny Prijonoba5926a2007-05-02 11:29:37 +0000421
422private:
Benny Prijonoc71ad432007-05-04 07:25:19 +0000423 CActiveSchedulerWait *asw_;
424 CConsoleBase *con_;
Benny Prijonoba5926a2007-05-02 11:29:37 +0000425};
426
427
428ConsoleUI::ConsoleUI(CActiveSchedulerWait *asw, CConsoleBase *con)
429: CActive(EPriorityStandard), asw_(asw), con_(con)
430{
Benny Prijonoc71ad432007-05-04 07:25:19 +0000431 CActiveScheduler::Add(this);
Benny Prijonoba5926a2007-05-02 11:29:37 +0000432}
433
434// Run console UI
435void ConsoleUI::Run()
436{
Benny Prijonoc71ad432007-05-04 07:25:19 +0000437 con_->Read(iStatus);
438 SetActive();
Benny Prijonoba5926a2007-05-02 11:29:37 +0000439}
440
441// Stop console UI
442void ConsoleUI::Stop()
443{
Benny Prijonoc71ad432007-05-04 07:25:19 +0000444 DoCancel();
Benny Prijonoba5926a2007-05-02 11:29:37 +0000445}
446
447// Cancel asynchronous read.
448void ConsoleUI::DoCancel()
449{
Benny Prijonoc71ad432007-05-04 07:25:19 +0000450 con_->ReadCancel();
Benny Prijonoba5926a2007-05-02 11:29:37 +0000451}
452
Benny Prijono72a81aa2007-05-02 23:06:11 +0000453static void PrintMenu()
454{
Benny Prijonoc71ad432007-05-04 07:25:19 +0000455 PJ_LOG(3, (THIS_FILE, "\n\n"
456 "Menu:\n"
457 " d Dump states\n"
Benny Prijono1f61a8f2007-08-16 10:11:44 +0000458 " D Dump states detail\n"
Benny Prijonoc71ad432007-05-04 07:25:19 +0000459 " P Dump pool factory\n"
Benny Prijono5df8bb62007-12-28 18:55:02 +0000460 " l Start loopback audio device\n"
461 " L Stop loopback audio device\n"
Benny Prijono70c5ba02007-12-31 11:27:35 +0000462 " m Call " SIP_DST_URI "\n"
463 " a Answer call\n"
464 " g Hangup all calls\n"
Benny Prijono1f61a8f2007-08-16 10:11:44 +0000465 " s Subscribe " SIP_DST_URI "\n"
Benny Prijonoc71ad432007-05-04 07:25:19 +0000466 " S Unsubscribe presence\n"
467 " o Set account online\n"
468 " O Set account offline\n"
Benny Prijono70c5ba02007-12-31 11:27:35 +0000469 " w Quit\n"));
Benny Prijono72a81aa2007-05-02 23:06:11 +0000470}
471
Benny Prijonoba5926a2007-05-02 11:29:37 +0000472// Implementation: called when read has completed.
473void ConsoleUI::RunL()
474{
Benny Prijonoc71ad432007-05-04 07:25:19 +0000475 TKeyCode kc = con_->KeyCode();
476 pj_bool_t reschedule = PJ_TRUE;
477
478 switch (kc) {
Benny Prijono70c5ba02007-12-31 11:27:35 +0000479 case 'w':
Benny Prijonoc71ad432007-05-04 07:25:19 +0000480 asw_->AsyncStop();
481 reschedule = PJ_FALSE;
482 break;
483 case 'D':
484 case 'd':
485 pjsua_dump(kc == 'D');
486 break;
487 case 'p':
488 case 'P':
Benny Prijono1f61a8f2007-08-16 10:11:44 +0000489 pj_pool_factory_dump(pjsua_get_pool_factory(), PJ_TRUE);
Benny Prijonoc71ad432007-05-04 07:25:19 +0000490 break;
Benny Prijono5df8bb62007-12-28 18:55:02 +0000491 case 'l':
492 pjsua_conf_connect(0, 0);
493 break;
494 case 'L':
495 pjsua_conf_disconnect(0, 0);
496 break;
Benny Prijono70c5ba02007-12-31 11:27:35 +0000497 case 'm':
Benny Prijonoc71ad432007-05-04 07:25:19 +0000498 if (g_call_id != PJSUA_INVALID_ID) {
499 PJ_LOG(3,(THIS_FILE, "Another call is active"));
500 break;
501 }
502
503 if (pjsua_verify_sip_url(SIP_DST_URI) == PJ_SUCCESS) {
504 pj_str_t dst = pj_str(SIP_DST_URI);
505 pjsua_call_make_call(g_acc_id, &dst, 0, NULL,
506 NULL, &g_call_id);
507 } else {
508 PJ_LOG(3,(THIS_FILE, "Invalid SIP URI"));
509 }
510 break;
Benny Prijono70c5ba02007-12-31 11:27:35 +0000511 case 'a':
Benny Prijonoc71ad432007-05-04 07:25:19 +0000512 if (g_call_id != PJSUA_INVALID_ID)
513 pjsua_call_answer(g_call_id, 200, NULL, NULL);
514 break;
Benny Prijono70c5ba02007-12-31 11:27:35 +0000515 case 'g':
Benny Prijonoc71ad432007-05-04 07:25:19 +0000516 pjsua_call_hangup_all();
517 break;
518 case 's':
519 case 'S':
520 if (g_buddy_id != PJSUA_INVALID_ID)
521 pjsua_buddy_subscribe_pres(g_buddy_id, kc=='s');
522 break;
523 case 'o':
524 case 'O':
525 pjsua_acc_set_online_status(g_acc_id, kc=='o');
526 break;
527 default:
528 PJ_LOG(3,(THIS_FILE, "Keycode '%c' (%d) is pressed",
529 kc, kc));
530 break;
531 }
Benny Prijono72a81aa2007-05-02 23:06:11 +0000532
Benny Prijonoc71ad432007-05-04 07:25:19 +0000533 PrintMenu();
534
535 if (reschedule)
536 Run();
Benny Prijonoba5926a2007-05-02 11:29:37 +0000537}
538
Benny Prijono70c5ba02007-12-31 11:27:35 +0000539#if 0
540// IP networking related testing
541static pj_status_t test_addr(void)
542{
543 int af;
544 unsigned i, count;
545 pj_addrinfo ai[8];
546 pj_sockaddr ifs[8];
547 const pj_str_t *hostname;
548 pj_hostent he;
549 pj_status_t status;
550
551 pj_log_set_log_func(&log_writer);
552
553 status = pj_init();
554 if (status != PJ_SUCCESS) {
555 pjsua_perror(THIS_FILE, "pj_init() error", status);
556 return status;
557 }
558
559 af = pj_AF_INET();
560
Benny Prijono684c0ad2008-01-03 18:50:27 +0000561#if 0
562 pj_in_addr in_addr;
563 pj_str_t aa = pj_str("1.1.1.1");
564 in_addr = pj_inet_addr(&aa);
565 char *the_addr = pj_inet_ntoa(in_addr);
566 PJ_LOG(3,(THIS_FILE, "IP addr=%s", the_addr));
567
568 aa = pj_str("192.168.0.15");
569 in_addr = pj_inet_addr(&aa);
570 the_addr = pj_inet_ntoa(in_addr);
571 PJ_LOG(3,(THIS_FILE, "IP addr=%s", the_addr));
572
573 aa = pj_str("2.2.2.2");
574 in_addr = pj_inet_addr(&aa);
575 the_addr = pj_inet_ntoa(in_addr);
576 PJ_LOG(3,(THIS_FILE, "IP addr=%s", the_addr));
577
578 return -1;
579#endif
580
Benny Prijono70c5ba02007-12-31 11:27:35 +0000581 // Hostname
582 hostname = pj_gethostname();
583 if (hostname == NULL) {
584 status = PJ_ERESOLVE;
585 pjsua_perror(THIS_FILE, "pj_gethostname() error", status);
586 goto on_return;
587 }
588
589 PJ_LOG(3,(THIS_FILE, "Hostname: %.*s", hostname->slen, hostname->ptr));
590
591 // Gethostbyname
592 status = pj_gethostbyname(hostname, &he);
593 if (status != PJ_SUCCESS) {
594 pjsua_perror(THIS_FILE, "pj_gethostbyname() error", status);
595 } else {
596 PJ_LOG(3,(THIS_FILE, "gethostbyname: %s",
597 pj_inet_ntoa(*(pj_in_addr*)he.h_addr)));
598 }
599
600 // Getaddrinfo
601 count = PJ_ARRAY_SIZE(ai);
602 status = pj_getaddrinfo(af, hostname, &count, ai);
603 if (status != PJ_SUCCESS) {
604 pjsua_perror(THIS_FILE, "pj_getaddrinfo() error", status);
605 } else {
606 for (i=0; i<count; ++i) {
607 char ipaddr[PJ_INET6_ADDRSTRLEN+2];
608 PJ_LOG(3,(THIS_FILE, "Addrinfo: %s",
609 pj_sockaddr_print(&ai[i].ai_addr, ipaddr, sizeof(ipaddr), 2)));
610 }
611 }
612
613 // Enum interface
614 count = PJ_ARRAY_SIZE(ifs);
615 status = pj_enum_ip_interface(af, &count, ifs);
616 if (status != PJ_SUCCESS) {
617 pjsua_perror(THIS_FILE, "pj_enum_ip_interface() error", status);
618 } else {
619 for (i=0; i<count; ++i) {
620 char ipaddr[PJ_INET6_ADDRSTRLEN+2];
621 PJ_LOG(3,(THIS_FILE, "Interface: %s",
622 pj_sockaddr_print(&ifs[i], ipaddr, sizeof(ipaddr), 2)));
623 }
624 }
625
626 // Get default iinterface
627 status = pj_getdefaultipinterface(af, &ifs[0]);
628 if (status != PJ_SUCCESS) {
629 pjsua_perror(THIS_FILE, "pj_getdefaultipinterface() error", status);
630 } else {
631 char ipaddr[PJ_INET6_ADDRSTRLEN+2];
632 PJ_LOG(3,(THIS_FILE, "Default IP: %s",
633 pj_sockaddr_print(&ifs[0], ipaddr, sizeof(ipaddr), 2)));
634 }
635
636 // Get default IP address
637 status = pj_gethostip(af, &ifs[0]);
638 if (status != PJ_SUCCESS) {
639 pjsua_perror(THIS_FILE, "pj_gethostip() error", status);
640 } else {
641 char ipaddr[PJ_INET6_ADDRSTRLEN+2];
642 PJ_LOG(3,(THIS_FILE, "Host IP: %s",
643 pj_sockaddr_print(&ifs[0], ipaddr, sizeof(ipaddr), 2)));
644 }
645
646 status = -1;
647
648on_return:
649 pj_shutdown();
650 return status;
651}
652#endif
653
654
Benny Prijono6b3ccdf2008-01-14 11:54:21 +0000655#include <es_sock.h>
Benny Prijono897f9f82007-05-03 19:56:21 +0000656
Benny Prijonoba5926a2007-05-02 11:29:37 +0000657////////////////////////////////////////////////////////////////////////////
658int ua_main()
659{
Benny Prijono70c5ba02007-12-31 11:27:35 +0000660 RSocketServ aSocketServer;
661 RConnection aConn;
662 TInt err;
663 pj_symbianos_params sym_params;
Benny Prijonoc71ad432007-05-04 07:25:19 +0000664 pj_status_t status;
665
Benny Prijono70c5ba02007-12-31 11:27:35 +0000666 // Initialize RSocketServ
667 if ((err=aSocketServer.Connect()) != KErrNone)
668 return PJ_STATUS_FROM_OS(err);
669
670 // Open up a connection
671 if ((err=aConn.Open(aSocketServer)) != KErrNone) {
672 aSocketServer.Close();
673 return PJ_STATUS_FROM_OS(err);
674 }
675
676 if ((err=aConn.Start()) != KErrNone) {
677 aSocketServer.Close();
678 return PJ_STATUS_FROM_OS(err);
679 }
680
681 // Set Symbian OS parameters in pjlib.
682 // This must be done before pj_init() is called.
683 pj_bzero(&sym_params, sizeof(sym_params));
684 sym_params.rsocketserv = &aSocketServer;
685 sym_params.rconnection = &aConn;
686 pj_symbianos_set_params(&sym_params);
687
Benny Prijonoc71ad432007-05-04 07:25:19 +0000688 // Initialize pjsua
689 status = app_startup();
Benny Prijono70c5ba02007-12-31 11:27:35 +0000690 //status = test_addr();
691 if (status != PJ_SUCCESS) {
692 aConn.Close();
693 aSocketServer.Close();
Benny Prijonoc71ad432007-05-04 07:25:19 +0000694 return status;
Benny Prijono70c5ba02007-12-31 11:27:35 +0000695 }
Benny Prijono897f9f82007-05-03 19:56:21 +0000696
Benny Prijonoc71ad432007-05-04 07:25:19 +0000697 // Run the UI
698 CActiveSchedulerWait *asw = new CActiveSchedulerWait;
699 ConsoleUI *con = new ConsoleUI(asw, console);
700
701 con->Run();
702
703 PrintMenu();
704 asw->Start();
705
706 delete con;
707 delete asw;
Benny Prijono684c0ad2008-01-03 18:50:27 +0000708
709 // Dump memory statistics
710 PJ_LOG(3,(THIS_FILE, "Max heap usage: %u.%03uMB",
711 pjsua_var.cp.peak_used_size / 1000000,
712 (pjsua_var.cp.peak_used_size % 1000000)/1000));
Benny Prijonoc71ad432007-05-04 07:25:19 +0000713
Benny Prijono684c0ad2008-01-03 18:50:27 +0000714 // check max stack usage
715#if defined(PJ_OS_HAS_CHECK_STACK) && PJ_OS_HAS_CHECK_STACK!=0
716 pj_thread_t* this_thread = pj_thread_this();
717 if (!this_thread)
718 return status;
719
720 const char* max_stack_file;
721 int max_stack_line;
722 status = pj_thread_get_stack_info(this_thread, &max_stack_file, &max_stack_line);
723
724 PJ_LOG(3,(THIS_FILE, "Max stack usage: %u at %s:%d",
725 pj_thread_get_stack_max_usage(this_thread),
726 max_stack_file, max_stack_line));
727#endif
728
Benny Prijonoc71ad432007-05-04 07:25:19 +0000729 // Shutdown pjsua
730 pjsua_destroy();
731
Benny Prijono70c5ba02007-12-31 11:27:35 +0000732 // Close connection and socket server
733 aConn.Close();
734 aSocketServer.Close();
735
Benny Prijono797e3382007-12-01 09:10:07 +0000736 return status;
Benny Prijonoba5926a2007-05-02 11:29:37 +0000737}
738