blob: dd4c0c57bcb6d7a9c17fd88d5a3e6985d63cdd1b [file] [log] [blame]
Benny Prijono268ca612006-02-07 12:34:11 +00001/* $Id$ */
2/*
3 * Copyright (C) 2003-2006 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 */
19#include "pjsua.h"
20
Benny Prijono268ca612006-02-07 12:34:11 +000021
22#define THIS_FILE "pjsua.c"
23
Benny Prijono6782e092006-02-07 20:56:50 +000024struct pjsua_t pjsua;
Benny Prijono268ca612006-02-07 12:34:11 +000025
Benny Prijonoccf95622006-02-07 18:48:01 +000026#define PJSUA_LOCAL_URI "<sip:user@127.0.0.1>"
Benny Prijono268ca612006-02-07 12:34:11 +000027
28static char *PJSUA_DUMMY_SDP_OFFER =
29 "v=0\r\n"
30 "o=offer 2890844526 2890844526 IN IP4 127.0.0.1\r\n"
31 "s= \r\n"
32 "c=IN IP4 127.0.0.1\r\n"
33 "t=0 0\r\n"
34 "m=audio 49170 RTP/AVP 0\r\n"
35 "a=rtpmap:0 PCMU/8000\r\n";
36
37static char *PJSUA_DUMMY_SDP_ANSWER =
38 "v=0\r\n"
39 "o=answer 2890844730 2890844730 IN IP4 127.0.0.1\r\n"
40 "s= \r\n"
41 "c=IN IP4 127.0.0.1\r\n"
42 "t=0 0\r\n"
43 "m=audio 49920 RTP/AVP 0\r\n"
44 "a=rtpmap:0 PCMU/8000\r\n";
45
46/*
47 * Init default application parameters.
48 */
49void pjsua_default(void)
50{
51
52 /* Normally need another thread for console application, because main
53 * thread will be blocked in fgets().
54 */
55 pjsua.thread_cnt = 1;
56
57
58 /* Default transport settings: */
59
60 pjsua.sip_port = 5060;
61
62
63 /* Default logging settings: */
64
65 pjsua.log_level = 5;
66 pjsua.app_log_level = 4;
67 pjsua.log_decor = PJ_LOG_HAS_SENDER | PJ_LOG_HAS_TIME |
68 PJ_LOG_HAS_MICRO_SEC | PJ_LOG_HAS_NEWLINE;
69
70 /* Default: do not use STUN: */
71
72 pjsua.stun_port1 = pjsua.stun_port2 = 0;
Benny Prijonoccf95622006-02-07 18:48:01 +000073
74 /* Default URIs: */
75
76 pjsua.local_uri = pj_str(PJSUA_LOCAL_URI);
Benny Prijono268ca612006-02-07 12:34:11 +000077}
78
79
80/*
81 * Display error message for the specified error code.
82 */
83void pjsua_perror(const char *title, pj_status_t status)
84{
85 char errmsg[PJ_ERR_MSG_SIZE];
86
87 pj_strerror(status, errmsg, sizeof(errmsg));
88
89 PJ_LOG(1,(THIS_FILE, "%s: %s", title, errmsg));
90}
91
92
93/*
94 * Handler for receiving incoming requests.
95 *
96 * This handler serves multiple purposes:
97 * - it receives requests outside dialogs.
98 * - it receives requests inside dialogs, when the requests are
99 * unhandled by other dialog usages. Example of these
100 * requests are: MESSAGE.
101 */
102static pj_bool_t mod_pjsua_on_rx_request(pjsip_rx_data *rdata)
103{
104 PJ_UNUSED_ARG(rdata);
105 PJ_TODO(IMPLEMENT_UAS);
106 return PJ_FALSE;
107}
108
109
110/*
111 * Handler for receiving incoming responses.
112 *
113 * This handler serves multiple purposes:
114 * - it receives strayed responses (i.e. outside any dialog and
115 * outside any transactions).
116 * - it receives responses coming to a transaction, when pjsua
117 * module is set as transaction user for the transaction.
118 * - it receives responses inside a dialog, when these responses
119 * are unhandled by other dialog usages.
120 */
121static pj_bool_t mod_pjsua_on_rx_response(pjsip_rx_data *rdata)
122{
123 PJ_UNUSED_ARG(rdata);
124 PJ_TODO(IMPLEMENT_UAS);
125 return PJ_FALSE;
126}
127
128
129/*
130 * This callback receives notification from invite session when the
131 * session state has changed.
132 */
133static void pjsua_inv_on_state_changed(pjsip_inv_session *inv, pjsip_event *e)
134{
Benny Prijonoccf95622006-02-07 18:48:01 +0000135 pjsua_ui_inv_on_state_changed(inv, e);
Benny Prijono268ca612006-02-07 12:34:11 +0000136}
137
138
139/*
140 * This callback is called by invite session framework when UAC session
141 * has forked.
142 */
143static void pjsua_inv_on_new_session(pjsip_inv_session *inv, pjsip_event *e)
144{
145 PJ_UNUSED_ARG(inv);
146 PJ_UNUSED_ARG(e);
147
148 PJ_TODO(HANDLE_FORKED_DIALOG);
149}
150
151/*
152 * Initialize sockets and optionally get the public address via STUN.
153 */
154static pj_status_t init_sockets()
155{
156 enum {
157 RTP_START_PORT = 4000,
158 RTP_RANDOM_START = 2,
159 RTP_RETRY = 10
160 };
161 enum {
162 SIP_SOCK,
163 RTP_SOCK,
164 RTCP_SOCK,
165 };
166 int i;
167 pj_uint16_t rtp_port;
168 pj_sock_t sock[3];
169 pj_sockaddr_in mapped_addr[3];
170 pj_status_t status;
171
172 for (i=0; i<3; ++i)
173 sock[i] = PJ_INVALID_SOCKET;
174
175 /* Create and bind SIP UDP socket. */
176 status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock[SIP_SOCK]);
177 if (status != PJ_SUCCESS) {
178 pjsua_perror("socket() error", status);
179 goto on_error;
180 }
181
182 status = pj_sock_bind_in(sock[SIP_SOCK], 0, pjsua.sip_port);
183 if (status != PJ_SUCCESS) {
184 pjsua_perror("bind() error", status);
185 goto on_error;
186 }
187
188 /* Initialize start of RTP port to try. */
189 rtp_port = (pj_uint16_t)(RTP_START_PORT + (pj_rand() % RTP_RANDOM_START) / 2);
190
191 /* Loop retry to bind RTP and RTCP sockets. */
192 for (i=0; i<RTP_RETRY; ++i, rtp_port += 2) {
193
194 /* Create and bind RTP socket. */
195 status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock[RTP_SOCK]);
196 if (status != PJ_SUCCESS) {
197 pjsua_perror("socket() error", status);
198 goto on_error;
199 }
200
201 status = pj_sock_bind_in(sock[RTP_SOCK], 0, rtp_port);
202 if (status != PJ_SUCCESS) {
203 pj_sock_close(sock[RTP_SOCK]);
204 sock[RTP_SOCK] = PJ_INVALID_SOCKET;
205 continue;
206 }
207
208 /* Create and bind RTCP socket. */
209 status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock[RTCP_SOCK]);
210 if (status != PJ_SUCCESS) {
211 pjsua_perror("socket() error", status);
212 goto on_error;
213 }
214
215 status = pj_sock_bind_in(sock[RTCP_SOCK], 0, (pj_uint16_t)(rtp_port+1));
216 if (status != PJ_SUCCESS) {
217 pj_sock_close(sock[RTP_SOCK]);
218 sock[RTP_SOCK] = PJ_INVALID_SOCKET;
219
220 pj_sock_close(sock[RTCP_SOCK]);
221 sock[RTCP_SOCK] = PJ_INVALID_SOCKET;
222 continue;
223 }
224
225 /*
226 * If we're configured to use STUN, then find out the mapped address,
227 * and make sure that the mapped RTCP port is adjacent with the RTP.
228 */
229 if (pjsua.stun_port1 == 0) {
230 const pj_str_t *hostname;
231 pj_sockaddr_in addr;
232
233 /* Get local IP address. */
234 hostname = pj_gethostname();
235
236 pj_memset( &addr, 0, sizeof(addr));
237 addr.sin_family = PJ_AF_INET;
238 status = pj_sockaddr_in_set_str_addr( &addr, hostname);
239 if (status != PJ_SUCCESS) {
240 pjsua_perror("Unresolvable local hostname", status);
241 goto on_error;
242 }
243
244 for (i=0; i<3; ++i)
245 pj_memcpy(&mapped_addr[i], &addr, sizeof(addr));
246
247 mapped_addr[SIP_SOCK].sin_port = pj_htons((pj_uint16_t)pjsua.sip_port);
248 mapped_addr[RTP_SOCK].sin_port = pj_htons((pj_uint16_t)rtp_port);
249 mapped_addr[RTCP_SOCK].sin_port = pj_htons((pj_uint16_t)(rtp_port+1));
250 break;
251 } else {
252 status = pj_stun_get_mapped_addr( &pjsua.cp.factory, 3, sock,
253 &pjsua.stun_srv1, pjsua.stun_port1,
254 &pjsua.stun_srv2, pjsua.stun_port2,
255 mapped_addr);
256 if (status != PJ_SUCCESS) {
257 pjsua_perror("STUN error", status);
258 goto on_error;
259 }
260
261 if (pj_ntohs(mapped_addr[2].sin_port) == pj_ntohs(mapped_addr[1].sin_port)+1)
262 break;
263
264 pj_sock_close(sock[RTP_SOCK]); sock[RTP_SOCK] = PJ_INVALID_SOCKET;
265 pj_sock_close(sock[RTCP_SOCK]); sock[RTCP_SOCK] = PJ_INVALID_SOCKET;
266 }
267 }
268
269 if (sock[RTP_SOCK] == PJ_INVALID_SOCKET) {
270 PJ_LOG(1,(THIS_FILE, "Unable to find appropriate RTP/RTCP ports combination"));
271 goto on_error;
272 }
273
274 pjsua.sip_sock = sock[SIP_SOCK];
275 pj_memcpy(&pjsua.sip_sock_name, &mapped_addr[SIP_SOCK], sizeof(pj_sockaddr_in));
276 pjsua.rtp_sock = sock[RTP_SOCK];
277 pj_memcpy(&pjsua.rtp_sock_name, &mapped_addr[RTP_SOCK], sizeof(pj_sockaddr_in));
278 pjsua.rtcp_sock = sock[RTCP_SOCK];
279 pj_memcpy(&pjsua.rtcp_sock_name, &mapped_addr[RTCP_SOCK], sizeof(pj_sockaddr_in));
280
281 PJ_LOG(4,(THIS_FILE, "SIP UDP socket reachable at %s:%d",
282 pj_inet_ntoa(pjsua.sip_sock_name.sin_addr),
283 pj_ntohs(pjsua.sip_sock_name.sin_port)));
284 PJ_LOG(4,(THIS_FILE, "RTP socket reachable at %s:%d",
285 pj_inet_ntoa(pjsua.rtp_sock_name.sin_addr),
286 pj_ntohs(pjsua.rtp_sock_name.sin_port)));
287 PJ_LOG(4,(THIS_FILE, "RTCP UDP socket reachable at %s:%d",
288 pj_inet_ntoa(pjsua.rtcp_sock_name.sin_addr),
289 pj_ntohs(pjsua.rtcp_sock_name.sin_port)));
290
291 return PJ_SUCCESS;
292
293on_error:
294 for (i=0; i<3; ++i) {
295 if (sock[i] != PJ_INVALID_SOCKET)
296 pj_sock_close(sock[i]);
297 }
298 return status;
299}
300
301
302
303/*
304 * Initialize stack.
305 */
306static pj_status_t init_stack(void)
307{
308 pj_status_t status;
309
310 /* Create global endpoint: */
311
312 {
313 const pj_str_t *hostname;
314 const char *endpt_name;
315
316 /* Endpoint MUST be assigned a globally unique name.
317 * The name will be used as the hostname in Warning header.
318 */
319
320 /* For this implementation, we'll use hostname for simplicity */
321 hostname = pj_gethostname();
322 endpt_name = hostname->ptr;
323
324 /* Create the endpoint: */
325
326 status = pjsip_endpt_create(&pjsua.cp.factory, endpt_name,
327 &pjsua.endpt);
328 if (status != PJ_SUCCESS) {
329 pjsua_perror("Unable to create SIP endpoint", status);
330 return status;
331 }
332 }
333
334
335 /* Initialize transaction layer: */
336
337 status = pjsip_tsx_layer_init(pjsua.endpt);
338 if (status != PJ_SUCCESS) {
339 pjsua_perror("Transaction layer initialization error", status);
340 goto on_error;
341 }
342
343 /* Initialize UA layer module: */
344
345 status = pjsip_ua_init( pjsua.endpt, NULL );
346 if (status != PJ_SUCCESS) {
347 pjsua_perror("UA layer initialization error", status);
348 goto on_error;
349 }
350
351 /* Initialize and register pjsua's application module: */
352
353 {
354 pjsip_module my_mod =
355 {
356 NULL, NULL, /* prev, next. */
357 { "mod-pjsua", 9 }, /* Name. */
358 -1, /* Id */
359 PJSIP_MOD_PRIORITY_APPLICATION, /* Priority */
360 NULL, /* User data. */
361 NULL, /* load() */
362 NULL, /* start() */
363 NULL, /* stop() */
364 NULL, /* unload() */
365 &mod_pjsua_on_rx_request, /* on_rx_request() */
366 &mod_pjsua_on_rx_response, /* on_rx_response() */
367 NULL, /* on_tx_request. */
368 NULL, /* on_tx_response() */
369 NULL, /* on_tsx_state() */
370 };
371
372 pjsua.mod = my_mod;
373
374 status = pjsip_endpt_register_module(pjsua.endpt, &pjsua.mod);
375 if (status != PJ_SUCCESS) {
376 pjsua_perror("Unable to register pjsua module", status);
377 goto on_error;
378 }
379 }
380
381 /* Initialize invite session module: */
382
383 {
384
385 /* Initialize invite session callback. */
386 pjsip_inv_callback inv_cb;
387
388 pj_memset(&inv_cb, 0, sizeof(inv_cb));
389 inv_cb.on_state_changed = &pjsua_inv_on_state_changed;
390 inv_cb.on_new_session = &pjsua_inv_on_new_session;
391
392 /* Initialize invite session module: */
393 status = pjsip_inv_usage_init(pjsua.endpt, &pjsua.mod, &inv_cb);
394 if (status != PJ_SUCCESS) {
395 pjsua_perror("Invite usage initialization error", status);
396 goto on_error;
397 }
398
399 }
400
401
Benny Prijonoccf95622006-02-07 18:48:01 +0000402 /* Done */
Benny Prijono268ca612006-02-07 12:34:11 +0000403
404 return PJ_SUCCESS;
405
406
407on_error:
408 pjsip_endpt_destroy(pjsua.endpt);
409 pjsua.endpt = NULL;
410 return status;
411}
412
413
414static int PJ_THREAD_FUNC pjsua_worker_thread(void *arg)
415{
416 PJ_UNUSED_ARG(arg);
417
418 while (!pjsua.quit_flag) {
419 pj_time_val timeout = { 0, 10 };
420 pjsip_endpt_handle_events (pjsua.endpt, &timeout);
421 }
422
423 return 0;
424}
425
426/*
427 * Initialize pjsua application.
Benny Prijonoccf95622006-02-07 18:48:01 +0000428 * This will initialize all libraries, create endpoint instance, and register
429 * pjsip modules.
Benny Prijono268ca612006-02-07 12:34:11 +0000430 */
431pj_status_t pjsua_init(void)
432{
Benny Prijono268ca612006-02-07 12:34:11 +0000433 pj_status_t status;
434
435 /* Init PJLIB logging: */
436
437 pj_log_set_level(pjsua.log_level);
438 pj_log_set_decor(pjsua.log_decor);
439
440
441 /* Init PJLIB: */
442
443 status = pj_init();
444 if (status != PJ_SUCCESS) {
445 pjsua_perror("pj_init() error", status);
446 return status;
447 }
448
449 /* Init memory pool: */
450
451 /* Init caching pool. */
452 pj_caching_pool_init(&pjsua.cp, &pj_pool_factory_default_policy, 0);
453
454 /* Create memory pool for application. */
455 pjsua.pool = pj_pool_create(&pjsua.cp.factory, "pjsua", 4000, 4000, NULL);
456
457
Benny Prijonoccf95622006-02-07 18:48:01 +0000458 /* Init PJSIP and all the modules: */
459
460 status = init_stack();
461 if (status != PJ_SUCCESS) {
462 pj_caching_pool_destroy(&pjsua.cp);
463 pjsua_perror("Stack initialization has returned error", status);
464 return status;
465 }
466
467 /* Done. */
468 return PJ_SUCCESS;
469}
470
471
472
473/*
474 * Start pjsua stack.
475 * This will start the registration process, if registration is configured.
476 */
477pj_status_t pjsua_start(void)
478{
479 int i; /* Must be signed */
480 pjsip_transport *udp_transport;
481 pj_status_t status;
482
Benny Prijono268ca612006-02-07 12:34:11 +0000483 /* Init sockets (STUN etc): */
484
485 status = init_sockets();
486 if (status != PJ_SUCCESS) {
487 pj_caching_pool_destroy(&pjsua.cp);
488 pjsua_perror("init_sockets() has returned error", status);
489 return status;
490 }
491
492
Benny Prijonoccf95622006-02-07 18:48:01 +0000493 /* Add UDP transport: */
Benny Prijono268ca612006-02-07 12:34:11 +0000494
Benny Prijonoccf95622006-02-07 18:48:01 +0000495 {
496 /* Init the published name for the transport.
497 * Depending whether STUN is used, this may be the STUN mapped
498 * address, or socket's bound address.
499 */
500 pjsip_host_port addr_name;
501
502 addr_name.host.ptr = pj_inet_ntoa(pjsua.sip_sock_name.sin_addr);
503 addr_name.host.slen = pj_native_strlen(addr_name.host.ptr);
504 addr_name.port = pj_ntohs(pjsua.sip_sock_name.sin_port);
505
506 /* Create UDP transport from previously created UDP socket: */
507
508 status = pjsip_udp_transport_attach( pjsua.endpt, pjsua.sip_sock,
509 &addr_name, 1,
510 &udp_transport);
511 if (status != PJ_SUCCESS) {
512 pjsua_perror("Unable to start UDP transport", status);
513 return status;
514 }
Benny Prijono268ca612006-02-07 12:34:11 +0000515 }
516
Benny Prijonoccf95622006-02-07 18:48:01 +0000517 /* Initialize Contact URI, if one is not specified: */
518
519 if (pjsua.contact_uri.slen == 0 && pjsua.local_uri.slen) {
520
521 pjsip_uri *uri;
522 pjsip_sip_uri *sip_uri;
523 char contact[128];
524 int len;
525
526 /* The local Contact is the username@ip-addr, where
527 * - username is taken from the local URI,
528 * - ip-addr in UDP transport's address name (which may have been
529 * resolved from STUN.
530 */
531
532 /* Need to parse local_uri to get the elements: */
533
534 uri = pjsip_parse_uri(pjsua.pool, pjsua.local_uri.ptr,
535 pjsua.local_uri.slen, 0);
536 if (uri == NULL) {
537 pjsua_perror("Invalid local URI", PJSIP_EINVALIDURI);
538 return PJSIP_EINVALIDURI;
539 }
540
541
542 /* Local URI MUST be a SIP or SIPS: */
543
544 if (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri)) {
545 pjsua_perror("Invalid local URI", PJSIP_EINVALIDSCHEME);
546 return PJSIP_EINVALIDSCHEME;
547 }
548
549
550 /* Get the SIP URI object: */
551
552 sip_uri = (pjsip_sip_uri*) pjsip_uri_get_uri(uri);
553
554
555 /* Build temporary contact string. */
556
557 if (sip_uri->user.slen) {
558
559 /* With the user part. */
560 len = pj_snprintf(contact, sizeof(contact),
561 "<sip:%.*s@%.*s:%d>",
562 sip_uri->user.slen,
563 sip_uri->user.ptr,
564 udp_transport->local_name.host.slen,
565 udp_transport->local_name.host.ptr,
566 udp_transport->local_name.port);
567 } else {
568
569 /* Without user part */
570
571 len = pj_snprintf(contact, sizeof(contact),
572 "<sip:%.*s:%d>",
573 udp_transport->local_name.host.slen,
574 udp_transport->local_name.host.ptr,
575 udp_transport->local_name.port);
576 }
577
578 if (len < 1 || len >= sizeof(contact)) {
579 pjsua_perror("Invalid Contact", PJSIP_EURITOOLONG);
580 return PJSIP_EURITOOLONG;
581 }
582
583 /* Duplicate Contact uri. */
584
585 pj_strdup2(pjsua.pool, &pjsua.contact_uri, contact);
586
587 }
588
589 /* Initialize global route_set: */
590
591 PJ_TODO(INIT_GLOBAL_ROUTE_SET);
592
593
Benny Prijono268ca612006-02-07 12:34:11 +0000594 /* Create worker thread(s), if required: */
595
596 for (i=0; i<pjsua.thread_cnt; ++i) {
597 status = pj_thread_create( pjsua.pool, "pjsua", &pjsua_worker_thread,
598 NULL, 0, 0, &pjsua.threads[i]);
599 if (status != PJ_SUCCESS) {
600 pjsua.quit_flag = 1;
601 for (--i; i>=0; --i) {
602 pj_thread_join(pjsua.threads[i]);
603 pj_thread_destroy(pjsua.threads[i]);
604 }
605 pj_caching_pool_destroy(&pjsua.cp);
606 return status;
607 }
608 }
609
Benny Prijonoccf95622006-02-07 18:48:01 +0000610 /* Start registration: */
611
612 /* Create client registration session: */
613
614 status = pjsua_regc_init();
615 if (status != PJ_SUCCESS)
616 return status;
617
618 /* Perform registration, if required. */
619 if (pjsua.regc) {
620 pjsua_regc_update(1);
621 }
622
623
624
Benny Prijono268ca612006-02-07 12:34:11 +0000625 return PJ_SUCCESS;
626}
627
628
629/*
630 * Destroy pjsua.
631 */
632pj_status_t pjsua_destroy(void)
633{
634 int i;
635
Benny Prijonoccf95622006-02-07 18:48:01 +0000636 /* Unregister, if required: */
637 if (pjsua.regc) {
638
639 pjsua_regc_update(0);
640
641 /* Wait for some time to allow unregistration to complete: */
642
643 pj_thread_sleep(500);
644 }
645
Benny Prijono268ca612006-02-07 12:34:11 +0000646 /* Signal threads to quit: */
647
648 pjsua.quit_flag = 1;
649
650 /* Wait worker threads to quit: */
651
652 for (i=0; i<pjsua.thread_cnt; ++i) {
653
654 pj_thread_join(pjsua.threads[i]);
655 pj_thread_destroy(pjsua.threads[i]);
656 }
657
658 /* Destroy endpoint. */
659 pjsip_endpt_destroy(pjsua.endpt);
660 pjsua.endpt = NULL;
661
662 /* Destroy caching pool. */
663 pj_caching_pool_destroy(&pjsua.cp);
664
665
666 /* Done. */
667
668 return PJ_SUCCESS;
669}
670
671
672/**
673 * Make outgoing call.
674 */
675pj_status_t pjsua_invite(const char *cstr_dest_uri,
676 pjsip_inv_session **p_inv)
677{
678 pj_str_t dest_uri;
679 pjsip_dialog *dlg;
680 pjmedia_sdp_session *offer;
681 pjsip_inv_session *inv;
682 pjsip_tx_data *tdata;
683 pj_status_t status;
684
685 /* Convert cstr_dest_uri to dest_uri */
686
687 dest_uri = pj_str((char*)cstr_dest_uri);
688
689 /* Create outgoing dialog: */
690
691 status = pjsip_dlg_create_uac( pjsip_ua_instance(), &pjsua.local_uri,
692 &pjsua.contact_uri, &dest_uri, &dest_uri,
693 &dlg);
694 if (status != PJ_SUCCESS) {
695 pjsua_perror("Dialog creation failed", status);
696 return status;
697 }
698
699 /* Create dummy SDP for offer: */
700
701 status = pjmedia_sdp_parse(dlg->pool, PJSUA_DUMMY_SDP_OFFER,
702 pj_native_strlen(PJSUA_DUMMY_SDP_OFFER),
703 &offer);
704 if (status != PJ_SUCCESS) {
705 pjsua_perror("Dummy SDP offer parsing failed", status);
706 goto on_error;
707 }
708
709 /* Create the INVITE session: */
710
711 status = pjsip_inv_create_uac( dlg, offer, 0, &inv);
712 if (status != PJ_SUCCESS) {
713 pjsua_perror("Invite session creation failed", status);
714 goto on_error;
715 }
716
717
Benny Prijonoccf95622006-02-07 18:48:01 +0000718 /* Set dialog Route-Set: */
719
720 PJ_TODO(INIT_DIALOG_ROUTE_SET);
721
Benny Prijono268ca612006-02-07 12:34:11 +0000722 /* Set credentials: */
723
Benny Prijonoccf95622006-02-07 18:48:01 +0000724 pjsip_auth_clt_set_credentials( &dlg->auth_sess, pjsua.cred_count,
725 pjsua.cred_info);
Benny Prijono268ca612006-02-07 12:34:11 +0000726
727
728 /* Create initial INVITE: */
729
730 status = pjsip_inv_invite(inv, &tdata);
731 if (status != PJ_SUCCESS) {
732 pjsua_perror("Unable to create initial INVITE request", status);
733 goto on_error;
734 }
735
736
737 /* Send initial INVITE: */
738
739 status = pjsip_inv_send_msg(inv, tdata, NULL);
740 if (status != PJ_SUCCESS) {
741 pjsua_perror("Unable to send initial INVITE request", status);
742 goto on_error;
743 }
744
745
746 /* Done. */
747
748 *p_inv = inv;
749
750 return PJ_SUCCESS;
751
752
753on_error:
754
755 PJ_TODO(DESTROY_DIALOG_ON_FAIL);
756 return status;
757}
758