sip-lab 1.22.0 → 1.23.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/README.md +3 -2
- package/build_deps.sh +2 -1
- package/index.js +1 -0
- package/package.json +1 -1
- package/prebuilds/linux-x64/sip-lab.node +0 -0
- package/samples/start_play_wav_with_end_of_file_event.js +269 -0
- package/samples/start_play_wav_with_no_loop.js +257 -0
- package/samples/tcp_and_extra_headers.js +3 -0
- package/samples/text_to_speech.js +22 -3
- package/src/addon.cpp +35 -0
- package/src/event_templates.cpp +14 -7
- package/src/event_templates.hpp +4 -0
- package/src/pjmedia/include/pjmedia/flite_port.h +10 -4
- package/src/pjmedia/src/pjmedia/flite_port.c +87 -18
- package/src/pjmedia/src/pjmedia/pocketsphinx_port.c +150 -0
- package/src/sip.cpp +326 -251
- package/src/sip.hpp +2 -0
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ It uses pjproject for SIP and media processing.
|
|
|
8
8
|
It permits to:
|
|
9
9
|
- make audio calls using UDP, TCP and TLS transports
|
|
10
10
|
- send/receive DTMF inband/RFC2833/INFO.
|
|
11
|
-
- play/record
|
|
11
|
+
- play/record audio on a call from/to a wav file
|
|
12
12
|
- send/receive fax (T.30 only)
|
|
13
13
|
- send/receive MRCPv2 messages (TCP only, no TLS)
|
|
14
14
|
- send/receive audio using SRTP
|
|
@@ -17,8 +17,9 @@ It permits to:
|
|
|
17
17
|
TODO:
|
|
18
18
|
- add support for video playing/recording from/to file
|
|
19
19
|
- add support for speech recognition using pocketsphinx
|
|
20
|
+
- add support for speech synth/recog via websocket server
|
|
20
21
|
- add support for T.38 fax
|
|
21
|
-
- add support for WebSocket
|
|
22
|
+
- add support for SIP over WebSocket
|
|
22
23
|
- add support for WebRTC
|
|
23
24
|
- add support for MSRP
|
|
24
25
|
|
package/build_deps.sh
CHANGED
|
@@ -55,7 +55,8 @@ then
|
|
|
55
55
|
#git checkout 33a3c9e0a5eb84426edef05a9aa98af17d8011c3 # required for bcg729
|
|
56
56
|
#git checkout 797088ed133c98492519b7d042b75735f6f9388c # updated as part of #21
|
|
57
57
|
#git checkout 651df5b50129b7c5a5feec8336dda4468d53d2b0 # updated to latest to see of crash issues improve
|
|
58
|
-
git checkout 043926a5846963a2c99378e8daa495230923eaab #
|
|
58
|
+
#git checkout 043926a5846963a2c99378e8daa495230923eaab # updated to try to solve #49 (but issue remains)
|
|
59
|
+
git checkout c36802585ddefb3ca477d1f6d773d179510c5412 # updated to try to solve #83 (but issue remains)
|
|
59
60
|
|
|
60
61
|
cat > user.mak <<EOF
|
|
61
62
|
export CFLAGS += -fPIC -g
|
package/index.js
CHANGED
|
@@ -67,6 +67,7 @@ addon.call = {
|
|
|
67
67
|
start_fax: (c_id, params) => { return addon.call_start_fax(c_id, JSON.stringify(params)) },
|
|
68
68
|
stop_fax: (c_id, params) => { return addon.call_stop_fax(c_id, JSON.stringify(params ? params : {})) },
|
|
69
69
|
start_speech_synth: (c_id, params) => { return addon.call_start_speech_synth(c_id, JSON.stringify(params)) },
|
|
70
|
+
stop_speech_synth: (c_id, params) => { return addon.call_stop_speech_synth(c_id, JSON.stringify(params ? params : {})) },
|
|
70
71
|
get_stream_stat: (c_id, params) => { return addon.call_get_stream_stat(c_id, JSON.stringify(params ? params : {})) },
|
|
71
72
|
//refer: (c_id, params) => { return addon.call_refer(c_id, JSON.stringify(params)) },
|
|
72
73
|
get_info: addon.call_get_info,
|
package/package.json
CHANGED
|
Binary file
|
|
@@ -0,0 +1,269 @@
|
|
|
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(6)
|
|
10
|
+
sip.dtmf_aggregation_on(500)
|
|
11
|
+
|
|
12
|
+
z.trap_events(sip.event_source, 'event', (evt) => {
|
|
13
|
+
var e = evt.args[0]
|
|
14
|
+
return e
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
console.log(sip.start((data) => { console.log(data)} ))
|
|
18
|
+
|
|
19
|
+
t1 = sip.transport.create({address: "127.0.0.1"})
|
|
20
|
+
t2 = sip.transport.create({address: "127.0.0.1"})
|
|
21
|
+
|
|
22
|
+
console.log("t1", t1)
|
|
23
|
+
console.log("t2", t2)
|
|
24
|
+
|
|
25
|
+
oc = sip.call.create(t1.id, {
|
|
26
|
+
from_uri: '"abc"<sip:alice@test.com>',
|
|
27
|
+
to_uri: `sip:bob@${t2.address}:${t2.port}`,
|
|
28
|
+
headers: {
|
|
29
|
+
'X-MyHeader1': 'abc',
|
|
30
|
+
'X-MyHeader2': 'def',
|
|
31
|
+
},
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
await z.wait([
|
|
35
|
+
{
|
|
36
|
+
event: "incoming_call",
|
|
37
|
+
call_id: m.collect("call_id"),
|
|
38
|
+
msg: sip_msg({
|
|
39
|
+
$rm: 'INVITE',
|
|
40
|
+
$fU: 'alice',
|
|
41
|
+
$fd: 'test.com',
|
|
42
|
+
$tU: 'bob',
|
|
43
|
+
'$hdr(X-MyHeader1)': 'abc',
|
|
44
|
+
'hdr_x_myheader2': 'def',
|
|
45
|
+
}),
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
event: 'response',
|
|
49
|
+
call_id: oc.id,
|
|
50
|
+
method: 'INVITE',
|
|
51
|
+
msg: sip_msg({
|
|
52
|
+
$rs: '100',
|
|
53
|
+
$rr: 'Trying',
|
|
54
|
+
'$(hdrcnt(via))': 1,
|
|
55
|
+
'hdr_call_id': m.collect('sip_call_id'),
|
|
56
|
+
$fU: 'alice',
|
|
57
|
+
$fd: 'test.com',
|
|
58
|
+
$tU: 'bob',
|
|
59
|
+
'$hdr(l)': '0',
|
|
60
|
+
}),
|
|
61
|
+
},
|
|
62
|
+
], 1000)
|
|
63
|
+
|
|
64
|
+
ic = {
|
|
65
|
+
id: z.store.call_id,
|
|
66
|
+
sip_call_id: z.store.sip_call_id,
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
sip.call.respond(ic.id, {
|
|
70
|
+
code: 200,
|
|
71
|
+
reason:'OK',
|
|
72
|
+
headers: {
|
|
73
|
+
'X-MyHeader3': 'ghi',
|
|
74
|
+
'X-MyHeader4': 'jkl',
|
|
75
|
+
},
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
await z.wait([
|
|
79
|
+
{
|
|
80
|
+
event: 'media_update',
|
|
81
|
+
call_id: oc.id,
|
|
82
|
+
status: 'ok',
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
event: 'media_update',
|
|
86
|
+
call_id: ic.id,
|
|
87
|
+
status: 'ok',
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
event: 'response',
|
|
91
|
+
call_id: oc.id,
|
|
92
|
+
method: 'INVITE',
|
|
93
|
+
msg: sip_msg({
|
|
94
|
+
$rs: '200',
|
|
95
|
+
$rr: 'OK',
|
|
96
|
+
'$(hdrcnt(v))': 1,
|
|
97
|
+
$fU: 'alice',
|
|
98
|
+
$fd: 'test.com',
|
|
99
|
+
$tU: 'bob',
|
|
100
|
+
'$hdr(content-type)': 'application/sdp',
|
|
101
|
+
$rb: '!{_}a=sendrecv',
|
|
102
|
+
'$hdr(X-MyHeader3)': 'ghi',
|
|
103
|
+
'$hdr(X-MyHeader4)': 'jkl',
|
|
104
|
+
}),
|
|
105
|
+
},
|
|
106
|
+
], 1000)
|
|
107
|
+
|
|
108
|
+
sip.call.start_record_wav(oc.id, {file: './oc.wav'})
|
|
109
|
+
sip.call.start_record_wav(ic.id, {file: './ic.wav'})
|
|
110
|
+
|
|
111
|
+
await z.sleep(100)
|
|
112
|
+
|
|
113
|
+
sip.call.start_play_wav(oc.id, {file: 'samples/artifacts/yosemitesam.wav', end_of_file_event: true})
|
|
114
|
+
sip.call.start_play_wav(ic.id, {file: 'samples/artifacts/yosemitesam.wav', end_of_file_event: true})
|
|
115
|
+
|
|
116
|
+
await z.sleep(500)
|
|
117
|
+
|
|
118
|
+
sip.call.reinvite(oc.id)
|
|
119
|
+
|
|
120
|
+
await z.wait([
|
|
121
|
+
{
|
|
122
|
+
event: 'reinvite',
|
|
123
|
+
call_id: ic.id
|
|
124
|
+
},
|
|
125
|
+
], 1000)
|
|
126
|
+
|
|
127
|
+
sip.call.respond(ic.id, {code: 200, reason: 'OK'})
|
|
128
|
+
|
|
129
|
+
await z.wait([
|
|
130
|
+
{
|
|
131
|
+
event: 'response',
|
|
132
|
+
call_id: oc.id,
|
|
133
|
+
method: 'INVITE',
|
|
134
|
+
msg: sip_msg({
|
|
135
|
+
$rs: '100',
|
|
136
|
+
}),
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
event: 'response',
|
|
140
|
+
call_id: oc.id,
|
|
141
|
+
method: 'INVITE',
|
|
142
|
+
msg: sip_msg({
|
|
143
|
+
$rs: '200',
|
|
144
|
+
$rr: 'OK',
|
|
145
|
+
$rb: '!{_}a=sendrecv',
|
|
146
|
+
}),
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
event: 'media_update',
|
|
150
|
+
call_id: oc.id,
|
|
151
|
+
status: 'ok',
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
event: 'media_update',
|
|
155
|
+
call_id: ic.id,
|
|
156
|
+
status: 'ok',
|
|
157
|
+
},
|
|
158
|
+
], 500)
|
|
159
|
+
|
|
160
|
+
await z.wait([
|
|
161
|
+
{
|
|
162
|
+
event: 'end_of_file',
|
|
163
|
+
call_id: ic.id,
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
event: 'end_of_file',
|
|
167
|
+
call_id: oc.id,
|
|
168
|
+
},
|
|
169
|
+
], 2000)
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
sip.call.reinvite(ic.id)
|
|
173
|
+
|
|
174
|
+
await z.wait([
|
|
175
|
+
{
|
|
176
|
+
event: 'reinvite',
|
|
177
|
+
call_id: oc.id
|
|
178
|
+
},
|
|
179
|
+
], 1000)
|
|
180
|
+
|
|
181
|
+
sip.call.respond(oc.id, {code: 200, reason: 'OK'})
|
|
182
|
+
|
|
183
|
+
await z.wait([
|
|
184
|
+
{
|
|
185
|
+
event: 'response',
|
|
186
|
+
call_id: ic.id,
|
|
187
|
+
method: 'INVITE',
|
|
188
|
+
msg: sip_msg({
|
|
189
|
+
$rs: '100',
|
|
190
|
+
}),
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
event: 'response',
|
|
194
|
+
call_id: ic.id,
|
|
195
|
+
method: 'INVITE',
|
|
196
|
+
msg: sip_msg({
|
|
197
|
+
$rs: '200',
|
|
198
|
+
$rr: 'OK',
|
|
199
|
+
$rb: '!{_}a=sendrecv',
|
|
200
|
+
}),
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
event: 'media_update',
|
|
204
|
+
call_id: oc.id,
|
|
205
|
+
status: 'ok',
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
event: 'media_update',
|
|
209
|
+
call_id: ic.id,
|
|
210
|
+
status: 'ok',
|
|
211
|
+
},
|
|
212
|
+
], 500)
|
|
213
|
+
|
|
214
|
+
await z.wait([
|
|
215
|
+
{
|
|
216
|
+
event: 'end_of_file',
|
|
217
|
+
call_id: ic.id,
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
event: 'end_of_file',
|
|
221
|
+
call_id: oc.id,
|
|
222
|
+
},
|
|
223
|
+
], 5000)
|
|
224
|
+
|
|
225
|
+
stat1 = sip.call.get_stream_stat(oc.id, {media_id: 0})
|
|
226
|
+
stat2 = sip.call.get_stream_stat(ic.id, {media_id: 0})
|
|
227
|
+
|
|
228
|
+
console.log("stat1", stat1)
|
|
229
|
+
console.log("stat2", stat2)
|
|
230
|
+
|
|
231
|
+
sip.call.stop_record_wav(oc.id)
|
|
232
|
+
sip.call.stop_record_wav(ic.id)
|
|
233
|
+
|
|
234
|
+
sip.call.terminate(oc.id)
|
|
235
|
+
|
|
236
|
+
await z.wait([
|
|
237
|
+
{
|
|
238
|
+
event: 'call_ended',
|
|
239
|
+
call_id: oc.id,
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
event: 'call_ended',
|
|
243
|
+
call_id: ic.id,
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
event: 'response',
|
|
247
|
+
call_id: oc.id,
|
|
248
|
+
method: 'BYE',
|
|
249
|
+
msg: sip_msg({
|
|
250
|
+
$rs: '200',
|
|
251
|
+
$rr: 'OK',
|
|
252
|
+
}),
|
|
253
|
+
},
|
|
254
|
+
], 1000)
|
|
255
|
+
|
|
256
|
+
await z.sleep(1000)
|
|
257
|
+
|
|
258
|
+
console.log("Success")
|
|
259
|
+
|
|
260
|
+
sip.stop()
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
test()
|
|
265
|
+
.catch(e => {
|
|
266
|
+
console.error(e)
|
|
267
|
+
process.exit(1)
|
|
268
|
+
})
|
|
269
|
+
|
|
@@ -0,0 +1,257 @@
|
|
|
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(6)
|
|
10
|
+
sip.dtmf_aggregation_on(500)
|
|
11
|
+
|
|
12
|
+
z.trap_events(sip.event_source, 'event', (evt) => {
|
|
13
|
+
var e = evt.args[0]
|
|
14
|
+
return e
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
console.log(sip.start((data) => { console.log(data)} ))
|
|
18
|
+
|
|
19
|
+
t1 = sip.transport.create({address: "127.0.0.1"})
|
|
20
|
+
t2 = sip.transport.create({address: "127.0.0.1"})
|
|
21
|
+
|
|
22
|
+
console.log("t1", t1)
|
|
23
|
+
console.log("t2", t2)
|
|
24
|
+
|
|
25
|
+
oc = sip.call.create(t1.id, {
|
|
26
|
+
from_uri: '"abc"<sip:alice@test.com>',
|
|
27
|
+
to_uri: `sip:bob@${t2.address}:${t2.port}`,
|
|
28
|
+
headers: {
|
|
29
|
+
'X-MyHeader1': 'abc',
|
|
30
|
+
'X-MyHeader2': 'def',
|
|
31
|
+
},
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
await z.wait([
|
|
35
|
+
{
|
|
36
|
+
event: "incoming_call",
|
|
37
|
+
call_id: m.collect("call_id"),
|
|
38
|
+
msg: sip_msg({
|
|
39
|
+
$rm: 'INVITE',
|
|
40
|
+
$fU: 'alice',
|
|
41
|
+
$fd: 'test.com',
|
|
42
|
+
$tU: 'bob',
|
|
43
|
+
'$hdr(X-MyHeader1)': 'abc',
|
|
44
|
+
'hdr_x_myheader2': 'def',
|
|
45
|
+
}),
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
event: 'response',
|
|
49
|
+
call_id: oc.id,
|
|
50
|
+
method: 'INVITE',
|
|
51
|
+
msg: sip_msg({
|
|
52
|
+
$rs: '100',
|
|
53
|
+
$rr: 'Trying',
|
|
54
|
+
'$(hdrcnt(via))': 1,
|
|
55
|
+
'hdr_call_id': m.collect('sip_call_id'),
|
|
56
|
+
$fU: 'alice',
|
|
57
|
+
$fd: 'test.com',
|
|
58
|
+
$tU: 'bob',
|
|
59
|
+
'$hdr(l)': '0',
|
|
60
|
+
}),
|
|
61
|
+
},
|
|
62
|
+
], 1000)
|
|
63
|
+
|
|
64
|
+
ic = {
|
|
65
|
+
id: z.store.call_id,
|
|
66
|
+
sip_call_id: z.store.sip_call_id,
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
sip.call.respond(ic.id, {
|
|
70
|
+
code: 200,
|
|
71
|
+
reason:'OK',
|
|
72
|
+
headers: {
|
|
73
|
+
'X-MyHeader3': 'ghi',
|
|
74
|
+
'X-MyHeader4': 'jkl',
|
|
75
|
+
},
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
await z.wait([
|
|
79
|
+
{
|
|
80
|
+
event: 'media_update',
|
|
81
|
+
call_id: oc.id,
|
|
82
|
+
status: 'ok',
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
event: 'media_update',
|
|
86
|
+
call_id: ic.id,
|
|
87
|
+
status: 'ok',
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
event: 'response',
|
|
91
|
+
call_id: oc.id,
|
|
92
|
+
method: 'INVITE',
|
|
93
|
+
msg: sip_msg({
|
|
94
|
+
$rs: '200',
|
|
95
|
+
$rr: 'OK',
|
|
96
|
+
'$(hdrcnt(v))': 1,
|
|
97
|
+
$fU: 'alice',
|
|
98
|
+
$fd: 'test.com',
|
|
99
|
+
$tU: 'bob',
|
|
100
|
+
'$hdr(content-type)': 'application/sdp',
|
|
101
|
+
$rb: '!{_}a=sendrecv',
|
|
102
|
+
'$hdr(X-MyHeader3)': 'ghi',
|
|
103
|
+
'$hdr(X-MyHeader4)': 'jkl',
|
|
104
|
+
}),
|
|
105
|
+
},
|
|
106
|
+
], 1000)
|
|
107
|
+
|
|
108
|
+
sip.call.start_record_wav(oc.id, {file: './oc.wav'})
|
|
109
|
+
sip.call.start_record_wav(ic.id, {file: './ic.wav'})
|
|
110
|
+
|
|
111
|
+
await z.sleep(100)
|
|
112
|
+
|
|
113
|
+
sip.call.start_play_wav(oc.id, {file: 'samples/artifacts/yosemitesam.wav', end_of_file_event: true, no_loop: true})
|
|
114
|
+
sip.call.start_play_wav(ic.id, {file: 'samples/artifacts/yosemitesam.wav', end_of_file_event: true, no_loop: true})
|
|
115
|
+
|
|
116
|
+
sip.call.reinvite(oc.id)
|
|
117
|
+
|
|
118
|
+
await z.wait([
|
|
119
|
+
{
|
|
120
|
+
event: 'reinvite',
|
|
121
|
+
call_id: ic.id
|
|
122
|
+
},
|
|
123
|
+
], 1000)
|
|
124
|
+
|
|
125
|
+
sip.call.respond(ic.id, {code: 200, reason: 'OK'})
|
|
126
|
+
|
|
127
|
+
await z.wait([
|
|
128
|
+
{
|
|
129
|
+
event: 'response',
|
|
130
|
+
call_id: oc.id,
|
|
131
|
+
method: 'INVITE',
|
|
132
|
+
msg: sip_msg({
|
|
133
|
+
$rs: '100',
|
|
134
|
+
}),
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
event: 'response',
|
|
138
|
+
call_id: oc.id,
|
|
139
|
+
method: 'INVITE',
|
|
140
|
+
msg: sip_msg({
|
|
141
|
+
$rs: '200',
|
|
142
|
+
$rr: 'OK',
|
|
143
|
+
$rb: '!{_}a=sendrecv',
|
|
144
|
+
}),
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
event: 'media_update',
|
|
148
|
+
call_id: oc.id,
|
|
149
|
+
status: 'ok',
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
event: 'media_update',
|
|
153
|
+
call_id: ic.id,
|
|
154
|
+
status: 'ok',
|
|
155
|
+
},
|
|
156
|
+
], 500)
|
|
157
|
+
|
|
158
|
+
sip.call.reinvite(ic.id)
|
|
159
|
+
|
|
160
|
+
await z.wait([
|
|
161
|
+
{
|
|
162
|
+
event: 'reinvite',
|
|
163
|
+
call_id: oc.id
|
|
164
|
+
},
|
|
165
|
+
], 1000)
|
|
166
|
+
|
|
167
|
+
sip.call.respond(oc.id, {code: 200, reason: 'OK'})
|
|
168
|
+
|
|
169
|
+
await z.wait([
|
|
170
|
+
{
|
|
171
|
+
event: 'response',
|
|
172
|
+
call_id: ic.id,
|
|
173
|
+
method: 'INVITE',
|
|
174
|
+
msg: sip_msg({
|
|
175
|
+
$rs: '100',
|
|
176
|
+
}),
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
event: 'response',
|
|
180
|
+
call_id: ic.id,
|
|
181
|
+
method: 'INVITE',
|
|
182
|
+
msg: sip_msg({
|
|
183
|
+
$rs: '200',
|
|
184
|
+
$rr: 'OK',
|
|
185
|
+
$rb: '!{_}a=sendrecv',
|
|
186
|
+
}),
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
event: 'media_update',
|
|
190
|
+
call_id: oc.id,
|
|
191
|
+
status: 'ok',
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
event: 'media_update',
|
|
195
|
+
call_id: ic.id,
|
|
196
|
+
status: 'ok',
|
|
197
|
+
},
|
|
198
|
+
], 500)
|
|
199
|
+
|
|
200
|
+
await z.wait([
|
|
201
|
+
{
|
|
202
|
+
event: 'end_of_file',
|
|
203
|
+
call_id: ic.id,
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
event: 'end_of_file',
|
|
207
|
+
call_id: oc.id,
|
|
208
|
+
},
|
|
209
|
+
], 3000)
|
|
210
|
+
|
|
211
|
+
await z.sleep(3000) // we should not receive end_of_file events again
|
|
212
|
+
|
|
213
|
+
stat1 = sip.call.get_stream_stat(oc.id, {media_id: 0})
|
|
214
|
+
stat2 = sip.call.get_stream_stat(ic.id, {media_id: 0})
|
|
215
|
+
|
|
216
|
+
console.log("stat1", stat1)
|
|
217
|
+
console.log("stat2", stat2)
|
|
218
|
+
|
|
219
|
+
sip.call.stop_record_wav(oc.id)
|
|
220
|
+
sip.call.stop_record_wav(ic.id)
|
|
221
|
+
|
|
222
|
+
sip.call.terminate(oc.id)
|
|
223
|
+
|
|
224
|
+
await z.wait([
|
|
225
|
+
{
|
|
226
|
+
event: 'call_ended',
|
|
227
|
+
call_id: oc.id,
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
event: 'call_ended',
|
|
231
|
+
call_id: ic.id,
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
event: 'response',
|
|
235
|
+
call_id: oc.id,
|
|
236
|
+
method: 'BYE',
|
|
237
|
+
msg: sip_msg({
|
|
238
|
+
$rs: '200',
|
|
239
|
+
$rr: 'OK',
|
|
240
|
+
}),
|
|
241
|
+
},
|
|
242
|
+
], 1000)
|
|
243
|
+
|
|
244
|
+
await z.sleep(1000)
|
|
245
|
+
|
|
246
|
+
console.log("Success")
|
|
247
|
+
|
|
248
|
+
sip.stop()
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
test()
|
|
253
|
+
.catch(e => {
|
|
254
|
+
console.error(e)
|
|
255
|
+
process.exit(1)
|
|
256
|
+
})
|
|
257
|
+
|
|
@@ -345,6 +345,9 @@ async function test() {
|
|
|
345
345
|
console.log("stat1", stat1)
|
|
346
346
|
console.log("stat2", stat2)
|
|
347
347
|
|
|
348
|
+
sip.call.stop_play_wav(oc.id) // this is not really necessary. We are just confirming it works
|
|
349
|
+
sip.call.stop_play_wav(ic.id) // this is not really necessary. We are just confirming it works
|
|
350
|
+
|
|
348
351
|
sip.call.stop_record_wav(oc.id)
|
|
349
352
|
sip.call.stop_record_wav(ic.id)
|
|
350
353
|
|
|
@@ -130,10 +130,29 @@ async function test() {
|
|
|
130
130
|
},
|
|
131
131
|
], 3000)
|
|
132
132
|
|
|
133
|
-
sip.call.start_speech_synth(oc.id, {voice: 'slt', text: 'Hello World.'})
|
|
134
|
-
sip.call.start_speech_synth(ic.id, {voice: 'kal', text: 'How are you?'})
|
|
133
|
+
sip.call.start_speech_synth(oc.id, {voice: 'slt', text: 'Hello World.', end_of_speech_event: true})
|
|
134
|
+
sip.call.start_speech_synth(ic.id, {voice: 'kal', text: 'How are you?', end_of_speech_event: true, no_loop: true})
|
|
135
135
|
|
|
136
|
-
await z.
|
|
136
|
+
await z.wait([
|
|
137
|
+
{
|
|
138
|
+
event: 'end_of_speech',
|
|
139
|
+
call_id: ic.id,
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
event: 'end_of_speech',
|
|
143
|
+
call_id: oc.id,
|
|
144
|
+
},
|
|
145
|
+
], 2000)
|
|
146
|
+
|
|
147
|
+
await z.wait([
|
|
148
|
+
{
|
|
149
|
+
event: 'end_of_speech',
|
|
150
|
+
call_id: oc.id,
|
|
151
|
+
},
|
|
152
|
+
], 2000)
|
|
153
|
+
|
|
154
|
+
sip.call.stop_speech_synth(oc.id) // this is not actually necessary. It is used just to confirm the command works
|
|
155
|
+
sip.call.stop_speech_synth(ic.id) // this is not actually necessary. It is used just to confirm the command works
|
|
137
156
|
|
|
138
157
|
sip.call.stop_record_wav(oc.id)
|
|
139
158
|
sip.call.stop_record_wav(ic.id)
|
package/src/addon.cpp
CHANGED
|
@@ -704,6 +704,40 @@ Napi::Value call_stop_fax(const Napi::CallbackInfo &info) {
|
|
|
704
704
|
return env.Null();
|
|
705
705
|
}
|
|
706
706
|
|
|
707
|
+
Napi::Value call_stop_speech_synth(const Napi::CallbackInfo &info) {
|
|
708
|
+
Napi::Env env = info.Env();
|
|
709
|
+
|
|
710
|
+
if (info.Length() != 2) {
|
|
711
|
+
Napi::Error::New(env, "Wrong number of arguments. Expected: call_id")
|
|
712
|
+
.ThrowAsJavaScriptException();
|
|
713
|
+
return env.Null();
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
if (!info[0].IsNumber()) {
|
|
717
|
+
Napi::TypeError::New(env, "call_id must be number.")
|
|
718
|
+
.ThrowAsJavaScriptException();
|
|
719
|
+
return env.Null();
|
|
720
|
+
}
|
|
721
|
+
int call_id = info[0].As<Napi::Number>().Int32Value();
|
|
722
|
+
|
|
723
|
+
if (!info[1].IsString()) {
|
|
724
|
+
Napi::TypeError::New(env, "params must be a JSON string.")
|
|
725
|
+
.ThrowAsJavaScriptException();
|
|
726
|
+
return env.Null();
|
|
727
|
+
}
|
|
728
|
+
const string json = info[1].As<Napi::String>().Utf8Value();
|
|
729
|
+
|
|
730
|
+
int res = pjw_call_stop_speech_synth(call_id, json.c_str());
|
|
731
|
+
|
|
732
|
+
if (res != 0) {
|
|
733
|
+
Napi::Error::New(env, pjw_get_error()).ThrowAsJavaScriptException();
|
|
734
|
+
return env.Null();
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
return env.Null();
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
|
|
707
741
|
Napi::Value call_get_stream_stat(const Napi::CallbackInfo &info) {
|
|
708
742
|
Napi::Env env = info.Env();
|
|
709
743
|
|
|
@@ -1307,6 +1341,7 @@ Napi::Object init(Napi::Env env, Napi::Object exports) {
|
|
|
1307
1341
|
exports.Set("call_stop_play_wav",
|
|
1308
1342
|
Napi::Function::New(env, call_stop_play_wav));
|
|
1309
1343
|
exports.Set("call_stop_fax", Napi::Function::New(env, call_stop_fax));
|
|
1344
|
+
exports.Set("call_stop_speech_synth", Napi::Function::New(env, call_stop_speech_synth));
|
|
1310
1345
|
exports.Set("call_get_stream_stat",
|
|
1311
1346
|
Napi::Function::New(env, call_get_stream_stat));
|
|
1312
1347
|
// exports.Set("call_refer", Napi::Function::New(env, call_refer));
|
package/src/event_templates.cpp
CHANGED
|
@@ -49,14 +49,9 @@ int make_evt_dtmf(char *dest, int size, long call_id, int digits_len,
|
|
|
49
49
|
|
|
50
50
|
int make_evt_call_ended(char *dest, int size, long call_id, int sip_msg_len,
|
|
51
51
|
const char *sip_msg) {
|
|
52
|
-
printf("make_evt_call_ended sip_msg_len=%i sip_msg=%
|
|
52
|
+
printf("make_evt_call_ended sip_msg_len=%i sip_msg=%p\n", sip_msg_len,
|
|
53
53
|
sip_msg);
|
|
54
|
-
if (
|
|
55
|
-
// received invalid pointer to sip_msg so do not add the message to the
|
|
56
|
-
// event
|
|
57
|
-
return snprintf(dest, size, "{\"event\": \"call_ended\", \"call_id\": %ld}",
|
|
58
|
-
call_id);
|
|
59
|
-
} else if (sip_msg_len > 500 && sip_msg_len < 2000 && sip_msg) {
|
|
54
|
+
if (sip_msg_len > 500 && sip_msg_len < 2000 && sip_msg) {
|
|
60
55
|
/* sip_msg_len sometimes show up as a large value like sip_msg_len=11560297
|
|
61
56
|
* which seems to be a bug in pjsip */
|
|
62
57
|
return snprintf(dest, size,
|
|
@@ -104,6 +99,18 @@ int make_evt_fax_result(char *dest, int size, long call_id, int result) {
|
|
|
104
99
|
result);
|
|
105
100
|
}
|
|
106
101
|
|
|
102
|
+
int make_evt_end_of_file(char *dest, int size, long call_id) {
|
|
103
|
+
return snprintf(
|
|
104
|
+
dest, size,
|
|
105
|
+
"{\"event\": \"end_of_file\", \"call_id\": %ld}", call_id);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
int make_evt_end_of_speech(char *dest, int size, long call_id) {
|
|
109
|
+
return snprintf(
|
|
110
|
+
dest, size,
|
|
111
|
+
"{\"event\": \"end_of_speech\", \"call_id\": %ld}", call_id);
|
|
112
|
+
}
|
|
113
|
+
|
|
107
114
|
int make_evt_tcp_msg(char *dest, int size, long call_id, const char *protocol, char *data, int data_len) {
|
|
108
115
|
return snprintf(
|
|
109
116
|
dest, size,
|