sip-lab 1.14.0 → 1.15.0
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.
- package/DEV.md +2 -2
- package/package.json +2 -2
- package/prebuilds/linux-x64/node.abi102.node +0 -0
- package/prebuilds/linux-x64/node.abi108.node +0 -0
- package/prebuilds/linux-x64/node.abi88.node +0 -0
- package/prebuilds/linux-x64/node.abi93.node +0 -0
- package/prebuilds/linux-x64/sip-lab.node +0 -0
- package/samples/srtp.js +346 -0
- package/src/sip.cpp +92 -16
- package/samples/t +0 -457
package/DEV.md
CHANGED
|
@@ -48,14 +48,14 @@ Previously we would do:
|
|
|
48
48
|
|
|
49
49
|
```
|
|
50
50
|
nvm use v16.13.1 # if we try with v17 it will fail to build for -t 15.0.0
|
|
51
|
-
npx prebuildify --strip -t 15.0.0 -t 16.0.0 -t 17.0.0 -t 18.0.0
|
|
51
|
+
npx prebuildify --strip -t 15.0.0 -t 16.0.0 -t 17.0.0 -t 18.0.0 19.0.0 20.0.0 21.0.0
|
|
52
52
|
```
|
|
53
53
|
However the above will build the addon to run on the current OS.
|
|
54
54
|
|
|
55
55
|
Instead we will force the build on debian11 (using docker). So do this instead:
|
|
56
56
|
```
|
|
57
57
|
nvm use v16.13.1
|
|
58
|
-
npx prebuildify-cross -i mayamatakeshi/sip-lab-debian11:latest -t 15.0.0 -t 16.0.0 -t 17.0.0 -t 18.0.0 --strip
|
|
58
|
+
npx prebuildify-cross -i mayamatakeshi/sip-lab-debian11:latest -t 15.0.0 -t 16.0.0 -t 17.0.0 -t 18.0.0 -t 19.0.0 -t 20.0.0 -t 21.0.0 --strip
|
|
59
59
|
```
|
|
60
60
|
|
|
61
61
|
#### Running tests
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sip-lab",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.15.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"engines": {
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"sip-matching": "^1.5.2"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
|
-
"prebuildify": "^
|
|
33
|
+
"prebuildify": "^6.0.0",
|
|
34
34
|
"prebuildify-cross": "github:MayamaTakeshi/prebuildify-cross#use_existing_images",
|
|
35
35
|
"sdp-matching": "^1.3.2"
|
|
36
36
|
},
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/samples/srtp.js
ADDED
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
// This test creates 2 UDP SIP endpoints, makes a call between them and disconeects.
|
|
2
|
+
|
|
3
|
+
const sip = require ('../index.js')
|
|
4
|
+
const Zeq = require('@mayama/zeq')
|
|
5
|
+
const m = require('data-matching')
|
|
6
|
+
const sip_msg = require('sip-matching')
|
|
7
|
+
const sdp = require('sdp-matching')
|
|
8
|
+
|
|
9
|
+
// here we create our Zeq instance
|
|
10
|
+
var z = new Zeq()
|
|
11
|
+
|
|
12
|
+
async function test() {
|
|
13
|
+
sip.dtmf_aggregation_on(500)
|
|
14
|
+
|
|
15
|
+
z.trap_events(sip.event_source, 'event', (evt) => {
|
|
16
|
+
var e = evt.args[0]
|
|
17
|
+
return e
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
// Let's ignore '100 Trying'
|
|
21
|
+
z.add_event_filter({
|
|
22
|
+
event: 'response',
|
|
23
|
+
msg: sip_msg({
|
|
24
|
+
$rs: '100',
|
|
25
|
+
}),
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
console.log(sip.start((data) => { console.log(data)} ))
|
|
29
|
+
|
|
30
|
+
const t1 = sip.transport.create({address: "127.0.0.1"})
|
|
31
|
+
const t2 = sip.transport.create({address: "127.0.0.1"})
|
|
32
|
+
|
|
33
|
+
console.log("t1", t1)
|
|
34
|
+
console.log("t2", t2)
|
|
35
|
+
|
|
36
|
+
const oc = sip.call.create(t1.id, {from_uri: 'sip:alice@test.com', to_uri: `sip:bob@${t2.address}:${t2.port}`,
|
|
37
|
+
media: [
|
|
38
|
+
{
|
|
39
|
+
type: 'audio',
|
|
40
|
+
secure: true,
|
|
41
|
+
},
|
|
42
|
+
]})
|
|
43
|
+
|
|
44
|
+
await z.wait([
|
|
45
|
+
{
|
|
46
|
+
event: "incoming_call",
|
|
47
|
+
call_id: m.collect("call_id"),
|
|
48
|
+
transport_id: t2.id,
|
|
49
|
+
},
|
|
50
|
+
], 1000)
|
|
51
|
+
|
|
52
|
+
const ic = {
|
|
53
|
+
id: z.store.call_id,
|
|
54
|
+
sip_call_id: z.store.sip_call_id,
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
sip.call.respond(ic.id, {code: 200, reason: 'OK', media: [
|
|
58
|
+
{
|
|
59
|
+
type: 'audio',
|
|
60
|
+
secure: true,
|
|
61
|
+
},
|
|
62
|
+
]})
|
|
63
|
+
|
|
64
|
+
await z.wait([
|
|
65
|
+
{
|
|
66
|
+
event: 'response',
|
|
67
|
+
call_id: oc.id,
|
|
68
|
+
method: 'INVITE',
|
|
69
|
+
msg: sip_msg({
|
|
70
|
+
$rs: '200',
|
|
71
|
+
$rr: 'OK',
|
|
72
|
+
'$(hdrcnt(VIA))': 1,
|
|
73
|
+
$fU: 'alice',
|
|
74
|
+
$fd: 'test.com',
|
|
75
|
+
$tU: 'bob',
|
|
76
|
+
'$hdr(content-type)': 'application/sdp',
|
|
77
|
+
$rb: '!{_}a=sendrecv',
|
|
78
|
+
}),
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
event: 'media_update',
|
|
82
|
+
call_id: oc.id,
|
|
83
|
+
status: 'ok',
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
event: 'media_update',
|
|
87
|
+
call_id: ic.id,
|
|
88
|
+
status: 'ok',
|
|
89
|
+
},
|
|
90
|
+
], 1000)
|
|
91
|
+
|
|
92
|
+
sip.call.send_dtmf(oc.id, {digits: '1234', mode: 1})
|
|
93
|
+
sip.call.send_dtmf(ic.id, {digits: '1234', mode: 1})
|
|
94
|
+
|
|
95
|
+
await z.wait([
|
|
96
|
+
{
|
|
97
|
+
event: 'dtmf',
|
|
98
|
+
call_id: ic.id,
|
|
99
|
+
digits: '1234',
|
|
100
|
+
mode: 1,
|
|
101
|
+
media_id: 0,
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
event: 'dtmf',
|
|
105
|
+
call_id: oc.id,
|
|
106
|
+
digits: '1234',
|
|
107
|
+
mode: 1,
|
|
108
|
+
media_id: 0,
|
|
109
|
+
},
|
|
110
|
+
], 2000)
|
|
111
|
+
|
|
112
|
+
sip.call.reinvite(oc.id, {media: [
|
|
113
|
+
{
|
|
114
|
+
type: 'audio',
|
|
115
|
+
secure: true,
|
|
116
|
+
},
|
|
117
|
+
]})
|
|
118
|
+
|
|
119
|
+
await z.wait([
|
|
120
|
+
{
|
|
121
|
+
event: 'reinvite',
|
|
122
|
+
call_id: ic.id,
|
|
123
|
+
},
|
|
124
|
+
], 500)
|
|
125
|
+
|
|
126
|
+
sip.call.respond(ic.id, {code: 200, reason: 'OK', media: [
|
|
127
|
+
{
|
|
128
|
+
type: 'audio',
|
|
129
|
+
secure: true,
|
|
130
|
+
},
|
|
131
|
+
]})
|
|
132
|
+
|
|
133
|
+
await z.wait([
|
|
134
|
+
{
|
|
135
|
+
event: 'response',
|
|
136
|
+
call_id: oc.id,
|
|
137
|
+
method: 'INVITE',
|
|
138
|
+
msg: sip_msg({
|
|
139
|
+
$rs: '200',
|
|
140
|
+
$rb: sdp.jsonpath_matcher({
|
|
141
|
+
'$.media.length': [1],
|
|
142
|
+
'$.media[*].desc.type': ['audio'],
|
|
143
|
+
'$.media[*].desc.port': [m.nonzero],
|
|
144
|
+
'$.media[*].desc.protocol': ['RTP/SAVP'],
|
|
145
|
+
}),
|
|
146
|
+
}),
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
event: 'media_update',
|
|
150
|
+
call_id: ic.id,
|
|
151
|
+
status: 'ok',
|
|
152
|
+
media: m.fm([
|
|
153
|
+
m.pm({
|
|
154
|
+
type: 'audio',
|
|
155
|
+
transport: 'RTP/SAVP',
|
|
156
|
+
local: {
|
|
157
|
+
mode: 'sendrecv'
|
|
158
|
+
},
|
|
159
|
+
remote: {
|
|
160
|
+
mode: 'sendrecv'
|
|
161
|
+
},
|
|
162
|
+
fmt: [
|
|
163
|
+
'0 PCMU/8000',
|
|
164
|
+
'120 telephone-event/8000'
|
|
165
|
+
]
|
|
166
|
+
}),
|
|
167
|
+
]),
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
event: 'media_update',
|
|
171
|
+
call_id: oc.id,
|
|
172
|
+
status: 'ok',
|
|
173
|
+
media: m.fm([
|
|
174
|
+
m.pm({
|
|
175
|
+
type: 'audio',
|
|
176
|
+
transport: 'RTP/SAVP',
|
|
177
|
+
local: {
|
|
178
|
+
mode: 'sendrecv'
|
|
179
|
+
},
|
|
180
|
+
remote: {
|
|
181
|
+
mode: 'sendrecv'
|
|
182
|
+
},
|
|
183
|
+
fmt: [
|
|
184
|
+
'0 PCMU/8000',
|
|
185
|
+
'120 telephone-event/8000'
|
|
186
|
+
]
|
|
187
|
+
}),
|
|
188
|
+
]),
|
|
189
|
+
},
|
|
190
|
+
], 1000)
|
|
191
|
+
|
|
192
|
+
sip.call.send_dtmf(oc.id, {digits: '1234', mode: 1})
|
|
193
|
+
sip.call.send_dtmf(ic.id, {digits: '1234', mode: 1})
|
|
194
|
+
|
|
195
|
+
await z.wait([
|
|
196
|
+
{
|
|
197
|
+
event: 'dtmf',
|
|
198
|
+
call_id: ic.id,
|
|
199
|
+
digits: '1234',
|
|
200
|
+
mode: 1,
|
|
201
|
+
media_id: 0,
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
event: 'dtmf',
|
|
205
|
+
call_id: oc.id,
|
|
206
|
+
digits: '1234',
|
|
207
|
+
mode: 1,
|
|
208
|
+
media_id: 0,
|
|
209
|
+
},
|
|
210
|
+
], 2000)
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
sip.call.reinvite(ic.id, {media: [
|
|
214
|
+
{
|
|
215
|
+
type: 'audio',
|
|
216
|
+
secure: true,
|
|
217
|
+
},
|
|
218
|
+
]})
|
|
219
|
+
|
|
220
|
+
await z.wait([
|
|
221
|
+
{
|
|
222
|
+
event: 'reinvite',
|
|
223
|
+
call_id: oc.id,
|
|
224
|
+
},
|
|
225
|
+
], 500)
|
|
226
|
+
|
|
227
|
+
sip.call.respond(oc.id, {code: 200, reason: 'OK', media: [
|
|
228
|
+
{
|
|
229
|
+
type: 'audio',
|
|
230
|
+
secure: true,
|
|
231
|
+
},
|
|
232
|
+
]})
|
|
233
|
+
|
|
234
|
+
await z.wait([
|
|
235
|
+
{
|
|
236
|
+
event: 'response',
|
|
237
|
+
call_id: ic.id,
|
|
238
|
+
method: 'INVITE',
|
|
239
|
+
msg: sip_msg({
|
|
240
|
+
$rs: '200',
|
|
241
|
+
$rb: sdp.jsonpath_matcher({
|
|
242
|
+
'$.media.length': [1],
|
|
243
|
+
'$.media[*].desc.type': ['audio'],
|
|
244
|
+
'$.media[*].desc.port': [m.nonzero],
|
|
245
|
+
'$.media[*].desc.protocol': ['RTP/SAVP'],
|
|
246
|
+
}),
|
|
247
|
+
}),
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
event: 'media_update',
|
|
251
|
+
call_id: oc.id,
|
|
252
|
+
status: 'ok',
|
|
253
|
+
media: m.fm([
|
|
254
|
+
m.pm({
|
|
255
|
+
type: 'audio',
|
|
256
|
+
transport: 'RTP/SAVP',
|
|
257
|
+
local: {
|
|
258
|
+
mode: 'sendrecv'
|
|
259
|
+
},
|
|
260
|
+
remote: {
|
|
261
|
+
mode: 'sendrecv'
|
|
262
|
+
},
|
|
263
|
+
fmt: [
|
|
264
|
+
'0 PCMU/8000',
|
|
265
|
+
'120 telephone-event/8000'
|
|
266
|
+
]
|
|
267
|
+
}),
|
|
268
|
+
]),
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
event: 'media_update',
|
|
272
|
+
call_id: ic.id,
|
|
273
|
+
status: 'ok',
|
|
274
|
+
media: m.fm([
|
|
275
|
+
m.pm({
|
|
276
|
+
type: 'audio',
|
|
277
|
+
transport: 'RTP/SAVP',
|
|
278
|
+
local: {
|
|
279
|
+
mode: 'sendrecv'
|
|
280
|
+
},
|
|
281
|
+
remote: {
|
|
282
|
+
mode: 'sendrecv'
|
|
283
|
+
},
|
|
284
|
+
fmt: [
|
|
285
|
+
'0 PCMU/8000',
|
|
286
|
+
'120 telephone-event/8000'
|
|
287
|
+
]
|
|
288
|
+
}),
|
|
289
|
+
]),
|
|
290
|
+
},
|
|
291
|
+
], 1000)
|
|
292
|
+
|
|
293
|
+
sip.call.send_dtmf(oc.id, {digits: '1234', mode: 1})
|
|
294
|
+
sip.call.send_dtmf(ic.id, {digits: '1234', mode: 1})
|
|
295
|
+
|
|
296
|
+
await z.wait([
|
|
297
|
+
{
|
|
298
|
+
event: 'dtmf',
|
|
299
|
+
call_id: ic.id,
|
|
300
|
+
digits: '1234',
|
|
301
|
+
mode: 1,
|
|
302
|
+
media_id: 0,
|
|
303
|
+
},
|
|
304
|
+
{
|
|
305
|
+
event: 'dtmf',
|
|
306
|
+
call_id: oc.id,
|
|
307
|
+
digits: '1234',
|
|
308
|
+
mode: 1,
|
|
309
|
+
media_id: 0,
|
|
310
|
+
},
|
|
311
|
+
], 2000)
|
|
312
|
+
|
|
313
|
+
sip.call.terminate(oc.id)
|
|
314
|
+
|
|
315
|
+
await z.wait([
|
|
316
|
+
{
|
|
317
|
+
event: 'response',
|
|
318
|
+
call_id: oc.id,
|
|
319
|
+
method: 'BYE',
|
|
320
|
+
msg: sip_msg({
|
|
321
|
+
$rs: '200',
|
|
322
|
+
$rr: 'OK',
|
|
323
|
+
}),
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
event: 'call_ended',
|
|
327
|
+
call_id: oc.id,
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
event: 'call_ended',
|
|
331
|
+
call_id: ic.id,
|
|
332
|
+
},
|
|
333
|
+
], 1000)
|
|
334
|
+
|
|
335
|
+
console.log("Success")
|
|
336
|
+
|
|
337
|
+
sip.stop()
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
test()
|
|
342
|
+
.catch(e => {
|
|
343
|
+
console.error(e)
|
|
344
|
+
process.exit(1)
|
|
345
|
+
})
|
|
346
|
+
|
package/src/sip.cpp
CHANGED
|
@@ -384,6 +384,7 @@ struct MediaEndpoint {
|
|
|
384
384
|
pj_str_t addr;
|
|
385
385
|
int port;
|
|
386
386
|
int field_count;
|
|
387
|
+
bool secure;
|
|
387
388
|
char *field[MAX_ATTRS];
|
|
388
389
|
|
|
389
390
|
union {
|
|
@@ -630,7 +631,7 @@ void close_media_endpoint(MediaEndpoint *me);
|
|
|
630
631
|
|
|
631
632
|
void close_media(Call *c);
|
|
632
633
|
|
|
633
|
-
bool process_media(Call *c, pjsip_dialog *dlg, Document &document);
|
|
634
|
+
bool process_media(Call *c, pjsip_dialog *dlg, Document &document, bool answer);
|
|
634
635
|
|
|
635
636
|
typedef pj_status_t (*audio_endpoint_stop_op_t)(Call *call, AudioEndpoint *ae);
|
|
636
637
|
|
|
@@ -685,6 +686,13 @@ const char *translate_pjsip_inv_state(int state) {
|
|
|
685
686
|
}
|
|
686
687
|
}
|
|
687
688
|
|
|
689
|
+
static pj_bool_t create_transport_srtp(pjmedia_transport *med_transport, pjmedia_transport **srtp) {
|
|
690
|
+
pjmedia_srtp_setting opt;
|
|
691
|
+
pjmedia_srtp_setting_default(&opt);
|
|
692
|
+
printf("calling pjmedia_transport_srtp_create\n");
|
|
693
|
+
return pjmedia_transport_srtp_create(g_med_endpt, med_transport, &opt, srtp);
|
|
694
|
+
}
|
|
695
|
+
|
|
688
696
|
static int
|
|
689
697
|
find_endpoint_by_inband_dtmf_media_stream(Call *call,
|
|
690
698
|
pjmedia_stream *med_stream) {
|
|
@@ -2072,17 +2080,21 @@ int pjw_call_respond(long call_id, const char *json) {
|
|
|
2072
2080
|
}
|
|
2073
2081
|
|
|
2074
2082
|
if (183 == code || (code >= 200 && code < 300)) {
|
|
2075
|
-
if (!process_media(call, call->inv->dlg, document)) {
|
|
2076
|
-
goto out;
|
|
2077
|
-
}
|
|
2078
|
-
|
|
2079
2083
|
// process_media above set call->local_sdp based on document.
|
|
2080
2084
|
|
|
2081
2085
|
if (call->pending_rdata && call->pending_rdata->msg_info.msg->body &&
|
|
2082
2086
|
call->pending_rdata->msg_info.msg->body->len) {
|
|
2087
|
+
if (!process_media(call, call->inv->dlg, document, true)) {
|
|
2088
|
+
goto out;
|
|
2089
|
+
}
|
|
2090
|
+
|
|
2083
2091
|
status = pjsip_inv_set_sdp_answer(call->inv, call->local_sdp);
|
|
2084
2092
|
} else {
|
|
2085
2093
|
// delayed media. we need to sned the offer
|
|
2094
|
+
if (!process_media(call, call->inv->dlg, document, false)) {
|
|
2095
|
+
goto out;
|
|
2096
|
+
}
|
|
2097
|
+
|
|
2086
2098
|
status = pjmedia_sdp_neg_create_w_local_offer(
|
|
2087
2099
|
call->inv->dlg->pool, call->local_sdp, &call->inv->neg);
|
|
2088
2100
|
if (status != PJ_SUCCESS) {
|
|
@@ -2824,7 +2836,7 @@ int call_create(Transport *t, unsigned flags, pjsip_dialog *dlg,
|
|
|
2824
2836
|
|
|
2825
2837
|
pjmedia_sdp_session *sdp = 0;
|
|
2826
2838
|
|
|
2827
|
-
if (!process_media(call, dlg, document)) {
|
|
2839
|
+
if (!process_media(call, dlg, document, false)) {
|
|
2828
2840
|
close_media(call);
|
|
2829
2841
|
return -1;
|
|
2830
2842
|
}
|
|
@@ -3117,7 +3129,7 @@ int pjw_call_reinvite(long call_id, const char *json) {
|
|
|
3117
3129
|
}
|
|
3118
3130
|
}
|
|
3119
3131
|
|
|
3120
|
-
if (!process_media(call, inv->dlg, document)) {
|
|
3132
|
+
if (!process_media(call, inv->dlg, document, false)) {
|
|
3121
3133
|
goto out;
|
|
3122
3134
|
}
|
|
3123
3135
|
|
|
@@ -4064,7 +4076,7 @@ int find_sdp_media_by_media_endpt(const pjmedia_sdp_session *sdp,
|
|
|
4064
4076
|
printf("find_sdp_media_by_media_endpt %x\n", me);
|
|
4065
4077
|
for (int i = 0; i < sdp->media_count; i++) {
|
|
4066
4078
|
pjmedia_sdp_media *media = sdp->media[i];
|
|
4067
|
-
printf("i=%d media=%
|
|
4079
|
+
printf("i=%d me->port=%i media->desc.port=%i me->media=%.*s media->desc.media=%.*s\n", i, me->port, media->desc.port, me->media.slen, me->media.ptr, media->desc.media.slen, media->desc.media.ptr);
|
|
4068
4080
|
|
|
4069
4081
|
if ((me->port == media->desc.port) &&
|
|
4070
4082
|
(pj_strcmp(&me->media, &media->desc.media) == 0)) {
|
|
@@ -4116,10 +4128,10 @@ void gen_media_json(char *dest, int len, Call *call,
|
|
|
4116
4128
|
if(!me->port) {
|
|
4117
4129
|
switch (me->type) {
|
|
4118
4130
|
case ENDPOINT_TYPE_AUDIO:
|
|
4119
|
-
p += sprintf(p, "{\"type\": \"audio\", \"port\": 0}");
|
|
4131
|
+
p += sprintf(p, "{\"type\": \"audio\", \"transport\": \"%.*s\", \"port\": 0}", me->transport.slen, me->transport.ptr);
|
|
4120
4132
|
break;
|
|
4121
4133
|
case ENDPOINT_TYPE_MRCP:
|
|
4122
|
-
p += sprintf(p, "{\"type\": \"mrcp\", \"port\": 0}");
|
|
4134
|
+
p += sprintf(p, "{\"type\": \"mrcp\", \"transport\": \"%.*s\", \"port\": 0}", me->transport.slen, me->transport.ptr);
|
|
4123
4135
|
break;
|
|
4124
4136
|
default:
|
|
4125
4137
|
p += sprintf(p, "{\"type\": \"unknown\", \"port\": 0}");
|
|
@@ -4151,9 +4163,10 @@ void gen_media_json(char *dest, int len, Call *call,
|
|
|
4151
4163
|
pj_str_t *remote_addr = &remote_conn->addr;
|
|
4152
4164
|
|
|
4153
4165
|
p += sprintf(p,
|
|
4154
|
-
"{\"type\": \"audio\", \"local\": {\"addr\": \"%.*s\", "
|
|
4166
|
+
"{\"type\": \"audio\", \"transport\": \"%.*s\", \"local\": {\"addr\": \"%.*s\", "
|
|
4155
4167
|
"\"port\": %d, \"mode\": \"%s\"}, \"remote\": {\"addr\": "
|
|
4156
4168
|
"\"%.*s\", \"port\": %d, \"mode\": \"%s\"}, \"fmt\": [",
|
|
4169
|
+
me->transport.slen, me->transport.ptr,
|
|
4157
4170
|
local_addr->slen, local_addr->ptr, local_media->desc.port,
|
|
4158
4171
|
local_mode, remote_addr->slen, remote_addr->ptr,
|
|
4159
4172
|
remote_media->desc.port, remote_mode);
|
|
@@ -4175,8 +4188,9 @@ void gen_media_json(char *dest, int len, Call *call,
|
|
|
4175
4188
|
}
|
|
4176
4189
|
case ENDPOINT_TYPE_MRCP: {
|
|
4177
4190
|
p += sprintf(p,
|
|
4178
|
-
"{\"type\": \"mrcp\", \"local\": {\"port\": %d}, "
|
|
4191
|
+
"{\"type\": \"mrcp\", \"transport\": \"%.*s\", \"local\": {\"port\": %d}, "
|
|
4179
4192
|
"\"remote\": {\"port\": %d}}",
|
|
4193
|
+
me->transport.slen, me->transport.ptr,
|
|
4180
4194
|
local_sdp->media[idx]->desc.port,
|
|
4181
4195
|
remote_sdp->media[idx]->desc.port);
|
|
4182
4196
|
break;
|
|
@@ -4342,13 +4356,24 @@ bool restart_media_stream(Call *call, MediaEndpoint *me,
|
|
|
4342
4356
|
status = pjmedia_stream_set_dtmf_callback(ae->med_stream, &on_dtmf, call);
|
|
4343
4357
|
if (status != PJ_SUCCESS) {
|
|
4344
4358
|
make_evt_media_update(evt, sizeof(evt), call->id,
|
|
4345
|
-
"setup_failed (
|
|
4359
|
+
"setup_failed (pjmedia_stream_set_dtmf_callback)", "");
|
|
4346
4360
|
dispatch_event(evt);
|
|
4347
4361
|
return false;
|
|
4348
4362
|
}
|
|
4349
4363
|
|
|
4350
4364
|
/* Start the UDP media transport */
|
|
4351
|
-
pjmedia_transport_media_start(ae->med_transport,
|
|
4365
|
+
status = pjmedia_transport_media_start(ae->med_transport, call->inv->pool, local_sdp, remote_sdp, idx);
|
|
4366
|
+
if (status != PJ_SUCCESS) {
|
|
4367
|
+
printf("status=%i\n", status);
|
|
4368
|
+
char err[1024];
|
|
4369
|
+
pj_strerror(status, err, sizeof(err));
|
|
4370
|
+
printf("pjmedia_transport_media_start status: %s\n", err);
|
|
4371
|
+
|
|
4372
|
+
make_evt_media_update(evt, sizeof(evt), call->id,
|
|
4373
|
+
"setup_failed (pjmedia_transport_media_start failed)", "");
|
|
4374
|
+
dispatch_event(evt);
|
|
4375
|
+
return false;
|
|
4376
|
+
}
|
|
4352
4377
|
|
|
4353
4378
|
pjmedia_port *stream_port;
|
|
4354
4379
|
status = pjmedia_stream_get_port(ae->med_stream, &stream_port);
|
|
@@ -5827,8 +5852,36 @@ bool create_media_endpoint(Call *call, Document &document, Value &descr,
|
|
|
5827
5852
|
med_endpt->type = ENDPOINT_TYPE_AUDIO;
|
|
5828
5853
|
pj_strdup2(dlg->pool, &med_endpt->media, "audio");
|
|
5829
5854
|
pj_strdup(dlg->pool, &med_endpt->addr, &str_addr);
|
|
5830
|
-
|
|
5855
|
+
|
|
5856
|
+
if (descr.HasMember("secure")) {
|
|
5857
|
+
if (!descr["secure"].IsBool()) {
|
|
5858
|
+
set_error("Parameter secure must be a boolean");
|
|
5859
|
+
return false;
|
|
5860
|
+
}
|
|
5861
|
+
med_endpt->secure = descr["secure"].GetBool();
|
|
5862
|
+
}
|
|
5863
|
+
|
|
5864
|
+
if(med_endpt->secure){
|
|
5865
|
+
pjmedia_transport *srtp;
|
|
5866
|
+
pj_status_t status = create_transport_srtp(audio_endpt->med_transport, &srtp);
|
|
5867
|
+
if(status != PJ_SUCCESS) {
|
|
5868
|
+
set_error("create_transport_srtp failed");
|
|
5869
|
+
return false;
|
|
5870
|
+
}
|
|
5871
|
+
audio_endpt->med_transport = srtp;
|
|
5872
|
+
|
|
5873
|
+
status = pjmedia_transport_media_create(audio_endpt->med_transport, dlg->pool, NULL, NULL, 0);
|
|
5874
|
+
if(status != PJ_SUCCESS) {
|
|
5875
|
+
set_error("pjmedia_transport_media_create failed");
|
|
5876
|
+
return false;
|
|
5877
|
+
}
|
|
5878
|
+
pj_strdup2(dlg->pool, &med_endpt->transport, "RTP/SAVP");
|
|
5879
|
+
} else {
|
|
5880
|
+
pj_strdup2(dlg->pool, &med_endpt->transport, "RTP/AVP");
|
|
5881
|
+
}
|
|
5882
|
+
|
|
5831
5883
|
med_endpt->port = allocated_port;
|
|
5884
|
+
printf("med_endtp->port=%i\n", med_endpt->port);
|
|
5832
5885
|
med_endpt->endpoint.audio = audio_endpt;
|
|
5833
5886
|
} else if (strcmp("mrcp", type) == 0) {
|
|
5834
5887
|
MrcpEndpoint *mrcp_endpt = (MrcpEndpoint *)pj_pool_zalloc(dlg->pool, sizeof(MrcpEndpoint));
|
|
@@ -6019,7 +6072,7 @@ pjmedia_sdp_media *create_sdp_media(MediaEndpoint *me, pjsip_dialog *dlg) {
|
|
|
6019
6072
|
return media;
|
|
6020
6073
|
}
|
|
6021
6074
|
|
|
6022
|
-
bool process_media(Call *call, pjsip_dialog *dlg, Document &document) {
|
|
6075
|
+
bool process_media(Call *call, pjsip_dialog *dlg, Document &document, bool answer) {
|
|
6023
6076
|
printf("process_media call_id=%d\n", call->id);
|
|
6024
6077
|
|
|
6025
6078
|
bool in_use_chart[PJMEDIA_MAX_SDP_MEDIA] = {false};
|
|
@@ -6099,6 +6152,17 @@ bool process_media(Call *call, pjsip_dialog *dlg, Document &document) {
|
|
|
6099
6152
|
Value media = document["media"].GetArray();
|
|
6100
6153
|
assert(media.Size() <= PJMEDIA_MAX_SDP_MEDIA);
|
|
6101
6154
|
|
|
6155
|
+
const pjmedia_sdp_session *rem_sdp = NULL;
|
|
6156
|
+
if(answer) {
|
|
6157
|
+
if(call->inv && call->inv->neg) {
|
|
6158
|
+
status = pjmedia_sdp_neg_get_neg_remote(call->inv->neg, &rem_sdp);
|
|
6159
|
+
if(status != PJ_SUCCESS) {
|
|
6160
|
+
addon_log(L_DBG, "Internal Server Error (pjmedia_sdp_neg_get_neg_remote failed)");
|
|
6161
|
+
return false;
|
|
6162
|
+
}
|
|
6163
|
+
}
|
|
6164
|
+
}
|
|
6165
|
+
|
|
6102
6166
|
for (SizeType i = 0; i < media.Size(); i++) {
|
|
6103
6167
|
Value descr = media[i].GetObject();
|
|
6104
6168
|
|
|
@@ -6166,6 +6230,18 @@ bool process_media(Call *call, pjsip_dialog *dlg, Document &document) {
|
|
|
6166
6230
|
|
|
6167
6231
|
sdp->media[sdp->media_count++] = media;
|
|
6168
6232
|
}
|
|
6233
|
+
|
|
6234
|
+
if(me->secure && me->endpoint.audio) {
|
|
6235
|
+
pj_status_t status = pjmedia_transport_encode_sdp(me->endpoint.audio->med_transport, dlg->pool, sdp, rem_sdp, i);
|
|
6236
|
+
if(status != PJ_SUCCESS) {
|
|
6237
|
+
addon_log(L_DBG, "pjmedia_transport_encode_sdp failed");
|
|
6238
|
+
return false;
|
|
6239
|
+
}
|
|
6240
|
+
|
|
6241
|
+
// The below must be done after pjmedia_transport_encode_sdp() because although at this point med_transport is a transport_srtp, it calls the transport_encode_sdp of the underlying transpor_udp and it will fail when it sees "RTP/SAVP" instead of "RTP/AVP"
|
|
6242
|
+
// So we change from RTP/AVP to RTP/SAVP after we add the crypto lines.
|
|
6243
|
+
pj_strdup2(dlg->pool, &sdp->media[i]->desc.transport, "RTP/SAVP");
|
|
6244
|
+
}
|
|
6169
6245
|
}
|
|
6170
6246
|
|
|
6171
6247
|
call->local_sdp = sdp;
|
package/samples/t
DELETED
|
@@ -1,457 +0,0 @@
|
|
|
1
|
-
var sip = require ('../index.js')
|
|
2
|
-
var Zeq = require('@mayama/zeq')
|
|
3
|
-
var z = new Zeq()
|
|
4
|
-
var m = require('data-matching')
|
|
5
|
-
var sip_msg = require('sip-matching')
|
|
6
|
-
var sdp = require('sdp-matching')
|
|
7
|
-
|
|
8
|
-
async function test() {
|
|
9
|
-
sip.set_log_level(9)
|
|
10
|
-
|
|
11
|
-
//sip.set_log_level(6)
|
|
12
|
-
sip.dtmf_aggregation_on(500)
|
|
13
|
-
|
|
14
|
-
// Let's ignore '100 Trying'
|
|
15
|
-
z.add_event_filter({
|
|
16
|
-
event: 'response',
|
|
17
|
-
msg: sip_msg({
|
|
18
|
-
$rs: '100',
|
|
19
|
-
}),
|
|
20
|
-
})
|
|
21
|
-
|
|
22
|
-
z.trap_events(sip.event_source, 'event', (evt) => {
|
|
23
|
-
var e = evt.args[0]
|
|
24
|
-
return e
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
console.log(sip.start((data) => { console.log(data)} ))
|
|
28
|
-
|
|
29
|
-
t1 = sip.transport.create({address: "127.0.0.1", port: 5090, type: 'udp'})
|
|
30
|
-
t2 = sip.transport.create({address: "127.0.0.1", port: 5092, type: 'udp'})
|
|
31
|
-
|
|
32
|
-
console.log("t1", t1)
|
|
33
|
-
console.log("t2", t2)
|
|
34
|
-
|
|
35
|
-
oc = sip.call.create(t1.id, {from_uri: 'sip:alice@test.com', to_uri: `sip:bob@${t2.address}:${t2.port}`, media: "audio,audio"})
|
|
36
|
-
|
|
37
|
-
await z.wait([
|
|
38
|
-
{
|
|
39
|
-
event: "incoming_call",
|
|
40
|
-
call_id: m.collect("call_id"),
|
|
41
|
-
},
|
|
42
|
-
], 1000)
|
|
43
|
-
|
|
44
|
-
ic = {
|
|
45
|
-
id: z.store.call_id,
|
|
46
|
-
sip_call_id: z.store.sip_call_id,
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
sip.call.respond(ic.id, {code: 200, reason: 'OK', media: "audio"})
|
|
50
|
-
|
|
51
|
-
await z.wait([
|
|
52
|
-
{
|
|
53
|
-
event: 'response',
|
|
54
|
-
call_id: oc.id,
|
|
55
|
-
method: 'INVITE',
|
|
56
|
-
msg: sip_msg({
|
|
57
|
-
$rs: '200',
|
|
58
|
-
$rr: 'OK',
|
|
59
|
-
'$(hdrcnt(VIA))': 1,
|
|
60
|
-
$fU: 'alice',
|
|
61
|
-
$fd: 'test.com',
|
|
62
|
-
$tU: 'bob',
|
|
63
|
-
'$hdr(content-type)': 'application/sdp',
|
|
64
|
-
$rb: '!{_}a=sendrecv',
|
|
65
|
-
}),
|
|
66
|
-
},
|
|
67
|
-
{
|
|
68
|
-
event: 'media_update',
|
|
69
|
-
call_id: oc.id,
|
|
70
|
-
status: 'ok',
|
|
71
|
-
media: [
|
|
72
|
-
{
|
|
73
|
-
type: 'audio',
|
|
74
|
-
local: {},
|
|
75
|
-
},
|
|
76
|
-
{
|
|
77
|
-
type: 'audio',
|
|
78
|
-
port: 0,
|
|
79
|
-
}
|
|
80
|
-
],
|
|
81
|
-
},
|
|
82
|
-
{
|
|
83
|
-
event: 'media_update',
|
|
84
|
-
call_id: ic.id,
|
|
85
|
-
status: 'ok',
|
|
86
|
-
media: [
|
|
87
|
-
{
|
|
88
|
-
type: 'audio',
|
|
89
|
-
local: {},
|
|
90
|
-
},
|
|
91
|
-
{
|
|
92
|
-
type: 'audio',
|
|
93
|
-
port: 0,
|
|
94
|
-
}
|
|
95
|
-
],
|
|
96
|
-
},
|
|
97
|
-
], 1000)
|
|
98
|
-
|
|
99
|
-
sip.call.send_dtmf(oc.id, {digits: '1234', mode: 0})
|
|
100
|
-
sip.call.send_dtmf(ic.id, {digits: '4321', mode: 1})
|
|
101
|
-
|
|
102
|
-
await z.wait([
|
|
103
|
-
{
|
|
104
|
-
event: 'dtmf',
|
|
105
|
-
call_id: ic.id,
|
|
106
|
-
digits: '1234',
|
|
107
|
-
mode: 0,
|
|
108
|
-
media_id: 0
|
|
109
|
-
},
|
|
110
|
-
{
|
|
111
|
-
event: 'dtmf',
|
|
112
|
-
call_id: oc.id,
|
|
113
|
-
digits: '4321',
|
|
114
|
-
mode: 1,
|
|
115
|
-
media_id: 0
|
|
116
|
-
},
|
|
117
|
-
], 2000)
|
|
118
|
-
|
|
119
|
-
// now reinvite with two media
|
|
120
|
-
sip.call.reinvite(oc.id, {media: "audio,audio"})
|
|
121
|
-
|
|
122
|
-
await z.wait([
|
|
123
|
-
{
|
|
124
|
-
event: 'reinvite',
|
|
125
|
-
call_id: ic.id,
|
|
126
|
-
},
|
|
127
|
-
], 1000)
|
|
128
|
-
|
|
129
|
-
sip.call.respond(ic.id, {code: 200, reason: 'OK', media: "audio,audio"})
|
|
130
|
-
|
|
131
|
-
await z.wait([
|
|
132
|
-
{
|
|
133
|
-
event: 'response',
|
|
134
|
-
call_id: oc.id,
|
|
135
|
-
method: 'INVITE',
|
|
136
|
-
msg: sip_msg({
|
|
137
|
-
$rs: '200',
|
|
138
|
-
}),
|
|
139
|
-
},
|
|
140
|
-
{
|
|
141
|
-
event: 'media_update',
|
|
142
|
-
call_id: ic.id,
|
|
143
|
-
status: 'ok',
|
|
144
|
-
media: [
|
|
145
|
-
{
|
|
146
|
-
type: 'audio',
|
|
147
|
-
local: {
|
|
148
|
-
mode: 'sendrecv'
|
|
149
|
-
},
|
|
150
|
-
remote: {
|
|
151
|
-
mode: 'sendrecv'
|
|
152
|
-
},
|
|
153
|
-
fmt: [
|
|
154
|
-
'0 PCMU/8000',
|
|
155
|
-
'120 telephone-event/8000'
|
|
156
|
-
]
|
|
157
|
-
},
|
|
158
|
-
{
|
|
159
|
-
type: 'audio',
|
|
160
|
-
local: {
|
|
161
|
-
mode: 'sendrecv'
|
|
162
|
-
},
|
|
163
|
-
remote: {
|
|
164
|
-
mode: 'sendrecv'
|
|
165
|
-
},
|
|
166
|
-
fmt: [
|
|
167
|
-
'0 PCMU/8000',
|
|
168
|
-
'120 telephone-event/8000'
|
|
169
|
-
]
|
|
170
|
-
}
|
|
171
|
-
]
|
|
172
|
-
},
|
|
173
|
-
{
|
|
174
|
-
event: 'media_update',
|
|
175
|
-
call_id: oc.id,
|
|
176
|
-
status: 'ok',
|
|
177
|
-
media: [
|
|
178
|
-
{
|
|
179
|
-
type: 'audio',
|
|
180
|
-
local: {
|
|
181
|
-
mode: 'sendrecv'
|
|
182
|
-
},
|
|
183
|
-
remote: {
|
|
184
|
-
mode: 'sendrecv'
|
|
185
|
-
},
|
|
186
|
-
fmt: [
|
|
187
|
-
'0 PCMU/8000',
|
|
188
|
-
'120 telephone-event/8000'
|
|
189
|
-
]
|
|
190
|
-
},
|
|
191
|
-
{
|
|
192
|
-
type: 'audio',
|
|
193
|
-
local: {
|
|
194
|
-
mode: 'sendrecv'
|
|
195
|
-
},
|
|
196
|
-
remote: {
|
|
197
|
-
mode: 'sendrecv'
|
|
198
|
-
},
|
|
199
|
-
fmt: [
|
|
200
|
-
'0 PCMU/8000',
|
|
201
|
-
'120 telephone-event/8000'
|
|
202
|
-
]
|
|
203
|
-
}
|
|
204
|
-
]
|
|
205
|
-
},
|
|
206
|
-
], 1000)
|
|
207
|
-
|
|
208
|
-
await z.sleep(100)
|
|
209
|
-
|
|
210
|
-
// Now change to single media
|
|
211
|
-
sip.call.reinvite(oc.id, {media: "audio"})
|
|
212
|
-
|
|
213
|
-
await z.wait([
|
|
214
|
-
{
|
|
215
|
-
event: 'reinvite',
|
|
216
|
-
call_id: ic.id,
|
|
217
|
-
},
|
|
218
|
-
], 1000)
|
|
219
|
-
|
|
220
|
-
sip.call.respond(ic.id, {code: 200, reason: 'OK', media: "audio,audio"})
|
|
221
|
-
|
|
222
|
-
await z.wait([
|
|
223
|
-
{
|
|
224
|
-
event: 'response',
|
|
225
|
-
call_id: oc.id,
|
|
226
|
-
method: 'INVITE',
|
|
227
|
-
msg: sip_msg({
|
|
228
|
-
$rs: '200',
|
|
229
|
-
}),
|
|
230
|
-
},
|
|
231
|
-
{
|
|
232
|
-
event: 'media_update',
|
|
233
|
-
call_id: ic.id,
|
|
234
|
-
status: 'ok',
|
|
235
|
-
media: [
|
|
236
|
-
{
|
|
237
|
-
type: 'audio',
|
|
238
|
-
local: {
|
|
239
|
-
mode: 'sendrecv'
|
|
240
|
-
},
|
|
241
|
-
remote: {
|
|
242
|
-
mode: 'sendrecv'
|
|
243
|
-
},
|
|
244
|
-
fmt: [
|
|
245
|
-
'0 PCMU/8000',
|
|
246
|
-
'120 telephone-event/8000'
|
|
247
|
-
]
|
|
248
|
-
},
|
|
249
|
-
{
|
|
250
|
-
type: 'audio',
|
|
251
|
-
port: 0,
|
|
252
|
-
},
|
|
253
|
-
]
|
|
254
|
-
},
|
|
255
|
-
{
|
|
256
|
-
event: 'media_update',
|
|
257
|
-
call_id: oc.id,
|
|
258
|
-
status: 'ok',
|
|
259
|
-
media: [
|
|
260
|
-
{
|
|
261
|
-
type: 'audio',
|
|
262
|
-
local: {
|
|
263
|
-
mode: 'sendrecv'
|
|
264
|
-
},
|
|
265
|
-
remote: {
|
|
266
|
-
mode: 'sendrecv'
|
|
267
|
-
},
|
|
268
|
-
fmt: [
|
|
269
|
-
'0 PCMU/8000',
|
|
270
|
-
'120 telephone-event/8000'
|
|
271
|
-
]
|
|
272
|
-
},
|
|
273
|
-
{
|
|
274
|
-
type: 'audio',
|
|
275
|
-
port: 0,
|
|
276
|
-
},
|
|
277
|
-
]
|
|
278
|
-
},
|
|
279
|
-
], 1000)
|
|
280
|
-
|
|
281
|
-
sip.call.send_dtmf(oc.id, {digits: '1234', mode: 0})
|
|
282
|
-
sip.call.send_dtmf(ic.id, {digits: '4321', mode: 1})
|
|
283
|
-
|
|
284
|
-
await z.wait([
|
|
285
|
-
{
|
|
286
|
-
event: 'dtmf',
|
|
287
|
-
call_id: ic.id,
|
|
288
|
-
digits: '1234',
|
|
289
|
-
mode: 0,
|
|
290
|
-
media_id: 0
|
|
291
|
-
},
|
|
292
|
-
{
|
|
293
|
-
event: 'dtmf',
|
|
294
|
-
call_id: oc.id,
|
|
295
|
-
digits: '4321',
|
|
296
|
-
mode: 1,
|
|
297
|
-
media_id: 0
|
|
298
|
-
},
|
|
299
|
-
], 1500)
|
|
300
|
-
|
|
301
|
-
// now switch back to two media
|
|
302
|
-
sip.call.reinvite(oc.id, {media: "audio,audio"})
|
|
303
|
-
|
|
304
|
-
await z.wait([
|
|
305
|
-
{
|
|
306
|
-
event: 'reinvite',
|
|
307
|
-
call_id: ic.id,
|
|
308
|
-
},
|
|
309
|
-
], 1000)
|
|
310
|
-
|
|
311
|
-
sip.call.respond(ic.id, {code: 200, reason: 'OK', media: "audio,audio"})
|
|
312
|
-
|
|
313
|
-
await z.wait([
|
|
314
|
-
{
|
|
315
|
-
event: 'response',
|
|
316
|
-
call_id: oc.id,
|
|
317
|
-
method: 'INVITE',
|
|
318
|
-
msg: sip_msg({
|
|
319
|
-
$rs: '200',
|
|
320
|
-
}),
|
|
321
|
-
},
|
|
322
|
-
{
|
|
323
|
-
event: 'media_update',
|
|
324
|
-
call_id: ic.id,
|
|
325
|
-
status: 'ok',
|
|
326
|
-
media: [
|
|
327
|
-
{
|
|
328
|
-
type: 'audio',
|
|
329
|
-
local: {
|
|
330
|
-
mode: 'sendrecv'
|
|
331
|
-
},
|
|
332
|
-
remote: {
|
|
333
|
-
mode: 'sendrecv'
|
|
334
|
-
},
|
|
335
|
-
fmt: [
|
|
336
|
-
'0 PCMU/8000',
|
|
337
|
-
'120 telephone-event/8000'
|
|
338
|
-
]
|
|
339
|
-
},
|
|
340
|
-
{
|
|
341
|
-
type: 'audio',
|
|
342
|
-
local: {
|
|
343
|
-
mode: 'sendrecv'
|
|
344
|
-
},
|
|
345
|
-
remote: {
|
|
346
|
-
mode: 'sendrecv'
|
|
347
|
-
},
|
|
348
|
-
fmt: [
|
|
349
|
-
'0 PCMU/8000',
|
|
350
|
-
'120 telephone-event/8000'
|
|
351
|
-
]
|
|
352
|
-
}
|
|
353
|
-
]
|
|
354
|
-
},
|
|
355
|
-
{
|
|
356
|
-
event: 'media_update',
|
|
357
|
-
call_id: oc.id,
|
|
358
|
-
status: 'ok',
|
|
359
|
-
media: [
|
|
360
|
-
{
|
|
361
|
-
type: 'audio',
|
|
362
|
-
local: {
|
|
363
|
-
mode: 'sendrecv'
|
|
364
|
-
},
|
|
365
|
-
remote: {
|
|
366
|
-
mode: 'sendrecv'
|
|
367
|
-
},
|
|
368
|
-
fmt: [
|
|
369
|
-
'0 PCMU/8000',
|
|
370
|
-
'120 telephone-event/8000'
|
|
371
|
-
]
|
|
372
|
-
},
|
|
373
|
-
{
|
|
374
|
-
type: 'audio',
|
|
375
|
-
local: {
|
|
376
|
-
mode: 'sendrecv'
|
|
377
|
-
},
|
|
378
|
-
remote: {
|
|
379
|
-
mode: 'sendrecv'
|
|
380
|
-
},
|
|
381
|
-
fmt: [
|
|
382
|
-
'0 PCMU/8000',
|
|
383
|
-
'120 telephone-event/8000'
|
|
384
|
-
]
|
|
385
|
-
}
|
|
386
|
-
]
|
|
387
|
-
},
|
|
388
|
-
], 1000)
|
|
389
|
-
|
|
390
|
-
sip.call.send_dtmf(oc.id, {digits: '1234', mode: 0})
|
|
391
|
-
sip.call.send_dtmf(ic.id, {digits: '4321', mode: 1})
|
|
392
|
-
|
|
393
|
-
await z.wait([
|
|
394
|
-
{
|
|
395
|
-
event: 'dtmf',
|
|
396
|
-
call_id: ic.id,
|
|
397
|
-
digits: '1234',
|
|
398
|
-
mode: 0,
|
|
399
|
-
media_id: 0
|
|
400
|
-
},
|
|
401
|
-
{
|
|
402
|
-
event: 'dtmf',
|
|
403
|
-
call_id: oc.id,
|
|
404
|
-
digits: '4321',
|
|
405
|
-
mode: 1,
|
|
406
|
-
media_id: 0
|
|
407
|
-
},
|
|
408
|
-
{
|
|
409
|
-
event: 'dtmf',
|
|
410
|
-
call_id: ic.id,
|
|
411
|
-
digits: '1234',
|
|
412
|
-
mode: 0,
|
|
413
|
-
media_id: 1
|
|
414
|
-
},
|
|
415
|
-
{
|
|
416
|
-
event: 'dtmf',
|
|
417
|
-
call_id: oc.id,
|
|
418
|
-
digits: '4321',
|
|
419
|
-
mode: 1,
|
|
420
|
-
media_id: 1
|
|
421
|
-
},
|
|
422
|
-
], 2000)
|
|
423
|
-
|
|
424
|
-
sip.call.terminate(oc.id)
|
|
425
|
-
|
|
426
|
-
await z.wait([
|
|
427
|
-
{
|
|
428
|
-
event: 'call_ended',
|
|
429
|
-
call_id: oc.id,
|
|
430
|
-
},
|
|
431
|
-
{
|
|
432
|
-
event: 'call_ended',
|
|
433
|
-
call_id: ic.id,
|
|
434
|
-
},
|
|
435
|
-
{
|
|
436
|
-
event: 'response',
|
|
437
|
-
call_id: oc.id,
|
|
438
|
-
method: 'BYE',
|
|
439
|
-
msg: sip_msg({
|
|
440
|
-
$rs: '200',
|
|
441
|
-
$rr: 'OK',
|
|
442
|
-
}),
|
|
443
|
-
},
|
|
444
|
-
], 1000)
|
|
445
|
-
|
|
446
|
-
console.log("Success")
|
|
447
|
-
|
|
448
|
-
sip.stop()
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
test()
|
|
453
|
-
.catch(e => {
|
|
454
|
-
console.error(e)
|
|
455
|
-
process.exit(1)
|
|
456
|
-
})
|
|
457
|
-
|