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
package/src/sip.cpp ADDED
@@ -0,0 +1,4891 @@
1
+ #include <arpa/inet.h>
2
+
3
+ #include "sip.hpp"
4
+
5
+ #include <string>
6
+ #include <iostream>
7
+ #include <sstream>
8
+ #include <deque>
9
+ #include <map>
10
+ #include <set>
11
+
12
+ #include <boost/circular_buffer.hpp>
13
+ #include <algorithm>
14
+
15
+ #include <pthread.h>
16
+
17
+ #include <ctime>
18
+
19
+ #include "idmanager.hpp"
20
+ #include "packetdumper.hpp"
21
+ #include "event_templates.hpp"
22
+
23
+ //Customized media ports that can be chained
24
+ #include "chainlink.h"
25
+ #include "chainlink_wire_port.h"
26
+ #include "chainlink_dtmfdet.h"
27
+ #include "chainlink_tonegen.h"
28
+ #include "chainlink_wav_port.h"
29
+
30
+ #include <ctime>
31
+
32
+ #include <sys/syscall.h>
33
+
34
+ #include "log.hpp"
35
+
36
+ using namespace std;
37
+
38
+ #define EVT_DATA_SEP "|"
39
+
40
+ #define IDS_MAX (2000)
41
+
42
+ IdManager g_transport_ids(IDS_MAX);
43
+ IdManager g_account_ids(IDS_MAX);
44
+ IdManager g_call_ids(IDS_MAX);
45
+ IdManager g_subscription_ids(IDS_MAX);
46
+ IdManager g_subscriber_ids(IDS_MAX);
47
+ IdManager g_dialog_ids(IDS_MAX);
48
+
49
+ PacketDumper *g_PacketDumper = 0;
50
+
51
+ #define AF pj_AF_INET()
52
+ #define DEFAULT_ILBC_MODE (30)
53
+ #define DEFAULT_CODEC_QUALITY (5)
54
+
55
+ #define UNKNOWN 0
56
+ #define SENDRECV 1
57
+ #define SENDONLY 2
58
+ #define RECVONLY 3
59
+ #define INACTIVE 4
60
+
61
+ static pjsip_endpoint *g_sip_endpt;
62
+ static pj_caching_pool cp;
63
+ static pj_pool_t *g_pool;
64
+ static pjmedia_endpt *g_med_endpt;
65
+
66
+ static pj_thread_t *g_thread = NULL;
67
+ static pj_bool_t g_thread_quit_flag;
68
+
69
+ static deque<string> g_events;
70
+ static pthread_mutex_t g_mutex;
71
+
72
+ static char pjw_errorstring[4096];
73
+
74
+ void clear_error() {
75
+ pjw_errorstring[0] = 0;
76
+ }
77
+
78
+ void set_error(char *err) {
79
+ //printf("set_error: %s\n", err);
80
+ strcpy(pjw_errorstring, err);
81
+ }
82
+
83
+ char *pjw_get_error() {
84
+ return pjw_errorstring;
85
+ }
86
+
87
+ #define PJW_LOCK() pthread_mutex_lock(&g_mutex)
88
+ #define PJW_UNLOCK() pthread_mutex_unlock(&g_mutex)
89
+
90
+ char *trim(char *dest, char *src){
91
+ while(*src == ' ' || *src == '\t') src++;
92
+ strcpy(dest, src);
93
+
94
+ int len = strlen(dest);
95
+ char *end = dest + len -1;
96
+
97
+ while(*end == ' ' || *end == '\t') *end-- = 0;
98
+ return dest;
99
+ }
100
+
101
+ pj_thread_desc g_main_thread_descriptor;
102
+ pj_thread_t *g_main_thread = NULL;
103
+
104
+ pj_thread_desc g_poll_thread_descriptor;
105
+ pj_thread_t *g_poll_thread = NULL;
106
+
107
+ int ms_timestamp();
108
+
109
+ bool g_shutting_down;
110
+
111
+ int g_dtmf_inter_digit_timer = 0;
112
+
113
+ pj_str_t g_sip_ipaddress;
114
+
115
+ unsigned g_flags = 0;
116
+
117
+ pjsip_route_hdr route_set;
118
+ pjsip_route_hdr *route;
119
+ const pj_str_t hname = { "Route", 5 };
120
+
121
+ #define MAXDIGITS 256
122
+ #define INITIAL_DIGITBUFFERLENGTH 1
123
+
124
+ #define DTMF_MODE_RFC2833 0
125
+ #define DTMF_MODE_INBAND 1
126
+
127
+ struct Subscriber {
128
+ int id;
129
+ int transport_id;
130
+ pjsip_evsub *evsub;
131
+ pjsip_dialog *dlg;
132
+ bool created_by_refer;
133
+ };
134
+
135
+ struct Transport {
136
+ int id;
137
+ pjsip_transport_type_e type;
138
+ pjsip_transport *sip_transport;
139
+ pjsip_tpfactory *tpfactory;
140
+ char domain[100];
141
+ char username[100];
142
+ char password[100];
143
+ };
144
+
145
+ struct Subscription {
146
+ int id;
147
+ pjsip_evsub *evsub;
148
+ pjsip_dialog *dlg;
149
+ char event[200];
150
+ char accept[200];
151
+ bool initialized;
152
+ };
153
+
154
+ struct Call {
155
+ int id;
156
+ pjsip_inv_session *inv;
157
+ pjmedia_transport *med_transport;
158
+ pjmedia_stream *med_stream;
159
+ pj_bool_t local_hold;
160
+ pj_bool_t remote_hold;
161
+ pjmedia_master_port *master_port;
162
+ pjmedia_port *media_port; //will contain Null Port, WAV File Player etc.
163
+
164
+ pjmedia_port *null_port;
165
+ chainlink *wav_writer;
166
+ chainlink *wav_player;
167
+ chainlink *tonegen;
168
+ chainlink *dtmfdet;
169
+
170
+ Transport *transport;
171
+
172
+ bool outgoing;
173
+
174
+ char DigitBuffers[2][MAXDIGITS + 1];
175
+ int DigitBufferLength[2];
176
+ int last_digit_timestamp[2];
177
+
178
+ pjsip_evsub *xfer_sub; // Xfer server subscription, if this call was triggered by xfer.
179
+
180
+ pjsip_rx_data *initial_invite_rdata;
181
+ };
182
+
183
+
184
+ struct Pair_Call_CallId {
185
+ Call *pCall;
186
+ long id;
187
+ bool operator==(const Pair_Call_CallId &pcc) const{
188
+ if(this->pCall == pcc.pCall) return true;
189
+ return false;
190
+ };
191
+ };
192
+ typedef boost::circular_buffer<Pair_Call_CallId> Pair_Call_CallId_Buf;
193
+ Pair_Call_CallId_Buf g_LastCalls(1000);
194
+
195
+
196
+ typedef map<pjsip_transport*, int> SipTransportMap;
197
+ SipTransportMap g_SipTransportMap;
198
+ int g_TlsTransportId = -100;
199
+
200
+ typedef set< pair<string,string> > PackageSet;
201
+ PackageSet g_PackageSet;
202
+
203
+ #define DEFAULT_EXPIRES 600
204
+
205
+ static void pool_callback(pj_pool_t *pool, pj_size_t size)
206
+ {
207
+ PJ_CHECK_STACK();
208
+ PJ_UNUSED_ARG(pool);
209
+ PJ_UNUSED_ARG(size);
210
+
211
+ PJ_THROW(PJ_NO_MEMORY_EXCEPTION);
212
+ }
213
+
214
+ void handle_events(){
215
+ unsigned count = 0;
216
+ //pj_time_val tv = {0, 500};
217
+ //pj_time_val tv = {0,10};
218
+ //pj_time_val tv = {0,100};
219
+ pj_time_val tv = {0,1};
220
+ //pj_time_val_normalize(&tv);
221
+ pj_status_t status;
222
+ status = pjsip_endpt_handle_events(g_sip_endpt, &tv);
223
+ }
224
+
225
+ static int worker_thread(void *arg)
226
+ {
227
+ //addon_log(LOG_LEVEL_DEBUG, "Starting worker_thread\n");
228
+
229
+ pj_thread_set_prio(pj_thread_this(),
230
+ pj_thread_get_prio_min(pj_thread_this()));
231
+
232
+ enum { TIMEOUT = 10 };
233
+
234
+ PJ_UNUSED_ARG(arg);
235
+
236
+ while(!g_thread_quit_flag){
237
+ PJW_LOCK();
238
+ //addon_log(LOG_LEVEL_DEBUG, ".");
239
+ handle_events();
240
+ PJW_UNLOCK();
241
+
242
+ usleep(10);
243
+ }
244
+ return 0;
245
+ }
246
+
247
+ void init_tpselector(Transport *t, pjsip_tpselector *sel) {
248
+ unsigned flag;
249
+
250
+ pj_bzero(sel, sizeof(*sel));
251
+
252
+ flag = pjsip_transport_get_flag_from_type(t->type);
253
+
254
+ if (flag & PJSIP_TRANSPORT_DATAGRAM) {
255
+ sel->type = PJSIP_TPSELECTOR_TRANSPORT;
256
+ sel->u.transport = t->sip_transport;
257
+ } else {
258
+ sel->type = PJSIP_TPSELECTOR_LISTENER;
259
+ sel->u.listener = t->tpfactory;
260
+ }
261
+ }
262
+
263
+
264
+
265
+ bool start_digit_buffer_thread();
266
+
267
+ /* Callback to be called when SDP negotiation is done in the call: */
268
+ static void on_media_update( pjsip_inv_session *inv,
269
+ pj_status_t status);
270
+
271
+ /* Callback to be called when invite session's state has changed: */
272
+ static void on_state_changed( pjsip_inv_session *inv,
273
+ pjsip_event *e);
274
+
275
+ /* Callback to be called when dialog has forked: */
276
+ static void on_forked(pjsip_inv_session *inv, pjsip_event *e);
277
+
278
+ /* Callback to be called to handle incoming requests */
279
+ static pj_bool_t on_rx_request( pjsip_rx_data *rdata );
280
+
281
+ /* Callback to be called when responses are received */
282
+ static pj_bool_t on_rx_response( pjsip_rx_data *rdata );
283
+
284
+ /* Callback to be called when media offer is received (in REINVITEs but also in late negotiaion scenario) */
285
+ static void on_rx_offer(pjsip_inv_session *inv, const pjmedia_sdp_session *offer);
286
+
287
+ /* Callback to be called when REINVITE is received */
288
+ //static pj_status_t on_rx_reinvite(pjsip_inv_session *inv, const pjmedia_sdp_session *offer, pjsip_rx_data *rdata);
289
+
290
+ /* Callback to be called when Redirect is received */
291
+ static pjsip_redirect_op on_redirected(pjsip_inv_session *inv, const pjsip_uri *target, const pjsip_event *e);
292
+
293
+ /* Callback to be called when DTMF is received */
294
+ static void on_dtmf(pjmedia_stream *stream, void *user_data, int digit);
295
+
296
+ /* Callback for Registration Status */
297
+ static void on_registration_status(pjsip_regc_cbparam *param);
298
+
299
+ static void on_tsx_state_changed(pjsip_inv_session *inv,
300
+ pjsip_transaction *tsx,
301
+ pjsip_event *e);
302
+
303
+ static void client_on_evsub_state( pjsip_evsub *sub, pjsip_event *event);
304
+ static void on_client_refresh( pjsip_evsub *sub );
305
+ void on_rx_notify(pjsip_evsub *sub, pjsip_rx_data *rdata, int *p_st_code, pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body);
306
+
307
+ static void server_on_evsub_state( pjsip_evsub *sub, pjsip_event *event);
308
+ static void server_on_evsub_rx_refresh(pjsip_evsub *sub, pjsip_rx_data *rdata, int *p_st_code, pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body);
309
+
310
+ bool dlg_create(pjsip_dialog **dlg, Transport *transport, const char *from_uri, const char *to_uri, const char *request_uri, const char *realm, const char *username, const char *password, const char *local_contact);
311
+
312
+ static int call_create(Transport *t, unsigned flags, pjsip_dialog *dlg, const char *proxy_uri, const char *additional_headers);
313
+
314
+ static int subscription_create(pjsip_dialog *dlg, const char *event, const char *proxy_uri, const char *additional_headers);
315
+ bool subscription_subscribe(Subscription *s, int expires, const char *additional_headers);
316
+
317
+ static pjmedia_transport *create_media_transport(const pj_str_t *addr);
318
+ void close_media_transport(pjmedia_transport *med_transport);
319
+ pjsip_transport *create_udp_transport(pjsip_endpoint* sip_endpt, pj_str_t *ipaddr, int *allocated_port);
320
+ pjsip_transport *allocate_udp_transport(pjsip_endpoint* sip_endpt, pj_str_t *ipaddr, int port);
321
+
322
+ pjsip_tpfactory *create_tls_tpfactory(pjsip_endpoint* sip_endpt, pj_str_t *ipaddr, int *allocated_port);
323
+ pjsip_tpfactory *allocate_tls_tpfactory(pjsip_endpoint* sip_endpt, pj_str_t *ipaddr, int port);
324
+
325
+ bool set_proxy(pjsip_dialog *dlg, const char *proxy_uri);
326
+
327
+ void build_local_contact(char *dest, pjsip_transport *transport, const char *contact_username);
328
+ void build_local_contact_from_tpfactory(char *dest, pjsip_tpfactory *tpfactory, const char *contact_username);
329
+
330
+ pj_bool_t add_additional_headers(pj_pool_t *pool, pjsip_tx_data *tdata, const char *additional_headers);
331
+
332
+ pj_bool_t add_additional_headers_for_account(pjsip_regc* regc, const char *additional_headers);
333
+
334
+ pj_bool_t get_content_type_and_subtype_from_additional_headers(const char *additional_headers, char *type, char *subtype);
335
+
336
+ bool build_subscribe_info(ostringstream *oss, pjsip_rx_data *rdata, Subscriber *s);
337
+ //bool build_notify_info(pjsip_rx_data *rdata, Subscription *s);
338
+
339
+ bool add_header_info(ostringstream *oss, pjsip_rx_data *rdata, const char *headers_names, bool fail_on_not_found);
340
+
341
+ void process_in_dialog_refer(pjsip_dialog *dlg, pjsip_rx_data *rdata);
342
+
343
+ //void process_response(pjsip_rx_data *rdata, const char *entity_name, int entity_id);
344
+
345
+ void process_in_dialog_subscribe(pjsip_dialog *dlg, pjsip_rx_data *rdata);
346
+
347
+ static pj_bool_t set_ports(Call *call, pjmedia_port *stream_port, pjmedia_port *media_port);
348
+ //static pj_bool_t stop_media_operation(Call *call);
349
+ static void build_stream_stat(ostringstream &oss, pjmedia_rtcp_stat *stat, pjmedia_port *port);
350
+
351
+ bool init_media_ports(Call *c, unsigned sampling_rate, unsigned channel_count, unsigned samples_per_frame, unsigned bits_per_sample);
352
+ void connect_media_ports(Call *c);
353
+
354
+ bool prepare_wire(pj_pool_t *pool, chainlink **link, unsigned sampling_rate, unsigned channel_count, unsigned samples_per_frame, unsigned bits_per_sample);
355
+
356
+ bool prepare_tonegen(Call *c);
357
+ bool prepare_wav_player(Call *c, const char *file);
358
+ bool prepare_wav_writer(Call *c, const char *file);
359
+
360
+ void prepare_error_event(ostringstream *oss, char *scope, char *details);
361
+ //void prepare_pjsipcall_error_event(ostringstream *oss, char *scope, char *function, pj_status_t s);
362
+ void append_status(ostringstream *oss, pj_status_t s);
363
+
364
+ static pjsip_module mod_tester =
365
+ {
366
+ NULL, NULL, /* prev, next. */
367
+ { "mod_tester", 10 }, /* Name. */
368
+ -1, /* Id */
369
+ //PJSIP_MOD_PRIORITY_APPLICATION, /* Priority */
370
+ PJSIP_MOD_PRIORITY_DIALOG_USAGE, /* Priority */
371
+ NULL, /* load() */
372
+ NULL, /* start() */
373
+ NULL, /* stop() */
374
+ NULL, /* unload() */
375
+ &on_rx_request, /* on_rx_request() */
376
+ &on_rx_response, /* on_rx_response() */
377
+ NULL, /* on_tx_request. */
378
+ NULL, /* on_tx_response() */
379
+ NULL, /* on_tsx_state() */
380
+ };
381
+
382
+
383
+ struct Timer
384
+ {
385
+ pj_timer_entry timer_entry;
386
+ pj_time_val delay;
387
+ pj_bool_t in_use;
388
+ unsigned id;
389
+ };
390
+
391
+ Timer _timer;
392
+
393
+ void dispatch_event(const char * evt);
394
+
395
+ int check_uri(const char *uri) {
396
+ return (strstr(uri, "sip:") != NULL);
397
+ }
398
+
399
+ const char *translate_pjsip_inv_state(int state)
400
+ {
401
+ switch(state)
402
+ {
403
+ case PJSIP_INV_STATE_NULL: return "null";
404
+ case PJSIP_INV_STATE_CALLING: return "calling";
405
+ case PJSIP_INV_STATE_INCOMING: return "incoming";
406
+ case PJSIP_INV_STATE_EARLY: return "early";
407
+ case PJSIP_INV_STATE_CONNECTING: return "connecting";
408
+ case PJSIP_INV_STATE_CONFIRMED: return "confirmed";
409
+ case PJSIP_INV_STATE_DISCONNECTED: return "disconnected";
410
+ default: return "unknown";
411
+ }
412
+ }
413
+
414
+ static void on_inband_dtmf(pjmedia_port *port, void *user_data, char digit){
415
+ if(g_shutting_down) return;
416
+
417
+ long call_id;
418
+ if( !g_call_ids.get_id((long)user_data, call_id) ){
419
+ addon_log(LOG_LEVEL_DEBUG, "on_inband_dtmf: Failed to get call_id. Event will not be notified.\n");
420
+ return;
421
+ }
422
+
423
+ char d = tolower(digit);
424
+ if(d == '*') d = 'e';
425
+ if(d == '#') d = 'f';
426
+
427
+ Call *c = (Call*)user_data;
428
+
429
+ int mode = DTMF_MODE_INBAND;
430
+
431
+ if(g_dtmf_inter_digit_timer) {
432
+
433
+ PJW_LOCK();
434
+ int *pLen = &c->DigitBufferLength[mode];
435
+
436
+ if(*pLen > MAXDIGITS) {
437
+ PJW_UNLOCK();
438
+ addon_log(LOG_LEVEL_DEBUG, "No more space for digits in inband buffer\n");
439
+ return;
440
+ }
441
+
442
+ c->DigitBuffers[mode][*pLen] = d;
443
+ (*pLen)++;
444
+ c->last_digit_timestamp[mode] = ms_timestamp();
445
+ PJW_UNLOCK();
446
+ } else {
447
+ /*
448
+ ostringstream oss;
449
+
450
+ oss << "event=dtmf" << EVT_DATA_SEP << "call=" << call_id << EVT_DATA_SEP << "digits=" << d << EVT_DATA_SEP << "mode=" << DTMF_MODE_INBAND;
451
+ dispatch_event(oss.str().c_str());
452
+ */
453
+
454
+ char evt[256];
455
+ make_evt_dtmf(evt, sizeof(evt), call_id, 1, &d, mode);
456
+ dispatch_event(evt);
457
+ }
458
+ }
459
+
460
+ void dispatch_event(const char * evt)
461
+ {
462
+ //addon_log(LOG_LEVEL_DEBUG, "dispach_event called\n");
463
+ //g_event_sink(evt);
464
+
465
+ g_events.push_back(evt);
466
+ }
467
+
468
+ static char *get_media_mode_str(int mode) {
469
+ if(mode == SENDRECV) return "sendrecv";
470
+ if(mode == SENDONLY) return "sendonly";
471
+ if(mode == RECVONLY) return "recvonly";
472
+ if(mode == INACTIVE) return "inactive";
473
+ if(mode == UNKNOWN) return "unknown";
474
+ }
475
+
476
+ static int get_media_mode(pjmedia_sdp_attr **attrs, int count) {
477
+ int i;
478
+ for(i=0 ; i<count ; ++i) {
479
+ pjmedia_sdp_attr *a = attrs[i];
480
+ if(pj_strcmp2(&a->name, "sendrecv")==0) {
481
+ return SENDRECV;
482
+ } else if(pj_strcmp2(&a->name, "sendonly")==0) {
483
+ return SENDONLY;
484
+ } else if(pj_strcmp2(&a->name, "recvonly")==0) {
485
+ return RECVONLY;
486
+ } else if(pj_strcmp2(&a->name, "inactive")==0) {
487
+ return INACTIVE;
488
+ }
489
+ }
490
+ return UNKNOWN;
491
+ }
492
+
493
+ int __pjw_init()
494
+ {
495
+ addon_log(LOG_LEVEL_DEBUG, "pjw_init thread_id=%i\n", syscall(SYS_gettid));
496
+
497
+ g_shutting_down = false;
498
+
499
+ pj_status_t status;
500
+
501
+ status = pj_init();
502
+ if(status != PJ_SUCCESS)
503
+ {
504
+ addon_log(LOG_LEVEL_DEBUG, "pj_init failed\n");
505
+ return 1;
506
+ }
507
+
508
+ status = pjlib_util_init();
509
+ if(status != PJ_SUCCESS)
510
+ {
511
+ addon_log(LOG_LEVEL_DEBUG, "pj_lib_util_init failed\n");
512
+ return 1;
513
+ }
514
+
515
+ pthread_mutex_init(&g_mutex,NULL);
516
+
517
+ pj_log_set_level(0);
518
+
519
+ pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);
520
+
521
+ char *sip_endpt_name = "mysip";
522
+
523
+ status = pjsip_endpt_create(&cp.factory, sip_endpt_name, &g_sip_endpt);
524
+ if(status != PJ_SUCCESS)
525
+ {
526
+ addon_log(LOG_LEVEL_DEBUG, "pjsip_endpt_create failed\n");
527
+ return 1;
528
+ }
529
+
530
+ const pj_str_t msg_tag = { "MESSAGE", 7 };
531
+ const pj_str_t STR_MIME_TEXT_PLAIN = { "text/plain", 10 };
532
+ const pj_str_t STR_MIME_APP_ISCOMPOSING = { "application/im-iscomposing+xml", 30 };
533
+
534
+ /* Register support for MESSAGE method. */
535
+ status = pjsip_endpt_add_capability(g_sip_endpt, &mod_tester, PJSIP_H_ALLOW,
536
+ NULL, 1, &msg_tag);
537
+ if(status != PJ_SUCCESS)
538
+ {
539
+ addon_log(LOG_LEVEL_DEBUG, "pjsip_endpt_add_capability PJSIP_H_ALLOW failed\n");
540
+ return 1;
541
+ }
542
+
543
+ /* Register support for "application/im-iscomposing+xml" content */
544
+ pjsip_endpt_add_capability(g_sip_endpt, &mod_tester, PJSIP_H_ACCEPT,
545
+ NULL, 1, &STR_MIME_APP_ISCOMPOSING);
546
+ if(status != PJ_SUCCESS)
547
+ {
548
+ addon_log(LOG_LEVEL_DEBUG, "pjsip_endpt_add_capability PJSIP_H_ACCEPT for MIME_APP_ISCOMPOSING failed\n");
549
+ return 1;
550
+ }
551
+
552
+ /* Register support for "text/plain" content */
553
+ pjsip_endpt_add_capability(g_sip_endpt, &mod_tester, PJSIP_H_ACCEPT,
554
+ NULL, 1, &STR_MIME_TEXT_PLAIN);
555
+ if(status != PJ_SUCCESS)
556
+ {
557
+ addon_log(LOG_LEVEL_DEBUG, "pjsip_endpt_add_capability PJSIP_H_ACCEPT for MIME_TEXT_PLAIN failed\n");
558
+ return 1;
559
+ }
560
+
561
+ status = pjsip_tsx_layer_init_module(g_sip_endpt);
562
+ if(status != PJ_SUCCESS)
563
+ {
564
+ addon_log(LOG_LEVEL_DEBUG, "pjsip_tsx_layer_init_module failed\n");
565
+ return 1;
566
+ }
567
+
568
+ status = pjsip_ua_init_module(g_sip_endpt, NULL);
569
+ if(status != PJ_SUCCESS)
570
+ {
571
+ addon_log(LOG_LEVEL_DEBUG, "pjsip_ua_init_module failed\n");
572
+ return 1;
573
+ }
574
+
575
+ status = pjsip_evsub_init_module(g_sip_endpt);
576
+ if(status != PJ_SUCCESS)
577
+ {
578
+ addon_log(LOG_LEVEL_DEBUG, "pjsip_evsub_init_module failed\n");
579
+ return 1;
580
+ }
581
+
582
+ status = pjsip_xfer_init_module(g_sip_endpt);
583
+ if(status != PJ_SUCCESS)
584
+ {
585
+ addon_log(LOG_LEVEL_DEBUG, "pjsip_xfer_init_module failed\n");
586
+ return 1;
587
+ }
588
+
589
+ status = pjsip_replaces_init_module(g_sip_endpt);
590
+ if(status != PJ_SUCCESS)
591
+ {
592
+ addon_log(LOG_LEVEL_DEBUG, "pjsip_replaces_init_module failed\n");
593
+ return 1;
594
+ }
595
+
596
+ pjsip_inv_callback inv_cb;
597
+ pj_bzero(&inv_cb, sizeof(inv_cb));
598
+ inv_cb.on_state_changed = &on_state_changed;
599
+ inv_cb.on_new_session = &on_forked;
600
+ inv_cb.on_media_update = &on_media_update;
601
+ inv_cb.on_rx_offer = &on_rx_offer;
602
+ //inv_cb.on_rx_reinvite = &on_rx_reinvite;
603
+ inv_cb.on_tsx_state_changed = &on_tsx_state_changed;
604
+ inv_cb.on_redirected = &on_redirected;
605
+
606
+ status = pjsip_inv_usage_init(g_sip_endpt, &inv_cb);
607
+ if(status != PJ_SUCCESS)
608
+ {
609
+ addon_log(LOG_LEVEL_DEBUG, "pjsip_inv_usage_init failed\n");
610
+ return 1;
611
+ }
612
+
613
+ status = pjsip_100rel_init_module(g_sip_endpt);
614
+ if(status != PJ_SUCCESS)
615
+ {
616
+ addon_log(LOG_LEVEL_DEBUG, "pjsip_100rel_init_module failed\n");
617
+ return 1;
618
+ }
619
+
620
+ status = pjsip_endpt_register_module(g_sip_endpt, &mod_tester);
621
+ if(status != PJ_SUCCESS)
622
+ {
623
+ addon_log(LOG_LEVEL_DEBUG, "pjsip_endpt_register_module failed\n");
624
+ return 1;
625
+ }
626
+ #if PJ_HAS_THREADS
627
+ status = pjmedia_endpt_create2(&cp.factory, NULL, 1, &g_med_endpt);
628
+ #else
629
+ status = pjmedia_endpt_create2(&cp.factory,
630
+ pjsip_endpt_get_ioqueue(g_sip_endpt),
631
+ 0, &g_med_endpt);
632
+ #endif
633
+ if(status != PJ_SUCCESS)
634
+ {
635
+ addon_log(LOG_LEVEL_DEBUG, "pjmedia_endpt_create failed\n");
636
+ return 1;
637
+ }
638
+
639
+ #if defined(PJMEDIA_HAS_G711_CODEC) && PJMEDIA_HAS_G711_CODEC!=0
640
+ status = pjmedia_codec_g711_init(g_med_endpt);
641
+ if(status != PJ_SUCCESS)
642
+ {
643
+ addon_log(LOG_LEVEL_DEBUG, "pjmedia_codec_g711_init failed\n");
644
+ return 1;
645
+ }
646
+ #endif
647
+
648
+ #if defined(PJMEDIA_HAS_GSM_CODEC) && PJMEDIA_HAS_GSM_CODEC!=0
649
+ status = pjmedia_codec_gsm_init(g_med_endpt);
650
+ if(status != PJ_SUCCESS)
651
+ {
652
+ addon_log(LOG_LEVEL_DEBUG, "pjmedia_codec_gsm_init failed\n");
653
+ return 1;
654
+ }
655
+ #endif
656
+
657
+ #if defined(PJMEDIA_HAS_l16_CODEC) && PJMEDIA_HAS_l16_CODEC!=0
658
+ status = pjmedia_codec_l16_init(g_med_endpt, 0);
659
+ if(status != PJ_SUCCESS)
660
+ {
661
+ addon_log(LOG_LEVEL_DEBUG, "pjmedia_codec_l16_init failed\n");
662
+ return 1;
663
+ }
664
+ #endif
665
+
666
+ #if defined(PJMEDIA_HAS_ILBC_CODEC) && PJMEDIA_HAS_ILBC_CODEC!=0
667
+ status = pjmedia_codec_ilbc_init(g_med_endpt, DEFAULT_ILBC_MODE);
668
+ if(status != PJ_SUCCESS)
669
+ {
670
+ addon_log(LOG_LEVEL_DEBUG, "pjmedia_codec_ilbc_init failed\n");
671
+ return 1;
672
+ }
673
+ #endif
674
+
675
+ #if defined(PJMEDIA_HAS_SPEEX_CODEC) && PJMEDIA_HAS_SPEEX_CODEC!=0
676
+ status = pjmedia_codec_speex_init(g_med_endpt,
677
+ 0,
678
+ DEFAULT_CODEC_QUALITY,
679
+ -1);
680
+ if(status != PJ_SUCCESS)
681
+ {
682
+ addon_log(LOG_LEVEL_DEBUG, "pjmedia_codec_speex_init failed\n");
683
+ return 1;
684
+ }
685
+ #endif
686
+
687
+ #if defined(PJMEDIA_HAS_G722_CODEC) && PJMEDIA_HAS_G722_CODEC!=0
688
+ status = pjmedia_codec_g722_init(g_med_endpt);
689
+ if(status != PJ_SUCCESS)
690
+ {
691
+ addon_log(LOG_LEVEL_DEBUG, "pjmedia_codec_g722_init failed\n");
692
+ return 1;
693
+ }
694
+ #endif
695
+
696
+ status = pj_thread_register("main_thread", g_main_thread_descriptor, &g_main_thread);
697
+ if(status != PJ_SUCCESS)
698
+ {
699
+ addon_log(LOG_LEVEL_DEBUG, "pj_thread_register(main_thread) failed\n");
700
+ exit(1);
701
+ } else {
702
+ //addon_log(LOG_LEVEL_DEBUG, "pj_thread_register(main_thread) success\n");
703
+ ;
704
+ }
705
+
706
+ if(!start_digit_buffer_thread()) {
707
+ addon_log(LOG_LEVEL_DEBUG, "start_digit_buffer_thread() failed\n");
708
+ return 1;
709
+ }
710
+
711
+ return 0;
712
+ }
713
+
714
+ int __pjw_poll(char *out_evt){
715
+ if(!pj_thread_is_registered()) {
716
+ pj_status_t status;
717
+ status = pj_thread_register("poll_thread", g_poll_thread_descriptor, &g_poll_thread);
718
+ if(status != PJ_SUCCESS)
719
+ {
720
+ addon_log(LOG_LEVEL_DEBUG, "pj_thread_register(poll_thread) failed\n");
721
+ exit(1);
722
+ } else {
723
+ //addon_log(LOG_LEVEL_DEBUG, "pj_thread_register(poll_thread) success\n");
724
+ ;
725
+ }
726
+ }
727
+
728
+ string evt;
729
+ PJW_LOCK();
730
+ handle_events();
731
+ if(!g_events.empty()){
732
+ evt = g_events[0];
733
+ g_events.pop_front();
734
+ }
735
+ PJW_UNLOCK();
736
+ if(evt != "") {
737
+ strcpy(out_evt, evt.c_str());
738
+ return 0;
739
+ }
740
+ return -1;
741
+ }
742
+
743
+ pjsip_transport *allocate_udp_transport(pjsip_endpoint* sip_endpt, pj_str_t *ipaddr, int port) {
744
+ pj_status_t status;
745
+ pjsip_transport *transport;
746
+
747
+ pj_sockaddr addr;
748
+ pj_sockaddr_init(AF, &addr, ipaddr, port);
749
+
750
+ if (AF == pj_AF_INET()) {
751
+ status = pjsip_udp_transport_start( sip_endpt,
752
+ &addr.ipv4,
753
+ NULL,
754
+ 1, &transport);
755
+ } else if (AF == pj_AF_INET6()) {
756
+ status = pjsip_udp_transport_start6( sip_endpt,
757
+ &addr.ipv6,
758
+ NULL,
759
+ 1, &transport);
760
+ } else {
761
+ status = PJ_EAFNOTSUP;
762
+ }
763
+
764
+ if (status == PJ_SUCCESS) {
765
+ return transport;
766
+ }
767
+ return NULL;
768
+ }
769
+
770
+ pjsip_transport *create_udp_transport(pjsip_endpoint* sip_endpt, pj_str_t *ipaddr, int *allocated_port)
771
+ {
772
+ pj_status_t status;
773
+ pjsip_transport *transport;
774
+
775
+ int port = 5060;
776
+ for(int i=0 ; i<1000 ; ++i)
777
+ {
778
+ port += i;
779
+ transport = allocate_udp_transport(sip_endpt, ipaddr, port);
780
+ if (transport) {
781
+ *allocated_port = port;
782
+ return transport;
783
+ }
784
+ }
785
+
786
+ return NULL;
787
+ }
788
+
789
+ pjsip_tpfactory *allocate_tls_tpfactory(pjsip_endpoint* sip_endpt, pj_str_t *ipaddr, int port) {
790
+ addon_log(LOG_LEVEL_DEBUG, "allocate_tls_tpfactory ipaddr=%.*s port=%i\n", ipaddr->slen, ipaddr->ptr, port);
791
+ pj_status_t status;
792
+ pjsip_tpfactory *tpfactory;
793
+ pj_sockaddr local_addr;
794
+ pjsip_host_port a_name;
795
+
796
+ int af;
797
+ af = pj_AF_INET();
798
+ pj_sockaddr_init(af, &local_addr, NULL, 0);
799
+
800
+ pj_sockaddr_set_port(&local_addr, (pj_uint16_t)port);
801
+
802
+ status = pj_sockaddr_set_str_addr(af, &local_addr, ipaddr);
803
+ if (status != PJ_SUCCESS) {
804
+ return NULL;
805
+ }
806
+
807
+ pjsip_tls_setting tls_opt;
808
+ pjsip_tls_setting_default(&tls_opt);
809
+
810
+ status = pjsip_tls_transport_start2(sip_endpt, &tls_opt, &local_addr, NULL, 1, &tpfactory);
811
+ if (status != PJ_SUCCESS) {
812
+ addon_log(LOG_LEVEL_DEBUG, "status=%i\n", status);
813
+ return NULL;
814
+ }
815
+
816
+ return tpfactory;
817
+ }
818
+
819
+ pjsip_tpfactory *create_tls_tpfactory(pjsip_endpoint* sip_endpt, pj_str_t *ipaddr, int *allocated_port)
820
+ {
821
+ pj_status_t status;
822
+ pjsip_tpfactory *tpfactory;
823
+
824
+ int port = 6060;
825
+ for(int i=0 ; i<1000 ; ++i)
826
+ {
827
+ port += i;
828
+ tpfactory = allocate_tls_tpfactory(sip_endpt, ipaddr, port);
829
+ if (tpfactory) {
830
+ *allocated_port = port;
831
+ return tpfactory;
832
+ }
833
+ }
834
+
835
+ return NULL;
836
+ }
837
+
838
+ int pjw_transport_create(const char *sip_ipaddr, int port, pjsip_transport_type_e type, int *out_t_id, int *out_port)
839
+ {
840
+ PJW_LOCK();
841
+ clear_error();
842
+
843
+ pj_str_t ipaddr = pj_str((char*)sip_ipaddr);
844
+
845
+ pj_status_t status;
846
+ Transport *t = NULL;
847
+ long t_id;
848
+
849
+ if(type == PJSIP_TRANSPORT_UDP) {
850
+ pjsip_transport *sip_transport = NULL;
851
+
852
+ if(port != 0) {
853
+ sip_transport = allocate_udp_transport(g_sip_endpt, &ipaddr, port);
854
+ } else {
855
+ sip_transport = create_udp_transport(g_sip_endpt, &ipaddr, &port);
856
+ }
857
+
858
+ if(!sip_transport)
859
+ {
860
+ PJW_UNLOCK();
861
+ set_error("Unable to start UDP transport");
862
+ return -1;
863
+ }
864
+
865
+ t = new Transport;
866
+ t->type = PJSIP_TRANSPORT_UDP;
867
+ t->sip_transport = sip_transport;
868
+
869
+ if(!g_transport_ids.add((long)t, t_id)){
870
+ status = pjsip_udp_transport_pause(sip_transport,PJSIP_UDP_TRANSPORT_DESTROY_SOCKET);
871
+ //ToDo: log status
872
+
873
+ PJW_UNLOCK();
874
+ set_error("Failed to allocate id");
875
+ return -1;
876
+ }
877
+
878
+ if(type == PJSIP_TRANSPORT_UDP) {
879
+ g_SipTransportMap.insert(make_pair(sip_transport, t_id));
880
+ }
881
+
882
+ } else {
883
+ pjsip_tpfactory *tpfactory;
884
+ int af;
885
+
886
+
887
+ if(port != 0) {
888
+ tpfactory = allocate_tls_tpfactory(g_sip_endpt, &ipaddr, port);
889
+ } else {
890
+ tpfactory = create_tls_tpfactory(g_sip_endpt, &ipaddr, &port);
891
+ }
892
+
893
+ if(!tpfactory)
894
+ {
895
+ PJW_UNLOCK();
896
+ set_error("Unable to start TLS transport");
897
+ return -1;
898
+ }
899
+
900
+ t = new Transport;
901
+ t->type = PJSIP_TRANSPORT_TLS;
902
+ t->tpfactory = tpfactory;
903
+
904
+ if(!g_transport_ids.add((long)t, t_id)){
905
+ status = (tpfactory->destroy)(tpfactory);
906
+
907
+ PJW_UNLOCK();
908
+ set_error("Failed to allocate id");
909
+ return -1;
910
+ }
911
+
912
+ g_TlsTransportId = t_id;
913
+ }
914
+
915
+ t->id = t_id;
916
+
917
+ PJW_UNLOCK();
918
+
919
+ if(g_PacketDumper) {
920
+ g_PacketDumper->add_endpoint( inet_addr(sip_ipaddr), htons(port) );
921
+ }
922
+
923
+ *out_t_id = t_id;
924
+ *out_port = port;
925
+ return 0;
926
+ }
927
+
928
+ int pjw_transport_get_info(int t_id, char *out_sip_ipaddr, int *out_port)
929
+ {
930
+ PJW_LOCK();
931
+ clear_error();
932
+
933
+ long val;
934
+
935
+ if(!g_transport_ids.get(t_id, val)){
936
+ PJW_UNLOCK();
937
+ set_error("Invalid transport_id");
938
+ return -1;
939
+ }
940
+
941
+ Transport *t = (Transport*)val;
942
+
943
+ int port = t->sip_transport->local_name.port;
944
+ int len = t->sip_transport->local_name.host.slen;
945
+ char addr[100];
946
+ strncpy(out_sip_ipaddr, t->sip_transport->local_name.host.ptr, len);
947
+ out_sip_ipaddr[len] = 0;
948
+ *out_port = port;
949
+
950
+ PJW_UNLOCK();
951
+ return 0;
952
+ }
953
+
954
+ int pjw_account_create(int t_id, const char *domain, const char *server, const char *username, const char *password, const char *additional_headers, const char *c_to_url, int expires, int *out_acc_id)
955
+ {
956
+ //printf("domain=%s, server=%s, username=%s, password=%s, additional_headers=%s, c_to_url=%s expires=%u\n", domain, server, username, password, additional_headers, c_to_url, expires);
957
+ PJW_LOCK();
958
+ clear_error();
959
+
960
+ long val;
961
+
962
+ if(!g_transport_ids.get(t_id, val)){
963
+ PJW_UNLOCK();
964
+ set_error("Invalid transport id");
965
+ return -1;
966
+ }
967
+
968
+ Transport *t = (Transport*)val;
969
+
970
+ pj_status_t status;
971
+ pjsip_regc *regc;
972
+
973
+ status = pjsip_regc_create(g_sip_endpt, NULL, on_registration_status, &regc);
974
+ if(status != PJ_SUCCESS)
975
+ {
976
+ PJW_UNLOCK();
977
+ set_error("pjsip_regc_create failed");
978
+ return -1;
979
+ }
980
+
981
+ if(additional_headers) {
982
+ if(!add_additional_headers_for_account(regc, additional_headers)) {
983
+ PJW_UNLOCK();
984
+ set_error("add_additional_headers_for_account failed");
985
+ return -1;
986
+ }
987
+ }
988
+
989
+ long acc_id;
990
+ if(!g_account_ids.add((long)regc, acc_id)){
991
+ PJW_UNLOCK();
992
+ set_error("Failed to allocate id");
993
+ return -1;
994
+ }
995
+
996
+ int local_port;
997
+ int len;
998
+ char local_addr[100];
999
+ if(t->type == PJSIP_TRANSPORT_UDP) {
1000
+ local_port = t->sip_transport->local_name.port;
1001
+ len= t->sip_transport->local_name.host.slen;
1002
+ strncpy(local_addr, t->sip_transport->local_name.host.ptr, len);
1003
+ } else {
1004
+ local_port = t->tpfactory->addr_name.port;
1005
+ len= t->tpfactory->addr_name.host.slen;
1006
+ strncpy(local_addr, t->tpfactory->addr_name.host.ptr, len);
1007
+ }
1008
+ local_addr[len] = 0;
1009
+
1010
+ char temp[400];
1011
+ char *p = temp;
1012
+
1013
+ len = sprintf(p, "sip:%s", server);
1014
+ pj_str_t server_url = pj_str(p);
1015
+ p += len + 2;
1016
+
1017
+ len = sprintf(p, "<sip:%s@%s>", username, domain);
1018
+ pj_str_t from_url = pj_str(p);
1019
+ p += len + 2;
1020
+
1021
+ pj_str_t to_url = from_url;
1022
+
1023
+ if(c_to_url && c_to_url[0]) {
1024
+ to_url = pj_str((char*)c_to_url);
1025
+ }
1026
+
1027
+ if(expires <= 0) {
1028
+ expires = 60;
1029
+ }
1030
+
1031
+ len = sprintf(p, "sip:%s@%s:%u", username, local_addr, local_port);
1032
+ pj_str_t contact = pj_str(p);
1033
+ p += len + 2;
1034
+
1035
+ status = pjsip_regc_init(regc,
1036
+ &server_url,
1037
+ &from_url,
1038
+ &to_url,
1039
+ 1, &contact,
1040
+ expires);
1041
+ if(status != PJ_SUCCESS)
1042
+ {
1043
+ status = pjsip_regc_destroy(regc);
1044
+ //ToDo: log status
1045
+ PJW_UNLOCK();
1046
+ set_error("pjsip_regc_init failed");
1047
+ return -1;
1048
+ }
1049
+
1050
+ pjsip_cred_info cred;
1051
+ pj_bzero(&cred, sizeof(cred));
1052
+ cred.realm = pj_str("*");
1053
+ cred.scheme = pj_str("digest");
1054
+ cred.username = pj_str((char*)username);
1055
+ cred.data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
1056
+ cred.data = pj_str((char*)password);
1057
+ status = pjsip_regc_set_credentials(regc, 1, &cred);
1058
+ if(status != PJ_SUCCESS)
1059
+ {
1060
+ status = pjsip_regc_destroy(regc);
1061
+ //ToDo: log status
1062
+ PJW_UNLOCK();
1063
+ set_error("pjsip_regc_set_credentials failed");
1064
+ return -1;
1065
+ }
1066
+
1067
+ pjsip_tpselector sel;
1068
+ pj_bzero(&sel, sizeof(sel));
1069
+ if(t->type == PJSIP_TRANSPORT_UDP) {
1070
+ sel.type = PJSIP_TPSELECTOR_TRANSPORT;
1071
+ sel.u.transport = t->sip_transport;
1072
+ } else {
1073
+ sel.type = PJSIP_TPSELECTOR_LISTENER;
1074
+ sel.u.listener = t->tpfactory;
1075
+ }
1076
+
1077
+ status = pjsip_regc_set_transport(regc, &sel);
1078
+ if(status != PJ_SUCCESS)
1079
+ {
1080
+ status = pjsip_regc_destroy(regc);
1081
+ //ToDo: log status
1082
+ PJW_UNLOCK();
1083
+ set_error("pjsip_regc_set_transport failed");
1084
+ return -1;
1085
+ }
1086
+ PJW_UNLOCK();
1087
+ *out_acc_id = acc_id;
1088
+ return 0;
1089
+ }
1090
+
1091
+ int pjw_account_register(long acc_id, pj_bool_t autoreg)
1092
+ {
1093
+ PJW_LOCK();
1094
+ clear_error();
1095
+
1096
+ long val;
1097
+
1098
+ if(!g_account_ids.get(acc_id, val)){
1099
+ PJW_UNLOCK();
1100
+ set_error("Invalid account_id");
1101
+ return -1;
1102
+ }
1103
+
1104
+ pjsip_regc *regc = (pjsip_regc*)val;
1105
+
1106
+ pj_status_t status;
1107
+ pjsip_tx_data *tdata;
1108
+
1109
+ status = pjsip_regc_register(regc, autoreg, &tdata);
1110
+ if(status != PJ_SUCCESS)
1111
+ {
1112
+ PJW_UNLOCK();
1113
+ set_error("pjsip_regc_register failed");
1114
+ return -1;
1115
+ }
1116
+
1117
+ status = pjsip_regc_send(regc, tdata);
1118
+ if(status != PJ_SUCCESS)
1119
+ {
1120
+ PJW_UNLOCK();
1121
+ set_error("pjsip_regc_send failed");
1122
+ return -1;
1123
+ }
1124
+
1125
+ PJW_UNLOCK();
1126
+ return 0;
1127
+ }
1128
+
1129
+ int pjw_account_unregister(long acc_id)
1130
+ {
1131
+ PJW_LOCK();
1132
+ clear_error();
1133
+
1134
+ long val;
1135
+
1136
+ if(!g_account_ids.get(acc_id, val)){
1137
+ PJW_UNLOCK();
1138
+ set_error("Invalid account_id");
1139
+ return -1;
1140
+ }
1141
+
1142
+ pjsip_regc *regc = (pjsip_regc*)val;
1143
+
1144
+ pj_status_t status;
1145
+ pjsip_tx_data *tdata;
1146
+
1147
+ status = pjsip_regc_unregister(regc, &tdata);
1148
+ if(status != PJ_SUCCESS)
1149
+ {
1150
+ PJW_UNLOCK();
1151
+ set_error("pjsip_regc_unregister failed");
1152
+ return -1;
1153
+ }
1154
+
1155
+ status = pjsip_regc_send(regc, tdata);
1156
+ if(status != PJ_SUCCESS)
1157
+ {
1158
+ PJW_UNLOCK();
1159
+ set_error("pjsip_regc_send failed");
1160
+ return -1;
1161
+ }
1162
+
1163
+ PJW_UNLOCK();
1164
+ return 0;
1165
+ }
1166
+
1167
+ int pjw_call_respond(long call_id, int code, const char *reason, const char *additional_headers)
1168
+ {
1169
+ printf("pjw_call_respond: call_id=%i code=%i reason=%s additional_headers=%s\n", call_id, code, reason, additional_headers);
1170
+ PJW_LOCK();
1171
+
1172
+ long val;
1173
+
1174
+ if(!g_call_ids.get(call_id, val)){
1175
+ PJW_UNLOCK();
1176
+ set_error("Invalid call_id");
1177
+ return -1;
1178
+ }
1179
+
1180
+ Call *call = (Call*)val;
1181
+
1182
+ if(call->outgoing) {
1183
+ PJW_UNLOCK();
1184
+ set_error("You cannot respond an outgoing call");
1185
+ return -1;
1186
+ }
1187
+
1188
+ pj_str_t r = pj_str((char*)reason);
1189
+
1190
+ pj_status_t status;
1191
+
1192
+ pjsip_tx_data *tdata;
1193
+
1194
+ if(call->initial_invite_rdata) {
1195
+ status = pjsip_inv_initial_answer(call->inv, call->initial_invite_rdata,
1196
+ code,
1197
+ &r,
1198
+ NULL,
1199
+ &tdata);
1200
+ if(status != PJ_SUCCESS) {
1201
+ PJW_UNLOCK();
1202
+ set_error("pjsip_inv_initial_answer failed");
1203
+ return -1;
1204
+ }
1205
+
1206
+ status = pjsip_rx_data_free_cloned(call->initial_invite_rdata);
1207
+ if(status != PJ_SUCCESS) {
1208
+ PJW_UNLOCK();
1209
+ set_error("pjsip_rx_data_free_cloned failed");
1210
+ return -1;
1211
+ }
1212
+ call->initial_invite_rdata = 0;
1213
+ } else {
1214
+ status = pjsip_inv_answer(call->inv,
1215
+ code,
1216
+ &r,
1217
+ NULL,
1218
+ &tdata);
1219
+
1220
+ if(status != PJ_SUCCESS){
1221
+ PJW_UNLOCK();
1222
+ set_error("pjsip_inv_answer failed");
1223
+ return -1;
1224
+ }
1225
+
1226
+ if(!add_additional_headers(call->inv->dlg->pool, tdata, additional_headers)) {
1227
+ goto out;
1228
+ }
1229
+ }
1230
+
1231
+ status = pjsip_inv_send_msg(call->inv, tdata);
1232
+ if(status != PJ_SUCCESS){
1233
+ PJW_UNLOCK();
1234
+ set_error("pjsip_inv_send_msg failed");
1235
+ return -1;
1236
+ }
1237
+
1238
+ out:
1239
+ PJW_UNLOCK();
1240
+
1241
+ if(pjw_errorstring[0]) {
1242
+ return -1;
1243
+ }
1244
+
1245
+ return 0;
1246
+ }
1247
+
1248
+ int pjw_call_terminate(long call_id, int code, const char *reason, const char *additional_headers)
1249
+ {
1250
+ PJW_LOCK();
1251
+
1252
+ long val;
1253
+
1254
+ if(!g_call_ids.get(call_id, val)){
1255
+ PJW_UNLOCK();
1256
+ set_error("Invalid call_id");
1257
+ return -1;
1258
+ }
1259
+
1260
+ Call *call = (Call*)val;
1261
+
1262
+ pj_str_t r = pj_str((char*)reason);
1263
+
1264
+ pjsip_tx_data *tdata;
1265
+ pj_status_t status;
1266
+ status = pjsip_inv_end_session(call->inv,
1267
+ code,
1268
+ &r,
1269
+ &tdata);
1270
+ if(status != PJ_SUCCESS){
1271
+ PJW_UNLOCK();
1272
+ set_error("pjsip_inv_end_session failed");
1273
+ return -1;
1274
+ }
1275
+
1276
+ if(!tdata)
1277
+ {
1278
+ //if tdata was not set by pjsip_inv_end_session, it means we didn't receive any response yet (100 Trying) and we cannot send CANCEL in this situation. So we just can return here without calling pjsip_inv_send_msg.
1279
+ PJW_UNLOCK();
1280
+ return 0;
1281
+ }
1282
+
1283
+ if(!add_additional_headers(call->inv->dlg->pool, tdata, additional_headers)) {
1284
+ PJW_UNLOCK();
1285
+ set_error("add_additional_headers failed");
1286
+ return -1;
1287
+ }
1288
+
1289
+ status = pjsip_inv_send_msg(call->inv, tdata);
1290
+ if(status != PJ_SUCCESS){
1291
+ PJW_UNLOCK();
1292
+ set_error("pjsip_inv_send_msg failed");
1293
+ return -1;
1294
+ }
1295
+
1296
+ PJW_UNLOCK();
1297
+ return 0;
1298
+ }
1299
+
1300
+
1301
+ int pjw_call_create(long t_id, unsigned flags, const char *from_uri, const char *to_uri, const char *request_uri, const char *proxy_uri, const char *additional_headers, const char *realm, const char *username, const char *password, long *out_call_id, char *out_sip_call_id)
1302
+ {
1303
+ PJW_LOCK();
1304
+ clear_error();
1305
+
1306
+ int n;
1307
+ long val;
1308
+ Transport *t;
1309
+ char *start;
1310
+ char *end;
1311
+ char local_contact[400];
1312
+ char *p;
1313
+ int len;
1314
+ const char *contact_username = "sip";
1315
+ int call_id;
1316
+
1317
+
1318
+ pjsip_dialog *dlg;
1319
+
1320
+ if(!g_transport_ids.get(t_id, val)){
1321
+ set_error("Invalid transport_id");
1322
+ goto out;
1323
+ }
1324
+ t = (Transport*)val;
1325
+
1326
+ if(!check_uri(from_uri)) {
1327
+ set_error("Invalid from_uri");
1328
+ goto out;
1329
+ }
1330
+
1331
+ if(!check_uri(to_uri)) {
1332
+ set_error("Invalid to_uri");
1333
+ goto out;
1334
+ }
1335
+
1336
+ if(request_uri){
1337
+ if(request_uri[0]) {
1338
+ if(!check_uri(request_uri)) {
1339
+ set_error("Invalid request_uri");
1340
+ goto out;
1341
+ }
1342
+ } else {
1343
+ request_uri = to_uri;
1344
+ }
1345
+ }else{
1346
+ request_uri = to_uri;
1347
+ }
1348
+
1349
+ if(proxy_uri){
1350
+ if(proxy_uri[0]) {
1351
+ if(!check_uri(proxy_uri)) {
1352
+ set_error("Invalid proxy_uri");
1353
+ goto out;
1354
+ }
1355
+ }
1356
+ }
1357
+
1358
+ if(realm){
1359
+ if(!username || !password) {
1360
+ set_error("Incomplete credentials");
1361
+ goto out;
1362
+ }
1363
+ contact_username = username;
1364
+ }
1365
+
1366
+ if(t->type == PJSIP_TRANSPORT_UDP) {
1367
+ build_local_contact(local_contact, t->sip_transport, contact_username);
1368
+ } else {
1369
+ build_local_contact_from_tpfactory(local_contact, t->tpfactory, contact_username);
1370
+ }
1371
+
1372
+ if(!dlg_create(&dlg, t, from_uri, to_uri, request_uri, realm, username, password, local_contact)) {
1373
+ goto out;
1374
+ }
1375
+
1376
+ call_id = call_create(t, flags, dlg, proxy_uri, additional_headers);
1377
+ if(call_id < 0) {
1378
+ goto out;
1379
+ }
1380
+
1381
+ out:
1382
+ PJW_UNLOCK();
1383
+ if(pjw_errorstring[0]){
1384
+ return -1;
1385
+ }
1386
+
1387
+ *out_call_id = call_id;
1388
+ strncpy(out_sip_call_id, dlg->call_id->id.ptr, dlg->call_id->id.slen);
1389
+ out_sip_call_id[dlg->call_id->id.slen] = 0;
1390
+ return 0;
1391
+ }
1392
+
1393
+
1394
+ bool set_transport(pjsip_transport *sip_transport, pjsip_dialog *dlg) {
1395
+ //Maybe we don't need to allocation sel from the pool
1396
+ pjsip_tpselector *sel = (pjsip_tpselector*)pj_pool_zalloc(dlg->pool, sizeof(pjsip_tpselector));
1397
+ //pjsip_tpselector sel;
1398
+ //pj_bzero(&sel, sizeof(sel));
1399
+ sel->type = PJSIP_TPSELECTOR_TRANSPORT;
1400
+ sel->u.transport = sip_transport;
1401
+ pj_status_t status = pjsip_dlg_set_transport(dlg, sel);
1402
+ if(status != PJ_SUCCESS)
1403
+ {
1404
+ status = pjsip_dlg_terminate(dlg); //ToDo:
1405
+ set_error("pjsip_dlg_set_transport failed");
1406
+ return false;
1407
+ }
1408
+ return true;
1409
+ }
1410
+
1411
+ bool set_transport_by_t(Transport *t, pjsip_dialog *dlg) {
1412
+ //Maybe we don't need to allocation sel from the pool
1413
+ pjsip_tpselector *sel = (pjsip_tpselector*)pj_pool_zalloc(dlg->pool, sizeof(pjsip_tpselector));
1414
+ //pjsip_tpselector sel;
1415
+ //pj_bzero(&sel, sizeof(sel));
1416
+ if(t->type == PJSIP_TRANSPORT_UDP) {
1417
+ sel->type = PJSIP_TPSELECTOR_TRANSPORT;
1418
+ sel->u.transport = t->sip_transport;
1419
+ } else {
1420
+ sel->type = PJSIP_TPSELECTOR_LISTENER;
1421
+ sel->u.listener = t->tpfactory;
1422
+ }
1423
+ pj_status_t status = pjsip_dlg_set_transport(dlg, sel);
1424
+ if(status != PJ_SUCCESS)
1425
+ {
1426
+ status = pjsip_dlg_terminate(dlg); //ToDo:
1427
+ set_error("pjsip_dlg_set_transport failed");
1428
+ return false;
1429
+ }
1430
+ return true;
1431
+ }
1432
+
1433
+
1434
+ void build_local_contact(char *dest, pjsip_transport *t, const char *contact_username) {
1435
+ char *p = dest;
1436
+ int len;
1437
+ p += sprintf(p, "<sip:%s@", contact_username);
1438
+ len = t->local_name.host.slen;
1439
+ memcpy(p, t->local_name.host.ptr, len);
1440
+ p += len;
1441
+ if(t->local_name.port) {
1442
+ p += sprintf(p, ":%d",t->local_name.port);
1443
+ }
1444
+ if(t->key.type == PJSIP_TRANSPORT_UDP) {
1445
+ p += sprintf(p,">");
1446
+ } else {
1447
+ p += sprintf(p,";transport=tls>");
1448
+ }
1449
+ }
1450
+
1451
+ void build_local_contact_from_tpfactory(char *dest, pjsip_tpfactory *tpfactory, const char *contact_username) {
1452
+ char *p = dest;
1453
+ int len;
1454
+ p += sprintf(p, "<sip:%s@", contact_username);
1455
+ len = tpfactory->addr_name.host.slen;
1456
+ memcpy(p, tpfactory->addr_name.host.ptr, len);
1457
+ p += len;
1458
+ if(tpfactory->addr_name.port) {
1459
+ p += sprintf(p, ":%d",tpfactory->addr_name.port);
1460
+ }
1461
+ p += sprintf(p,";transport=tls>");
1462
+ }
1463
+
1464
+
1465
+ bool set_proxy(pjsip_dialog *dlg, const char *proxy_uri) {
1466
+ //Very important: although this function only requires dlg and the proxy_uri, it cannot be called before the function that creates the initial request is called. If we call pjsip_inv_create_uac after this function is called, assertion failure will happen. This is the reason why we didn't put the call to this function inside function dlg_create.
1467
+
1468
+ pj_status_t status;
1469
+
1470
+ if(!proxy_uri || !proxy_uri[0]) return true; //nothing to do proxy_uri was not set
1471
+
1472
+ //proxy_uri must contain ";lr".
1473
+ char *buf = (char*)pj_pool_zalloc(dlg->pool, 500);
1474
+ //char buf[500];
1475
+ strcpy(buf,proxy_uri);
1476
+ if(!strstr(proxy_uri,";lr")){
1477
+ strcat(buf,";lr");
1478
+ }
1479
+ //addon_log(LOG_LEVEL_DEBUG, ">>%s<<\n",buf);
1480
+
1481
+ // pjsip_route_hdr route_set;
1482
+ // pjsip_route_hdr *route;
1483
+ // const pj_str_t hname = { "Route", 5 };
1484
+
1485
+ pj_list_init(&route_set);
1486
+
1487
+ route = (pjsip_route_hdr*)pjsip_parse_hdr( dlg->pool, &hname,
1488
+ (char*)buf, strlen(buf),
1489
+ NULL);
1490
+ if(!route){
1491
+ status = pjsip_dlg_terminate(dlg); //ToDo:
1492
+ set_error("pjsip_parse_hdr failed");
1493
+ return false;
1494
+ }
1495
+
1496
+ pj_list_push_back(&route_set, route);
1497
+
1498
+ pjsip_dlg_set_route_set(dlg, &route_set);
1499
+
1500
+ return true;
1501
+ }
1502
+
1503
+
1504
+
1505
+ bool dlg_create(pjsip_dialog **dlg, Transport *transport, const char *from_uri, const char *to_uri, const char *request_uri, const char *realm, const char *username, const char *password, const char *local_contact) {
1506
+ //obs: local contact must exists in the stack somewhere. It cannot be allocated dynamically because we don't have a dlg nor a dlg->pool yet.
1507
+
1508
+ pj_status_t status;
1509
+ pjsip_dialog *p_dlg;
1510
+
1511
+ pj_str_t from = pj_str((char*)from_uri);
1512
+ pj_str_t to = pj_str((char*)to_uri);
1513
+ pj_str_t request = pj_str((char*)request_uri);
1514
+
1515
+ pj_str_t contact = pj_str((char*)local_contact);
1516
+
1517
+ status = pjsip_dlg_create_uac(pjsip_ua_instance(),
1518
+ &from,
1519
+ &contact,
1520
+ &to,
1521
+ &request,
1522
+ &p_dlg);
1523
+ if(status != PJ_SUCCESS) {
1524
+ set_error("pjsip_dlg_create_uac failed");
1525
+ return false;
1526
+ }
1527
+
1528
+ if(realm && realm[0]){
1529
+ pjsip_cred_info cred[1];
1530
+ cred[0].scheme = pj_str("digest");
1531
+ cred[0].realm = pj_str((char*)realm);
1532
+ cred[0].username = pj_str((char*)username);
1533
+ cred[0].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
1534
+ cred[0].data = pj_str((char*)password);
1535
+ status = pjsip_auth_clt_set_credentials(&p_dlg->auth_sess, 1, cred);
1536
+ if(status != PJ_SUCCESS) {
1537
+ status = pjsip_dlg_terminate(p_dlg); //ToDo:
1538
+ set_error("pjsip_auth_clt_set_credentials failed");
1539
+ return false;
1540
+ }
1541
+ }
1542
+
1543
+ return *dlg = p_dlg;
1544
+ }
1545
+
1546
+
1547
+ int call_create(Transport *t, unsigned flags, pjsip_dialog *dlg, const char *proxy_uri, const char *additional_headers)
1548
+ {
1549
+ pjsip_inv_session *inv;
1550
+ //in_addr addr;
1551
+ //addr.s_addr = t->local_addr.ipv4.sin_addr.s_addr;
1552
+ //pj_str_t str_addr = pj_str( inet_ntoa(addr) );
1553
+ in_addr in_a;
1554
+ if(t->type == PJSIP_TRANSPORT_UDP) {
1555
+ in_a = (in_addr&)t->sip_transport->local_addr.ipv4.sin_addr.s_addr;
1556
+ } else {
1557
+ in_a = (in_addr&)t->tpfactory->local_addr.ipv4.sin_addr.s_addr;
1558
+ }
1559
+
1560
+ pj_str_t str_addr = pj_str( inet_ntoa(in_a) );
1561
+ pjmedia_transport *med_transport = create_media_transport(&str_addr);
1562
+
1563
+ pj_status_t status;
1564
+
1565
+ if(!med_transport)
1566
+ {
1567
+ status = pjsip_dlg_terminate(dlg); //ToDo:
1568
+ set_error("create_media_transport failed");
1569
+ return -1;
1570
+ }
1571
+
1572
+ pjmedia_transport_info med_tpinfo;
1573
+ pjmedia_transport_info_init(&med_tpinfo);
1574
+ pjmedia_transport_get_info(med_transport, &med_tpinfo);
1575
+
1576
+ pjmedia_sdp_session *sdp = 0;
1577
+
1578
+ if(!(flags & CALL_FLAG_LATE_NEGOTIATION)) {
1579
+ status = pjmedia_endpt_create_sdp( g_med_endpt,
1580
+ dlg->pool,
1581
+ 1,
1582
+ &med_tpinfo.sock_info,
1583
+ &sdp);
1584
+ if(status != PJ_SUCCESS) {
1585
+ close_media_transport(med_transport);
1586
+ status = pjsip_dlg_terminate(dlg); //ToDo:
1587
+ set_error("pjmedia_endpt_create_sdp failed");
1588
+ return -1;
1589
+ }
1590
+ }
1591
+
1592
+ status = pjsip_inv_create_uac(dlg, sdp, 0, &inv);
1593
+ if(status != PJ_SUCCESS) {
1594
+ close_media_transport(med_transport);
1595
+ status = pjsip_dlg_terminate(dlg); //ToDo:
1596
+ set_error("pjsip_inv_create_uac failed");
1597
+ return -1;
1598
+ }
1599
+
1600
+ if(!set_proxy(dlg, proxy_uri)) {
1601
+ return -1;
1602
+ }
1603
+
1604
+ Call *call = (Call*)pj_pool_alloc(dlg->pool, sizeof(Call));
1605
+ pj_bzero(call, sizeof(Call));
1606
+
1607
+
1608
+ call->inv = inv;
1609
+ call->med_transport = med_transport;
1610
+
1611
+ long call_id;
1612
+ if(!g_call_ids.add((long)call, call_id)){
1613
+ close_media_transport(med_transport);
1614
+ status = pjsip_dlg_terminate(dlg); //ToDo:
1615
+ set_error("Failed to allocate id");
1616
+ return -1;
1617
+ }
1618
+ call->transport = t;
1619
+ call->id = call_id;
1620
+ pjsip_tx_data *tdata;
1621
+ status = pjsip_inv_invite(inv, &tdata);
1622
+ if(status != PJ_SUCCESS) {
1623
+ g_call_ids.remove(call_id, (long &)call);
1624
+ close_media_transport(med_transport);
1625
+ status = pjsip_dlg_terminate(dlg); //ToDo:
1626
+ set_error("pjsip_inv_invite failed");
1627
+ return -1;
1628
+ }
1629
+
1630
+
1631
+
1632
+ if(!add_additional_headers(dlg->pool, tdata, additional_headers)) {
1633
+ g_call_ids.remove(call_id, (long &)call);
1634
+ close_media_transport(med_transport); //Todo:
1635
+ status = pjsip_dlg_terminate(dlg); //ToDo:
1636
+ return -1;
1637
+ }
1638
+
1639
+ if(!set_transport_by_t(t, dlg)){
1640
+ return -1;
1641
+ }
1642
+ addon_log(LOG_LEVEL_DEBUG, "inv=%x tdata=%x\n",inv,tdata);
1643
+
1644
+ status = pjsip_inv_send_msg(inv, tdata);
1645
+ addon_log(LOG_LEVEL_DEBUG, "status=%d\n",status);
1646
+ pj_perror(0, "", status, "");
1647
+ if(status != PJ_SUCCESS) {
1648
+ g_call_ids.remove(call_id, (long &)call);
1649
+ close_media_transport(med_transport); //Todo:
1650
+ //The below code cannot be called here it will cause seg fault
1651
+ //status = pjsip_dlg_terminate(dlg); //ToDo:
1652
+ set_error("pjsip_inv_send_msg failed");
1653
+ return -1;
1654
+ }
1655
+
1656
+ //Without this, on_rx_response will not be called
1657
+ status = pjsip_dlg_add_usage(dlg, &mod_tester, call);
1658
+ if(status != PJ_SUCCESS) {
1659
+ g_call_ids.remove(call_id, (long &)call);
1660
+ close_media_transport(med_transport); //Todo:
1661
+ status = pjsip_dlg_terminate(dlg); //ToDo:
1662
+ set_error("pjsip_dlg_add_usage failed");
1663
+ return -1;
1664
+ }
1665
+ //addon_log(LOG_LEVEL_DEBUG, "pjsip_dlg_add_usage OK\n");
1666
+
1667
+ call->outgoing = true;
1668
+
1669
+ return call_id;
1670
+ }
1671
+
1672
+ int pjw_call_send_dtmf(long call_id, const char *digits, int mode)
1673
+ {
1674
+ #define ON_DURATION 200
1675
+ #define OFF_DURATION 50
1676
+
1677
+ #define MAX_LENGTH 31 // pjsip allows for 31 digits (inband allows for 32 digits)
1678
+
1679
+ PJW_LOCK();
1680
+ int len = strlen(digits);
1681
+
1682
+ if(mode != DTMF_MODE_RFC2833 && mode != DTMF_MODE_INBAND) {
1683
+ PJW_UNLOCK();
1684
+ set_error("Invalid DTMF mode");
1685
+ return -1;
1686
+ }
1687
+
1688
+ if(len > MAX_LENGTH) {
1689
+ set_error("DTMF list too long");
1690
+ return -1;
1691
+ }
1692
+
1693
+ long val;
1694
+
1695
+ if(!g_call_ids.get(call_id, val)){
1696
+ PJW_UNLOCK();
1697
+ set_error("Invalid call_id");
1698
+ return -1;
1699
+ }
1700
+
1701
+ Call *call = (Call*)val;
1702
+
1703
+ if(!call->med_stream)
1704
+ {
1705
+ PJW_UNLOCK();
1706
+ set_error("Unable to send DTMF: Media not ready");
1707
+ return -1;
1708
+ }
1709
+
1710
+ char adjusted_digits[MAX_LENGTH+1]; // use the greater size
1711
+
1712
+ for(int i=0; i<len ; ++i) {
1713
+ if( !(digits[i] >= '0' && digits[i] <= '9') &&
1714
+ !(digits[i] >= 'a' && digits[i] <= 'f') &&
1715
+ !(digits[i] >= 'A' && digits[i] <= 'F') &&
1716
+ !(digits[i] == '*') &&
1717
+ !(digits[i] == '#') )
1718
+ {
1719
+ PJW_UNLOCK();
1720
+ set_error("Invalid character");
1721
+ return -1;
1722
+ }
1723
+ char d = digits[i];
1724
+ if(d == 'e' || d == 'E') {
1725
+ adjusted_digits[i] = '*';
1726
+ } else if(d == 'f' || d == 'F') {
1727
+ adjusted_digits[i] = '#';
1728
+ } else {
1729
+ adjusted_digits[i] = (char)tolower(d);
1730
+ }
1731
+ }
1732
+ adjusted_digits[len] = 0;
1733
+ //addon_log(LOG_LEVEL_DEBUG, ">>%s<<\n", adjusted_digits);
1734
+
1735
+ pj_str_t ds = pj_str((char*)adjusted_digits);
1736
+ pj_status_t status;
1737
+
1738
+ if(DTMF_MODE_RFC2833 == mode) {
1739
+ status = pjmedia_stream_dial_dtmf(call->med_stream, &ds);
1740
+ if(status != PJ_SUCCESS)
1741
+ {
1742
+ PJW_UNLOCK();
1743
+ set_error("pjmedia_stream_dial_dtmf failed.");
1744
+ return -1;
1745
+ }
1746
+ } else {
1747
+ if(!prepare_tonegen(call)) {
1748
+ PJW_UNLOCK();
1749
+ set_error("prepare_tonegen failed.");
1750
+ return -1;
1751
+ }
1752
+
1753
+ for(int i=0; i<len ; ++i) {
1754
+ pjmedia_tone_digit tone;
1755
+ tone.digit = adjusted_digits[i];
1756
+ tone.on_msec = ON_DURATION;
1757
+ tone.off_msec = OFF_DURATION;
1758
+ tone.volume = 0;
1759
+ status = chainlink_tonegen_play_digits((pjmedia_port*)call->tonegen, 1, &tone, 0);
1760
+ if(status != PJ_SUCCESS) {
1761
+ PJW_UNLOCK();
1762
+ set_error("chainlink_tonegen_play_digits failed.");
1763
+ return -1;
1764
+ }
1765
+ }
1766
+ }
1767
+
1768
+ PJW_UNLOCK();
1769
+ return 0;
1770
+ }
1771
+
1772
+ int pjw_call_reinvite(long call_id, int hold, unsigned flags)
1773
+ {
1774
+ PJW_LOCK();
1775
+
1776
+ long val;
1777
+
1778
+ if(!g_call_ids.get(call_id, val)){
1779
+ PJW_UNLOCK();
1780
+ set_error("Invalid call_id");
1781
+ return -1;
1782
+ }
1783
+
1784
+ Call *call = (Call*)val;
1785
+
1786
+ pj_status_t status;
1787
+
1788
+ pjmedia_sdp_session *sdp = 0;
1789
+
1790
+ call->local_hold = hold;
1791
+
1792
+ if(!(flags & CALL_FLAG_LATE_NEGOTIATION)) {
1793
+ pjmedia_transport_info tpinfo;
1794
+ pjmedia_transport_info_init(&tpinfo);
1795
+ pjmedia_transport_get_info(call->med_transport,&tpinfo);
1796
+
1797
+ status = pjmedia_endpt_create_sdp(g_med_endpt,
1798
+ call->inv->pool,
1799
+ 1,
1800
+ &tpinfo.sock_info,
1801
+ &sdp);
1802
+ if(status != PJ_SUCCESS){
1803
+ PJW_UNLOCK();
1804
+ set_error("pjmedia_endpt_create_sdp failed");
1805
+ return -1;
1806
+ }
1807
+
1808
+ pjmedia_sdp_attr *attr;
1809
+
1810
+ pjmedia_sdp_media_remove_all_attr(sdp->media[0], "sendrecv");
1811
+ pjmedia_sdp_media_remove_all_attr(sdp->media[0], "sendonly");
1812
+ pjmedia_sdp_media_remove_all_attr(sdp->media[0], "recvonly");
1813
+ pjmedia_sdp_media_remove_all_attr(sdp->media[0], "inactive");
1814
+
1815
+ if(call->local_hold){
1816
+ if(call->remote_hold) {
1817
+ attr = pjmedia_sdp_attr_create(call->inv->pool, "inactive", NULL);
1818
+ } else {
1819
+ attr = pjmedia_sdp_attr_create(call->inv->pool, "sendonly", NULL);
1820
+ }
1821
+ } else if(call->remote_hold) {
1822
+ attr = pjmedia_sdp_attr_create(call->inv->pool, "recvonly", NULL);
1823
+ } else {
1824
+ attr = pjmedia_sdp_attr_create(call->inv->pool, "sendrecv", NULL);
1825
+ }
1826
+
1827
+ pjmedia_sdp_media_add_attr(sdp->media[0], attr);
1828
+
1829
+ const pjmedia_sdp_session *old_sdp = NULL;
1830
+
1831
+ status = pjmedia_sdp_neg_get_active_local(call->inv->neg, &old_sdp);
1832
+ if (status != PJ_SUCCESS || old_sdp == NULL){
1833
+ PJW_UNLOCK();
1834
+ set_error("pjmedia_sdp_neg_get_active failed");
1835
+ return -1;
1836
+ }
1837
+
1838
+ sdp->origin.version = old_sdp->origin.version + 1;
1839
+ }
1840
+
1841
+ pjsip_tx_data *tdata;
1842
+ status = pjsip_inv_reinvite(call->inv, NULL, sdp, &tdata);
1843
+ if(status != PJ_SUCCESS){
1844
+ PJW_UNLOCK();
1845
+ set_error("pjsip_inv_reinvite failed");
1846
+ return -1;
1847
+ }
1848
+
1849
+ status = pjsip_inv_send_msg(call->inv, tdata);
1850
+ if(status != PJ_SUCCESS){
1851
+ PJW_UNLOCK();
1852
+ set_error("pjsip_inv_send_msg failed");
1853
+ return -1;
1854
+ }
1855
+
1856
+ PJW_UNLOCK();
1857
+ return 0;
1858
+ }
1859
+
1860
+ //To send INFO and other requests inside dialog
1861
+ int pjw_call_send_request(long call_id, const char *method_name, const char *additional_headers, const char *body, const char *ct_type, const char *ct_subtype)
1862
+ {
1863
+ PJW_LOCK();
1864
+ clear_error();
1865
+
1866
+ pj_str_t s_method_name;
1867
+ pjsip_tx_data *tdata;
1868
+ pj_status_t status;
1869
+ pjsip_method method;
1870
+
1871
+ pjsip_msg_body *msg_body;
1872
+
1873
+ pj_str_t s_ct_type;
1874
+ pj_str_t s_ct_subtype;
1875
+ pj_str_t s_body;
1876
+
1877
+ Call *call = NULL;
1878
+
1879
+ long val;
1880
+
1881
+ if(!g_call_ids.get(call_id, val)){
1882
+ set_error("Invalid call_id");
1883
+ goto out;
1884
+ }
1885
+
1886
+ call = (Call*)val;
1887
+
1888
+ if(strcmp(method_name,"INVITE")==0 || strcmp(method_name,"UPDATE")==0 || strcmp(method_name,"PRACK")==0 || strcmp(method_name,"BYE")==0) {
1889
+ set_error("Invalid method");
1890
+ goto out;
1891
+ }
1892
+
1893
+ if(body) {
1894
+ if(!ct_type || !ct_subtype) {
1895
+ set_error("If a body is specified, you must pass ct_type (Content-Type type) and ct_subtype (Content-Type subtype)");
1896
+ goto out;
1897
+ }
1898
+ }
1899
+
1900
+ s_method_name = pj_str((char*)method_name);
1901
+
1902
+ pjsip_method_init_np(&method, &s_method_name);
1903
+
1904
+ status = pjsip_dlg_create_request(call->inv->dlg, &method, -1, &tdata);
1905
+ if (status != PJ_SUCCESS) {
1906
+ set_error("pjsip_dlg_create_request failed");
1907
+ goto out;
1908
+ }
1909
+
1910
+ if(!add_additional_headers(call->inv->dlg->pool, tdata, additional_headers)) {
1911
+ goto out;
1912
+ }
1913
+
1914
+ if(body && body[0]) {
1915
+ s_ct_type = pj_str((char*)ct_type);
1916
+ s_ct_subtype = pj_str((char*)ct_subtype);
1917
+ s_body = pj_str((char*)body);
1918
+
1919
+ msg_body = pjsip_msg_body_create(tdata->pool, &s_ct_type, &s_ct_subtype, &s_body);
1920
+
1921
+ if(!msg_body) {
1922
+ set_error("pjsip_msg_body_create failed");
1923
+ goto out;
1924
+ }
1925
+ tdata->msg->body = msg_body;
1926
+ }
1927
+
1928
+ status = pjsip_dlg_send_request(call->inv->dlg, tdata, -1, NULL);
1929
+ if (status != PJ_SUCCESS) {
1930
+ set_error("pjsip_dlg_send_request failed");
1931
+ goto out;
1932
+ }
1933
+
1934
+ PJW_UNLOCK();
1935
+ return 0;
1936
+
1937
+ out:
1938
+ PJW_UNLOCK();
1939
+
1940
+ if(pjw_errorstring[0]) {
1941
+ return -1;
1942
+ }
1943
+ return 0;
1944
+
1945
+ }
1946
+
1947
+ int pjw_call_start_record_wav(long call_id, const char *file)
1948
+ {
1949
+ PJW_LOCK();
1950
+
1951
+ long val;
1952
+
1953
+ if(!g_call_ids.get(call_id, val)){
1954
+ PJW_UNLOCK();
1955
+ set_error("Invalid call_id");
1956
+ return -1;
1957
+ }
1958
+
1959
+ Call *call = (Call*)val;
1960
+
1961
+ if(!call->med_stream)
1962
+ {
1963
+ PJW_UNLOCK();
1964
+ set_error("Media not ready");
1965
+ return -1;
1966
+ }
1967
+
1968
+ pj_status_t status;
1969
+
1970
+ pjmedia_port *stream_port;
1971
+ status = pjmedia_stream_get_port(call->med_stream,
1972
+ &stream_port);
1973
+ if(status != PJ_SUCCESS)
1974
+ {
1975
+ PJW_UNLOCK();
1976
+ set_error("pjmedia_stream_get_port failed");
1977
+ return -1;
1978
+ }
1979
+
1980
+ if(!prepare_wav_writer(call, file)) {
1981
+ PJW_UNLOCK();
1982
+ set_error("prepare_wav_writer failed");
1983
+ return -1;
1984
+ }
1985
+
1986
+ PJW_UNLOCK();
1987
+ return 0;
1988
+ }
1989
+
1990
+
1991
+ int pjw_call_start_play_wav(long call_id, const char *file)
1992
+ {
1993
+ PJW_LOCK();
1994
+
1995
+ long val;
1996
+
1997
+ if(!g_call_ids.get(call_id, val)){
1998
+ PJW_UNLOCK();
1999
+ set_error("Invalid call_id");
2000
+ return -1;
2001
+ }
2002
+
2003
+ Call *call = (Call*)val;
2004
+
2005
+ if(!call->med_stream)
2006
+ {
2007
+ PJW_UNLOCK();
2008
+ set_error("Media not ready");
2009
+ return -1;
2010
+ }
2011
+
2012
+ pj_status_t status;
2013
+
2014
+ pjmedia_port *stream_port;
2015
+ status = pjmedia_stream_get_port(call->med_stream,
2016
+ &stream_port);
2017
+ if(status != PJ_SUCCESS)
2018
+ {
2019
+ PJW_UNLOCK();
2020
+ set_error("pjmedia_stream_get_port failed");
2021
+ return -1;
2022
+ }
2023
+
2024
+ if(!prepare_wav_player(call, file)){
2025
+ PJW_UNLOCK();
2026
+ set_error("pjmedia_wav_player_port_create failed");
2027
+ return -1;
2028
+ }
2029
+
2030
+ PJW_UNLOCK();
2031
+ return 0;
2032
+ }
2033
+
2034
+ int pjw_call_stop_play_wav(long call_id)
2035
+ {
2036
+ PJW_LOCK();
2037
+
2038
+ long val;
2039
+
2040
+ if(!g_call_ids.get(call_id, val)){
2041
+ PJW_UNLOCK();
2042
+ set_error("Invalid call_id");
2043
+ return -1;
2044
+ }
2045
+
2046
+ Call *call = (Call*)val;
2047
+
2048
+ pjmedia_port *stream_port;
2049
+ pj_status_t status;
2050
+ status = pjmedia_stream_get_port(call->med_stream,
2051
+ &stream_port);
2052
+ if(status != PJ_SUCCESS) {
2053
+ PJW_UNLOCK();
2054
+ set_error("pjmedia_stream_get_port failed.");
2055
+ return -1;
2056
+ }
2057
+
2058
+ if(!prepare_wire(call->inv->pool, &call->wav_player, PJMEDIA_PIA_SRATE(&stream_port->info), PJMEDIA_PIA_CCNT(&stream_port->info), PJMEDIA_PIA_SPF(&stream_port->info), PJMEDIA_PIA_BITS(&stream_port->info))) {
2059
+ PJW_UNLOCK();
2060
+ set_error("prepare_wire failed.");
2061
+ return -1;
2062
+ }
2063
+
2064
+ connect_media_ports(call);
2065
+
2066
+ PJW_UNLOCK();
2067
+ return 0;
2068
+ }
2069
+
2070
+ int pjw_call_stop_record_wav(long call_id)
2071
+ {
2072
+ PJW_LOCK();
2073
+
2074
+ long val;
2075
+
2076
+ if(!g_call_ids.get(call_id, val)){
2077
+ PJW_UNLOCK();
2078
+ set_error("Invalid call_id");
2079
+ return -1;
2080
+ }
2081
+
2082
+ Call *call = (Call*)val;
2083
+
2084
+ pjmedia_port *stream_port;
2085
+ pj_status_t status;
2086
+ status = pjmedia_stream_get_port(call->med_stream,
2087
+ &stream_port);
2088
+ if(status != PJ_SUCCESS) {
2089
+ PJW_UNLOCK();
2090
+ set_error("pjmedia_stream_get_port failed.");
2091
+ return -1;
2092
+ }
2093
+
2094
+ if(!prepare_wire(call->inv->pool, &call->wav_writer, PJMEDIA_PIA_SRATE(&stream_port->info), PJMEDIA_PIA_CCNT(&stream_port->info), PJMEDIA_PIA_SPF(&stream_port->info), PJMEDIA_PIA_BITS(&stream_port->info))) {
2095
+ PJW_UNLOCK();
2096
+ set_error("prepare_wire failed.");
2097
+ return -1;
2098
+ }
2099
+
2100
+ connect_media_ports(call);
2101
+
2102
+ PJW_UNLOCK();
2103
+ return 0;
2104
+ }
2105
+
2106
+ int pjw_call_get_stream_stat(long call_id, char *out_stats){
2107
+ PJW_LOCK();
2108
+
2109
+ long val;
2110
+
2111
+ if(!g_call_ids.get(call_id, val)){
2112
+ PJW_UNLOCK();
2113
+ set_error("Invalid call_id");
2114
+ return -1;
2115
+ }
2116
+
2117
+ Call *call = (Call*)val;
2118
+
2119
+ if(!call->med_stream){
2120
+ PJW_UNLOCK();
2121
+ set_error("Could not get stream stats. No media session");
2122
+ return -1;
2123
+ }
2124
+
2125
+ pj_status_t status;
2126
+
2127
+ pjmedia_rtcp_stat stat;
2128
+ pjmedia_port *port;
2129
+
2130
+ status = pjmedia_stream_get_stat(call->med_stream, &stat);
2131
+ if(status != PJ_SUCCESS){
2132
+ PJW_UNLOCK();
2133
+ set_error("Could not get stream stats. Call to pjmedia_stream_get_stream_stat failed.");
2134
+ return -1;
2135
+ }
2136
+
2137
+ status = pjmedia_stream_get_port(call->med_stream, &port);
2138
+ if(status != PJ_SUCCESS){
2139
+ PJW_UNLOCK();
2140
+ set_error("Could not get stream stats. Call to pjmedia_stream_get_port failed.");
2141
+ return -1;
2142
+ }
2143
+
2144
+ ostringstream oss;
2145
+ build_stream_stat(oss, &stat, port);
2146
+
2147
+ PJW_UNLOCK();
2148
+
2149
+ strcpy(out_stats, oss.str().c_str());
2150
+ return 0;
2151
+ }
2152
+
2153
+
2154
+ static void on_media_update( pjsip_inv_session *inv, pj_status_t status){
2155
+ addon_log(LOG_LEVEL_DEBUG, "on_media_update\n");
2156
+ char evt[256];
2157
+
2158
+ if(g_shutting_down) return;
2159
+
2160
+ Call *call = (Call*)inv->dlg->mod_data[mod_tester.id];
2161
+
2162
+ long call_id;
2163
+ if( !g_call_ids.get_id((long)call, call_id) ){
2164
+ addon_log(LOG_LEVEL_DEBUG, "on_media_update: Failed to get call_id. Event will not be notified.\n");
2165
+ return;
2166
+ }
2167
+
2168
+ pjmedia_stream_info stream_info;
2169
+ const pjmedia_sdp_session *local_sdp;
2170
+ const pjmedia_sdp_session *remote_sdp;
2171
+
2172
+ ostringstream oss;
2173
+
2174
+ if(status != PJ_SUCCESS){
2175
+ make_evt_media_status(evt, sizeof(evt), call_id, "negotiation_failed", "", "");
2176
+ dispatch_event(evt);
2177
+ return;
2178
+ }
2179
+
2180
+ if(call->master_port){
2181
+ status = pjmedia_master_port_stop(call->master_port);
2182
+ if(status != PJ_SUCCESS){
2183
+ make_evt_media_status(evt, sizeof(evt), call_id, "setup_failed", "", "");
2184
+ dispatch_event(evt);
2185
+ return;
2186
+ }
2187
+ }
2188
+
2189
+ status = pjmedia_sdp_neg_get_active_local(inv->neg, &local_sdp);
2190
+ if(status != PJ_SUCCESS){
2191
+ make_evt_media_status(evt, sizeof(evt), call_id, "setup_failed", "", "");
2192
+ dispatch_event(evt);
2193
+ return;
2194
+ }
2195
+
2196
+ status = pjmedia_sdp_neg_get_active_remote(inv->neg, &remote_sdp);
2197
+ if(status != PJ_SUCCESS){
2198
+ make_evt_media_status(evt, sizeof(evt), call_id, "setup_failed", "", "");
2199
+ dispatch_event(evt);
2200
+ return;
2201
+ }
2202
+
2203
+ status = pjmedia_stream_info_from_sdp(
2204
+ &stream_info,
2205
+ inv->dlg->pool,
2206
+ g_med_endpt,
2207
+ local_sdp,
2208
+ remote_sdp,
2209
+ 0);
2210
+ if(status != PJ_SUCCESS){
2211
+ make_evt_media_status(evt, sizeof(evt), call_id, "setup_failed", "", "");
2212
+ dispatch_event(evt);
2213
+ return;
2214
+ }
2215
+
2216
+ if(call->med_stream){
2217
+ status = pjmedia_stream_destroy(call->med_stream);
2218
+ if(status != PJ_SUCCESS){
2219
+ make_evt_media_status(evt, sizeof(evt), call_id, "setup_failed", "", "");
2220
+ dispatch_event(evt);
2221
+ return;
2222
+ }
2223
+ }
2224
+
2225
+ status = pjmedia_stream_create(
2226
+ g_med_endpt,
2227
+ inv->dlg->pool,
2228
+ &stream_info,
2229
+ call->med_transport,
2230
+ NULL,
2231
+ &call->med_stream);
2232
+ if(status != PJ_SUCCESS){
2233
+ make_evt_media_status(evt, sizeof(evt), call_id, "setup_failed", "", "");
2234
+ dispatch_event(evt);
2235
+ return;
2236
+ }
2237
+
2238
+ status = pjmedia_stream_start(call->med_stream);
2239
+ if(status != PJ_SUCCESS){
2240
+ make_evt_media_status(evt, sizeof(evt), call_id, "setup_failed", "", "");
2241
+ dispatch_event(evt);
2242
+ return;
2243
+ }
2244
+
2245
+ status = pjmedia_stream_set_dtmf_callback(call->med_stream,
2246
+ &on_dtmf,
2247
+ call);
2248
+ if(status != PJ_SUCCESS){
2249
+ make_evt_media_status(evt, sizeof(evt), call_id, "setup_failed", "", "");
2250
+ dispatch_event(evt);
2251
+ return;
2252
+ }
2253
+
2254
+ pjmedia_port *stream_port;
2255
+ status = pjmedia_stream_get_port(call->med_stream, &stream_port);
2256
+ if(status != PJ_SUCCESS){
2257
+ make_evt_media_status(evt, sizeof(evt), call_id, "setup_failed", "", "");
2258
+ dispatch_event(evt);
2259
+ return;
2260
+ }
2261
+
2262
+ if(!init_media_ports(call,
2263
+ PJMEDIA_PIA_SRATE(&stream_port->info),
2264
+ PJMEDIA_PIA_CCNT(&stream_port->info),
2265
+ PJMEDIA_PIA_SPF(&stream_port->info),
2266
+ PJMEDIA_PIA_BITS(&stream_port->info))) {
2267
+ make_evt_media_status(evt, sizeof(evt), call_id, "setup_failed", "", "");
2268
+ dispatch_event(evt);
2269
+ return;
2270
+ }
2271
+
2272
+ if(!set_ports(call, stream_port, (pjmedia_port*)call->dtmfdet))
2273
+ {
2274
+ make_evt_media_status(evt, sizeof(evt), call_id, "setup_failed", "", "");
2275
+ dispatch_event(evt);
2276
+ return;
2277
+ }
2278
+
2279
+ int local_media_mode = get_media_mode(local_sdp->media[0]->attr, local_sdp->media[0]->attr_count);
2280
+ int remote_media_mode = get_media_mode(remote_sdp->media[0]->attr, remote_sdp->media[0]->attr_count);
2281
+
2282
+ char *local_mode = get_media_mode_str(local_media_mode);
2283
+ char *remote_mode = get_media_mode_str(remote_media_mode);
2284
+
2285
+ make_evt_media_status(evt, sizeof(evt), call_id, "setup_ok", local_mode, remote_mode);
2286
+ dispatch_event(evt);
2287
+ }
2288
+
2289
+ static pj_bool_t set_ports(Call *call, pjmedia_port *stream_port, pjmedia_port *media_port)
2290
+ {
2291
+ pj_status_t status;
2292
+
2293
+ if(!call->master_port)
2294
+ {
2295
+ status = pjmedia_master_port_create(call->inv->pool,
2296
+ stream_port,
2297
+ media_port,
2298
+ 0,
2299
+ &call->master_port);
2300
+ if(status != PJ_SUCCESS){
2301
+ return PJ_FALSE;
2302
+ }
2303
+
2304
+ status = pjmedia_master_port_start(call->master_port);
2305
+ if(status != PJ_SUCCESS){
2306
+ return PJ_FALSE;
2307
+ }
2308
+
2309
+ call->media_port = media_port;
2310
+ return PJ_TRUE;
2311
+ }
2312
+
2313
+ status = pjmedia_master_port_stop(call->master_port);
2314
+ if(status != PJ_SUCCESS){
2315
+ return PJ_FALSE;
2316
+ }
2317
+
2318
+ status = pjmedia_master_port_set_uport(call->master_port,
2319
+ stream_port);
2320
+ if(status != PJ_SUCCESS){
2321
+ return PJ_FALSE;
2322
+ }
2323
+
2324
+ if(call->media_port)
2325
+ {
2326
+ if(call->media_port != media_port){
2327
+ status = pjmedia_port_destroy(call->media_port);
2328
+ if(status != PJ_SUCCESS){
2329
+ return PJ_FALSE;
2330
+ }
2331
+ }
2332
+ call->media_port = NULL;
2333
+ }
2334
+
2335
+ status = pjmedia_master_port_set_dport(call->master_port,
2336
+ media_port);
2337
+ if(status != PJ_SUCCESS){
2338
+ return PJ_FALSE;
2339
+ }
2340
+
2341
+ call->media_port = media_port;
2342
+
2343
+ status = pjmedia_master_port_start(call->master_port);
2344
+ if(status != PJ_SUCCESS){
2345
+ return PJ_FALSE;
2346
+ }
2347
+
2348
+ return PJ_TRUE;
2349
+ }
2350
+
2351
+ static void on_state_changed( pjsip_inv_session *inv,
2352
+ pjsip_event *e){
2353
+ addon_log(LOG_LEVEL_DEBUG, "on_state_changed\n");
2354
+
2355
+ // The below is just to document know-how for future improvements
2356
+ /*
2357
+ addon_log(LOG_LEVEL_DEBUG, "on_state_changed e->type=%i\n", e->type);
2358
+ if(e->type == PJSIP_EVENT_TSX_STATE && e->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
2359
+ // Read http://trac.pjsip.org/repos/wiki/SIP_Message_Buffer_Event
2360
+ addon_log(LOG_LEVEL_DEBUG, "Msg=%s\n", e->body.tsx_state.src.rdata->msg_info.msg_buf);
2361
+ }
2362
+ */
2363
+
2364
+ if(g_shutting_down) return;
2365
+
2366
+ if(PJSIP_INV_STATE_DISCONNECTED == inv->state)
2367
+ {
2368
+ Call *call = (Call*)inv->dlg->mod_data[mod_tester.id];
2369
+ //addon_log(LOG_LEVEL_DEBUG, "call will terminate call=%x\n",call);
2370
+ pj_status_t status;
2371
+
2372
+ long call_id;
2373
+ if( !g_call_ids.get_id((long)call, call_id) ){
2374
+ addon_log(LOG_LEVEL_DEBUG, "on_state_changed: Failed to get call_id. Event will not be notified.\n");
2375
+ return;
2376
+ }
2377
+
2378
+ if(call->master_port)
2379
+ {
2380
+ status = pjmedia_master_port_stop(call->master_port);
2381
+ if(status != PJ_SUCCESS)
2382
+ {
2383
+ addon_log(LOG_LEVEL_DEBUG, "pjmedia_master_port_stop failed\n");
2384
+ }
2385
+
2386
+ status = pjmedia_master_port_destroy(call->master_port, PJ_FALSE);
2387
+ if(status != PJ_SUCCESS)
2388
+ {
2389
+ addon_log(LOG_LEVEL_DEBUG, "pjmedia_master_port_destroy failed\n");
2390
+ }
2391
+ }
2392
+
2393
+ if(call->media_port)
2394
+ {
2395
+ status = pjmedia_port_destroy(call->media_port);
2396
+ if(status != PJ_SUCCESS)
2397
+ {
2398
+ addon_log(LOG_LEVEL_DEBUG, "pjmedia_port_destroy failed\n");
2399
+ }
2400
+ }
2401
+
2402
+ if(call->med_stream)
2403
+ {
2404
+ status = pjmedia_stream_destroy(call->med_stream);
2405
+ if(status != PJ_SUCCESS)
2406
+ {
2407
+ addon_log(LOG_LEVEL_DEBUG, "pjmedia_stream_destroy failed\n");
2408
+ }
2409
+ }
2410
+
2411
+ if(call->med_transport)
2412
+ {
2413
+ close_media_transport(call->med_transport);
2414
+ }
2415
+
2416
+ long val;
2417
+ if(!g_call_ids.remove(call_id, val))
2418
+ {
2419
+ addon_log(LOG_LEVEL_DEBUG, "g_call_ids.remove failed\n");
2420
+ }
2421
+
2422
+ Pair_Call_CallId pcc;
2423
+ pcc.pCall = call;
2424
+ pcc.id = call_id;
2425
+ g_LastCalls.push_back(pcc);
2426
+
2427
+ //delete call->last_responses;
2428
+
2429
+ /*
2430
+ ostringstream oss;
2431
+ oss << "event=termination" << EVT_DATA_SEP << "call=" << call_id;
2432
+ dispatch_event(oss.str().c_str());
2433
+ */
2434
+
2435
+ char evt[2048];
2436
+ int sip_msg_len = 0;
2437
+ char *sip_msg = "";
2438
+ if(e->type == PJSIP_EVENT_TSX_STATE) {
2439
+ sip_msg_len = e->body.rx_msg.rdata->msg_info.len;
2440
+ sip_msg = e->body.rx_msg.rdata->msg_info.msg_buf;
2441
+ }
2442
+ make_evt_call_ended(evt, sizeof(evt), call_id, sip_msg_len, sip_msg);
2443
+ dispatch_event(evt);
2444
+ }
2445
+ }
2446
+
2447
+ static void on_forked(pjsip_inv_session *inv, pjsip_event *e){
2448
+ if(g_shutting_down) return;
2449
+ }
2450
+
2451
+ static pjmedia_transport *create_media_transport(const pj_str_t *addr)
2452
+ {
2453
+ pjmedia_transport *med_transport;
2454
+ pj_status_t status;
2455
+ for(int i=0; i<1000 ; ++i)
2456
+ {
2457
+ int port = 10000 + (i*2);
2458
+ status = pjmedia_transport_udp_create3(g_med_endpt, AF,
2459
+ NULL,
2460
+ addr,
2461
+ port, 0, &med_transport);
2462
+ if( status == PJ_SUCCESS ) {
2463
+ pjmedia_transport_info tpinfo;
2464
+ pjmedia_transport_info_init(&tpinfo);
2465
+ status = pjmedia_transport_get_info(med_transport, &tpinfo);
2466
+ if( status == PJ_SUCCESS ) {
2467
+ if(g_PacketDumper){
2468
+ g_PacketDumper->add_endpoint( tpinfo.sock_info.rtp_addr_name.ipv4.sin_addr.s_addr, tpinfo.sock_info.rtp_addr_name.ipv4.sin_port );
2469
+ g_PacketDumper->add_endpoint( tpinfo.sock_info.rtcp_addr_name.ipv4.sin_addr.s_addr, tpinfo.sock_info.rtcp_addr_name.ipv4.sin_port );
2470
+ }
2471
+ }
2472
+ return med_transport;
2473
+ }
2474
+ }
2475
+ return NULL;
2476
+ }
2477
+
2478
+ static void process_subscribe_request(pjsip_rx_data *rdata) {
2479
+ char evt[2048];
2480
+ ostringstream oss_err;
2481
+ ostringstream oss;
2482
+ pjsip_dialog *dlg = NULL;
2483
+ pjsip_evsub_user user_cb;
2484
+ pjsip_evsub *evsub;
2485
+ pj_status_t status;
2486
+ Subscriber *subscriber;
2487
+ long subscriber_id;
2488
+ char local_contact[1000];
2489
+ pjsip_tx_data *tdata;
2490
+
2491
+ memset(&user_cb, 0, sizeof(user_cb));
2492
+ user_cb.on_evsub_state = server_on_evsub_state;
2493
+ user_cb.on_rx_refresh = server_on_evsub_rx_refresh;
2494
+
2495
+ build_local_contact(local_contact, rdata->tp_info.transport, "sip-tester");
2496
+ pj_str_t url = pj_str(local_contact);
2497
+
2498
+ status = pjsip_dlg_create_uas_and_inc_lock(pjsip_ua_instance(),
2499
+ rdata,
2500
+ &url,
2501
+ &dlg);
2502
+ if(status != PJ_SUCCESS) {
2503
+ make_evt_internal_error(evt, sizeof(evt), "error p1");
2504
+ dispatch_event(evt);
2505
+ goto out;
2506
+ }
2507
+
2508
+ status = pjsip_evsub_create_uas(dlg,
2509
+ &user_cb,
2510
+ rdata,
2511
+ 0,
2512
+ &evsub);
2513
+ if(status != PJ_SUCCESS) {
2514
+ make_evt_internal_error(evt, sizeof(evt), "error p2");
2515
+ dispatch_event(evt);
2516
+ goto out;
2517
+ }
2518
+
2519
+ subscriber = (Subscriber*)pj_pool_zalloc(dlg->pool, sizeof(Subscriber));
2520
+ if(!g_subscriber_ids.add((long)subscriber, subscriber_id)){
2521
+ make_evt_internal_error(evt, sizeof(evt), "error p3");
2522
+ dispatch_event(evt);
2523
+ goto out;
2524
+ }
2525
+ subscriber->id = subscriber_id;
2526
+ subscriber->evsub = evsub;
2527
+ subscriber->dlg = dlg;
2528
+
2529
+ pjsip_evsub_set_mod_data(evsub, mod_tester.id, subscriber);
2530
+
2531
+ status = pjsip_evsub_accept(evsub, rdata, 200, NULL);
2532
+ if(status != PJ_SUCCESS) {
2533
+ make_evt_internal_error(evt, sizeof(evt), "error p5");
2534
+ dispatch_event(evt);
2535
+ goto out;
2536
+ }
2537
+
2538
+ status = pjsip_evsub_notify(evsub, (pjsip_evsub_state)PJSIP_EVSUB_STATE_ACTIVE, NULL, NULL, &tdata);
2539
+ if(status != PJ_SUCCESS) {
2540
+ make_evt_internal_error(evt, sizeof(evt), "error p6");
2541
+ dispatch_event(evt);
2542
+ goto out;
2543
+ }
2544
+
2545
+ status = pjsip_evsub_send_request(evsub,tdata);
2546
+ if(status != PJ_SUCCESS) {
2547
+ make_evt_internal_error(evt, sizeof(evt), "error p7");
2548
+ dispatch_event(evt);
2549
+ goto out;
2550
+ }
2551
+
2552
+ out:
2553
+ if(status != PJ_SUCCESS) {
2554
+ pj_str_t s_reason = pj_str(pjw_errorstring);
2555
+ if(dlg) {
2556
+ status = pjsip_dlg_create_response(dlg, rdata, 500, NULL, &tdata);
2557
+ if(status == PJ_SUCCESS) {
2558
+ pjsip_dlg_send_response(dlg, pjsip_rdata_get_tsx(rdata), tdata);
2559
+ }
2560
+ }else {
2561
+ pjsip_endpt_respond_stateless(g_sip_endpt, rdata, 500, NULL, NULL, NULL);
2562
+ }
2563
+ } else {
2564
+ make_evt_request(evt, sizeof(evt), "subscriber", subscriber_id, rdata->msg_info.len, rdata->msg_info.msg_buf);
2565
+ dispatch_event(evt);
2566
+ }
2567
+ }
2568
+
2569
+ static pj_bool_t on_rx_request( pjsip_rx_data *rdata ){
2570
+ char evt[2048];
2571
+
2572
+ pj_str_t *method_name = &rdata->msg_info.msg->line.req.method.name;
2573
+ addon_log(LOG_LEVEL_DEBUG, "on_rx_request %.*s\n", method_name->slen, method_name->ptr);
2574
+ if(g_shutting_down) return PJ_TRUE;
2575
+
2576
+ pj_status_t status;
2577
+ pj_str_t reason;
2578
+
2579
+ pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);
2580
+
2581
+ addon_log(LOG_LEVEL_DEBUG, "dlg=%x\n", dlg);
2582
+
2583
+ if(dlg){
2584
+ if(pj_strcmp2(&rdata->msg_info.msg->line.req.method.name, "REFER") != 0){
2585
+ return PJ_TRUE;
2586
+ }
2587
+ }
2588
+
2589
+ //Just for future reference. The code below prints all headers in the request
2590
+ /*
2591
+ pjsip_hdr *hdr;
2592
+ pjsip_hdr *hdr_list = &rdata->msg_info.msg->hdr;
2593
+ for(hdr=hdr_list->next; hdr!=hdr_list ; hdr=hdr->next){
2594
+ char buf[1000];
2595
+ int len = pjsip_hdr_print_on(hdr, buf, sizeof(buf));
2596
+ buf[len] = 0;
2597
+ addon_log(LOG_LEVEL_DEBUG, "Header: %s\n", buf);
2598
+ }
2599
+ */
2600
+
2601
+ if(dlg && (pj_strcmp2(&rdata->msg_info.msg->line.req.method.name, "REFER") == 0)) {
2602
+ //Refer within dialog
2603
+ //We cannot call process_in_dialog_refer from this callback (so we copied the way it is done by pjsua, using on_tsx_state_changed)
2604
+ //process_in_dialog_refer(&oss, dlg, rdata);
2605
+ //addon_log(LOG_LEVEL_DEBUG, "received REFER on_rx_request\n");
2606
+ return PJ_TRUE;
2607
+ }
2608
+
2609
+ if(dlg && (pj_strcmp2(&rdata->msg_info.msg->line.req.method.name, "INFO") == 0)) {
2610
+ return PJ_TRUE;
2611
+ }
2612
+
2613
+ if(pj_strcmp2(&rdata->msg_info.msg->line.req.method.name, "SUBSCRIBE") == 0){
2614
+ if(dlg) {
2615
+ process_in_dialog_subscribe(dlg,rdata);
2616
+ } else {
2617
+ process_subscribe_request(rdata);
2618
+ }
2619
+ return PJ_TRUE;
2620
+ }
2621
+
2622
+ Transport *transport;
2623
+
2624
+ if(rdata->msg_info.msg->line.req.method.id != PJSIP_INVITE_METHOD)
2625
+ {
2626
+ /*
2627
+ ostringstream oss;
2628
+ build_basic_request_info(&oss, rdata, &transport);
2629
+ */
2630
+
2631
+ reason = pj_str("OK");
2632
+
2633
+ pjsip_hdr hdr_list;
2634
+ pj_list_init(&hdr_list);
2635
+
2636
+ if(rdata->msg_info.msg->line.req.method.id == PJSIP_REGISTER_METHOD) {
2637
+ pjsip_hdr *hdr_from_request;
2638
+
2639
+ //Add Contact header from Request, if present
2640
+ pj_str_t STR_CONTACT = { "Contact" , 7 };
2641
+ hdr_from_request = (pjsip_hdr*)pjsip_msg_find_hdr_by_name(rdata->msg_info.msg,
2642
+ &STR_CONTACT,
2643
+ NULL);
2644
+ if(hdr_from_request) {
2645
+ pjsip_hdr *clone_hdr = (pjsip_hdr*) pjsip_hdr_clone(rdata->tp_info.pool, hdr_from_request);
2646
+ pj_list_push_back(&hdr_list, clone_hdr);
2647
+ }
2648
+
2649
+ //Add Expires header from Request, if present
2650
+ pj_str_t STR_EXPIRES = { "Expires" , 7 };
2651
+ hdr_from_request = (pjsip_hdr*)pjsip_msg_find_hdr_by_name(rdata->msg_info.msg,
2652
+ &STR_EXPIRES,
2653
+ NULL);
2654
+ if(hdr_from_request) {
2655
+ pjsip_hdr *clone_hdr = (pjsip_hdr*) pjsip_hdr_clone(rdata->tp_info.pool, hdr_from_request);
2656
+ pj_list_push_back(&hdr_list, clone_hdr);
2657
+ }
2658
+
2659
+ }
2660
+
2661
+ pjsip_endpt_respond_stateless(g_sip_endpt, rdata, 200, &reason, &hdr_list, NULL);
2662
+
2663
+ make_evt_non_dialog_request(evt, sizeof(evt), rdata->msg_info.len, rdata->msg_info.msg_buf);
2664
+ dispatch_event(evt);
2665
+ return PJ_TRUE;
2666
+ }
2667
+
2668
+ unsigned options = 0;
2669
+ status = pjsip_inv_verify_request(rdata, &options, NULL, NULL, g_sip_endpt, NULL);
2670
+ if(status != PJ_SUCCESS) {
2671
+ reason = pj_str("Unable to handle this INVITE");
2672
+ pjsip_endpt_respond_stateless(g_sip_endpt, rdata, 500, &reason, NULL, NULL);
2673
+ return PJ_TRUE;
2674
+ }
2675
+
2676
+ char local_contact[1000];
2677
+ build_local_contact(local_contact, rdata->tp_info.transport, "sip-tester");
2678
+ pj_str_t url = pj_str(local_contact);
2679
+
2680
+ status = pjsip_dlg_create_uas_and_inc_lock(pjsip_ua_instance(),
2681
+ rdata,
2682
+ &url,
2683
+ &dlg);
2684
+
2685
+ if(status != PJ_SUCCESS) {
2686
+ reason = pj_str("Internal Server Error (pjsip_dlg_create_uas_and_inc_lock failed)");
2687
+ pjsip_endpt_respond_stateless(g_sip_endpt, rdata, 500, &reason, NULL, NULL);
2688
+ return PJ_TRUE;
2689
+ }
2690
+
2691
+ pjsip_transport *t = rdata->tp_info.transport;
2692
+ pj_str_t str_addr = pj_str( inet_ntoa( (in_addr&)t->local_addr.ipv4.sin_addr.s_addr ) );
2693
+ pjmedia_transport *med_transport = create_media_transport(&str_addr);
2694
+
2695
+ if(!med_transport)
2696
+ {
2697
+ reason = pj_str("Internal Server Error (could not create media transport)");
2698
+ pjsip_endpt_respond_stateless(g_sip_endpt, rdata, 500, &reason, NULL, NULL);
2699
+ return PJ_TRUE;
2700
+ }
2701
+
2702
+ pjmedia_transport_info med_tpinfo;
2703
+ pjmedia_transport_info_init(&med_tpinfo);
2704
+ pjmedia_transport_get_info(med_transport, &med_tpinfo);
2705
+
2706
+ pjmedia_sdp_session *sdp;
2707
+ status = pjmedia_endpt_create_sdp( g_med_endpt, rdata->tp_info.pool, 1,
2708
+ &med_tpinfo.sock_info,
2709
+ &sdp);
2710
+ if(status != PJ_SUCCESS) {
2711
+ close_media_transport(med_transport);
2712
+ reason = pj_str("Internal Server Error (pjmedia_endprt_create_sdp failed)");
2713
+ pjsip_endpt_respond_stateless(g_sip_endpt, rdata, 500, &reason, NULL, NULL);
2714
+ return PJ_TRUE;
2715
+ }
2716
+
2717
+ pjsip_inv_session *inv;
2718
+ status = pjsip_inv_create_uas(dlg, rdata, sdp, 0, &inv);
2719
+ if(status != PJ_SUCCESS) {
2720
+ close_media_transport(med_transport);
2721
+ reason = pj_str("Internal Server Error (pjsip_inv_create_uas failed)");
2722
+ pjsip_endpt_respond_stateless(g_sip_endpt, rdata, 500, &reason, NULL, NULL);
2723
+ return PJ_TRUE;
2724
+ }
2725
+
2726
+ if(!set_transport(t, dlg)) {
2727
+ close_media_transport(med_transport);
2728
+ reason = pj_str("Internal Server Error (set_transport failed)");
2729
+ pjsip_endpt_respond_stateless(g_sip_endpt, rdata, 500, &reason, NULL, NULL);
2730
+ return PJ_TRUE;
2731
+ }
2732
+
2733
+ pjsip_rx_data *cloned_rdata = 0;
2734
+
2735
+ if(!(g_flags & FLAG_NO_AUTO_100_TRYING)) {
2736
+ pjsip_tx_data *tdata;
2737
+ //First response to an INVITE must be created with pjsip_inv_initial_answer(). Subsequent responses to the same transaction MUST use pjsip_inv_answer().
2738
+ //Create 100 response
2739
+ status = pjsip_inv_initial_answer(inv, rdata,
2740
+ 100,
2741
+ NULL, NULL, &tdata);
2742
+ if(status != PJ_SUCCESS) {
2743
+ close_media_transport(med_transport);
2744
+ reason = pj_str("Internal Server Error (pjsip_inv_initial_answer failed)");
2745
+ pjsip_endpt_respond_stateless(g_sip_endpt, rdata, 500, &reason, NULL, NULL);
2746
+ return PJ_TRUE;
2747
+ }
2748
+
2749
+ //Send 100 response
2750
+ status = pjsip_inv_send_msg(inv, tdata);
2751
+ if(status != PJ_SUCCESS) {
2752
+ close_media_transport(med_transport);
2753
+ reason = pj_str("Internal Server Error (pjsip_inv_send_msg failed)");
2754
+ pjsip_endpt_respond_stateless(g_sip_endpt, rdata, 500, &reason, NULL, NULL);
2755
+ return PJ_TRUE;
2756
+ }
2757
+ } else {
2758
+ status = pjsip_rx_data_clone(rdata, 0, &cloned_rdata);
2759
+
2760
+ if(status != PJ_SUCCESS) {
2761
+ close_media_transport(med_transport);
2762
+ reason = pj_str("Internal Server Error (pjsip_rx_data_clone failed)");
2763
+ pjsip_endpt_respond_stateless(g_sip_endpt, rdata, 500, &reason, NULL, NULL);
2764
+ return PJ_TRUE;
2765
+ }
2766
+ }
2767
+
2768
+ Call *call = (Call*)pj_pool_alloc(inv->pool, sizeof(Call));
2769
+ pj_bzero(call, sizeof(Call));
2770
+
2771
+ call->initial_invite_rdata = cloned_rdata;
2772
+
2773
+ if(status != PJ_SUCCESS) {
2774
+ close_media_transport(med_transport);
2775
+ reason = pj_str("Internal Server Error (pjsip_rx_data_clone failed)");
2776
+ pjsip_endpt_respond_stateless(g_sip_endpt, rdata, 500, &reason, NULL, NULL);
2777
+ return PJ_TRUE;
2778
+ }
2779
+
2780
+ call->inv = inv;
2781
+ call->med_transport = med_transport;
2782
+
2783
+ if(!inv->dlg) {
2784
+ return PJ_TRUE;
2785
+ }
2786
+
2787
+ inv->dlg->mod_data[mod_tester.id] = call;
2788
+
2789
+ //Without this, on_rx_response will not be called
2790
+ status = pjsip_dlg_add_usage(dlg, &mod_tester, call);
2791
+ if(status != PJ_SUCCESS) {
2792
+ close_media_transport(med_transport);
2793
+ reason = pj_str("Internal Server Error (pjsip_dlg_add_usage failed)");
2794
+ pjsip_endpt_respond_stateless(g_sip_endpt, rdata, 500, &reason, NULL, NULL);
2795
+ return PJ_TRUE;
2796
+ }
2797
+
2798
+ long call_id;
2799
+ if(!g_call_ids.add((long)call, call_id)){
2800
+ addon_log(LOG_LEVEL_DEBUG, "Failed to allocate call_id. Event will not be notifield\n");
2801
+ return PJ_TRUE;
2802
+ }
2803
+
2804
+ call->transport = transport;
2805
+ call->id = call_id;
2806
+
2807
+ int transport_id;
2808
+
2809
+ SipTransportMap::iterator iter = g_SipTransportMap.find(t);
2810
+ if( iter != g_SipTransportMap.end() ){
2811
+ transport_id = iter->second;
2812
+ } else {
2813
+ if(t->key.type == PJSIP_TRANSPORT_TLS) {
2814
+ transport_id = g_TlsTransportId;
2815
+ } else {
2816
+ transport_id = -1;
2817
+ }
2818
+ }
2819
+
2820
+ make_evt_incoming_call(evt, sizeof(evt), transport_id, call_id, rdata->msg_info.len, rdata->msg_info.msg_buf);
2821
+ dispatch_event(evt);
2822
+
2823
+ return PJ_TRUE;
2824
+ }
2825
+
2826
+ static pj_bool_t on_rx_response( pjsip_rx_data *rdata ){
2827
+ //addon_log(LOG_LEVEL_DEBUG, "on_rx_response\n");
2828
+ //Very important: this callback notifies reception of any SIP response
2829
+ //received by the endpoint, no matter if the endpoint was the one
2830
+ //that sent the request or not (for example, if the app is running
2831
+ //in a loop and breaks and restarts immediately, it will get responses
2832
+ //destined to its previous incarnation. So we must check if the
2833
+ //response is associated with a dialog, otherwise: crash.
2834
+ if(g_shutting_down) return PJ_TRUE;
2835
+
2836
+ char evt[2048];
2837
+ pj_str_t mname;
2838
+
2839
+ pjsip_cseq_hdr *cseq = rdata->msg_info.cseq;
2840
+ char method[100];
2841
+ int len = cseq->method.name.slen;
2842
+ strncpy(method, cseq->method.name.ptr, len);
2843
+ method[len] = 0;
2844
+
2845
+ ostringstream oss;
2846
+
2847
+ pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata);
2848
+ if(!dlg){
2849
+ //addon_log(LOG_LEVEL_DEBUG, "No dialog associated with rdata\n");
2850
+ return PJ_TRUE;
2851
+ }
2852
+
2853
+ if(strcmp(method, "SUBSCRIBE") == 0) {
2854
+ Subscription *subscription = (Subscription*)dlg->mod_data[mod_tester.id];
2855
+ int code = rdata->msg_info.msg->line.status.code;
2856
+ if(!subscription->initialized && code >= 200 && code <= 299) {
2857
+ //Status code 2XX will cause pjsip_evsub to be called.
2858
+ subscription->initialized = true;
2859
+ return PJ_FALSE;
2860
+ }
2861
+
2862
+
2863
+ long subscription_id;
2864
+
2865
+ if(subscription) {
2866
+ if( !g_subscription_ids.get_id((long)subscription, subscription_id) ){
2867
+ /*
2868
+ oss.seekp(0);
2869
+ oss << "event=internal_error" << EVT_DATA_SEP << "details=Failed to get subscription_id";
2870
+ */
2871
+
2872
+ make_evt_internal_error(evt, sizeof(evt), "failed to get subscription_id");
2873
+ dispatch_event(evt);
2874
+ return true;
2875
+ }
2876
+ } else {
2877
+ addon_log(LOG_LEVEL_DEBUG, "Ignoring response for mod_data not set to a subscription\n");
2878
+ return PJ_TRUE;
2879
+ }
2880
+
2881
+ mname = rdata->msg_info.cseq->method.name;
2882
+ make_evt_response(evt, sizeof(evt), "subscription", subscription_id, mname.slen, mname.ptr, rdata->msg_info.len, rdata->msg_info.msg_buf);
2883
+ dispatch_event(evt);
2884
+
2885
+ return PJ_TRUE;
2886
+ }
2887
+
2888
+
2889
+ Call *call = (Call*)dlg->mod_data[mod_tester.id];
2890
+ long call_id;
2891
+
2892
+ if(call) {
2893
+ //addon_log(LOG_LEVEL_DEBUG, "call:%x\n",call);
2894
+ if( !g_call_ids.get_id((long)call, call_id) ){
2895
+ //addon_log(LOG_LEVEL_DEBUG, "The call is not present in g_call_ids.\n");
2896
+ // It means the call terminated and was removed from g_call_ids\n");
2897
+ //So let's try to find it at g_LastCalls
2898
+
2899
+ boost::circular_buffer<Pair_Call_CallId>::iterator iter;
2900
+ Pair_Call_CallId pcc;
2901
+ pcc.pCall = call;
2902
+ iter = find(g_LastCalls.begin(), g_LastCalls.end(), pcc);
2903
+ if(iter == g_LastCalls.end())
2904
+ {
2905
+ oss.seekp(0);
2906
+ oss << "event=internal_error" << EVT_DATA_SEP << "details=Failed to get call_id";
2907
+ addon_log(LOG_LEVEL_DEBUG, "on_rx_response failed to resolve call_id\n");
2908
+ return true;
2909
+ }
2910
+ call_id = iter->id;
2911
+ }
2912
+ } else {
2913
+ addon_log(LOG_LEVEL_DEBUG, "Ignoring response for mod_data not set to a call\n");
2914
+ return PJ_TRUE;
2915
+ }
2916
+
2917
+ mname = rdata->msg_info.cseq->method.name;
2918
+ make_evt_response(evt, sizeof(evt), "call", call_id, mname.slen, mname.ptr, rdata->msg_info.len, rdata->msg_info.msg_buf);
2919
+ dispatch_event(evt);
2920
+
2921
+ return PJ_TRUE;
2922
+ }
2923
+
2924
+ static pjsip_redirect_op on_redirected(pjsip_inv_session *inv, const pjsip_uri *target, const pjsip_event *e) {
2925
+ PJ_UNUSED_ARG(e);
2926
+ return PJSIP_REDIRECT_ACCEPT;
2927
+ }
2928
+
2929
+ static void on_rx_offer(pjsip_inv_session *inv, const pjmedia_sdp_session *offer){
2930
+ addon_log(LOG_LEVEL_DEBUG, "on_rx_offer offer=%x\n", offer);
2931
+ if(g_shutting_down) return;
2932
+
2933
+ bool is_reinvite = false;
2934
+
2935
+ if(inv->state == PJSIP_INV_STATE_CONFIRMED) {
2936
+ is_reinvite = true;
2937
+ }
2938
+
2939
+ char evt[2048];
2940
+
2941
+ char *type;
2942
+
2943
+ Call *call = (Call*)inv->dlg->mod_data[mod_tester.id];
2944
+
2945
+ pj_status_t status;
2946
+
2947
+ pjmedia_sdp_conn *conn;
2948
+ conn = offer->media[0]->conn;
2949
+ if(!conn) conn = offer->conn;
2950
+
2951
+ pjmedia_transport_info tpinfo;
2952
+ pjmedia_transport_info_init(&tpinfo);
2953
+ pjmedia_transport_get_info(call->med_transport,&tpinfo);
2954
+
2955
+ pjmedia_sdp_session *answer;
2956
+ status = pjmedia_endpt_create_sdp(g_med_endpt,
2957
+ inv->pool,
2958
+ 1,
2959
+ &tpinfo.sock_info,
2960
+ &answer);
2961
+ if(status != PJ_SUCCESS){
2962
+ make_evt_internal_error(evt, sizeof(evt), "on_rx_offer: pjmedia_endpt_create_sdp failed");
2963
+ dispatch_event(evt);
2964
+ return;
2965
+ }
2966
+
2967
+ int remote_mode = get_media_mode(offer->media[0]->attr, offer->media[0]->attr_count);
2968
+ if(remote_mode == SENDONLY) {
2969
+ call->remote_hold = 1;
2970
+ } else if(remote_mode == INACTIVE) {
2971
+ call->remote_hold = 1;
2972
+ } else if(remote_mode == SENDRECV) {
2973
+ call->remote_hold = 0;
2974
+ } else if(remote_mode == RECVONLY) {
2975
+ call->remote_hold = 0;
2976
+ } else {
2977
+ call->remote_hold = 0;
2978
+ }
2979
+
2980
+ char *mode = get_media_mode_str(remote_mode);
2981
+
2982
+ pjmedia_sdp_attr *attr;
2983
+
2984
+ // Remove existing directions attributes
2985
+ pjmedia_sdp_media_remove_all_attr(answer->media[0], "sendrecv");
2986
+ pjmedia_sdp_media_remove_all_attr(answer->media[0], "sendonly");
2987
+ pjmedia_sdp_media_remove_all_attr(answer->media[0], "recvonly");
2988
+ pjmedia_sdp_media_remove_all_attr(answer->media[0], "inactive");
2989
+
2990
+ if(call->local_hold) {
2991
+ // Keep call on-hold by setting 'sendonly' attribute.
2992
+ // (See RFC 3264 Section 8.4 and RFC 4317 Section 3.1)
2993
+ if(call->remote_hold) {
2994
+ printf("p1\n");
2995
+ attr = pjmedia_sdp_attr_create(inv->pool, "inactive", NULL);
2996
+ } else {
2997
+ printf("p2\n");
2998
+ attr = pjmedia_sdp_attr_create(inv->pool, "sendonly", NULL);
2999
+ }
3000
+ } else if(call->remote_hold) {
3001
+ printf("p3\n");
3002
+ attr = pjmedia_sdp_attr_create(inv->pool, "recvonly", NULL);
3003
+ } else {
3004
+ printf("p4\n");
3005
+ attr = pjmedia_sdp_attr_create(inv->pool, "sendrecv", NULL);
3006
+ }
3007
+ pjmedia_sdp_media_add_attr(answer->media[0], attr);
3008
+
3009
+ status = pjsip_inv_set_sdp_answer(inv, answer);
3010
+ if(status != PJ_SUCCESS){
3011
+ make_evt_internal_error(evt, sizeof(evt), "on_rx_offer: pjsip_inv_set_sdp_answer failed");
3012
+ dispatch_event(evt);
3013
+ return;
3014
+ }
3015
+
3016
+ long call_id;
3017
+ if( !g_call_ids.get_id((long)call, call_id) ){
3018
+ make_evt_internal_error(evt, sizeof(evt), "on_rx_offer: Failed to get call_id.\n");
3019
+ dispatch_event(evt);
3020
+ return;
3021
+ }
3022
+
3023
+ /*
3024
+ if(is_reinvite) {
3025
+ make_evt_reinvite(evt, sizeof(evt), call_id, type);
3026
+ dispatch_event(evt);
3027
+ }
3028
+ */
3029
+
3030
+ return;
3031
+ }
3032
+
3033
+ static void on_dtmf(pjmedia_stream *stream, void *user_data, int digit){
3034
+ if(g_shutting_down) return;
3035
+
3036
+ char evt[256];
3037
+
3038
+ long call_id;
3039
+ if( !g_call_ids.get_id((long)user_data, call_id) ){
3040
+ addon_log(LOG_LEVEL_DEBUG, "on_dtmf: Failed to get call_id. Event will not be notified.\n");
3041
+ return;
3042
+ }
3043
+
3044
+ char d = (char)tolower((char)digit);
3045
+ if(d == '*') d = 'e';
3046
+ if(d == '#') d = 'f';
3047
+
3048
+ Call *c = (Call*)user_data;
3049
+
3050
+ int mode = DTMF_MODE_RFC2833;
3051
+
3052
+ if(g_dtmf_inter_digit_timer) {
3053
+
3054
+ PJW_LOCK();
3055
+ int *pLen = &c->DigitBufferLength[mode];
3056
+
3057
+ if(*pLen > MAXDIGITS) {
3058
+ PJW_UNLOCK();
3059
+ addon_log(LOG_LEVEL_DEBUG, "No more space for digits in rfc2833 buffer\n");
3060
+ return;
3061
+ }
3062
+
3063
+ c->DigitBuffers[mode][*pLen] = d;
3064
+ (*pLen)++;
3065
+ c->last_digit_timestamp[mode] = ms_timestamp();
3066
+ PJW_UNLOCK();
3067
+ } else {
3068
+ make_evt_dtmf(evt, sizeof(evt), call_id, 1, &d, mode);
3069
+ dispatch_event(evt);
3070
+ }
3071
+ }
3072
+
3073
+ static void on_registration_status(pjsip_regc_cbparam *param){
3074
+ //addon_log(LOG_LEVEL_DEBUG, "on_registration_status\n");
3075
+ if(g_shutting_down) return;
3076
+
3077
+ char evt[1024];
3078
+
3079
+ long acc_id;
3080
+ if( !g_account_ids.get_id((long)param->regc, acc_id) ){
3081
+ addon_log(LOG_LEVEL_DEBUG, "on_registration_status: Failed to get account_id. Event will not be notified.\n");
3082
+ return;
3083
+ }
3084
+
3085
+ char reason[100];
3086
+ int len = param->reason.slen;
3087
+ strncpy(reason, param->reason.ptr, len);
3088
+ reason[len] = 0;
3089
+
3090
+ make_evt_registration_status(evt, sizeof(evt), acc_id, param->code, reason, param->expiration);
3091
+ dispatch_event(evt);
3092
+ }
3093
+
3094
+ int pjw_packetdump_start(const char *dev, const char *file){
3095
+ PJW_LOCK();
3096
+
3097
+ if(g_PacketDumper) delete g_PacketDumper;
3098
+
3099
+ g_PacketDumper = new PacketDumper();
3100
+ if(!g_PacketDumper->init(dev, file)){
3101
+ PJW_UNLOCK();
3102
+ set_error("Failed to start packetdumping");
3103
+ return -1;
3104
+ }
3105
+
3106
+ PJW_UNLOCK();
3107
+ return 0;
3108
+ }
3109
+
3110
+ int pjw_packetdump_stop(){
3111
+ PJW_LOCK();
3112
+
3113
+ if(g_PacketDumper) delete g_PacketDumper;
3114
+ g_PacketDumper = NULL;
3115
+
3116
+ PJW_UNLOCK();
3117
+ return 0;
3118
+ }
3119
+
3120
+ int pjw_get_codecs(char *out_codecs)
3121
+ {
3122
+ clear_error();
3123
+
3124
+ pjmedia_codec_mgr *codec_mgr;
3125
+ pjmedia_codec_info codec_info[100];
3126
+ unsigned count = sizeof(codec_info);
3127
+ unsigned prio[100];
3128
+ pj_status_t status;
3129
+ ostringstream oss;
3130
+
3131
+ PJW_LOCK();
3132
+
3133
+ codec_mgr = pjmedia_endpt_get_codec_mgr(g_med_endpt);
3134
+ if(!codec_mgr) {
3135
+ set_error("pjmedia_endpt_get_codec_mgr failed");
3136
+ goto out;
3137
+ }
3138
+
3139
+ status = pjmedia_codec_mgr_enum_codecs(codec_mgr,
3140
+ &count,
3141
+ codec_info,
3142
+ prio);
3143
+ if(status != PJ_SUCCESS) {
3144
+ set_error("pjmedia_codec_mgr_enum_codecs failed");
3145
+ goto out;
3146
+ }
3147
+
3148
+ for(int i=0; i<count; ++i) {
3149
+ pjmedia_codec_info *info = &codec_info[i];
3150
+ if(i != 0) oss << " ";
3151
+ oss.write(info->encoding_name.ptr, info->encoding_name.slen);
3152
+ oss << "/" << info->clock_rate;
3153
+ oss << "/" << info->channel_cnt;
3154
+ oss << ":" << prio[i];
3155
+ }
3156
+
3157
+ out:
3158
+ PJW_UNLOCK();
3159
+
3160
+ if(pjw_errorstring[0]){
3161
+ return -1;
3162
+ }
3163
+
3164
+ strcpy(out_codecs, oss.str().c_str());
3165
+ return 0;
3166
+ }
3167
+
3168
+ int pjw_set_codecs(const char *in_codec_info) {
3169
+ clear_error();
3170
+
3171
+ char error[1000];
3172
+ pjmedia_codec_mgr *codec_mgr;
3173
+ pj_status_t status;
3174
+ char codec_info[1000];
3175
+ pj_str_t codec_id;
3176
+ char *tok;
3177
+
3178
+ PJW_LOCK();
3179
+
3180
+ codec_mgr = pjmedia_endpt_get_codec_mgr(g_med_endpt);
3181
+ if(!codec_mgr) {
3182
+ set_error("pjmedia_endpt_get_codec_mgr failed");
3183
+ goto out;
3184
+ }
3185
+
3186
+ codec_id = pj_str("");
3187
+ status = pjmedia_codec_mgr_set_codec_priority(codec_mgr, &codec_id, 0);
3188
+ if(status != PJ_SUCCESS) {
3189
+ set_error("pjmedia_codec_mgr_set_codec_priority(zero all) failed.");
3190
+ goto out;
3191
+ }
3192
+
3193
+ strcpy(codec_info, in_codec_info);
3194
+
3195
+ tok = strtok(codec_info, ":");
3196
+ while(tok) {
3197
+ if(!tok) {
3198
+ set_error("malformed argument codec_info");
3199
+ goto out;
3200
+ }
3201
+ char *prio = strtok(NULL, " ");
3202
+ if(!prio) {
3203
+ set_error("malformed argument codec_info");
3204
+ goto out;
3205
+ }
3206
+
3207
+ codec_id = pj_str(tok);
3208
+ status = pjmedia_codec_mgr_set_codec_priority(codec_mgr, &codec_id, atoi(prio));
3209
+ if(status != PJ_SUCCESS) {
3210
+ set_error("pjmedia_codec_mgr_set_codec_priority failed");
3211
+ goto out;
3212
+ }
3213
+ tok = strtok(NULL, " ");
3214
+ }
3215
+
3216
+ out:
3217
+ PJW_UNLOCK();
3218
+
3219
+ if(pjw_errorstring[0]){
3220
+ //Try to put default priority to all codecs
3221
+ codec_id = pj_str("");
3222
+ status = pjmedia_codec_mgr_set_codec_priority(codec_mgr, &codec_id, 128);
3223
+ return -1;
3224
+ }
3225
+
3226
+ return 0;
3227
+ }
3228
+
3229
+ int __pjw_shutdown()
3230
+ {
3231
+ //addon_log(LOG_LEVEL_DEBUG, "pjw_shutdown thread_id=%i\n", syscall(SYS_gettid));
3232
+ PJW_LOCK();
3233
+
3234
+ g_shutting_down = true;
3235
+
3236
+ map<long, long>::iterator iter;
3237
+ iter = g_call_ids.id_map.begin();
3238
+ while(iter != g_call_ids.id_map.end()){
3239
+ Call *call = (Call*)iter->second;
3240
+
3241
+ addon_log(LOG_LEVEL_DEBUG, "Terminating call %d\n", iter->first);
3242
+
3243
+ pjsip_tx_data *tdata;
3244
+ pj_status_t status;
3245
+ status = pjsip_inv_end_session(call->inv,
3246
+ 603,
3247
+ NULL,
3248
+ &tdata); //Copied from pjsua
3249
+ if(status != PJ_SUCCESS){
3250
+ //ignore
3251
+ char err[256];
3252
+ pj_strerror(status, err, sizeof(err));
3253
+ addon_log(LOG_LEVEL_DEBUG, "pjsip_inv_end_session failed statut=%i (%s)\n", status, err);
3254
+ ++iter;
3255
+ continue;
3256
+ }
3257
+
3258
+ if(!tdata)
3259
+ {
3260
+ //if tdata was not set by pjsip_inv_end_session, it means we didn't receive any response yet (100 Trying) and we cannot send CANCEL in this situation. So we just can return here without calling pjsip_inv_send_msg.
3261
+ ++iter;
3262
+ addon_log(LOG_LEVEL_DEBUG, "no tdata\n");
3263
+ continue;
3264
+ }
3265
+
3266
+ status = pjsip_inv_send_msg(call->inv, tdata);
3267
+ if(status != PJ_SUCCESS){
3268
+ addon_log(LOG_LEVEL_DEBUG, "pjsip_inv_send_msg failed\n");
3269
+ }
3270
+ ++iter;
3271
+ }
3272
+
3273
+ iter = g_account_ids.id_map.begin();
3274
+ while(iter != g_account_ids.id_map.end()){
3275
+ pjsip_regc *regc = (pjsip_regc*)iter->second;
3276
+
3277
+ addon_log(LOG_LEVEL_DEBUG, "Unregistering account %d\n", iter->first);
3278
+
3279
+ pjsip_tx_data *tdata;
3280
+ pj_status_t status;
3281
+
3282
+ status = pjsip_regc_unregister(regc, &tdata);
3283
+ if(status != PJ_SUCCESS)
3284
+ {
3285
+ addon_log(LOG_LEVEL_DEBUG, "pjsip_regc_unregister failed\n");
3286
+ }
3287
+
3288
+ status = pjsip_regc_send(regc, tdata);
3289
+ if(status != PJ_SUCCESS)
3290
+ {
3291
+ addon_log(LOG_LEVEL_DEBUG, "pjsip_regc_send failed\n");
3292
+ }
3293
+ ++iter;
3294
+ }
3295
+
3296
+ Subscription *subscription;
3297
+ iter = g_subscription_ids.id_map.begin();
3298
+ while(iter != g_subscription_ids.id_map.end()){
3299
+ addon_log(LOG_LEVEL_DEBUG, "Unsubscribing subscription %d\n", iter->first);
3300
+
3301
+ subscription = (Subscription*)iter->second;
3302
+ if(!subscription_subscribe(subscription, 0, NULL)) {
3303
+ addon_log(LOG_LEVEL_DEBUG, "Unsubscription failed failed\n");
3304
+ }
3305
+ ++iter;
3306
+ }
3307
+
3308
+ PJW_UNLOCK();
3309
+
3310
+ //uint32_t wait = 100000 * (g_call_ids.id_map.size() + g_account_ids.id_map.size()));
3311
+ //wait += 1000000; //Wait one whole second to permit packet capture to get any final packets
3312
+
3313
+ /*
3314
+ time_t end,start;
3315
+ time(&start);
3316
+ end = start;
3317
+ */
3318
+ timeval tv_start;
3319
+ timeval tv_end;
3320
+ gettimeofday(&tv_start, NULL);
3321
+ gettimeofday(&tv_end, NULL);
3322
+
3323
+ unsigned int start = tv_start.tv_sec * 1000 + (tv_start.tv_usec / 1000);
3324
+ unsigned int end = tv_end.tv_sec * 1000 + (tv_end.tv_usec / 1000);
3325
+
3326
+ int DELAY = 2000; // 1000 ms delay
3327
+ while(end - start < DELAY) {
3328
+ pj_time_val tv = {0, 500};
3329
+ pj_status_t status;
3330
+ status = pjsip_endpt_handle_events(g_sip_endpt, &tv);
3331
+
3332
+ gettimeofday(&tv_end, NULL);
3333
+ end = tv_end.tv_sec * 1000 + (tv_end.tv_usec / 1000);
3334
+ //time(&end);
3335
+ }
3336
+
3337
+ return 0;
3338
+ }
3339
+
3340
+ //Copied from streamutil.c (pjsip sample)
3341
+ static const char *good_number(char *buf, pj_int32_t val)
3342
+ {
3343
+ if (val < 1000) {
3344
+ pj_ansi_sprintf(buf, "%d", val);
3345
+ } else if (val < 1000000) {
3346
+ pj_ansi_sprintf(buf, "%d.%dK",
3347
+ val / 1000,
3348
+ (val % 1000) / 100);
3349
+ } else {
3350
+ pj_ansi_sprintf(buf, "%d.%02dM",
3351
+ val / 1000000,
3352
+ (val % 1000000) / 10000);
3353
+ }
3354
+
3355
+ return buf;
3356
+ }
3357
+
3358
+ static void build_stream_stat(ostringstream &oss, pjmedia_rtcp_stat *stat, pjmedia_port* port)
3359
+ {
3360
+ char temp[200];
3361
+ char duration[80], last_update[80];
3362
+ char bps[16], ipbps[16], packets[16], bytes[16], ipbytes[16];
3363
+ pj_time_val now;
3364
+
3365
+ pj_gettimeofday(&now);
3366
+
3367
+ oss << "{ ";
3368
+
3369
+ PJ_TIME_VAL_SUB(now, stat->start);
3370
+ sprintf(duration, "'Duration':'%02ld:%02ld:%02ld.%03ld'",
3371
+ now.sec / 3600,
3372
+ (now.sec % 3600) / 60,
3373
+ (now.sec % 60),
3374
+ now.msec);
3375
+
3376
+ oss << duration;
3377
+
3378
+ sprintf(temp, ", 'CodecInfo':'%.*s@%dHz'",
3379
+ /*
3380
+ (int)port->info.encoding_name.slen,
3381
+ port->info.encoding_name.ptr,
3382
+ port->info.clock_rate);
3383
+ */
3384
+ /* lets put fake info for now */
3385
+ 4,
3386
+ "FAKE",
3387
+ 0);
3388
+
3389
+ oss << temp << ",";
3390
+
3391
+ oss << " 'RX' : { "; //Opening RX
3392
+
3393
+ if (stat->rx.update_cnt == 0)
3394
+ strcpy(last_update, "'LastUpdate':''");
3395
+ else {
3396
+ sprintf(last_update, "'LastUpdate':'%ld.%ld'",
3397
+ stat->rx.update.sec,
3398
+ stat->rx.update.msec);
3399
+ }
3400
+
3401
+ oss << last_update;
3402
+
3403
+ oss << ", 'Packets': " << good_number(packets, stat->rx.pkt);
3404
+ oss << ", 'Loss':" << stat->rx.loss;
3405
+ oss << ", 'Dup':" << stat->rx.dup;
3406
+ oss << ", 'Reorder':" << stat->rx.reorder;
3407
+
3408
+ oss << ", 'LossPeriod': {";
3409
+ oss << "'Min':" << stat->rx.loss_period.min / 1000.0;
3410
+ oss << ", 'Mean':" << stat->rx.loss_period.mean / 1000.0;
3411
+ oss << ", 'Max':" << stat->rx.loss_period.max / 1000.0;
3412
+ oss << ", 'Last':" << stat->rx.loss_period.last / 1000.0;
3413
+ oss << ", 'StandardDeviation':" << pj_math_stat_get_stddev(&stat->rx.loss_period) / 1000.0 << " }";
3414
+
3415
+ oss << ", 'Jitter': { ";
3416
+ oss << "'Min':" << stat->rx.jitter.min / 1000.0;
3417
+ oss << ", 'Mean':" << stat->rx.jitter.mean / 1000.0;
3418
+ oss << ", 'Max':" << stat->rx.jitter.max / 1000.0;
3419
+ oss << ", 'Last':" << stat->rx.jitter.last / 1000.0;
3420
+ oss << ", 'StandardDeviation':" << pj_math_stat_get_stddev(&stat->rx.jitter) / 1000.0 << " }";
3421
+
3422
+ oss << " }"; //Closing RX
3423
+
3424
+
3425
+ oss << ", 'TX' : { "; //Opening TX
3426
+
3427
+ if (stat->tx.update_cnt == 0)
3428
+ strcpy(last_update, "'LastUpdate':''");
3429
+ else {
3430
+ sprintf(last_update, "'LastUpdate':'%ld.%ld'",
3431
+ stat->tx.update.sec,
3432
+ stat->tx.update.msec);
3433
+ }
3434
+
3435
+
3436
+ oss << last_update;
3437
+
3438
+ oss << ", 'Packets': " << good_number(packets, stat->tx.pkt);
3439
+ oss << ", 'Loss':" << stat->tx.loss;
3440
+ oss << ", 'Dup':" << stat->tx.dup;
3441
+ oss << ", 'Reorder':" << stat->tx.reorder;
3442
+
3443
+ oss << ", 'LossPeriod': { ";
3444
+ oss << "'Min':" << stat->tx.loss_period.min / 1000.0;
3445
+ oss << ", 'Mean':" << stat->tx.loss_period.mean / 1000.0;
3446
+ oss << ", 'Max':" << stat->tx.loss_period.max / 1000.0;
3447
+ oss << ", 'Last':" << stat->tx.loss_period.last / 1000.0;
3448
+ oss << ", 'StandardDeviation':" << pj_math_stat_get_stddev(&stat->tx.loss_period) / 1000.0 << " }";
3449
+
3450
+ oss << ", 'Jitter': { ";
3451
+ oss << "'Min':" << stat->tx.jitter.min / 1000.0;
3452
+ oss << ", 'Mean':" << stat->tx.jitter.mean / 1000.0;
3453
+ oss << ", 'Max':" << stat->tx.jitter.max / 1000.0;
3454
+ oss << ", 'Last':" << stat->tx.jitter.last / 1000.0;
3455
+ oss << ", 'StandardDeviation':" << pj_math_stat_get_stddev(&stat->tx.jitter) / 1000.0 << " }";
3456
+
3457
+ oss << " }"; //Closing TX
3458
+
3459
+ oss << ", 'RTT': { "; // Opening RTT
3460
+
3461
+ oss << "'Min':" << stat->rtt.min / 1000.0;
3462
+ oss << ", 'Mean':" << stat->rtt.mean / 1000.0;
3463
+ oss << ", 'Max':" << stat->rtt.max / 1000.0;
3464
+ oss << ", 'Last':" << stat->rtt.last / 1000.0;
3465
+ oss << ", 'StandardDeviation':" << pj_math_stat_get_stddev(&stat->rtt) / 1000.0;
3466
+ oss << " }"; //Closing RTT
3467
+ oss << " }";
3468
+ }
3469
+
3470
+ void close_media_transport(pjmedia_transport *med_transport) {
3471
+ pjmedia_transport_info tpinfo;
3472
+ pjmedia_transport_info_init(&tpinfo);
3473
+ pj_status_t status = pjmedia_transport_get_info(med_transport, &tpinfo);
3474
+ if( status != PJ_SUCCESS ) return;
3475
+
3476
+ if(g_PacketDumper){
3477
+ g_PacketDumper->remove_endpoint( tpinfo.sock_info.rtp_addr_name.ipv4.sin_addr.s_addr, tpinfo.sock_info.rtp_addr_name.ipv4.sin_port );
3478
+ g_PacketDumper->remove_endpoint( tpinfo.sock_info.rtcp_addr_name.ipv4.sin_addr.s_addr, tpinfo.sock_info.rtcp_addr_name.ipv4.sin_port );
3479
+ }
3480
+
3481
+ status = pjmedia_transport_close(med_transport);
3482
+ if( status != PJ_SUCCESS ) {
3483
+ addon_log(LOG_LEVEL_DEBUG, "Critical Error: pjmedia_transport_close failed. status=%d\n", status);
3484
+ }
3485
+ }
3486
+
3487
+
3488
+ bool init_media_ports(Call *c, unsigned sampling_rate, unsigned channel_count, unsigned samples_per_frame, unsigned bits_per_sample) {
3489
+ pj_status_t status;
3490
+
3491
+ if(!c->null_port) {
3492
+ status = pjmedia_null_port_create(c->inv->pool,
3493
+ sampling_rate,
3494
+ channel_count,
3495
+ samples_per_frame,
3496
+ bits_per_sample,
3497
+ &c->null_port);
3498
+ if(status != PJ_SUCCESS) return false;
3499
+ }
3500
+
3501
+ if(!c->wav_writer) {
3502
+ if(!prepare_wire(c->inv->pool, &c->wav_writer, sampling_rate, channel_count, samples_per_frame, bits_per_sample)) {
3503
+ return false;
3504
+ }
3505
+ }
3506
+
3507
+ if(!c->wav_player) {
3508
+ if(!prepare_wire(c->inv->pool, &c->wav_player, sampling_rate, channel_count, samples_per_frame, bits_per_sample)) {
3509
+ return false;
3510
+ }
3511
+ }
3512
+
3513
+ if(!c->tonegen) {
3514
+ if(!prepare_wire(c->inv->pool, &c->tonegen, sampling_rate, channel_count, samples_per_frame, bits_per_sample)) {
3515
+ return false;
3516
+ }
3517
+ }
3518
+
3519
+ if(!c->dtmfdet) {
3520
+ status = chainlink_dtmfdet_create(c->inv->pool,
3521
+ sampling_rate,
3522
+ channel_count,
3523
+ samples_per_frame,
3524
+ bits_per_sample,
3525
+ on_inband_dtmf,
3526
+ c,
3527
+ (pjmedia_port**)&c->dtmfdet);
3528
+ if(status != PJ_SUCCESS) return false;
3529
+ }
3530
+
3531
+ connect_media_ports(c);
3532
+ return true;
3533
+ }
3534
+
3535
+ void connect_media_ports(Call *c) {
3536
+ ((chainlink*)c->dtmfdet)->next = (pjmedia_port*)c->tonegen;
3537
+ ((chainlink*)c->tonegen)->next = (pjmedia_port*)c->wav_player;
3538
+ ((chainlink*)c->wav_player)->next = (pjmedia_port*)c->wav_writer;
3539
+ ((chainlink*)c->wav_writer)->next = c->null_port;
3540
+ }
3541
+
3542
+ bool prepare_tonegen(Call *c) {
3543
+ pj_status_t status;
3544
+
3545
+ chainlink *link = (chainlink*)c->tonegen;
3546
+
3547
+ pjmedia_port *stream_port;
3548
+ status = pjmedia_stream_get_port(c->med_stream,
3549
+ &stream_port);
3550
+ if(status != PJ_SUCCESS)
3551
+ {
3552
+ return false;
3553
+ }
3554
+
3555
+ if(link->port.info.signature == CHAINLINK_WIRE_PORT_SIGNATURE) {
3556
+ status = chainlink_tonegen_create(c->inv->pool,
3557
+ PJMEDIA_PIA_SRATE(&stream_port->info),
3558
+ PJMEDIA_PIA_CCNT(&stream_port->info),
3559
+ PJMEDIA_PIA_SPF(&stream_port->info),
3560
+ PJMEDIA_PIA_BITS(&stream_port->info),
3561
+ 0,
3562
+ (pjmedia_port**)&c->tonegen);
3563
+ if(status != PJ_SUCCESS) return false;
3564
+ }
3565
+
3566
+ connect_media_ports(c);
3567
+ return true;
3568
+ }
3569
+
3570
+ bool prepare_wav_player(Call *c, const char *file) {
3571
+ pj_status_t status;
3572
+
3573
+ chainlink *link = (chainlink*)c->wav_player;
3574
+
3575
+ pjmedia_port *stream_port;
3576
+ status = pjmedia_stream_get_port(c->med_stream,
3577
+ &stream_port);
3578
+ if(status != PJ_SUCCESS) return false;
3579
+
3580
+ unsigned wav_ptime;
3581
+ wav_ptime = PJMEDIA_PIA_SPF(&stream_port->info) * 1000 / PJMEDIA_PIA_SRATE(&stream_port->info);
3582
+
3583
+ status = pjmedia_port_destroy((pjmedia_port*)link);
3584
+ if(status != PJ_SUCCESS) return false;
3585
+
3586
+ status = chainlink_wav_player_port_create(c->inv->pool,
3587
+ file,
3588
+ wav_ptime,
3589
+ 0,
3590
+ -1,
3591
+ (pjmedia_port**)&c->wav_player);
3592
+ if(status != PJ_SUCCESS) return false;
3593
+
3594
+ connect_media_ports(c);
3595
+ return true;
3596
+ }
3597
+
3598
+ bool prepare_wav_writer(Call *c, const char *file) {
3599
+ pj_status_t status;
3600
+
3601
+ chainlink *link = (chainlink*)c->wav_writer;
3602
+
3603
+ pjmedia_port *stream_port;
3604
+ status = pjmedia_stream_get_port(c->med_stream,
3605
+ &stream_port);
3606
+ if(status != PJ_SUCCESS) return false;
3607
+
3608
+ status = pjmedia_port_destroy((pjmedia_port*)link);
3609
+ if(status != PJ_SUCCESS) return false;
3610
+
3611
+ status = chainlink_wav_writer_port_create(c->inv->pool,
3612
+ file,
3613
+ PJMEDIA_PIA_SRATE(&stream_port->info),
3614
+ PJMEDIA_PIA_CCNT(&stream_port->info),
3615
+ PJMEDIA_PIA_SPF(&stream_port->info),
3616
+ PJMEDIA_PIA_BITS(&stream_port->info),
3617
+ PJMEDIA_FILE_WRITE_PCM,
3618
+ 0,
3619
+ (pjmedia_port**)&c->wav_writer);
3620
+ if(status != PJ_SUCCESS) return false;
3621
+
3622
+ connect_media_ports(c);
3623
+ return true;
3624
+ }
3625
+
3626
+ bool prepare_wire(pj_pool_t *pool, chainlink **link, unsigned sampling_rate, unsigned channel_count, unsigned samples_per_frame, unsigned bits_per_sample) {
3627
+ pj_status_t status;
3628
+
3629
+ if(*link) {
3630
+ //addon_log(LOG_LEVEL_DEBUG, "prepare_wire: link is set. It will be destroyed\n");
3631
+ pjmedia_port *port = (pjmedia_port*)*link;
3632
+ status = pjmedia_port_destroy(port);
3633
+ *link = NULL;
3634
+ if(status != PJ_SUCCESS) return false;
3635
+ }
3636
+
3637
+ status = chainlink_wire_port_create(pool,
3638
+ sampling_rate,
3639
+ channel_count,
3640
+ samples_per_frame,
3641
+ bits_per_sample,
3642
+ (pjmedia_port**)link);
3643
+ if(status != PJ_SUCCESS) return false;
3644
+
3645
+ return true;
3646
+ }
3647
+
3648
+ void on_rx_notify(pjsip_evsub *sub, pjsip_rx_data *rdata, int *p_st_code, pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body) {
3649
+ //addon_log(LOG_LEVEL_DEBUG, "on_rx_notify\n");
3650
+
3651
+ char evt[2048];
3652
+
3653
+ if(g_shutting_down) return;
3654
+
3655
+ ostringstream oss;
3656
+ Subscription *s;
3657
+
3658
+ s = (Subscription*)pjsip_evsub_get_mod_data(sub, mod_tester.id);
3659
+ if(!s) {
3660
+ addon_log(LOG_LEVEL_DEBUG, "Subscription not set at mod_data. Ignoring\n");
3661
+ return;
3662
+ }
3663
+
3664
+ make_evt_request(evt, sizeof(evt), "subscription", s->id, rdata->msg_info.len, rdata->msg_info.msg_buf);
3665
+ dispatch_event(evt);
3666
+ }
3667
+
3668
+ static void on_client_refresh( pjsip_evsub *sub ) {
3669
+ Subscription *subscription;
3670
+ pj_status_t status;
3671
+
3672
+ subscription = (Subscription*) pjsip_evsub_get_mod_data(sub, mod_tester.id);
3673
+
3674
+ if(!subscription) {
3675
+ set_error("on_client_refresh: pjsip_evsub_get_mod_data returned 0");
3676
+ goto out;
3677
+ }
3678
+
3679
+ if(!subscription_subscribe(subscription, -1, "")) {
3680
+ goto out;
3681
+ }
3682
+
3683
+ //addon_log(LOG_LEVEL_DEBUG, "on_client_refresh: SUBSCRIBE dispatched\n");
3684
+
3685
+ out:
3686
+ if(pjw_errorstring[0]) {
3687
+ dispatch_event(pjw_errorstring);
3688
+ }
3689
+ }
3690
+
3691
+ static void client_on_evsub_state( pjsip_evsub *sub, pjsip_event *event) {
3692
+ if(g_shutting_down) return;
3693
+
3694
+ char evt[2048];
3695
+ pj_str_t mname;
3696
+
3697
+ //addon_log(LOG_LEVEL_DEBUG, "client_on_evsub_state: %s\n", pjsip_evsub_get_state_name(sub));
3698
+
3699
+ PJ_UNUSED_ARG(event);
3700
+
3701
+ pjsip_rx_data *rdata;
3702
+ Subscription *subscription = (Subscription*)pjsip_evsub_get_mod_data(sub, mod_tester.id);
3703
+ if(!subscription) {
3704
+ //addon_log(LOG_LEVEL_DEBUG, "mod_data set to NULL (it means subscription doesn't exist anymore). Ignoring\n");
3705
+ addon_log(LOG_LEVEL_DEBUG, "mod_data set to NULL (we don't know what this means yet. Ignoring\n");
3706
+ return;
3707
+ }
3708
+
3709
+ pjsip_generic_string_hdr *refer_sub;
3710
+ const pj_str_t REFER_SUB = { "Refer-Sub", 9 };
3711
+ ostringstream oss;
3712
+
3713
+ // When subscription is accepted (got 200/OK)
3714
+ int state = pjsip_evsub_get_state(sub);
3715
+ if(state == PJSIP_EVSUB_STATE_ACCEPTED) {
3716
+
3717
+ pj_assert(event->type == PJSIP_EVENT_TSX_STATE &&
3718
+ event->body.tsx_state.type == PJSIP_EVENT_RX_MSG);
3719
+
3720
+ rdata = event->body.tsx_state.src.rdata;
3721
+
3722
+ mname = rdata->msg_info.cseq->method.name;
3723
+ make_evt_response(evt, sizeof(evt), "subscription", subscription->id, mname.slen, mname.ptr, rdata->msg_info.len, rdata->msg_info.msg_buf);
3724
+ dispatch_event(evt);
3725
+
3726
+
3727
+ //Find Refer-Sub header
3728
+ refer_sub = (pjsip_generic_string_hdr*)
3729
+ pjsip_msg_find_hdr_by_name(rdata->msg_info.msg,
3730
+ &REFER_SUB,
3731
+ NULL);
3732
+
3733
+ if(refer_sub && pj_strcmp2(&refer_sub->hvalue, "false") == 0) {
3734
+ pjsip_evsub_terminate(sub, PJ_TRUE);
3735
+ }
3736
+
3737
+ } else if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_ACTIVE ||
3738
+ pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) {
3739
+ //Here we catch incoming NOTIFY
3740
+
3741
+ //addon_log(LOG_LEVEL_DEBUG, "NOTIFY\n");
3742
+
3743
+ //When subscription is terminated
3744
+ if(pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) {
3745
+ pjsip_evsub_set_mod_data(sub, mod_tester.id, NULL);
3746
+ }
3747
+
3748
+ return;
3749
+
3750
+ rdata = event->body.tsx_state.src.rdata;
3751
+
3752
+ Transport *t;
3753
+ //build_basic_request_info(&oss, rdata, &t);
3754
+
3755
+ long subscription_id;
3756
+ if( !g_subscription_ids.get_id((long)subscription, subscription_id) ){
3757
+ /*
3758
+ addon_log(LOG_LEVEL_DEBUG, "FAILURE\n");
3759
+ oss.seekp(0);
3760
+ oss << "event=internal_error" << EVT_DATA_SEP << "details=Failed to get call_id";
3761
+ dispatch_event(oss.str().c_str());
3762
+ */
3763
+
3764
+ char error_msg[] = "failed to get subscription_id";
3765
+ make_evt_internal_error(evt, sizeof(evt), error_msg);
3766
+ dispatch_event(evt);
3767
+ return;
3768
+ }
3769
+
3770
+ //addon_log(LOG_LEVEL_DEBUG, "dispatching NOTIFY event\n");
3771
+ //dispatch_event(oss.str().c_str());
3772
+
3773
+ make_evt_request(evt, sizeof(evt), "subscription", subscription_id, rdata->msg_info.len, rdata->msg_info.msg_buf);
3774
+ dispatch_event(evt);
3775
+
3776
+ if(pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) {
3777
+ pjsip_evsub_set_mod_data(sub, mod_tester.id, NULL);
3778
+ }
3779
+
3780
+ } else {
3781
+ //It is not message. Just ignore.
3782
+ return;
3783
+ }
3784
+ }
3785
+
3786
+ static void server_on_evsub_state( pjsip_evsub *sub, pjsip_event *event)
3787
+ {
3788
+ Subscriber *s;
3789
+ pj_status_t status;
3790
+ pjsip_tx_data *tdata;
3791
+
3792
+ //addon_log(LOG_LEVEL_DEBUG, "server_on_evsub_state\n");
3793
+ if(!sub) {
3794
+ addon_log(LOG_LEVEL_DEBUG, "server_on_evesub_state: sub not set. Ignoring\n");
3795
+ return;
3796
+ }
3797
+ //addon_log(LOG_LEVEL_DEBUG, "state= %d\n", pjsip_evsub_get_state(sub));
3798
+ //addon_log(LOG_LEVEL_DEBUG, "server_on_evsub_state %s\n", pjsip_evsub_get_state_name(sub));
3799
+
3800
+ if(g_shutting_down) return;
3801
+
3802
+ PJ_UNUSED_ARG(event);
3803
+
3804
+ s = (Subscriber*)pjsip_evsub_get_mod_data(sub, mod_tester.id);
3805
+ if (!s) {
3806
+ addon_log(LOG_LEVEL_DEBUG, "server_on_evsub_state: Subscriber not set as mod_data. Ignoring\n");
3807
+ return;
3808
+ }
3809
+
3810
+ /*
3811
+ * When subscription is terminated, clear the xfer_sub member of
3812
+ * the inv_data.
3813
+ */
3814
+
3815
+ if (pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) {
3816
+ pjsip_evsub_set_mod_data(sub, mod_tester.id, NULL);
3817
+ }
3818
+ }
3819
+
3820
+ //Called when incoming SUBSCRIBE (or any method taht establishes a subscription like REFER) is received
3821
+ static void server_on_evsub_rx_refresh(pjsip_evsub *sub, pjsip_rx_data *rdata, int *p_st_code, pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body)
3822
+ {
3823
+ char evt[2048];
3824
+
3825
+ pjw_errorstring[0] = 0;
3826
+
3827
+ pj_status_t status;
3828
+ pjsip_tx_data *tdata;
3829
+
3830
+ ostringstream oss;
3831
+ Subscriber *s;
3832
+ Transport *t;
3833
+
3834
+ if(g_shutting_down) return;
3835
+ addon_log(LOG_LEVEL_DEBUG, "server_on_evsub_rx_refresh\n");
3836
+
3837
+ s = (Subscriber*)pjsip_evsub_get_mod_data(sub, mod_tester.id);
3838
+ if(!s) {
3839
+ set_error("pjsip_evsub_get_mod_data failed");
3840
+ goto out;
3841
+ }
3842
+
3843
+ make_evt_request(evt, sizeof(evt), "subscriber", s->id, rdata->msg_info.len, rdata->msg_info.msg_buf);
3844
+ dispatch_event(evt);
3845
+
3846
+ if( pjsip_evsub_get_state(sub) == PJSIP_EVSUB_STATE_TERMINATED) {
3847
+ pj_str_t reason = { "noresource", 10 };
3848
+ status = pjsip_evsub_notify(sub,
3849
+ PJSIP_EVSUB_STATE_TERMINATED,
3850
+ NULL,
3851
+ &reason,
3852
+ &tdata);
3853
+ if(status != PJ_SUCCESS) {
3854
+ set_error("pjsip_evsub_notify failed");
3855
+ goto out;
3856
+ }
3857
+ } else {
3858
+ status = pjsip_evsub_current_notify(sub, &tdata);
3859
+ if(status != PJ_SUCCESS) {
3860
+ set_error("pjsip_evsub_current_notify failed");
3861
+ goto out;
3862
+ }
3863
+ }
3864
+
3865
+ status = pjsip_evsub_send_request(sub,tdata);
3866
+ if(status != PJ_SUCCESS) {
3867
+ set_error("pjsip_send_request failed");
3868
+ goto out;
3869
+ }
3870
+ addon_log(LOG_LEVEL_DEBUG, "server_on_evsub_rx_refresh: NOTIFY containing subscription state should have been sent\n");
3871
+
3872
+ out:
3873
+ if(pjw_errorstring[0]) {
3874
+ make_evt_internal_error(evt, sizeof(evt), pjw_errorstring);
3875
+ dispatch_event(evt);
3876
+ }
3877
+ }
3878
+
3879
+
3880
+ //Adapted (mostly copied) from pjsua function on_call_transfered
3881
+ void process_in_dialog_refer(pjsip_dialog *dlg, pjsip_rx_data *rdata)
3882
+ {
3883
+ addon_log(LOG_LEVEL_DEBUG, "process_in_dialog_refer\n");
3884
+
3885
+ char evt[2048];
3886
+
3887
+ pj_status_t status;
3888
+ pjsip_tx_data *tdata;
3889
+ int new_call;
3890
+ const pj_str_t str_refer_to = { "Refer-To", 8};
3891
+ const pj_str_t str_refer_sub = { "Refer-Sub", 9 };
3892
+ const pj_str_t str_ref_by = { "Referred-By", 11 };
3893
+ pjsip_generic_string_hdr *refer_to;
3894
+ pjsip_generic_string_hdr *refer_sub;
3895
+ pjsip_hdr *ref_by_hdr;
3896
+ pj_bool_t no_refer_sub = PJ_FALSE;
3897
+ char *uri;
3898
+ pj_str_t tmp;
3899
+ pjsip_status_code code;
3900
+ pjsip_evsub *sub;
3901
+
3902
+ Call *call = (Call*)dlg->mod_data[mod_tester.id];
3903
+ long call_id;
3904
+ if( !g_call_ids.get_id((long)call, call_id) ){
3905
+ addon_log(LOG_LEVEL_DEBUG, "process_in_dialog_refer: Failed to get call_id. Event will not be notified.\n");
3906
+ return;
3907
+ }
3908
+
3909
+ /* Find the Refer-To header */
3910
+ refer_to = (pjsip_generic_string_hdr*)
3911
+ pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_refer_to, NULL);
3912
+
3913
+ if (refer_to == NULL) {
3914
+ /* Invalid Request.
3915
+ * No Refer-To header!
3916
+ */
3917
+ pjsip_dlg_respond( dlg, rdata, 400, NULL, NULL, NULL);
3918
+ //dispatch_event("event=broken_refer");
3919
+ return;
3920
+ }
3921
+
3922
+ /* Find optional Referred-By header (to be copied onto outgoing INVITE
3923
+ * request.
3924
+ */
3925
+ ref_by_hdr = (pjsip_hdr*)
3926
+ pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_ref_by,
3927
+ NULL);
3928
+
3929
+ if(ref_by_hdr) {
3930
+ pjsip_generic_string_hdr *referred_by = (pjsip_generic_string_hdr*)ref_by_hdr;
3931
+ }
3932
+
3933
+ /* Find optional Refer-Sub header */
3934
+ refer_sub = (pjsip_generic_string_hdr*)
3935
+ pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &str_refer_sub, NULL);
3936
+
3937
+ if (refer_sub) {
3938
+ if (!pj_strnicmp2(&refer_sub->hvalue, "true", 4)==0) {
3939
+ //Header Refer-sub (Refer Subscription) set to something other than true (probably to 'false').
3940
+ //This means the requester doesn't want to be subscribed to refer events
3941
+ // For details look for ietf draft : Suppression of Session Initiation Protocol REFER Method Implicit Subscription
3942
+ // draft-ietf-sip-refer-with-norefersub-04
3943
+ no_refer_sub = PJ_TRUE;
3944
+ }
3945
+ }
3946
+
3947
+ code = PJSIP_SC_ACCEPTED;
3948
+
3949
+ if (no_refer_sub) {
3950
+ /*
3951
+ * Always answer with 2xx.
3952
+ */
3953
+ pjsip_tx_data *tdata;
3954
+ const pj_str_t str_false = { "false", 5};
3955
+ pjsip_hdr *hdr;
3956
+
3957
+ status = pjsip_dlg_create_response(dlg, rdata, code, NULL,
3958
+ &tdata);
3959
+ if (status != PJ_SUCCESS) {
3960
+ make_evt_internal_error(evt, sizeof(evt), "REFER response creation failure");
3961
+ dispatch_event(evt);
3962
+ return;
3963
+ }
3964
+
3965
+ /* Add Refer-Sub header */
3966
+ hdr = (pjsip_hdr*)
3967
+ pjsip_generic_string_hdr_create(tdata->pool, &str_refer_sub,
3968
+ &str_false);
3969
+ pjsip_msg_add_hdr(tdata->msg, hdr);
3970
+
3971
+
3972
+ /* Send answer */
3973
+ status = pjsip_dlg_send_response(dlg, pjsip_rdata_get_tsx(rdata),
3974
+ tdata);
3975
+ if (status != PJ_SUCCESS) {
3976
+ make_evt_internal_error(evt, sizeof(evt), "REFER response transmission failure");
3977
+ dispatch_event(evt);
3978
+ return;
3979
+ }
3980
+
3981
+ /* Don't have subscription */
3982
+ sub = NULL;
3983
+
3984
+ } else {
3985
+ struct pjsip_evsub_user xfer_cb;
3986
+ pjsip_hdr hdr_list;
3987
+
3988
+ /* Init callback */
3989
+ pj_bzero(&xfer_cb, sizeof(xfer_cb));
3990
+ xfer_cb.on_evsub_state = &server_on_evsub_state;
3991
+
3992
+ /* Init additional header list to be sent with REFER response */
3993
+ pj_list_init(&hdr_list);
3994
+
3995
+ /* Create transferee event subscription */
3996
+ status = pjsip_xfer_create_uas( call->inv->dlg, &xfer_cb, rdata, &sub);
3997
+ if (status != PJ_SUCCESS) {
3998
+ make_evt_internal_error(evt, sizeof(evt), "xfer_uas_creation failure");
3999
+ dispatch_event(evt);
4000
+ pjsip_dlg_respond( call->inv->dlg, rdata, 500, NULL, NULL, NULL);
4001
+ return;
4002
+ }
4003
+
4004
+ /* If there's Refer-Sub header and the value is "true", send back
4005
+ * Refer-Sub in the response with value "true" too.
4006
+ */
4007
+ if (refer_sub) {
4008
+ const pj_str_t str_true = { "true", 4 };
4009
+ pjsip_hdr *hdr;
4010
+
4011
+ hdr = (pjsip_hdr*)
4012
+ pjsip_generic_string_hdr_create(call->inv->dlg->pool,
4013
+ &str_refer_sub,
4014
+ &str_true);
4015
+ pj_list_push_back(&hdr_list, hdr);
4016
+
4017
+ }
4018
+
4019
+ /* Accept the REFER request, send 2xx. */
4020
+ pjsip_xfer_accept(sub, rdata, code, &hdr_list);
4021
+
4022
+ }
4023
+
4024
+ if (sub) {
4025
+ //If the REFER caused subscription of the referer...
4026
+ Subscriber *subscriber = (Subscriber*)pj_pool_zalloc(dlg->pool, sizeof(Subscriber));
4027
+ subscriber->evsub = sub;
4028
+ subscriber->created_by_refer = true;
4029
+
4030
+ long subscriber_id;
4031
+ if(!g_subscriber_ids.add((long)subscriber, subscriber_id)) {
4032
+ make_evt_internal_error(evt, sizeof(evt), "Failed to allocate id for subscriber");
4033
+ dispatch_event(evt);
4034
+ return;
4035
+ }
4036
+ subscriber->id = subscriber_id;
4037
+ pjsip_evsub_set_mod_data(sub, mod_tester.id, subscriber);
4038
+
4039
+ make_evt_request(evt, sizeof(evt), "subscriber", subscriber_id, rdata->msg_info.len, rdata->msg_info.msg_buf);
4040
+ dispatch_event(evt);
4041
+ }
4042
+ }
4043
+
4044
+ static void on_tsx_state_changed(pjsip_inv_session *inv,
4045
+ pjsip_transaction *tsx,
4046
+ pjsip_event *e)
4047
+ {
4048
+ if(g_shutting_down) return;
4049
+
4050
+ char evt[2048];
4051
+
4052
+ Call *call;
4053
+
4054
+ if(!inv->dlg) return;
4055
+
4056
+ call = (Call*) inv->dlg->mod_data[mod_tester.id];
4057
+
4058
+ if (call == NULL) {
4059
+ return;
4060
+ }
4061
+
4062
+ if (call->inv == NULL) {
4063
+ /* Shouldn't happen. It happens only when we don't terminate the
4064
+ * server subscription caused by REFER after the call has been
4065
+ * transfered (and this call has been disconnected), and we
4066
+ * receive another REFER for this call.
4067
+ */
4068
+ return;
4069
+ }
4070
+
4071
+ //ostringstream oss;
4072
+ Transport *t;
4073
+ if (tsx->role==PJSIP_ROLE_UAS &&
4074
+ tsx->state==PJSIP_TSX_STATE_TRYING) {
4075
+ if(pjsip_method_cmp(&tsx->method, pjsip_get_refer_method())==0) {
4076
+ /*
4077
+ * Incoming REFER request.
4078
+ */
4079
+
4080
+ process_in_dialog_refer(call->inv->dlg, e->body.tsx_state.src.rdata);
4081
+ } else {
4082
+ make_evt_request(evt, sizeof(evt), "call", call->id, e->body.tsx_state.src.rdata->msg_info.len, e->body.tsx_state.src.rdata->msg_info.msg_buf);
4083
+ dispatch_event(evt);
4084
+
4085
+ pjsip_dlg_respond(call->inv->dlg, e->body.tsx_state.src.rdata, 200, NULL, NULL, NULL);
4086
+ }
4087
+ }
4088
+ }
4089
+
4090
+ int pjw_call_refer(long call_id, const char *dest_uri, const char *additional_headers, long *out_subscription_id)
4091
+ {
4092
+ PJW_LOCK();
4093
+ clear_error();
4094
+
4095
+ int n;
4096
+ long val;
4097
+ Call *call;
4098
+ Subscription *s;
4099
+ pj_str_t s_dest_uri;
4100
+
4101
+ long subscription_id;
4102
+ struct pjsip_evsub_user xfer_cb;
4103
+ pjsip_evsub *sub;
4104
+ pjsip_tx_data *tdata;
4105
+ pj_status_t status;
4106
+
4107
+ if(!g_call_ids.get(call_id, val)){
4108
+ set_error("Invalid call_id");
4109
+ goto out;
4110
+ }
4111
+
4112
+ call = (Call*)val;
4113
+
4114
+ if(!check_uri(dest_uri)) {
4115
+ set_error("Invalid dest_uri");
4116
+ goto out;
4117
+ }
4118
+
4119
+ pj_bzero(&xfer_cb, sizeof(xfer_cb));
4120
+ xfer_cb.on_evsub_state = &client_on_evsub_state;
4121
+ xfer_cb.on_rx_notify = &on_rx_notify;
4122
+
4123
+ status = pjsip_xfer_create_uac(call->inv->dlg, &xfer_cb, &sub);
4124
+ if(status != PJ_SUCCESS) {
4125
+ set_error("pjsip_xfer_create_uac failed");
4126
+ goto out;
4127
+ }
4128
+
4129
+ s_dest_uri = pj_str((char*)dest_uri);
4130
+ status = pjsip_xfer_initiate(sub, &s_dest_uri, &tdata);
4131
+
4132
+ if(!add_additional_headers(call->inv->dlg->pool, tdata, additional_headers)) {
4133
+ goto out;
4134
+ }
4135
+
4136
+ status = pjsip_xfer_send_request(sub, tdata);
4137
+ if(status != PJ_SUCCESS) {
4138
+ set_error("pjsip_xfer_send_request failed");
4139
+ goto out;
4140
+ }
4141
+
4142
+ out:
4143
+ PJW_UNLOCK();
4144
+
4145
+ if(pjw_errorstring[0]) {
4146
+ return -1;
4147
+ }
4148
+ *out_subscription_id = subscription_id;
4149
+ return 0;
4150
+ }
4151
+
4152
+ int pjw_call_get_info(long call_id, const char *required_info, char *out_info)
4153
+ {
4154
+ PJW_LOCK();
4155
+
4156
+ long val;
4157
+
4158
+ char info[1000];
4159
+
4160
+ if(!g_call_ids.get(call_id, val)){
4161
+ PJW_UNLOCK();
4162
+ set_error("Invalid call_id");
4163
+ return -1;
4164
+ }
4165
+
4166
+ Call *call = (Call*)val;
4167
+
4168
+ if(strcmp(required_info, "Call-ID") == 0) {
4169
+ strncpy(info, call->inv->dlg->call_id->id.ptr, call->inv->dlg->call_id->id.slen);
4170
+ info[call->inv->dlg->call_id->id.slen] = 0;
4171
+ } else if(strcmp(required_info, "RemoteMediaEndPoint") == 0) {
4172
+ if(!call->med_stream) {
4173
+ PJW_UNLOCK();
4174
+ set_error("Unable to get RemoteMediaEndPoint: Media not ready");
4175
+ return -1;
4176
+ }
4177
+ pjmedia_stream_info session_info;
4178
+ if(pjmedia_stream_get_info(call->med_stream, &session_info) != PJ_SUCCESS) {
4179
+ PJW_UNLOCK();
4180
+ set_error("Unable to get RemoteMediaEndPoint: call to pjmedia_stream_info failed");
4181
+ return -1;
4182
+ }
4183
+ pj_str_t str_addr = pj_str( inet_ntoa( (in_addr&)session_info.rem_addr.ipv4.sin_addr.s_addr ) );
4184
+ pj_uint16_t port = session_info.rem_addr.ipv4.sin_port;
4185
+ sprintf(info, "%.*s:%u", str_addr.slen, str_addr.ptr, ntohs(port));
4186
+ } else {
4187
+ PJW_UNLOCK();
4188
+ set_error("Unsupported info");
4189
+ return -1;
4190
+ }
4191
+
4192
+ PJW_UNLOCK();
4193
+ strcpy(out_info, info);
4194
+ return 0;
4195
+ }
4196
+
4197
+ bool notify(pjsip_evsub *evsub, const char *content_type, const char *body, int subscription_state, const char *reason, const char *additional_headers) {
4198
+ pj_str_t s_content_type;
4199
+ pj_str_t s_body;
4200
+ pj_str_t s_reason;
4201
+
4202
+ char *temp;
4203
+ int bodylen;
4204
+
4205
+ char *tok;
4206
+
4207
+ pjsip_msg_body *msg_body;
4208
+
4209
+ char *content_type_buffer;
4210
+ pj_str_t s_content_type_type;
4211
+ pj_str_t s_content_type_subtype;
4212
+ pj_str_t s_content_type_param;
4213
+
4214
+ char *blank_string;
4215
+
4216
+ pjsip_tx_data *tdata;
4217
+ pj_status_t status;
4218
+
4219
+ s_reason = pj_str((char*)reason);
4220
+
4221
+ status = pjsip_evsub_notify(evsub, (pjsip_evsub_state)subscription_state, NULL, &s_reason, &tdata);
4222
+ if(status != PJ_SUCCESS) {
4223
+ set_error("pjsip_evsub_notify failed");
4224
+ return false;
4225
+ }
4226
+
4227
+ bodylen = strlen(body);
4228
+ temp = (char*)pj_pool_alloc(tdata->pool, bodylen+1);
4229
+ strcpy(temp,body);
4230
+
4231
+ msg_body = PJ_POOL_ZALLOC_T(tdata->pool, pjsip_msg_body);
4232
+
4233
+ content_type_buffer = (char*)pj_pool_alloc(tdata->pool, strlen(content_type) + 1);
4234
+ strcpy(content_type_buffer, content_type);
4235
+
4236
+ tok = strtok(content_type_buffer, "/");
4237
+ if(!tok) {
4238
+ set_error("Invalid Content-Type header (while checking type)");
4239
+ return false;
4240
+ }
4241
+ s_content_type_type = pj_str(tok);
4242
+
4243
+ //tok = strtok(NULL, ";");
4244
+ tok = strtok(NULL, "");
4245
+ if(!tok) {
4246
+ set_error("Invalid Content-Type header (while checking subtype)");
4247
+ return false;
4248
+ }
4249
+ s_content_type_subtype = pj_str(tok);
4250
+
4251
+ add_additional_headers(tdata->pool, tdata, additional_headers);
4252
+
4253
+ msg_body->content_type.type = s_content_type_type;
4254
+ msg_body->content_type.subtype = s_content_type_subtype;
4255
+ //msg_body->content_type.param = s_content_type_param;
4256
+ msg_body->data = temp;
4257
+ msg_body->len = bodylen;
4258
+ msg_body->print_body = &pjsip_print_text_body;
4259
+ msg_body->clone_data = &pjsip_clone_text_data;
4260
+
4261
+ tdata->msg->body = msg_body;
4262
+
4263
+ status = pjsip_evsub_send_request(evsub, tdata);
4264
+ if(status != PJ_SUCCESS) {
4265
+ set_error("pjsip_evsub_send_request failed");
4266
+ return false;
4267
+ }
4268
+
4269
+ return true;
4270
+ }
4271
+
4272
+ int pjw_notify(long subscriber_id, const char *content_type, const char *body, int subscription_state, const char *reason, const char *additional_headers)
4273
+ {
4274
+ PJW_LOCK();
4275
+
4276
+ clear_error();
4277
+
4278
+ int n;
4279
+ long val;
4280
+
4281
+ Subscriber *subscriber;
4282
+
4283
+ if(!g_subscriber_ids.get(subscriber_id, val)){
4284
+ set_error("Invalid subscriber_id");
4285
+ goto out;
4286
+ }
4287
+
4288
+ subscriber = (Subscriber*)val;
4289
+
4290
+ if(subscriber->created_by_refer) {
4291
+ set_error("Invalid subscriber_id: subscription was generated by REFER (use notify_xfer instead)");
4292
+ goto out;
4293
+ }
4294
+
4295
+ if(!notify(subscriber->evsub, content_type, body, subscription_state, reason, additional_headers)){
4296
+ goto out;
4297
+ }
4298
+
4299
+ out:
4300
+ PJW_UNLOCK();
4301
+
4302
+ if(pjw_errorstring[0]) {
4303
+ return -1;
4304
+ }
4305
+
4306
+ return 0;
4307
+ }
4308
+
4309
+
4310
+ int pjw_notify_xfer(long subscriber_id, int subscription_state, int xfer_status_code, const char *xfer_status_text) {
4311
+ PJW_LOCK();
4312
+
4313
+ clear_error();
4314
+
4315
+ int n;
4316
+ pjsip_tx_data *tdata;
4317
+ pj_status_t status;
4318
+
4319
+ long val;
4320
+
4321
+ Subscriber *subscriber;
4322
+ pj_str_t s_xfer_status_text;
4323
+
4324
+ if(!g_subscriber_ids.get(subscriber_id, val)){
4325
+ set_error("Invalid subscriber_id");
4326
+ goto out;
4327
+ }
4328
+
4329
+ subscriber = (Subscriber*)val;
4330
+
4331
+ if(!subscriber->created_by_refer) {
4332
+ set_error("Subscriber was not created by REFER");
4333
+ goto out;
4334
+ }
4335
+
4336
+ s_xfer_status_text = pj_str((char*)xfer_status_text);
4337
+
4338
+ status = pjsip_xfer_notify( subscriber->evsub,
4339
+ (pjsip_evsub_state)subscription_state,
4340
+ xfer_status_code,
4341
+ &s_xfer_status_text,
4342
+ &tdata);
4343
+ if (status != PJ_SUCCESS) {
4344
+ set_error( "Unable to create NOTIFY for 'Event: refer'");
4345
+ goto out;
4346
+ }
4347
+
4348
+ status = pjsip_xfer_send_request( subscriber->evsub, tdata);
4349
+ if (status != PJ_SUCCESS) {
4350
+ set_error("Unable to send NOTIFY for 'Event: refer'");
4351
+ goto out;
4352
+ }
4353
+
4354
+ out:
4355
+ PJW_UNLOCK();
4356
+
4357
+ if(pjw_errorstring[0]) {
4358
+ return -1;
4359
+ }
4360
+
4361
+ return 0;
4362
+ }
4363
+
4364
+ pj_bool_t add_additional_headers(pj_pool_t *pool, pjsip_tx_data *tdata, const char *additional_headers) {
4365
+
4366
+ if(additional_headers && additional_headers[0]){
4367
+ char buf[2048];
4368
+ strcpy(buf,additional_headers);
4369
+ char *saved;
4370
+ char *token = strtok_r(buf, "\n", &saved);
4371
+ while(token){
4372
+ char *name = strtok(token, ":");
4373
+ char *value = strtok(NULL, "\n");
4374
+ //addon_log(LOG_LEVEL_DEBUG, "Adding %s: %s\n", name, value);
4375
+
4376
+ if(!name || !value) {
4377
+ set_error("Invalid additional_header");
4378
+ return PJ_FALSE;
4379
+ }
4380
+
4381
+ pj_str_t hname = pj_str(name);
4382
+ pjsip_hdr *hdr = (pjsip_hdr*)pjsip_parse_hdr(pool,
4383
+ &hname,
4384
+ value,
4385
+ strlen(value),
4386
+ NULL);
4387
+
4388
+ if(!hdr) {
4389
+ set_error("Failed to parse additional header to INVITE");
4390
+ return PJ_FALSE;
4391
+ }
4392
+ pjsip_hdr *clone_hdr = (pjsip_hdr*) pjsip_hdr_clone(pool, hdr);
4393
+ pjsip_msg_add_hdr(tdata->msg, clone_hdr);
4394
+
4395
+ token = strtok_r(NULL, "\n", &saved);
4396
+ }
4397
+ }
4398
+ return PJ_TRUE;
4399
+ }
4400
+
4401
+ pj_bool_t add_additional_headers_for_account(pjsip_regc *regc, const char *additional_headers) {
4402
+
4403
+ if(additional_headers && additional_headers[0]){
4404
+ pjsip_hdr hdr_list;
4405
+ pj_list_init(&hdr_list);
4406
+
4407
+ char pool_buf[4096];
4408
+ pj_pool_t *pool;
4409
+ pool = pj_pool_create_on_buf(NULL, pool_buf, sizeof(pool_buf));
4410
+
4411
+ char buf[2048];
4412
+ strcpy(buf,additional_headers);
4413
+ char *saved;
4414
+ char *token = strtok_r(buf, "\n", &saved);
4415
+ while(token){
4416
+ char *name = strtok(token, ":");
4417
+ char *value = strtok(NULL, "\n");
4418
+ //addon_log(LOG_LEVEL_DEBUG, "Adding %s:%s\n", name, value);
4419
+
4420
+ if(!name || !value) {
4421
+ set_error("Invalid additional_header");
4422
+ return PJ_FALSE;
4423
+ }
4424
+
4425
+ pj_str_t hname = pj_str(name);
4426
+ pjsip_hdr *hdr = (pjsip_hdr*)pjsip_parse_hdr(pool,
4427
+ &hname,
4428
+ value,
4429
+ strlen(value),
4430
+ NULL);
4431
+
4432
+ if(!hdr) {
4433
+ set_error("Failed to parse additional header to INVITE");
4434
+ return PJ_FALSE;
4435
+ }
4436
+
4437
+ pj_list_push_back(&hdr_list, hdr);
4438
+ token = strtok_r(NULL, "\n", &saved);
4439
+ }
4440
+ pjsip_regc_add_headers(regc, &hdr_list);
4441
+ }
4442
+ return PJ_TRUE;
4443
+ }
4444
+
4445
+ pj_bool_t get_content_type_and_subtype_from_additional_headers(const char *additional_headers, char *type, char *subtype) {
4446
+
4447
+ if(!additional_headers || !additional_headers[0]){
4448
+ set_error("Header Content-Type not supplied");
4449
+ return PJ_FALSE;
4450
+ }
4451
+
4452
+ char buf[1000];
4453
+ strcpy(buf,additional_headers);
4454
+ char *saved;
4455
+ char *token = strtok_r(buf, "\n", &saved);
4456
+ while(token){
4457
+ char *name = strtok(token, ":");
4458
+ char *value = strtok(NULL, " ");
4459
+ addon_log(LOG_LEVEL_DEBUG, "Checking %s: %s\n", name, value);
4460
+
4461
+ if(!name || !value) {
4462
+ set_error("Invalid additional_header");
4463
+ return PJ_FALSE;
4464
+ }
4465
+
4466
+ if(strcmp(name, "Content-Type")==0) {
4467
+ char *token_type = strtok(value, "/");
4468
+ if(!token_type) {
4469
+ set_error("No type specified in header Content-Type");
4470
+ return PJ_FALSE;
4471
+ }
4472
+
4473
+ char *token_subtype = strtok(NULL, "\n");
4474
+ if(!token_subtype) {
4475
+ set_error("No subtype specified in header Content-Type");
4476
+ return PJ_FALSE;
4477
+ }
4478
+
4479
+ strcpy(type, token_type);
4480
+ strcpy(subtype, token_subtype);
4481
+ addon_log(LOG_LEVEL_DEBUG, "Checking parsing of Content-Type. type=%s: subtype=%s\n", type, subtype);
4482
+ return PJ_TRUE;
4483
+ }
4484
+ token = strtok_r(NULL, "\n", &saved);
4485
+ }
4486
+ set_error("Header Content-Type not supplied");
4487
+ return PJ_FALSE;
4488
+ }
4489
+
4490
+
4491
+
4492
+ bool register_pkg(const char *event, const char *accept) {
4493
+ PackageSet::iterator iter = g_PackageSet.find( make_pair( string(event), string(accept) ) );
4494
+ if(g_PackageSet.end() == iter) {
4495
+ g_PackageSet.insert( make_pair( string(event), string(accept) ) );
4496
+ pj_status_t status;
4497
+ pj_str_t s_event = pj_str((char*)event);
4498
+ pj_str_t s_accept = pj_str((char*)accept);
4499
+ status = pjsip_evsub_register_pkg(&mod_tester, &s_event, DEFAULT_EXPIRES, 1, &s_accept);
4500
+ if(status != PJ_SUCCESS) {
4501
+ set_error("pjsip_evsub_register_pkg failed");
4502
+ return false;
4503
+ }
4504
+ }
4505
+ return true;
4506
+ }
4507
+
4508
+ int pjw_register_pkg(const char *event, const char *accept) {
4509
+ PJW_LOCK();
4510
+
4511
+ clear_error();
4512
+
4513
+ int n;
4514
+
4515
+ if(!register_pkg(event, accept)) {
4516
+ goto out;
4517
+ }
4518
+
4519
+ out:
4520
+ PJW_UNLOCK();
4521
+ if(pjw_errorstring[0]) {
4522
+ return -1;
4523
+ }
4524
+
4525
+ return 0;
4526
+ }
4527
+
4528
+ int pjw_subscription_create(long transport_id, const char *event, const char *accept, const char *from_uri, const char *to_uri, const char *request_uri, const char *proxy_uri, const char *realm, const char *username, const char *password, long *out_subscription_id) {
4529
+ PJW_LOCK();
4530
+
4531
+ clear_error();
4532
+
4533
+ int n;
4534
+ long subscription_id;
4535
+ Subscription *subscription;
4536
+ Transport *t;
4537
+ long val;
4538
+ const char *contact_username = "sip";
4539
+
4540
+ char local_contact[400];
4541
+ char *start;
4542
+
4543
+ pjsip_dialog *dlg = NULL;
4544
+ pjsip_evsub *evsub = NULL;
4545
+ pjsip_evsub_user user_cb;
4546
+
4547
+ pj_str_t s_event;
4548
+
4549
+ pj_status_t status;
4550
+
4551
+ if(!g_transport_ids.get(transport_id, val)){
4552
+ set_error("Invalid transport_id");
4553
+ goto out;
4554
+ }
4555
+ t = (Transport*)val;
4556
+
4557
+ if(!check_uri(from_uri)) {
4558
+ set_error("Invalid from_uri");
4559
+ goto out;
4560
+ }
4561
+
4562
+ if(!check_uri(to_uri)) {
4563
+ set_error("Invalid to_uri");
4564
+ goto out;
4565
+ }
4566
+
4567
+ if(request_uri){
4568
+ if(!check_uri(request_uri)) {
4569
+ set_error("Invalid request_uri");
4570
+ goto out;
4571
+ }
4572
+ }else{
4573
+ request_uri = to_uri;
4574
+ }
4575
+
4576
+ if(realm) {
4577
+ if(!username || !password) {
4578
+ set_error("Not all authentication data was provided");
4579
+ goto out;
4580
+ }
4581
+ contact_username = username;
4582
+ }
4583
+
4584
+ build_local_contact(local_contact, t->sip_transport, contact_username);
4585
+
4586
+ if(!dlg_create(&dlg, t, from_uri, to_uri, request_uri, realm, username, password, local_contact)) {
4587
+ goto out;
4588
+ }
4589
+
4590
+ if(!register_pkg(event, accept)) {
4591
+ goto out;
4592
+ }
4593
+
4594
+ memset(&user_cb, 0, sizeof(user_cb));
4595
+ user_cb.on_evsub_state = client_on_evsub_state;
4596
+ user_cb.on_client_refresh = on_client_refresh;
4597
+ user_cb.on_rx_notify = on_rx_notify;
4598
+
4599
+ s_event = pj_str((char*)event);
4600
+
4601
+ status = pjsip_evsub_create_uac(dlg,
4602
+ &user_cb,
4603
+ &s_event,
4604
+ PJSIP_EVSUB_NO_EVENT_ID,
4605
+ &evsub);
4606
+ if(status != PJ_SUCCESS) {
4607
+ set_error("pjsip_evsub_create_uac failed");
4608
+ goto out;
4609
+ }
4610
+
4611
+ if(!set_transport_by_t(t, dlg)){
4612
+ goto out;
4613
+ }
4614
+
4615
+ if(!set_proxy(dlg, proxy_uri)) {
4616
+ goto out;
4617
+ }
4618
+
4619
+ subscription = (Subscription*)pj_pool_zalloc(dlg->pool, sizeof(Subscription));
4620
+
4621
+ if(!g_subscription_ids.add((long)subscription, subscription_id)){
4622
+ status = pjsip_dlg_terminate(dlg); //ToDo:
4623
+ set_error("Failed to allocate id");
4624
+ goto out;
4625
+ }
4626
+ subscription->id = subscription_id;
4627
+ subscription->evsub = evsub;
4628
+ subscription->dlg = dlg;
4629
+ strcpy(subscription->event, event);
4630
+ strcpy(subscription->accept, accept);
4631
+ pjsip_evsub_set_mod_data(evsub, mod_tester.id, subscription);
4632
+
4633
+ out:
4634
+ PJW_UNLOCK();
4635
+ if(pjw_errorstring[0]){
4636
+ return -1;
4637
+ }
4638
+
4639
+ *out_subscription_id = subscription_id;
4640
+ return 0;
4641
+ }
4642
+
4643
+ bool subscription_subscribe(Subscription *s, int expires, const char *additional_headers) {
4644
+ pj_status_t status;
4645
+ pjsip_tx_data *tdata;
4646
+
4647
+ status = pjsip_evsub_initiate(s->evsub,
4648
+ NULL,
4649
+ expires,
4650
+ &tdata);
4651
+ if(status != PJ_SUCCESS) {
4652
+ set_error("pjsip_evsub_initiate failed");
4653
+ return false;
4654
+ }
4655
+
4656
+ if(!add_additional_headers(s->dlg->pool, tdata, additional_headers)) {
4657
+ return false;
4658
+ }
4659
+
4660
+ status = pjsip_evsub_send_request(s->evsub, tdata);
4661
+ if(status != PJ_SUCCESS) {
4662
+ set_error("pjsip_inv_send_msg failed");
4663
+ return false;
4664
+ }
4665
+
4666
+ //Without this, on_rx_response will not be called
4667
+ status = pjsip_dlg_add_usage(s->dlg, &mod_tester, s);
4668
+ if(status != PJ_SUCCESS) {
4669
+ set_error("pjsip_dlg_add_usage failed");
4670
+ return false;
4671
+ }
4672
+
4673
+ return true;
4674
+ }
4675
+
4676
+ int pjw_subscription_subscribe(long subscription_id, int expires, const char *additional_headers) {
4677
+ PJW_LOCK();
4678
+
4679
+ clear_error();
4680
+
4681
+ Subscription *subscription;
4682
+
4683
+ long val;
4684
+
4685
+ if(!g_subscription_ids.get(subscription_id, val)){
4686
+ set_error("Invalid subscription_id");
4687
+ goto out;
4688
+ }
4689
+
4690
+ subscription = (Subscription*)val;
4691
+
4692
+ if(!subscription_subscribe(subscription, expires, additional_headers)) {
4693
+ goto out;
4694
+ }
4695
+
4696
+ out:
4697
+ PJW_UNLOCK();
4698
+
4699
+ if(pjw_errorstring[0]) {
4700
+ return -1;
4701
+ }
4702
+ return 0;
4703
+ }
4704
+
4705
+ void process_in_dialog_subscribe(pjsip_dialog *dlg, pjsip_rx_data *rdata) {
4706
+ char evt[2048];
4707
+
4708
+ Subscriber *s;
4709
+ Transport *t;
4710
+
4711
+ s = (Subscriber*)dlg->mod_data[mod_tester.id];
4712
+ if(!s) {
4713
+ make_evt_internal_error(evt, sizeof(evt), "no subscriber in mod_data");
4714
+ dispatch_event(evt);
4715
+ return;
4716
+ }
4717
+
4718
+ make_evt_request(evt, sizeof(evt), "subscriber", s->id, rdata->msg_info.len, rdata->msg_info.msg_buf);
4719
+ dispatch_event(evt);
4720
+ }
4721
+
4722
+ int pjw_call_gen_string_replaces(long call_id, char *out_replaces) {
4723
+ PJW_LOCK();
4724
+
4725
+ clear_error();
4726
+
4727
+ int n;
4728
+ long val;
4729
+ Call *call;
4730
+ pjsip_dialog *dlg;
4731
+ int len;
4732
+ char *p;
4733
+ char buf[2000];
4734
+ pjsip_uri* uri;
4735
+
4736
+ if(!g_call_ids.get(call_id, val)) {
4737
+ set_error("Invalid call_id");
4738
+ goto out;
4739
+ }
4740
+
4741
+ call = (Call*)val;
4742
+
4743
+ p = buf;
4744
+ p += sprintf(p, "%s", "<");
4745
+
4746
+ dlg = call->inv->dlg;
4747
+
4748
+ uri = (pjsip_uri*)pjsip_uri_get_uri(dlg->remote.info->uri);
4749
+ p += pjsip_uri_print(PJSIP_URI_IN_REQ_URI, uri, p, buf-p);
4750
+ p += pj_ansi_sprintf(p,
4751
+ "%.*s"
4752
+ ";to-tag=%.*s"
4753
+ ";from-tag=%.*s",
4754
+ (int)dlg->call_id->id.slen,
4755
+ dlg->call_id->id.ptr,
4756
+ (int)dlg->remote.info->tag.slen,
4757
+ dlg->remote.info->tag.ptr,
4758
+ (int)dlg->local.info->tag.slen,
4759
+ dlg->local.info->tag.ptr);
4760
+
4761
+ out:
4762
+ PJW_UNLOCK();
4763
+
4764
+ if(pjw_errorstring[0]) {
4765
+ return -1;
4766
+ }
4767
+ strcpy(out_replaces, buf);
4768
+ return 0;
4769
+ }
4770
+
4771
+
4772
+ int pjw_log_level(long log_level)
4773
+ {
4774
+ PJW_LOCK();
4775
+
4776
+ pj_log_set_level(log_level);
4777
+
4778
+ PJW_UNLOCK();
4779
+ return 0;
4780
+ }
4781
+
4782
+ int pjw_set_flags(unsigned flags)
4783
+ {
4784
+ PJW_LOCK();
4785
+
4786
+ g_flags = flags;
4787
+
4788
+ PJW_UNLOCK();
4789
+ return 0;
4790
+ }
4791
+
4792
+ static int g_now;
4793
+
4794
+
4795
+ void check_digit_buffer(Call *c, int mode) {
4796
+ //addon_log(LOG_LEVEL_DEBUG, "check_digit_buffer g_now=%i for call_id=%i and mode=%i timestamp=%i len=%i\n", g_now, c->id, mode, c->last_digit_timestamp[mode], c->DigitBufferLength[mode]);
4797
+ char evt[256];
4798
+
4799
+ if(c->last_digit_timestamp[mode] > 0 && g_now - c->last_digit_timestamp[mode] > g_dtmf_inter_digit_timer) {
4800
+ int *pLen = &c->DigitBufferLength[mode];
4801
+ c->DigitBuffers[mode][*pLen] = 0;
4802
+ make_evt_dtmf(evt, sizeof(evt), c->id, *pLen, c->DigitBuffers[mode], mode);
4803
+ dispatch_event(evt);
4804
+ *pLen = 0;
4805
+ c->last_digit_timestamp[mode] = 0;
4806
+ }
4807
+ }
4808
+
4809
+ void check_digit_buffers(long id, long val) {
4810
+ Call *c = (Call*)val;
4811
+
4812
+ check_digit_buffer(c, DTMF_MODE_RFC2833);
4813
+ check_digit_buffer(c, DTMF_MODE_INBAND);
4814
+ }
4815
+
4816
+ static int digit_buffer_thread(void *arg)
4817
+ {
4818
+ //addon_log(LOG_LEVEL_DEBUG, "Starting digit_buffer_thread\n");
4819
+
4820
+ pj_thread_set_prio(pj_thread_this(),
4821
+ pj_thread_get_prio_min(pj_thread_this()));
4822
+
4823
+ PJ_UNUSED_ARG(arg);
4824
+
4825
+ while(!g_shutting_down){
4826
+ PJW_LOCK();
4827
+ if(g_dtmf_inter_digit_timer > 0) {
4828
+ g_now = ms_timestamp();
4829
+ g_call_ids.iterate(check_digit_buffers);
4830
+ }
4831
+ PJW_UNLOCK();
4832
+
4833
+ pj_thread_sleep(100);
4834
+ }
4835
+ return 0;
4836
+ }
4837
+
4838
+
4839
+ bool start_digit_buffer_thread(){
4840
+ pj_status_t status;
4841
+ pj_pool_t *pool = pj_pool_create(&cp.factory, "digit_buffer_checker", 1000, 1000, NULL);
4842
+ pj_thread_t *t;
4843
+ status = pj_thread_create(pool, "digit_buffer_checker", &digit_buffer_thread, NULL, 0, 0, &t);
4844
+ if(status != PJ_SUCCESS)
4845
+ {
4846
+ addon_log(LOG_LEVEL_DEBUG, "start_digit_buffer_thread failed\n");
4847
+ return false;
4848
+ }
4849
+
4850
+ return true;
4851
+ }
4852
+
4853
+ /* provides timestamp in milliseconds */
4854
+ int ms_timestamp() {
4855
+ struct timeval tv;
4856
+ if (gettimeofday(&tv, NULL) != 0)
4857
+ {
4858
+ return -1;
4859
+ }
4860
+ return ((tv.tv_sec % 86400) * 1000 + tv.tv_usec / 1000);
4861
+ }
4862
+
4863
+ int pjw_dtmf_aggregation_on(int inter_digit_timer)
4864
+ {
4865
+ PJW_LOCK();
4866
+
4867
+ if(inter_digit_timer <= 0)
4868
+ {
4869
+ PJW_UNLOCK();
4870
+ set_error("Invalid argument: inter_digit_timer must be greater than zero");
4871
+ return -1;
4872
+ }
4873
+
4874
+ g_dtmf_inter_digit_timer = inter_digit_timer;
4875
+
4876
+ PJW_UNLOCK();
4877
+ return 0;
4878
+ }
4879
+
4880
+ int pjw_dtmf_aggregation_off()
4881
+ {
4882
+ PJW_LOCK();
4883
+
4884
+ g_dtmf_inter_digit_timer = 0;
4885
+
4886
+ PJW_UNLOCK();
4887
+ return 0;
4888
+ }
4889
+
4890
+
4891
+