sip-lab 1.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +38 -0
  2. package/a.js +280 -0
  3. package/binding.gyp +101 -0
  4. package/devjournal +435 -0
  5. package/index.js +68 -0
  6. package/install.sh +32 -0
  7. package/package.json +30 -0
  8. package/samples/late_negotiation.js +278 -0
  9. package/samples/simple.js +280 -0
  10. package/samples/sip_cancel.js +111 -0
  11. package/src/Makefile +42 -0
  12. package/src/README +3 -0
  13. package/src/addon.cpp +1418 -0
  14. package/src/event_templates.cpp +55 -0
  15. package/src/event_templates.hpp +27 -0
  16. package/src/idmanager.cpp +76 -0
  17. package/src/idmanager.hpp +26 -0
  18. package/src/log.cpp +18 -0
  19. package/src/log.hpp +15 -0
  20. package/src/packetdumper.cpp +234 -0
  21. package/src/packetdumper.hpp +67 -0
  22. package/src/pjmedia/Makefile +37 -0
  23. package/src/pjmedia/devjournal +26 -0
  24. package/src/pjmedia/include/chainlink/README +3 -0
  25. package/src/pjmedia/include/chainlink/chainlink.h +11 -0
  26. package/src/pjmedia/include/chainlink/chainlink_dtmfdet.h +56 -0
  27. package/src/pjmedia/include/chainlink/chainlink_tonegen.h +178 -0
  28. package/src/pjmedia/include/chainlink/chainlink_wav_port.h +231 -0
  29. package/src/pjmedia/include/chainlink/chainlink_wire_port.h +50 -0
  30. package/src/pjmedia/include/pjmedia/README +3 -0
  31. package/src/pjmedia/include/pjmedia/dtmfdet.h +74 -0
  32. package/src/pjmedia/src/chainlink/chainlink_dtmfdet.c +125 -0
  33. package/src/pjmedia/src/chainlink/chainlink_tonegen.c +901 -0
  34. package/src/pjmedia/src/chainlink/chainlink_wav_player.c +688 -0
  35. package/src/pjmedia/src/chainlink/chainlink_wav_writer.c +442 -0
  36. package/src/pjmedia/src/chainlink/chainlink_wire_port.c +93 -0
  37. package/src/pjmedia/src/pjmedia/dtmfdet.c +129 -0
  38. package/src/pjmedia/src/pjmedia/simpleua_dtmfdet.c +753 -0
  39. package/src/pjmedia/src/pjmedia/tonegen_dtmfdet.c +263 -0
  40. package/src/sip.cpp +4891 -0
  41. package/src/sip.hpp +64 -0
@@ -0,0 +1,753 @@
1
+ /* $Id: simpleua.c 2394 2008-12-23 17:27:53Z bennylp $ */
2
+ /*
3
+ * Copyright (C) 2008-2009 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
+ #define SIP_PORT 5060 /* Listening SIP port */
74
+ #define RTP_PORT 4000 /* RTP port */
75
+
76
+ /*
77
+ * Static variables.
78
+ */
79
+
80
+ static pj_bool_t g_complete; /* Quit flag. */
81
+ static pjsip_endpoint *g_endpt; /* SIP endpoint. */
82
+ static pj_caching_pool cp; /* Global pool factory. */
83
+
84
+ static pjmedia_endpt *g_med_endpt; /* Media endpoint. */
85
+ static pjmedia_transport_info g_med_tpinfo; /* Socket info for media */
86
+ static pjmedia_transport *g_med_transport;/* Media stream transport */
87
+
88
+ /* Call variables: */
89
+ static pjsip_inv_session *g_inv; /* Current invite session. */
90
+ static pjmedia_session *g_med_session; /* Call's media session. */
91
+ static pjmedia_snd_port *g_snd_player; /* Call's sound player */
92
+ static pjmedia_snd_port *g_snd_rec; /* Call's sound recorder. */
93
+
94
+ static pjmedia_port *g_master_port;
95
+ static pjmedia_port *g_dtmfdet;
96
+
97
+
98
+ /*
99
+ * Prototypes:
100
+ */
101
+
102
+ /* Callback to be called when SDP negotiation is done in the call: */
103
+ static void call_on_media_update( pjsip_inv_session *inv,
104
+ pj_status_t status);
105
+
106
+ /* Callback to be called when invite session's state has changed: */
107
+ static void call_on_state_changed( pjsip_inv_session *inv,
108
+ pjsip_event *e);
109
+
110
+ /* Callback to be called when dialog has forked: */
111
+ static void call_on_forked(pjsip_inv_session *inv, pjsip_event *e);
112
+
113
+ /* Callback to be called to handle incoming requests outside dialogs: */
114
+ static pj_bool_t on_rx_request( pjsip_rx_data *rdata );
115
+
116
+
117
+
118
+
119
+ /* This is a PJSIP module to be registered by application to handle
120
+ * incoming requests outside any dialogs/transactions. The main purpose
121
+ * here is to handle incoming INVITE request message, where we will
122
+ * create a dialog and INVITE session for it.
123
+ */
124
+ static pjsip_module mod_simpleua =
125
+ {
126
+ NULL, NULL, /* prev, next. */
127
+ { "mod-simpleua", 12 }, /* Name. */
128
+ -1, /* Id */
129
+ PJSIP_MOD_PRIORITY_APPLICATION, /* Priority */
130
+ NULL, /* load() */
131
+ NULL, /* start() */
132
+ NULL, /* stop() */
133
+ NULL, /* unload() */
134
+ &on_rx_request, /* on_rx_request() */
135
+ NULL, /* on_rx_response() */
136
+ NULL, /* on_tx_request. */
137
+ NULL, /* on_tx_response() */
138
+ NULL, /* on_tsx_state() */
139
+ };
140
+
141
+
142
+
143
+ /*
144
+ * main()
145
+ *
146
+ * If called with argument, treat argument as SIP URL to be called.
147
+ * Otherwise wait for incoming calls.
148
+ */
149
+ int main(int argc, char *argv[])
150
+ {
151
+ pj_status_t status;
152
+
153
+ /* Must init PJLIB first: */
154
+ status = pj_init();
155
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
156
+
157
+
158
+ /* Then init PJLIB-UTIL: */
159
+ status = pjlib_util_init();
160
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
161
+
162
+
163
+ /* Must create a pool factory before we can allocate any memory. */
164
+ pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);
165
+
166
+
167
+ /* Create global endpoint: */
168
+ {
169
+ const pj_str_t *hostname;
170
+ const char *endpt_name;
171
+
172
+ /* Endpoint MUST be assigned a globally unique name.
173
+ * The name will be used as the hostname in Warning header.
174
+ */
175
+
176
+ /* For this implementation, we'll use hostname for simplicity */
177
+ hostname = pj_gethostname();
178
+ endpt_name = hostname->ptr;
179
+
180
+ /* Create the endpoint: */
181
+
182
+ status = pjsip_endpt_create(&cp.factory, endpt_name,
183
+ &g_endpt);
184
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
185
+ }
186
+
187
+
188
+ /*
189
+ * Add UDP transport, with hard-coded port
190
+ * Alternatively, application can use pjsip_udp_transport_attach() to
191
+ * start UDP transport, if it already has an UDP socket (e.g. after it
192
+ * resolves the address with STUN).
193
+ */
194
+ {
195
+ pj_sockaddr addr;
196
+
197
+ pj_sockaddr_init(AF, &addr, NULL, (pj_uint16_t)SIP_PORT);
198
+
199
+ if (AF == pj_AF_INET()) {
200
+ status = pjsip_udp_transport_start( g_endpt, &addr.ipv4, NULL,
201
+ 1, NULL);
202
+ } else if (AF == pj_AF_INET6()) {
203
+ status = pjsip_udp_transport_start6(g_endpt, &addr.ipv6, NULL,
204
+ 1, NULL);
205
+ } else {
206
+ status = PJ_EAFNOTSUP;
207
+ }
208
+
209
+ if (status != PJ_SUCCESS) {
210
+ app_perror(THIS_FILE, "Unable to start UDP transport", status);
211
+ return 1;
212
+ }
213
+ }
214
+
215
+
216
+ /*
217
+ * Init transaction layer.
218
+ * This will create/initialize transaction hash tables etc.
219
+ */
220
+ status = pjsip_tsx_layer_init_module(g_endpt);
221
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
222
+
223
+
224
+ /*
225
+ * Initialize UA layer module.
226
+ * This will create/initialize dialog hash tables etc.
227
+ */
228
+ status = pjsip_ua_init_module( g_endpt, NULL );
229
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
230
+
231
+
232
+ /*
233
+ * Init invite session module.
234
+ * The invite session module initialization takes additional argument,
235
+ * i.e. a structure containing callbacks to be called on specific
236
+ * occurence of events.
237
+ *
238
+ * The on_state_changed and on_new_session callbacks are mandatory.
239
+ * Application must supply the callback function.
240
+ *
241
+ * We use on_media_update() callback in this application to start
242
+ * media transmission.
243
+ */
244
+ {
245
+ pjsip_inv_callback inv_cb;
246
+
247
+ /* Init the callback for INVITE session: */
248
+ pj_bzero(&inv_cb, sizeof(inv_cb));
249
+ inv_cb.on_state_changed = &call_on_state_changed;
250
+ inv_cb.on_new_session = &call_on_forked;
251
+ inv_cb.on_media_update = &call_on_media_update;
252
+
253
+ /* Initialize invite session module: */
254
+ status = pjsip_inv_usage_init(g_endpt, &inv_cb);
255
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
256
+ }
257
+
258
+ /* Initialize 100rel support */
259
+ status = pjsip_100rel_init_module(g_endpt);
260
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
261
+
262
+ /*
263
+ * Register our module to receive incoming requests.
264
+ */
265
+ status = pjsip_endpt_register_module( g_endpt, &mod_simpleua);
266
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
267
+
268
+
269
+ /*
270
+ * Initialize media endpoint.
271
+ * This will implicitly initialize PJMEDIA too.
272
+ */
273
+ #if PJ_HAS_THREADS
274
+ status = pjmedia_endpt_create(&cp.factory, NULL, 1, &g_med_endpt);
275
+ #else
276
+ status = pjmedia_endpt_create(&cp.factory,
277
+ pjsip_endpt_get_ioqueue(g_endpt),
278
+ 0, &g_med_endpt);
279
+ #endif
280
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
281
+
282
+ /*
283
+ * Add PCMA/PCMU codec to the media endpoint.
284
+ */
285
+ #if defined(PJMEDIA_HAS_G711_CODEC) && PJMEDIA_HAS_G711_CODEC!=0
286
+ status = pjmedia_codec_g711_init(g_med_endpt);
287
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
288
+ #endif
289
+
290
+
291
+ /*
292
+ * Create media transport used to send/receive RTP/RTCP socket.
293
+ * One media transport is needed for each call. Application may
294
+ * opt to re-use the same media transport for subsequent calls.
295
+ */
296
+ status = pjmedia_transport_udp_create3(g_med_endpt, AF, NULL, NULL,
297
+ RTP_PORT, 0, &g_med_transport);
298
+ if (status != PJ_SUCCESS) {
299
+ app_perror(THIS_FILE, "Unable to create media transport", status);
300
+ return 1;
301
+ }
302
+
303
+ /*
304
+ * Get socket info (address, port) of the media transport. We will
305
+ * need this info to create SDP (i.e. the address and port info in
306
+ * the SDP).
307
+ */
308
+ pjmedia_transport_info_init(&g_med_tpinfo);
309
+ pjmedia_transport_get_info(g_med_transport, &g_med_tpinfo);
310
+
311
+
312
+ /*
313
+ * If URL is specified, then make call immediately.
314
+ */
315
+ if (argc > 1) {
316
+ pj_sockaddr hostaddr;
317
+ char hostip[PJ_INET6_ADDRSTRLEN+2];
318
+ char temp[80];
319
+ pj_str_t dst_uri = pj_str(argv[1]);
320
+ pj_str_t local_uri;
321
+ pjsip_dialog *dlg;
322
+ pjmedia_sdp_session *local_sdp;
323
+ pjsip_tx_data *tdata;
324
+
325
+ if (pj_gethostip(AF, &hostaddr) != PJ_SUCCESS) {
326
+ app_perror(THIS_FILE, "Unable to retrieve local host IP", status);
327
+ return 1;
328
+ }
329
+ pj_sockaddr_print(&hostaddr, hostip, sizeof(hostip), 2);
330
+
331
+ pj_ansi_sprintf(temp, "<sip:simpleuac@%s:%d>",
332
+ hostip, SIP_PORT);
333
+ local_uri = pj_str(temp);
334
+
335
+ /* Create UAC dialog */
336
+ status = pjsip_dlg_create_uac( pjsip_ua_instance(),
337
+ &local_uri, /* local URI */
338
+ &local_uri, /* local Contact */
339
+ &dst_uri, /* remote URI */
340
+ &dst_uri, /* remote target */
341
+ &dlg); /* dialog */
342
+ if (status != PJ_SUCCESS) {
343
+ app_perror(THIS_FILE, "Unable to create UAC dialog", status);
344
+ return 1;
345
+ }
346
+
347
+ /* If we expect the outgoing INVITE to be challenged, then we should
348
+ * put the credentials in the dialog here, with something like this:
349
+ *
350
+ {
351
+ pjsip_cred_info cred[1];
352
+
353
+ cred[0].realm = pj_str("sip.server.realm");
354
+ cred[0].username = pj_str("theuser");
355
+ cred[0].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
356
+ cred[0].data = pj_str("thepassword");
357
+
358
+ pjsip_auth_clt_set_credentials( &dlg->auth_sess, 1, cred);
359
+ }
360
+ *
361
+ */
362
+
363
+
364
+ /* Get the SDP body to be put in the outgoing INVITE, by asking
365
+ * media endpoint to create one for us. The SDP will contain all
366
+ * codecs that have been registered to it (in this case, only
367
+ * PCMA and PCMU), plus telephony event.
368
+ */
369
+ status = pjmedia_endpt_create_sdp( g_med_endpt, /* the media endpt */
370
+ dlg->pool, /* pool. */
371
+ 1, /* # of streams */
372
+ &g_med_tpinfo.sock_info,
373
+ /* RTP sock info */
374
+ &local_sdp); /* the SDP result */
375
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
376
+
377
+
378
+
379
+ /* Create the INVITE session, and pass the SDP returned earlier
380
+ * as the session's initial capability.
381
+ */
382
+ status = pjsip_inv_create_uac( dlg, local_sdp, 0, &g_inv);
383
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
384
+
385
+ /* If we want the initial INVITE to travel to specific SIP proxies,
386
+ * then we should put the initial dialog's route set here. The final
387
+ * route set will be updated once a dialog has been established.
388
+ * To set the dialog's initial route set, we do it with something
389
+ * like this:
390
+ *
391
+ {
392
+ pjsip_route_hdr route_set;
393
+ pjsip_route_hdr *route;
394
+ const pj_str_t hname = { "Route", 5 };
395
+ char *uri = "sip:proxy.server;lr";
396
+
397
+ pj_list_init(&route_set);
398
+
399
+ route = pjsip_parse_hdr( dlg->pool, &hname,
400
+ uri, strlen(uri),
401
+ NULL);
402
+ PJ_ASSERT_RETURN(route != NULL, 1);
403
+ pj_list_push_back(&route_set, route);
404
+
405
+ pjsip_dlg_set_route_set(dlg, &route_set);
406
+ }
407
+ *
408
+ * Note that Route URI SHOULD have an ";lr" parameter!
409
+ */
410
+
411
+ /* Create initial INVITE request.
412
+ * This INVITE request will contain a perfectly good request and
413
+ * an SDP body as well.
414
+ */
415
+ status = pjsip_inv_invite(g_inv, &tdata);
416
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
417
+
418
+
419
+
420
+ /* Send initial INVITE request.
421
+ * From now on, the invite session's state will be reported to us
422
+ * via the invite session callbacks.
423
+ */
424
+ status = pjsip_inv_send_msg(g_inv, tdata);
425
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
426
+
427
+
428
+ } else {
429
+
430
+ /* No URL to make call to */
431
+
432
+ PJ_LOG(3,(THIS_FILE, "Ready to accept incoming calls..."));
433
+ }
434
+
435
+
436
+ /* Loop until one call is completed */
437
+ for (;!g_complete;) {
438
+ pj_time_val timeout = {0, 10};
439
+ pjsip_endpt_handle_events(g_endpt, &timeout);
440
+ }
441
+
442
+ /* On exit, dump current memory usage: */
443
+ dump_pool_usage(THIS_FILE, &cp);
444
+
445
+ return 0;
446
+ }
447
+
448
+
449
+
450
+ /*
451
+ * Callback when INVITE session state has changed.
452
+ * This callback is registered when the invite session module is initialized.
453
+ * We mostly want to know when the invite session has been disconnected,
454
+ * so that we can quit the application.
455
+ */
456
+ static void call_on_state_changed( pjsip_inv_session *inv,
457
+ pjsip_event *e)
458
+ {
459
+ PJ_UNUSED_ARG(e);
460
+
461
+ if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {
462
+
463
+ PJ_LOG(3,(THIS_FILE, "Call DISCONNECTED [reason=%d (%s)]",
464
+ inv->cause,
465
+ pjsip_get_status_text(inv->cause)->ptr));
466
+
467
+ PJ_LOG(3,(THIS_FILE, "One call completed, application quitting..."));
468
+ g_complete = 1;
469
+
470
+ } else {
471
+
472
+ PJ_LOG(3,(THIS_FILE, "Call state changed to %s",
473
+ pjsip_inv_state_name(inv->state)));
474
+
475
+ }
476
+ }
477
+
478
+
479
+ /* This callback is called when dialog has forked. */
480
+ static void call_on_forked(pjsip_inv_session *inv, pjsip_event *e)
481
+ {
482
+ /* To be done... */
483
+ PJ_UNUSED_ARG(inv);
484
+ PJ_UNUSED_ARG(e);
485
+ }
486
+
487
+
488
+ /*
489
+ * Callback when incoming requests outside any transactions and any
490
+ * dialogs are received. We're only interested to hande incoming INVITE
491
+ * request, and we'll reject any other requests with 500 response.
492
+ */
493
+ static pj_bool_t on_rx_request( pjsip_rx_data *rdata )
494
+ {
495
+ pj_sockaddr hostaddr;
496
+ char temp[80], hostip[PJ_INET6_ADDRSTRLEN];
497
+ pj_str_t local_uri;
498
+ pjsip_dialog *dlg;
499
+ pjmedia_sdp_session *local_sdp;
500
+ pjsip_tx_data *tdata;
501
+ unsigned options = 0;
502
+ pj_status_t status;
503
+
504
+
505
+ /*
506
+ * Respond (statelessly) any non-INVITE requests with 500
507
+ */
508
+ if (rdata->msg_info.msg->line.req.method.id != PJSIP_INVITE_METHOD) {
509
+
510
+ if (rdata->msg_info.msg->line.req.method.id != PJSIP_ACK_METHOD) {
511
+ pj_str_t reason = pj_str("Simple UA unable to handle "
512
+ "this request");
513
+
514
+ pjsip_endpt_respond_stateless( g_endpt, rdata,
515
+ 500, &reason,
516
+ NULL, NULL);
517
+ }
518
+ return PJ_TRUE;
519
+ }
520
+
521
+
522
+ /*
523
+ * Reject INVITE if we already have an INVITE session in progress.
524
+ */
525
+ if (g_inv) {
526
+
527
+ pj_str_t reason = pj_str("Another call is in progress");
528
+
529
+ pjsip_endpt_respond_stateless( g_endpt, rdata,
530
+ 500, &reason,
531
+ NULL, NULL);
532
+ return PJ_TRUE;
533
+
534
+ }
535
+
536
+ /* Verify that we can handle the request. */
537
+ status = pjsip_inv_verify_request(rdata, &options, NULL, NULL,
538
+ g_endpt, NULL);
539
+ if (status != PJ_SUCCESS) {
540
+
541
+ pj_str_t reason = pj_str("Sorry Simple UA can not handle this INVITE");
542
+
543
+ pjsip_endpt_respond_stateless( g_endpt, rdata,
544
+ 500, &reason,
545
+ NULL, NULL);
546
+ return PJ_TRUE;
547
+ }
548
+
549
+ /*
550
+ * Generate Contact URI
551
+ */
552
+ if (pj_gethostip(AF, &hostaddr) != PJ_SUCCESS) {
553
+ app_perror(THIS_FILE, "Unable to retrieve local host IP", status);
554
+ return PJ_TRUE;
555
+ }
556
+ pj_sockaddr_print(&hostaddr, hostip, sizeof(hostip), 2);
557
+
558
+ pj_ansi_sprintf(temp, "<sip:simpleuas@%s:%d>",
559
+ hostip, SIP_PORT);
560
+ local_uri = pj_str(temp);
561
+
562
+ /*
563
+ * Create UAS dialog.
564
+ */
565
+ status = pjsip_dlg_create_uas( pjsip_ua_instance(),
566
+ rdata,
567
+ &local_uri, /* contact */
568
+ &dlg);
569
+ if (status != PJ_SUCCESS) {
570
+ pjsip_endpt_respond_stateless(g_endpt, rdata, 500, NULL,
571
+ NULL, NULL);
572
+ return PJ_TRUE;
573
+ }
574
+
575
+ /*
576
+ * Get media capability from media endpoint:
577
+ */
578
+
579
+ status = pjmedia_endpt_create_sdp( g_med_endpt, rdata->tp_info.pool, 1,
580
+ &g_med_tpinfo.sock_info,
581
+ &local_sdp);
582
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, PJ_TRUE);
583
+
584
+
585
+ /*
586
+ * Create invite session, and pass both the UAS dialog and the SDP
587
+ * capability to the session.
588
+ */
589
+ status = pjsip_inv_create_uas( dlg, rdata, local_sdp, 0, &g_inv);
590
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, PJ_TRUE);
591
+
592
+
593
+ /*
594
+ * Initially send 180 response.
595
+ *
596
+ * The very first response to an INVITE must be created with
597
+ * pjsip_inv_initial_answer(). Subsequent responses to the same
598
+ * transaction MUST use pjsip_inv_answer().
599
+ */
600
+ status = pjsip_inv_initial_answer(g_inv, rdata,
601
+ 180,
602
+ NULL, NULL, &tdata);
603
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, PJ_TRUE);
604
+
605
+
606
+ /* Send the 180 response. */
607
+ status = pjsip_inv_send_msg(g_inv, tdata);
608
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, PJ_TRUE);
609
+
610
+
611
+ /*
612
+ * Now create 200 response.
613
+ */
614
+ status = pjsip_inv_answer( g_inv,
615
+ 200, NULL, /* st_code and st_text */
616
+ NULL, /* SDP already specified */
617
+ &tdata);
618
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, PJ_TRUE);
619
+
620
+ /*
621
+ * Send the 200 response.
622
+ */
623
+ status = pjsip_inv_send_msg(g_inv, tdata);
624
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, PJ_TRUE);
625
+
626
+
627
+ /* Done.
628
+ * When the call is disconnected, it will be reported via the callback.
629
+ */
630
+
631
+ return PJ_TRUE;
632
+ }
633
+
634
+ static void dtmf_callback(pjmedia_port *port, void *user_data, char digit)
635
+ {
636
+ printf("Digit arrived %c\n", digit);
637
+ }
638
+
639
+ /*
640
+ * Callback when SDP negotiation has completed.
641
+ * We are interested with this callback because we want to start media
642
+ * as soon as SDP negotiation is completed.
643
+ */
644
+ static void call_on_media_update( pjsip_inv_session *inv,
645
+ pj_status_t status)
646
+ {
647
+ pjmedia_session_info sess_info;
648
+ const pjmedia_sdp_session *local_sdp;
649
+ const pjmedia_sdp_session *remote_sdp;
650
+ pjmedia_port *media_port;
651
+
652
+ if (status != PJ_SUCCESS) {
653
+
654
+ app_perror(THIS_FILE, "SDP negotiation has failed", status);
655
+
656
+ /* Here we should disconnect call if we're not in the middle
657
+ * of initializing an UAS dialog and if this is not a re-INVITE.
658
+ */
659
+ return;
660
+ }
661
+
662
+ /* Get local and remote SDP.
663
+ * We need both SDPs to create a media session.
664
+ */
665
+ status = pjmedia_sdp_neg_get_active_local(inv->neg, &local_sdp);
666
+
667
+ status = pjmedia_sdp_neg_get_active_remote(inv->neg, &remote_sdp);
668
+
669
+
670
+ /* Create session info based on the two SDPs.
671
+ * We only support one stream per session for now.
672
+ */
673
+ status = pjmedia_session_info_from_sdp(inv->dlg->pool, g_med_endpt,
674
+ 1, &sess_info,
675
+ local_sdp, remote_sdp);
676
+ if (status != PJ_SUCCESS) {
677
+ app_perror( THIS_FILE, "Unable to create media session", status);
678
+ return;
679
+ }
680
+
681
+ /* If required, we can also change some settings in the session info,
682
+ * (such as jitter buffer settings, codec settings, etc) before we
683
+ * create the session.
684
+ */
685
+
686
+ /* Create new media session, passing the two SDPs, and also the
687
+ * media socket that we created earlier.
688
+ * The media session is active immediately.
689
+ */
690
+ status = pjmedia_session_create( g_med_endpt, &sess_info,
691
+ &g_med_transport, NULL, &g_med_session );
692
+ if (status != PJ_SUCCESS) {
693
+ app_perror( THIS_FILE, "Unable to create media session", status);
694
+ return;
695
+ }
696
+
697
+
698
+ /* Get the media port interface of the first stream in the session.
699
+ * Media port interface is basicly a struct containing get_frame() and
700
+ * put_frame() function. With this media port interface, we can attach
701
+ * the port interface to conference bridge, or directly to a sound
702
+ * player/recorder device.
703
+ */
704
+ pjmedia_session_get_port(g_med_session, 0, &media_port);
705
+
706
+ status = pjmedia_dtmfdet_create(
707
+ inv->pool,
708
+ media_port->info.clock_rate,
709
+ media_port->info.channel_count,
710
+ media_port->info.samples_per_frame,
711
+ media_port->info.bits_per_sample,
712
+ dtmf_callback,
713
+ 1234,
714
+ &g_dtmfdet);
715
+
716
+ printf("%i %i %i %i %X %X\n", media_port->info.clock_rate,
717
+ media_port->info.channel_count,
718
+ media_port->info.samples_per_frame,
719
+ media_port->info.bits_per_sample,
720
+ dtmf_callback,
721
+ g_dtmfdet);
722
+
723
+
724
+ if (status != PJ_SUCCESS) {
725
+ app_perror( THIS_FILE, "Unable to create dtmfdet", status);
726
+ PJ_LOG(3,(THIS_FILE, "%d %d %d %d",
727
+ media_port->info.clock_rate, /* clock rate */
728
+ media_port->info.channel_count, /* channel count */
729
+ media_port->info.samples_per_frame, /* samples per frame*/
730
+ media_port->info.bits_per_sample /* bits per sample */
731
+ ));
732
+ return;
733
+ }
734
+
735
+ status = pjmedia_master_port_create(inv->pool,
736
+ media_port,
737
+ g_dtmfdet,
738
+ 0,
739
+ &g_master_port);
740
+ if (status != PJ_SUCCESS) {
741
+ app_perror( THIS_FILE, "Unable to create master port", status);
742
+ return;
743
+ }
744
+
745
+ status = pjmedia_master_port_start(g_master_port);
746
+ if (status != PJ_SUCCESS) {
747
+ app_perror( THIS_FILE, "Unable to start master port", status);
748
+ return;
749
+ }
750
+
751
+ }
752
+
753
+