~ubuntu-branches/ubuntu/trusty/sflphone/trusty

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.1.0/pjsip-apps/src/samples/simpleua.c

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2014-01-28 18:23:36 UTC
  • mfrom: (4.3.4 sid)
  • Revision ID: package-import@ubuntu.com-20140128182336-jrsv0k9u6cawc068
Tags: 1.3.0-1
* New upstream release 
  - Fixes "New Upstream Release" (Closes: #735846)
  - Fixes "Ringtone does not stop" (Closes: #727164)
  - Fixes "[sflphone-kde] crash on startup" (Closes: #718178)
  - Fixes "sflphone GUI crashes when call is hung up" (Closes: #736583)
* Build-Depends: ensure GnuTLS 2.6
  - libucommon-dev (>= 6.0.7-1.1), libccrtp-dev (>= 2.0.6-3)
  - Fixes "FTBFS Build-Depends libgnutls{26,28}-dev" (Closes: #722040)
* Fix "boost 1.49 is going away" unversioned Build-Depends: (Closes: #736746)
* Add Build-Depends: libsndfile-dev, nepomuk-core-dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $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
 
 
88
static pj_bool_t             g_complete;    /* Quit flag.               */
 
89
static pjsip_endpoint       *g_endpt;       /* SIP endpoint.            */
 
90
static pj_caching_pool       cp;            /* Global pool factory.     */
 
91
 
 
92
static pjmedia_endpt        *g_med_endpt;   /* Media endpoint.          */
 
93
 
 
94
static pjmedia_transport_info g_med_tpinfo[MAX_MEDIA_CNT]; 
 
95
                                            /* Socket info for media    */
 
96
static pjmedia_transport    *g_med_transport[MAX_MEDIA_CNT];
 
97
                                            /* Media stream transport   */
 
98
static pjmedia_sock_info     g_sock_info[MAX_MEDIA_CNT];  
 
99
                                            /* Socket info array        */
 
100
 
 
101
/* Call variables: */
 
102
static pjsip_inv_session    *g_inv;         /* Current invite session.  */
 
103
static pjmedia_stream       *g_med_stream;  /* Call's audio stream.     */
 
104
static pjmedia_snd_port     *g_snd_port;    /* Sound device.            */
 
105
 
 
106
#if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0)
 
107
static pjmedia_vid_stream   *g_med_vstream; /* Call's video stream.     */
 
108
static pjmedia_vid_port     *g_vid_capturer;/* Call's video capturer.   */
 
109
static 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: */
 
117
static 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: */
 
121
static void call_on_state_changed( pjsip_inv_session *inv, 
 
122
                                   pjsip_event *e);
 
123
 
 
124
/* Callback to be called when dialog has forked: */
 
125
static void call_on_forked(pjsip_inv_session *inv, pjsip_event *e);
 
126
 
 
127
/* Callback to be called to handle incoming requests outside dialogs: */
 
128
static 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
 */
 
138
static 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 */
 
157
static 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 */
 
175
static 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. */
 
200
static 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
 */
 
225
int 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
 */
 
611
static 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. */
 
635
static 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
 */
 
648
static 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
 */
 
795
static 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