blob: 29063237078ffd200db37fe63f3f0b612b9f3038 [file] [log] [blame]
Tristan Matthews0a329cc2013-07-17 13:20:14 -04001/* $Id: simpleua.c 4051 2012-04-13 08:16:30Z ming $ */
2/*
3 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5 *
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 */
20
21
22/**
23 * simpleua.c
24 *
25 * This is a very simple SIP user agent complete with media. The user
26 * agent should do a proper SDP negotiation and start RTP media once
27 * SDP negotiation has completed.
28 *
29 * This program does not register to SIP server.
30 *
31 * Capabilities to be demonstrated here:
32 * - Basic call
33 * - Should support IPv6 (not tested)
34 * - UDP transport at port 5060 (hard coded)
35 * - RTP socket at port 4000 (hard coded)
36 * - proper SDP negotiation
37 * - PCMA/PCMU codec only.
38 * - Audio/media to sound device.
39 *
40 *
41 * Usage:
42 * - To make outgoing call, start simpleua with the URL of remote
43 * destination to contact.
44 * E.g.:
45 * simpleua sip:user@remote
46 *
47 * - Incoming calls will automatically be answered with 180, then 200.
48 *
49 * This program does not disconnect call.
50 *
51 * This program will quit once it has completed a single call.
52 */
53
54/* Include all headers. */
55#include <pjsip.h>
56#include <pjmedia.h>
57#include <pjmedia-codec.h>
58#include <pjsip_ua.h>
59#include <pjsip_simple.h>
60#include <pjlib-util.h>
61#include <pjlib.h>
62
63/* For logging purpose. */
64#define THIS_FILE "simpleua.c"
65
66#include "util.h"
67
68
69/* Settings */
70#define AF pj_AF_INET() /* Change to pj_AF_INET6() for IPv6.
71 * PJ_HAS_IPV6 must be enabled and
72 * your system must support IPv6. */
73#if 0
74#define SIP_PORT 5080 /* Listening SIP port */
75#define RTP_PORT 5000 /* RTP port */
76#else
77#define SIP_PORT 5060 /* Listening SIP port */
78#define RTP_PORT 4000 /* RTP port */
79#endif
80
81#define MAX_MEDIA_CNT 2 /* Media count, set to 1 for audio
82 * only or 2 for audio and video */
83
84/*
85 * Static variables.
86 */
87
88static pj_bool_t g_complete; /* Quit flag. */
89static pjsip_endpoint *g_endpt; /* SIP endpoint. */
90static pj_caching_pool cp; /* Global pool factory. */
91
92static pjmedia_endpt *g_med_endpt; /* Media endpoint. */
93
94static pjmedia_transport_info g_med_tpinfo[MAX_MEDIA_CNT];
95 /* Socket info for media */
96static pjmedia_transport *g_med_transport[MAX_MEDIA_CNT];
97 /* Media stream transport */
98static pjmedia_sock_info g_sock_info[MAX_MEDIA_CNT];
99 /* Socket info array */
100
101/* Call variables: */
102static pjsip_inv_session *g_inv; /* Current invite session. */
103static pjmedia_stream *g_med_stream; /* Call's audio stream. */
104static pjmedia_snd_port *g_snd_port; /* Sound device. */
105
106#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
107static pjmedia_vid_stream *g_med_vstream; /* Call's video stream. */
108static pjmedia_vid_port *g_vid_capturer;/* Call's video capturer. */
109static pjmedia_vid_port *g_vid_renderer;/* Call's video renderer. */
110#endif /* PJMEDIA_HAS_VIDEO */
111
112/*
113 * Prototypes:
114 */
115
116/* Callback to be called when SDP negotiation is done in the call: */
117static void call_on_media_update( pjsip_inv_session *inv,
118 pj_status_t status);
119
120/* Callback to be called when invite session's state has changed: */
121static void call_on_state_changed( pjsip_inv_session *inv,
122 pjsip_event *e);
123
124/* Callback to be called when dialog has forked: */
125static void call_on_forked(pjsip_inv_session *inv, pjsip_event *e);
126
127/* Callback to be called to handle incoming requests outside dialogs: */
128static pj_bool_t on_rx_request( pjsip_rx_data *rdata );
129
130
131
132
133/* This is a PJSIP module to be registered by application to handle
134 * incoming requests outside any dialogs/transactions. The main purpose
135 * here is to handle incoming INVITE request message, where we will
136 * create a dialog and INVITE session for it.
137 */
138static pjsip_module mod_simpleua =
139{
140 NULL, NULL, /* prev, next. */
141 { "mod-simpleua", 12 }, /* Name. */
142 -1, /* Id */
143 PJSIP_MOD_PRIORITY_APPLICATION, /* Priority */
144 NULL, /* load() */
145 NULL, /* start() */
146 NULL, /* stop() */
147 NULL, /* unload() */
148 &on_rx_request, /* on_rx_request() */
149 NULL, /* on_rx_response() */
150 NULL, /* on_tx_request. */
151 NULL, /* on_tx_response() */
152 NULL, /* on_tsx_state() */
153};
154
155
156/* Notification on incoming messages */
157static pj_bool_t logging_on_rx_msg(pjsip_rx_data *rdata)
158{
159 PJ_LOG(4,(THIS_FILE, "RX %d bytes %s from %s %s:%d:\n"
160 "%.*s\n"
161 "--end msg--",
162 rdata->msg_info.len,
163 pjsip_rx_data_get_info(rdata),
164 rdata->tp_info.transport->type_name,
165 rdata->pkt_info.src_name,
166 rdata->pkt_info.src_port,
167 (int)rdata->msg_info.len,
168 rdata->msg_info.msg_buf));
169
170 /* Always return false, otherwise messages will not get processed! */
171 return PJ_FALSE;
172}
173
174/* Notification on outgoing messages */
175static pj_status_t logging_on_tx_msg(pjsip_tx_data *tdata)
176{
177
178 /* Important note:
179 * tp_info field is only valid after outgoing messages has passed
180 * transport layer. So don't try to access tp_info when the module
181 * has lower priority than transport layer.
182 */
183
184 PJ_LOG(4,(THIS_FILE, "TX %d bytes %s to %s %s:%d:\n"
185 "%.*s\n"
186 "--end msg--",
187 (tdata->buf.cur - tdata->buf.start),
188 pjsip_tx_data_get_info(tdata),
189 tdata->tp_info.transport->type_name,
190 tdata->tp_info.dst_name,
191 tdata->tp_info.dst_port,
192 (int)(tdata->buf.cur - tdata->buf.start),
193 tdata->buf.start));
194
195 /* Always return success, otherwise message will not get sent! */
196 return PJ_SUCCESS;
197}
198
199/* The module instance. */
200static pjsip_module msg_logger =
201{
202 NULL, NULL, /* prev, next. */
203 { "mod-msg-log", 13 }, /* Name. */
204 -1, /* Id */
205 PJSIP_MOD_PRIORITY_TRANSPORT_LAYER-1,/* Priority */
206 NULL, /* load() */
207 NULL, /* start() */
208 NULL, /* stop() */
209 NULL, /* unload() */
210 &logging_on_rx_msg, /* on_rx_request() */
211 &logging_on_rx_msg, /* on_rx_response() */
212 &logging_on_tx_msg, /* on_tx_request. */
213 &logging_on_tx_msg, /* on_tx_response() */
214 NULL, /* on_tsx_state() */
215
216};
217
218
219/*
220 * main()
221 *
222 * If called with argument, treat argument as SIP URL to be called.
223 * Otherwise wait for incoming calls.
224 */
225int main(int argc, char *argv[])
226{
227 pj_pool_t *pool = NULL;
228 pj_status_t status;
229 unsigned i;
230
231 /* Must init PJLIB first: */
232 status = pj_init();
233 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
234
235 pj_log_set_level(5);
236
237 /* Then init PJLIB-UTIL: */
238 status = pjlib_util_init();
239 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
240
241
242 /* Must create a pool factory before we can allocate any memory. */
243 pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);
244
245
246 /* Create global endpoint: */
247 {
248 const pj_str_t *hostname;
249 const char *endpt_name;
250
251 /* Endpoint MUST be assigned a globally unique name.
252 * The name will be used as the hostname in Warning header.
253 */
254
255 /* For this implementation, we'll use hostname for simplicity */
256 hostname = pj_gethostname();
257 endpt_name = hostname->ptr;
258
259 /* Create the endpoint: */
260
261 status = pjsip_endpt_create(&cp.factory, endpt_name,
262 &g_endpt);
263 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
264 }
265
266
267 /*
268 * Add UDP transport, with hard-coded port
269 * Alternatively, application can use pjsip_udp_transport_attach() to
270 * start UDP transport, if it already has an UDP socket (e.g. after it
271 * resolves the address with STUN).
272 */
273 {
274 pj_sockaddr addr;
275
276 pj_sockaddr_init(AF, &addr, NULL, (pj_uint16_t)SIP_PORT);
277
278 if (AF == pj_AF_INET()) {
279 status = pjsip_udp_transport_start( g_endpt, &addr.ipv4, NULL,
280 1, NULL);
281 } else if (AF == pj_AF_INET6()) {
282 status = pjsip_udp_transport_start6(g_endpt, &addr.ipv6, NULL,
283 1, NULL);
284 } else {
285 status = PJ_EAFNOTSUP;
286 }
287
288 if (status != PJ_SUCCESS) {
289 app_perror(THIS_FILE, "Unable to start UDP transport", status);
290 return 1;
291 }
292 }
293
294
295 /*
296 * Init transaction layer.
297 * This will create/initialize transaction hash tables etc.
298 */
299 status = pjsip_tsx_layer_init_module(g_endpt);
300 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
301
302
303 /*
304 * Initialize UA layer module.
305 * This will create/initialize dialog hash tables etc.
306 */
307 status = pjsip_ua_init_module( g_endpt, NULL );
308 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
309
310
311 /*
312 * Init invite session module.
313 * The invite session module initialization takes additional argument,
314 * i.e. a structure containing callbacks to be called on specific
315 * occurence of events.
316 *
317 * The on_state_changed and on_new_session callbacks are mandatory.
318 * Application must supply the callback function.
319 *
320 * We use on_media_update() callback in this application to start
321 * media transmission.
322 */
323 {
324 pjsip_inv_callback inv_cb;
325
326 /* Init the callback for INVITE session: */
327 pj_bzero(&inv_cb, sizeof(inv_cb));
328 inv_cb.on_state_changed = &call_on_state_changed;
329 inv_cb.on_new_session = &call_on_forked;
330 inv_cb.on_media_update = &call_on_media_update;
331
332 /* Initialize invite session module: */
333 status = pjsip_inv_usage_init(g_endpt, &inv_cb);
334 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
335 }
336
337 /* Initialize 100rel support */
338 status = pjsip_100rel_init_module(g_endpt);
339 PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
340
341 /*
342 * Register our module to receive incoming requests.
343 */
344 status = pjsip_endpt_register_module( g_endpt, &mod_simpleua);
345 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
346
347 /*
348 * Register message logger module.
349 */
350 status = pjsip_endpt_register_module( g_endpt, &msg_logger);
351 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
352
353
354 /*
355 * Initialize media endpoint.
356 * This will implicitly initialize PJMEDIA too.
357 */
358#if PJ_HAS_THREADS
359 status = pjmedia_endpt_create(&cp.factory, NULL, 1, &g_med_endpt);
360#else
361 status = pjmedia_endpt_create(&cp.factory,
362 pjsip_endpt_get_ioqueue(g_endpt),
363 0, &g_med_endpt);
364#endif
365 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
366
367 /*
368 * Add PCMA/PCMU codec to the media endpoint.
369 */
370#if defined(PJMEDIA_HAS_G711_CODEC) && PJMEDIA_HAS_G711_CODEC!=0
371 status = pjmedia_codec_g711_init(g_med_endpt);
372 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
373#endif
374
375
376#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
377 /* Init video subsystem */
378 pool = pjmedia_endpt_create_pool(g_med_endpt, "Video subsystem", 512, 512);
379 status = pjmedia_video_format_mgr_create(pool, 64, 0, NULL);
380 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
381 status = pjmedia_converter_mgr_create(pool, NULL);
382 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
383 status = pjmedia_vid_codec_mgr_create(pool, NULL);
384 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
385 status = pjmedia_vid_dev_subsys_init(&cp.factory);
386 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
387
388# if defined(PJMEDIA_HAS_FFMPEG_VID_CODEC) && PJMEDIA_HAS_FFMPEG_VID_CODEC!=0
389 /* Init ffmpeg video codecs */
390 status = pjmedia_codec_ffmpeg_vid_init(NULL, &cp.factory);
391 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
392# endif /* PJMEDIA_HAS_FFMPEG_VID_CODEC */
393
394#endif /* PJMEDIA_HAS_VIDEO */
395
396 /*
397 * Create media transport used to send/receive RTP/RTCP socket.
398 * One media transport is needed for each call. Application may
399 * opt to re-use the same media transport for subsequent calls.
400 */
401 for (i = 0; i < PJ_ARRAY_SIZE(g_med_transport); ++i) {
402 status = pjmedia_transport_udp_create3(g_med_endpt, AF, NULL, NULL,
403 RTP_PORT + i*2, 0,
404 &g_med_transport[i]);
405 if (status != PJ_SUCCESS) {
406 app_perror(THIS_FILE, "Unable to create media transport", status);
407 return 1;
408 }
409
410 /*
411 * Get socket info (address, port) of the media transport. We will
412 * need this info to create SDP (i.e. the address and port info in
413 * the SDP).
414 */
415 pjmedia_transport_info_init(&g_med_tpinfo[i]);
416 pjmedia_transport_get_info(g_med_transport[i], &g_med_tpinfo[i]);
417
418 pj_memcpy(&g_sock_info[i], &g_med_tpinfo[i].sock_info,
419 sizeof(pjmedia_sock_info));
420 }
421
422 /*
423 * If URL is specified, then make call immediately.
424 */
425 if (argc > 1) {
426 pj_sockaddr hostaddr;
427 char hostip[PJ_INET6_ADDRSTRLEN+2];
428 char temp[80];
429 pj_str_t dst_uri = pj_str(argv[1]);
430 pj_str_t local_uri;
431 pjsip_dialog *dlg;
432 pjmedia_sdp_session *local_sdp;
433 pjsip_tx_data *tdata;
434
435 if (pj_gethostip(AF, &hostaddr) != PJ_SUCCESS) {
436 app_perror(THIS_FILE, "Unable to retrieve local host IP", status);
437 return 1;
438 }
439 pj_sockaddr_print(&hostaddr, hostip, sizeof(hostip), 2);
440
441 pj_ansi_sprintf(temp, "<sip:simpleuac@%s:%d>",
442 hostip, SIP_PORT);
443 local_uri = pj_str(temp);
444
445 /* Create UAC dialog */
446 status = pjsip_dlg_create_uac( pjsip_ua_instance(),
447 &local_uri, /* local URI */
448 &local_uri, /* local Contact */
449 &dst_uri, /* remote URI */
450 &dst_uri, /* remote target */
451 &dlg); /* dialog */
452 if (status != PJ_SUCCESS) {
453 app_perror(THIS_FILE, "Unable to create UAC dialog", status);
454 return 1;
455 }
456
457 /* If we expect the outgoing INVITE to be challenged, then we should
458 * put the credentials in the dialog here, with something like this:
459 *
460 {
461 pjsip_cred_info cred[1];
462
463 cred[0].realm = pj_str("sip.server.realm");
464 cred[0].scheme = pj_str("digest");
465 cred[0].username = pj_str("theuser");
466 cred[0].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
467 cred[0].data = pj_str("thepassword");
468
469 pjsip_auth_clt_set_credentials( &dlg->auth_sess, 1, cred);
470 }
471 *
472 */
473
474
475 /* Get the SDP body to be put in the outgoing INVITE, by asking
476 * media endpoint to create one for us.
477 */
478 status = pjmedia_endpt_create_sdp( g_med_endpt, /* the media endpt */
479 dlg->pool, /* pool. */
480 MAX_MEDIA_CNT, /* # of streams */
481 g_sock_info, /* RTP sock info */
482 &local_sdp); /* the SDP result */
483 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
484
485
486
487 /* Create the INVITE session, and pass the SDP returned earlier
488 * as the session's initial capability.
489 */
490 status = pjsip_inv_create_uac( dlg, local_sdp, 0, &g_inv);
491 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
492
493 /* If we want the initial INVITE to travel to specific SIP proxies,
494 * then we should put the initial dialog's route set here. The final
495 * route set will be updated once a dialog has been established.
496 * To set the dialog's initial route set, we do it with something
497 * like this:
498 *
499 {
500 pjsip_route_hdr route_set;
501 pjsip_route_hdr *route;
502 const pj_str_t hname = { "Route", 5 };
503 char *uri = "sip:proxy.server;lr";
504
505 pj_list_init(&route_set);
506
507 route = pjsip_parse_hdr( dlg->pool, &hname,
508 uri, strlen(uri),
509 NULL);
510 PJ_ASSERT_RETURN(route != NULL, 1);
511 pj_list_push_back(&route_set, route);
512
513 pjsip_dlg_set_route_set(dlg, &route_set);
514 }
515 *
516 * Note that Route URI SHOULD have an ";lr" parameter!
517 */
518
519 /* Create initial INVITE request.
520 * This INVITE request will contain a perfectly good request and
521 * an SDP body as well.
522 */
523 status = pjsip_inv_invite(g_inv, &tdata);
524 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
525
526
527
528 /* Send initial INVITE request.
529 * From now on, the invite session's state will be reported to us
530 * via the invite session callbacks.
531 */
532 status = pjsip_inv_send_msg(g_inv, tdata);
533 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
534
535
536 } else {
537
538 /* No URL to make call to */
539
540 PJ_LOG(3,(THIS_FILE, "Ready to accept incoming calls..."));
541 }
542
543
544 /* Loop until one call is completed */
545 for (;!g_complete;) {
546 pj_time_val timeout = {0, 10};
547 pjsip_endpt_handle_events(g_endpt, &timeout);
548 }
549
550 /* On exit, dump current memory usage: */
551 dump_pool_usage(THIS_FILE, &cp);
552
553 /* Destroy audio ports. Destroy the audio port first
554 * before the stream since the audio port has threads
555 * that get/put frames to the stream.
556 */
557 if (g_snd_port)
558 pjmedia_snd_port_destroy(g_snd_port);
559
560#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
561 /* Destroy video ports */
562 if (g_vid_capturer)
563 pjmedia_vid_port_destroy(g_vid_capturer);
564 if (g_vid_renderer)
565 pjmedia_vid_port_destroy(g_vid_renderer);
566#endif
567
568 /* Destroy streams */
569 if (g_med_stream)
570 pjmedia_stream_destroy(g_med_stream);
571#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
572 if (g_med_vstream)
573 pjmedia_vid_stream_destroy(g_med_vstream);
574
575 /* Deinit ffmpeg codec */
576# if defined(PJMEDIA_HAS_FFMPEG_VID_CODEC) && PJMEDIA_HAS_FFMPEG_VID_CODEC!=0
577 pjmedia_codec_ffmpeg_vid_deinit();
578# endif
579
580#endif
581
582 /* Destroy media transports */
583 for (i = 0; i < MAX_MEDIA_CNT; ++i) {
584 if (g_med_transport[i])
585 pjmedia_transport_close(g_med_transport[i]);
586 }
587
588 /* Deinit pjmedia endpoint */
589 if (g_med_endpt)
590 pjmedia_endpt_destroy(g_med_endpt);
591
592 /* Deinit pjsip endpoint */
593 if (g_endpt)
594 pjsip_endpt_destroy(g_endpt);
595
596 /* Release pool */
597 if (pool)
598 pj_pool_release(pool);
599
600 return 0;
601}
602
603
604
605/*
606 * Callback when INVITE session state has changed.
607 * This callback is registered when the invite session module is initialized.
608 * We mostly want to know when the invite session has been disconnected,
609 * so that we can quit the application.
610 */
611static void call_on_state_changed( pjsip_inv_session *inv,
612 pjsip_event *e)
613{
614 PJ_UNUSED_ARG(e);
615
616 if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {
617
618 PJ_LOG(3,(THIS_FILE, "Call DISCONNECTED [reason=%d (%s)]",
619 inv->cause,
620 pjsip_get_status_text(inv->cause)->ptr));
621
622 PJ_LOG(3,(THIS_FILE, "One call completed, application quitting..."));
623 g_complete = 1;
624
625 } else {
626
627 PJ_LOG(3,(THIS_FILE, "Call state changed to %s",
628 pjsip_inv_state_name(inv->state)));
629
630 }
631}
632
633
634/* This callback is called when dialog has forked. */
635static void call_on_forked(pjsip_inv_session *inv, pjsip_event *e)
636{
637 /* To be done... */
638 PJ_UNUSED_ARG(inv);
639 PJ_UNUSED_ARG(e);
640}
641
642
643/*
644 * Callback when incoming requests outside any transactions and any
645 * dialogs are received. We're only interested to hande incoming INVITE
646 * request, and we'll reject any other requests with 500 response.
647 */
648static pj_bool_t on_rx_request( pjsip_rx_data *rdata )
649{
650 pj_sockaddr hostaddr;
651 char temp[80], hostip[PJ_INET6_ADDRSTRLEN];
652 pj_str_t local_uri;
653 pjsip_dialog *dlg;
654 pjmedia_sdp_session *local_sdp;
655 pjsip_tx_data *tdata;
656 unsigned options = 0;
657 pj_status_t status;
658
659
660 /*
661 * Respond (statelessly) any non-INVITE requests with 500
662 */
663 if (rdata->msg_info.msg->line.req.method.id != PJSIP_INVITE_METHOD) {
664
665 if (rdata->msg_info.msg->line.req.method.id != PJSIP_ACK_METHOD) {
666 pj_str_t reason = pj_str("Simple UA unable to handle "
667 "this request");
668
669 pjsip_endpt_respond_stateless( g_endpt, rdata,
670 500, &reason,
671 NULL, NULL);
672 }
673 return PJ_TRUE;
674 }
675
676
677 /*
678 * Reject INVITE if we already have an INVITE session in progress.
679 */
680 if (g_inv) {
681
682 pj_str_t reason = pj_str("Another call is in progress");
683
684 pjsip_endpt_respond_stateless( g_endpt, rdata,
685 500, &reason,
686 NULL, NULL);
687 return PJ_TRUE;
688
689 }
690
691 /* Verify that we can handle the request. */
692 status = pjsip_inv_verify_request(rdata, &options, NULL, NULL,
693 g_endpt, NULL);
694 if (status != PJ_SUCCESS) {
695
696 pj_str_t reason = pj_str("Sorry Simple UA can not handle this INVITE");
697
698 pjsip_endpt_respond_stateless( g_endpt, rdata,
699 500, &reason,
700 NULL, NULL);
701 return PJ_TRUE;
702 }
703
704 /*
705 * Generate Contact URI
706 */
707 if (pj_gethostip(AF, &hostaddr) != PJ_SUCCESS) {
708 app_perror(THIS_FILE, "Unable to retrieve local host IP", status);
709 return PJ_TRUE;
710 }
711 pj_sockaddr_print(&hostaddr, hostip, sizeof(hostip), 2);
712
713 pj_ansi_sprintf(temp, "<sip:simpleuas@%s:%d>",
714 hostip, SIP_PORT);
715 local_uri = pj_str(temp);
716
717 /*
718 * Create UAS dialog.
719 */
720 status = pjsip_dlg_create_uas( pjsip_ua_instance(),
721 rdata,
722 &local_uri, /* contact */
723 &dlg);
724 if (status != PJ_SUCCESS) {
725 pjsip_endpt_respond_stateless(g_endpt, rdata, 500, NULL,
726 NULL, NULL);
727 return PJ_TRUE;
728 }
729
730 /*
731 * Get media capability from media endpoint:
732 */
733
734 status = pjmedia_endpt_create_sdp( g_med_endpt, rdata->tp_info.pool,
735 MAX_MEDIA_CNT, g_sock_info, &local_sdp);
736 PJ_ASSERT_RETURN(status == PJ_SUCCESS, PJ_TRUE);
737
738
739 /*
740 * Create invite session, and pass both the UAS dialog and the SDP
741 * capability to the session.
742 */
743 status = pjsip_inv_create_uas( dlg, rdata, local_sdp, 0, &g_inv);
744 PJ_ASSERT_RETURN(status == PJ_SUCCESS, PJ_TRUE);
745
746
747 /*
748 * Initially send 180 response.
749 *
750 * The very first response to an INVITE must be created with
751 * pjsip_inv_initial_answer(). Subsequent responses to the same
752 * transaction MUST use pjsip_inv_answer().
753 */
754 status = pjsip_inv_initial_answer(g_inv, rdata,
755 180,
756 NULL, NULL, &tdata);
757 PJ_ASSERT_RETURN(status == PJ_SUCCESS, PJ_TRUE);
758
759
760 /* Send the 180 response. */
761 status = pjsip_inv_send_msg(g_inv, tdata);
762 PJ_ASSERT_RETURN(status == PJ_SUCCESS, PJ_TRUE);
763
764
765 /*
766 * Now create 200 response.
767 */
768 status = pjsip_inv_answer( g_inv,
769 200, NULL, /* st_code and st_text */
770 NULL, /* SDP already specified */
771 &tdata);
772 PJ_ASSERT_RETURN(status == PJ_SUCCESS, PJ_TRUE);
773
774 /*
775 * Send the 200 response.
776 */
777 status = pjsip_inv_send_msg(g_inv, tdata);
778 PJ_ASSERT_RETURN(status == PJ_SUCCESS, PJ_TRUE);
779
780
781 /* Done.
782 * When the call is disconnected, it will be reported via the callback.
783 */
784
785 return PJ_TRUE;
786}
787
788
789
790/*
791 * Callback when SDP negotiation has completed.
792 * We are interested with this callback because we want to start media
793 * as soon as SDP negotiation is completed.
794 */
795static void call_on_media_update( pjsip_inv_session *inv,
796 pj_status_t status)
797{
798 pjmedia_stream_info stream_info;
799 const pjmedia_sdp_session *local_sdp;
800 const pjmedia_sdp_session *remote_sdp;
801 pjmedia_port *media_port;
802
803 if (status != PJ_SUCCESS) {
804
805 app_perror(THIS_FILE, "SDP negotiation has failed", status);
806
807 /* Here we should disconnect call if we're not in the middle
808 * of initializing an UAS dialog and if this is not a re-INVITE.
809 */
810 return;
811 }
812
813 /* Get local and remote SDP.
814 * We need both SDPs to create a media session.
815 */
816 status = pjmedia_sdp_neg_get_active_local(inv->neg, &local_sdp);
817
818 status = pjmedia_sdp_neg_get_active_remote(inv->neg, &remote_sdp);
819
820
821 /* Create stream info based on the media audio SDP. */
822 status = pjmedia_stream_info_from_sdp(&stream_info, inv->dlg->pool,
823 g_med_endpt,
824 local_sdp, remote_sdp, 0);
825 if (status != PJ_SUCCESS) {
826 app_perror(THIS_FILE,"Unable to create audio stream info",status);
827 return;
828 }
829
830 /* If required, we can also change some settings in the stream info,
831 * (such as jitter buffer settings, codec settings, etc) before we
832 * create the stream.
833 */
834
835 /* Create new audio media stream, passing the stream info, and also the
836 * media socket that we created earlier.
837 */
838 status = pjmedia_stream_create(g_med_endpt, inv->dlg->pool, &stream_info,
839 g_med_transport[0], NULL, &g_med_stream);
840 if (status != PJ_SUCCESS) {
841 app_perror( THIS_FILE, "Unable to create audio stream", status);
842 return;
843 }
844
845 /* Start the audio stream */
846 status = pjmedia_stream_start(g_med_stream);
847 if (status != PJ_SUCCESS) {
848 app_perror( THIS_FILE, "Unable to start audio stream", status);
849 return;
850 }
851
852 /* Get the media port interface of the audio stream.
853 * Media port interface is basicly a struct containing get_frame() and
854 * put_frame() function. With this media port interface, we can attach
855 * the port interface to conference bridge, or directly to a sound
856 * player/recorder device.
857 */
858 pjmedia_stream_get_port(g_med_stream, &media_port);
859
860 /* Create sound port */
861 pjmedia_snd_port_create(inv->pool,
862 PJMEDIA_AUD_DEFAULT_CAPTURE_DEV,
863 PJMEDIA_AUD_DEFAULT_PLAYBACK_DEV,
864 PJMEDIA_PIA_SRATE(&media_port->info),/* clock rate */
865 PJMEDIA_PIA_CCNT(&media_port->info),/* channel count */
866 PJMEDIA_PIA_SPF(&media_port->info), /* samples per frame*/
867 PJMEDIA_PIA_BITS(&media_port->info),/* bits per sample */
868 0,
869 &g_snd_port);
870
871 if (status != PJ_SUCCESS) {
872 app_perror( THIS_FILE, "Unable to create sound port", status);
873 PJ_LOG(3,(THIS_FILE, "%d %d %d %d",
874 PJMEDIA_PIA_SRATE(&media_port->info),/* clock rate */
875 PJMEDIA_PIA_CCNT(&media_port->info),/* channel count */
876 PJMEDIA_PIA_SPF(&media_port->info), /* samples per frame*/
877 PJMEDIA_PIA_BITS(&media_port->info) /* bits per sample */
878 ));
879 return;
880 }
881
882 status = pjmedia_snd_port_connect(g_snd_port, media_port);
883
884
885 /* Get the media port interface of the second stream in the session,
886 * which is video stream. With this media port interface, we can attach
887 * the port directly to a renderer/capture video device.
888 */
889#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
890 if (local_sdp->media_count > 1) {
891 pjmedia_vid_stream_info vstream_info;
892 pjmedia_vid_port_param vport_param;
893
894 pjmedia_vid_port_param_default(&vport_param);
895
896 /* Create stream info based on the media video SDP. */
897 status = pjmedia_vid_stream_info_from_sdp(&vstream_info,
898 inv->dlg->pool, g_med_endpt,
899 local_sdp, remote_sdp, 1);
900 if (status != PJ_SUCCESS) {
901 app_perror(THIS_FILE,"Unable to create video stream info",status);
902 return;
903 }
904
905 /* If required, we can also change some settings in the stream info,
906 * (such as jitter buffer settings, codec settings, etc) before we
907 * create the video stream.
908 */
909
910 /* Create new video media stream, passing the stream info, and also the
911 * media socket that we created earlier.
912 */
913 status = pjmedia_vid_stream_create(g_med_endpt, NULL, &vstream_info,
914 g_med_transport[1], NULL,
915 &g_med_vstream);
916 if (status != PJ_SUCCESS) {
917 app_perror( THIS_FILE, "Unable to create video stream", status);
918 return;
919 }
920
921 /* Start the video stream */
922 status = pjmedia_vid_stream_start(g_med_vstream);
923 if (status != PJ_SUCCESS) {
924 app_perror( THIS_FILE, "Unable to start video stream", status);
925 return;
926 }
927
928 if (vstream_info.dir & PJMEDIA_DIR_DECODING) {
929 status = pjmedia_vid_dev_default_param(
930 inv->pool, PJMEDIA_VID_DEFAULT_RENDER_DEV,
931 &vport_param.vidparam);
932 if (status != PJ_SUCCESS) {
933 app_perror(THIS_FILE, "Unable to get default param of video "
934 "renderer device", status);
935 return;
936 }
937
938 /* Get video stream port for decoding direction */
939 pjmedia_vid_stream_get_port(g_med_vstream, PJMEDIA_DIR_DECODING,
940 &media_port);
941
942 /* Set format */
943 pjmedia_format_copy(&vport_param.vidparam.fmt,
944 &media_port->info.fmt);
945 vport_param.vidparam.dir = PJMEDIA_DIR_RENDER;
946 vport_param.active = PJ_TRUE;
947
948 /* Create renderer */
949 status = pjmedia_vid_port_create(inv->pool, &vport_param,
950 &g_vid_renderer);
951 if (status != PJ_SUCCESS) {
952 app_perror(THIS_FILE, "Unable to create video renderer device",
953 status);
954 return;
955 }
956
957 /* Connect renderer to media_port */
958 status = pjmedia_vid_port_connect(g_vid_renderer, media_port,
959 PJ_FALSE);
960 if (status != PJ_SUCCESS) {
961 app_perror(THIS_FILE, "Unable to connect renderer to stream",
962 status);
963 return;
964 }
965 }
966
967 /* Create capturer */
968 if (vstream_info.dir & PJMEDIA_DIR_ENCODING) {
969 status = pjmedia_vid_dev_default_param(
970 inv->pool, PJMEDIA_VID_DEFAULT_CAPTURE_DEV,
971 &vport_param.vidparam);
972 if (status != PJ_SUCCESS) {
973 app_perror(THIS_FILE, "Unable to get default param of video "
974 "capture device", status);
975 return;
976 }
977
978 /* Get video stream port for decoding direction */
979 pjmedia_vid_stream_get_port(g_med_vstream, PJMEDIA_DIR_ENCODING,
980 &media_port);
981
982 /* Get capturer format from stream info */
983 pjmedia_format_copy(&vport_param.vidparam.fmt,
984 &media_port->info.fmt);
985 vport_param.vidparam.dir = PJMEDIA_DIR_CAPTURE;
986 vport_param.active = PJ_TRUE;
987
988 /* Create capturer */
989 status = pjmedia_vid_port_create(inv->pool, &vport_param,
990 &g_vid_capturer);
991 if (status != PJ_SUCCESS) {
992 app_perror(THIS_FILE, "Unable to create video capture device",
993 status);
994 return;
995 }
996
997 /* Connect capturer to media_port */
998 status = pjmedia_vid_port_connect(g_vid_capturer, media_port,
999 PJ_FALSE);
1000 if (status != PJ_SUCCESS) {
1001 app_perror(THIS_FILE, "Unable to connect capturer to stream",
1002 status);
1003 return;
1004 }
1005 }
1006
1007 /* Start streaming */
1008 if (g_vid_renderer) {
1009 status = pjmedia_vid_port_start(g_vid_renderer);
1010 if (status != PJ_SUCCESS) {
1011 app_perror(THIS_FILE, "Unable to start video renderer",
1012 status);
1013 return;
1014 }
1015 }
1016 if (g_vid_capturer) {
1017 status = pjmedia_vid_port_start(g_vid_capturer);
1018 if (status != PJ_SUCCESS) {
1019 app_perror(THIS_FILE, "Unable to start video capturer",
1020 status);
1021 return;
1022 }
1023 }
1024 }
1025#endif /* PJMEDIA_HAS_VIDEO */
1026
1027 /* Done with media. */
1028}
1029
1030