sip-lab 1.27.1 → 1.28.1
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 +30 -2
- package/binding.gyp +8 -0
- package/build_deps.sh +9 -0
- package/package.json +2 -1
- package/prebuilds/linux-x64/sip-lab.node +0 -0
- package/samples/play_wav_and_speech_recog.bad_transcript.pcmu8000.js +4 -4
- package/samples/speech_synth_and_recog.speex16000.js +6 -6
- package/samples/text_to_speech.js +5 -12
- package/samples_extra/ws_speech_server.dtmf.js +194 -0
- package/samples_extra/ws_speech_server.google.js +190 -0
- package/src/event_templates.cpp +11 -4
- package/src/event_templates.hpp +4 -2
- package/src/pjmedia/include/pjmedia/flite_port.h +2 -2
- package/src/pjmedia/include/pjmedia/ws_speech_port.h +37 -0
- package/src/pjmedia/src/pjmedia/flite_port.c +16 -11
- package/src/pjmedia/src/pjmedia/ws_speech_port.cpp +377 -0
- package/src/sip.cpp +311 -95
package/README.md
CHANGED
|
@@ -14,10 +14,10 @@ It permits to:
|
|
|
14
14
|
- send/receive audio using SRTP
|
|
15
15
|
- do speech synth using flite
|
|
16
16
|
- do speech recog using pocketsphinx (but only works well with sampling rate of 16000)
|
|
17
|
+
- do speech synth/recog using [ws_speech_server](https://github.com/MayamaTakeshi/ws_speech_server) (this permits to use google/amazon/azure/etc speech services)
|
|
17
18
|
|
|
18
19
|
TODO:
|
|
19
20
|
- add support for video playing/recording from/to file
|
|
20
|
-
- add support for speech synth/recog via websocket server to permit to access Google Speech, Whisper, Amazon Poly etc.
|
|
21
21
|
- add support for T.38 fax
|
|
22
22
|
- add support for SIP over WebSocket
|
|
23
23
|
- add support for WebRTC
|
|
@@ -40,13 +40,41 @@ npm install sip-lab
|
|
|
40
40
|
|
|
41
41
|
Then run some sample script from subfolder samples:
|
|
42
42
|
```
|
|
43
|
-
node samples/simple.js
|
|
43
|
+
node node_modules/sip-lab/samples/simple.js
|
|
44
44
|
```
|
|
45
45
|
|
|
46
46
|
The above script has detailed comments.
|
|
47
47
|
|
|
48
48
|
Please read it to undestand how to write your own test scripts.
|
|
49
49
|
|
|
50
|
+
|
|
51
|
+
### Samples
|
|
52
|
+
|
|
53
|
+
See general sample scripts in folder samples.
|
|
54
|
+
|
|
55
|
+
There are additional samples scripts in folder samples_extra but they require [ws_speech_server](https://github.com/MayamaTakeshi/ws_speech_server) to be running locally (and it should be started with GOOGLE_APPLICATION_CREDENTIALS set).
|
|
56
|
+
|
|
57
|
+
To run ws_speech_server, do this:
|
|
58
|
+
```
|
|
59
|
+
https://github.com/MayamaTakeshi/ws_speech_server
|
|
60
|
+
cd ws_speech_server
|
|
61
|
+
npm i
|
|
62
|
+
npm run build
|
|
63
|
+
cp config/default.js.sample config/default.js
|
|
64
|
+
export GOOGLE_APPLICATION_CREDENTIALS=/path/to/your/credentials/file
|
|
65
|
+
node src/App.bs.js
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Then you should be able to test with dtmf language:
|
|
69
|
+
```
|
|
70
|
+
node node_modules/sip-lab/samples_extra/ws_speech_server.dtmf.js
|
|
71
|
+
```
|
|
72
|
+
or with google speech service:
|
|
73
|
+
```
|
|
74
|
+
node node_modules/sip-lab/samples_extra/ws_speech_server.google.js
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
|
|
50
78
|
### About the code
|
|
51
79
|
|
|
52
80
|
Although the code in written in *.cpp/*.hpp named files, this is not actually a C++ project.
|
package/binding.gyp
CHANGED
|
@@ -19,10 +19,12 @@
|
|
|
19
19
|
"3rdParty/spandsp/src",
|
|
20
20
|
"3rdParty/pocketsphinx/include",
|
|
21
21
|
"3rdParty/pocketsphinx/build/include",
|
|
22
|
+
"3rdParty/pjwebsock/websock",
|
|
22
23
|
"<!@(node -p \"require('node-addon-api').include\")",
|
|
23
24
|
],
|
|
24
25
|
'conditions': [
|
|
25
26
|
[ 'OS!="win"', {
|
|
27
|
+
'cflags': ['-g'],
|
|
26
28
|
'cflags_cc': [
|
|
27
29
|
'-g',
|
|
28
30
|
'-fexceptions',
|
|
@@ -120,6 +122,12 @@
|
|
|
120
122
|
'src/pjmedia/src/pjmedia/fax_port.c',
|
|
121
123
|
'src/pjmedia/src/pjmedia/flite_port.c',
|
|
122
124
|
'src/pjmedia/src/pjmedia/pocketsphinx_port.c',
|
|
125
|
+
'src/pjmedia/src/pjmedia/ws_speech_port.cpp',
|
|
126
|
+
'3rdParty/pjwebsock/websock/http.c',
|
|
127
|
+
'3rdParty/pjwebsock/websock/websock_transport_tcp.c',
|
|
128
|
+
'3rdParty/pjwebsock/websock/websock_transport_tls.c',
|
|
129
|
+
'3rdParty/pjwebsock/websock/websock.c',
|
|
130
|
+
'3rdParty/pjwebsock/websock/websock_transport.c',
|
|
123
131
|
],
|
|
124
132
|
},
|
|
125
133
|
],
|
package/build_deps.sh
CHANGED
|
@@ -102,6 +102,15 @@ then
|
|
|
102
102
|
fi
|
|
103
103
|
|
|
104
104
|
|
|
105
|
+
cd $START_DIR/3rdParty
|
|
106
|
+
if [[ ! -d pjwebsock ]]
|
|
107
|
+
then
|
|
108
|
+
git clone https://github.com/jimying/pjwebsock
|
|
109
|
+
cd pjwebsock
|
|
110
|
+
git checkout a0616ea27f01d5e3bdfd5b801fb1499473a0b0cb
|
|
111
|
+
fi
|
|
112
|
+
|
|
113
|
+
|
|
105
114
|
#cd $START_DIR/3rdParty
|
|
106
115
|
#if [[ ! -d openssl ]]
|
|
107
116
|
#then
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sip-lab",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.28.1",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"engines": {
|
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
"README.md",
|
|
45
45
|
"DEV.md",
|
|
46
46
|
"samples",
|
|
47
|
+
"samples_extra",
|
|
47
48
|
"prebuilds",
|
|
48
49
|
"pocketsphinx",
|
|
49
50
|
"runtests"
|
|
Binary file
|
|
@@ -115,7 +115,7 @@ async function test() {
|
|
|
115
115
|
sip.call.start_speech_recog(oc.id)
|
|
116
116
|
sip.call.start_speech_recog(ic.id)
|
|
117
117
|
|
|
118
|
-
await z.sleep(
|
|
118
|
+
await z.sleep(200)
|
|
119
119
|
|
|
120
120
|
sip.call.start_play_wav(oc.id, {file: 'samples/artifacts/hello_good_morning.wav', end_of_file_event: true, no_loop: true})
|
|
121
121
|
sip.call.start_play_wav(ic.id, {file: 'samples/artifacts/hello_good_morning.wav', end_of_file_event: true, no_loop: true})
|
|
@@ -130,16 +130,16 @@ async function test() {
|
|
|
130
130
|
call_id: oc.id,
|
|
131
131
|
},
|
|
132
132
|
{
|
|
133
|
-
event: '
|
|
133
|
+
event: 'speech',
|
|
134
134
|
call_id: oc.id,
|
|
135
135
|
//transcript: 'hello good morning', // bad transcript (will not match)
|
|
136
136
|
},
|
|
137
137
|
{
|
|
138
|
-
event: '
|
|
138
|
+
event: 'speech',
|
|
139
139
|
call_id: ic.id,
|
|
140
140
|
//transcript: 'hello good morning', // bad transcript (will not match)
|
|
141
141
|
},
|
|
142
|
-
],
|
|
142
|
+
], 5000)
|
|
143
143
|
|
|
144
144
|
sip.call.stop_record_wav(oc.id)
|
|
145
145
|
sip.call.stop_record_wav(ic.id)
|
|
@@ -117,25 +117,25 @@ async function test() {
|
|
|
117
117
|
|
|
118
118
|
await z.sleep(100)
|
|
119
119
|
|
|
120
|
-
sip.call.start_speech_synth(oc.id, {voice: 'kal16', text: 'Good morning.'
|
|
121
|
-
sip.call.start_speech_synth(ic.id, {voice: 'kal16', text: 'How are you?'
|
|
120
|
+
sip.call.start_speech_synth(oc.id, {voice: 'kal16', text: 'Good morning.'})
|
|
121
|
+
sip.call.start_speech_synth(ic.id, {voice: 'kal16', text: 'How are you?'})
|
|
122
122
|
|
|
123
123
|
await z.wait([
|
|
124
124
|
{
|
|
125
|
-
event: '
|
|
125
|
+
event: 'speech_synth_complete',
|
|
126
126
|
call_id: ic.id,
|
|
127
127
|
},
|
|
128
128
|
{
|
|
129
|
-
event: '
|
|
129
|
+
event: 'speech_synth_complete',
|
|
130
130
|
call_id: oc.id,
|
|
131
131
|
},
|
|
132
132
|
{
|
|
133
|
-
event: '
|
|
133
|
+
event: 'speech',
|
|
134
134
|
call_id: oc.id,
|
|
135
135
|
transcript: 'how are you',
|
|
136
136
|
},
|
|
137
137
|
{
|
|
138
|
-
event: '
|
|
138
|
+
event: 'speech',
|
|
139
139
|
call_id: ic.id,
|
|
140
140
|
transcript: 'good morning',
|
|
141
141
|
},
|
|
@@ -130,26 +130,19 @@ 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.'})
|
|
134
|
+
sip.call.start_speech_synth(ic.id, {voice: 'kal', text: 'How are you?'})
|
|
135
135
|
|
|
136
136
|
await z.wait([
|
|
137
137
|
{
|
|
138
|
-
event: '
|
|
138
|
+
event: 'speech_synth_complete',
|
|
139
139
|
call_id: ic.id,
|
|
140
140
|
},
|
|
141
141
|
{
|
|
142
|
-
event: '
|
|
142
|
+
event: 'speech_synth_complete',
|
|
143
143
|
call_id: oc.id,
|
|
144
144
|
},
|
|
145
|
-
],
|
|
146
|
-
|
|
147
|
-
await z.wait([
|
|
148
|
-
{
|
|
149
|
-
event: 'end_of_speech',
|
|
150
|
-
call_id: oc.id,
|
|
151
|
-
},
|
|
152
|
-
], 2000)
|
|
145
|
+
], 3000)
|
|
153
146
|
|
|
154
147
|
sip.call.stop_speech_synth(oc.id) // this is not actually necessary. It is used just to confirm the command works
|
|
155
148
|
sip.call.stop_speech_synth(ic.id) // this is not actually necessary. It is used just to confirm the command works
|
|
@@ -0,0 +1,194 @@
|
|
|
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
|
+
sip.set_codecs("PCMU/8000/1:128")
|
|
13
|
+
|
|
14
|
+
z.trap_events(sip.event_source, 'event', (evt) => {
|
|
15
|
+
var e = evt.args[0]
|
|
16
|
+
return e
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
console.log(sip.start((data) => { console.log(data)} ))
|
|
20
|
+
|
|
21
|
+
t1 = sip.transport.create({address: "127.0.0.1", type: 'tcp'})
|
|
22
|
+
t2 = sip.transport.create({address: "127.0.0.1", type: 'tcp'})
|
|
23
|
+
|
|
24
|
+
console.log("t1", t1)
|
|
25
|
+
console.log("t2", t2)
|
|
26
|
+
|
|
27
|
+
oc = sip.call.create(t1.id, {
|
|
28
|
+
from_uri: '"abc"<sip:alice@test.com>',
|
|
29
|
+
to_uri: `sip:bob@${t2.address}:${t2.port}`,
|
|
30
|
+
headers: {
|
|
31
|
+
'X-MyHeader1': 'abc',
|
|
32
|
+
'X-MyHeader2': 'def',
|
|
33
|
+
},
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
await z.wait([
|
|
37
|
+
{
|
|
38
|
+
event: "incoming_call",
|
|
39
|
+
call_id: m.collect("call_id"),
|
|
40
|
+
msg: sip_msg({
|
|
41
|
+
$rm: 'INVITE',
|
|
42
|
+
$fU: 'alice',
|
|
43
|
+
$fd: 'test.com',
|
|
44
|
+
$tU: 'bob',
|
|
45
|
+
'$hdr(X-MyHeader1)': 'abc',
|
|
46
|
+
'hdr_x_myheader2': 'def',
|
|
47
|
+
}),
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
event: 'response',
|
|
51
|
+
call_id: oc.id,
|
|
52
|
+
method: 'INVITE',
|
|
53
|
+
msg: sip_msg({
|
|
54
|
+
$rs: '100',
|
|
55
|
+
$rr: 'Trying',
|
|
56
|
+
'$(hdrcnt(via))': 1,
|
|
57
|
+
'hdr_call_id': m.collect('sip_call_id'),
|
|
58
|
+
$fU: 'alice',
|
|
59
|
+
$fd: 'test.com',
|
|
60
|
+
$tU: 'bob',
|
|
61
|
+
'$hdr(l)': '0',
|
|
62
|
+
}),
|
|
63
|
+
},
|
|
64
|
+
], 1000)
|
|
65
|
+
|
|
66
|
+
ic = {
|
|
67
|
+
id: z.store.call_id,
|
|
68
|
+
sip_call_id: z.store.sip_call_id,
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
sip.call.respond(ic.id, {
|
|
72
|
+
code: 200,
|
|
73
|
+
reason:'OK',
|
|
74
|
+
headers: {
|
|
75
|
+
'X-MyHeader3': 'ghi',
|
|
76
|
+
'X-MyHeader4': 'jkl',
|
|
77
|
+
},
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
await z.wait([
|
|
81
|
+
{
|
|
82
|
+
event: 'media_update',
|
|
83
|
+
call_id: oc.id,
|
|
84
|
+
status: 'ok',
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
event: 'media_update',
|
|
88
|
+
call_id: ic.id,
|
|
89
|
+
status: 'ok',
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
event: 'response',
|
|
93
|
+
call_id: oc.id,
|
|
94
|
+
method: 'INVITE',
|
|
95
|
+
msg: sip_msg({
|
|
96
|
+
$rs: '200',
|
|
97
|
+
$rr: 'OK',
|
|
98
|
+
'$(hdrcnt(v))': 1,
|
|
99
|
+
$fU: 'alice',
|
|
100
|
+
$fd: 'test.com',
|
|
101
|
+
$tU: 'bob',
|
|
102
|
+
'$hdr(content-type)': 'application/sdp',
|
|
103
|
+
$rb: '!{_}a=sendrecv',
|
|
104
|
+
'$hdr(X-MyHeader3)': 'ghi',
|
|
105
|
+
'$hdr(X-MyHeader4)': 'jkl',
|
|
106
|
+
}),
|
|
107
|
+
},
|
|
108
|
+
], 1000)
|
|
109
|
+
|
|
110
|
+
sip.call.start_record_wav(oc.id, {file: './oc.wav'})
|
|
111
|
+
sip.call.start_record_wav(ic.id, {file: './ic.wav'})
|
|
112
|
+
|
|
113
|
+
sip.call.start_speech_synth(oc.id, {server_url: 'ws://0.0.0.0:8080', engine: 'dtmf-gen', voice: 'dtmf', language: 'dtmf', text: 'abcd', times: 1})
|
|
114
|
+
sip.call.start_speech_synth(ic.id, {server_url: 'ws://0.0.0.0:8080', engine: 'dtmf-gen', voice: 'dtmf', language: 'dtmf', text: 'dcba', times: 1})
|
|
115
|
+
|
|
116
|
+
sip.call.start_speech_recog(oc.id, {server_url: 'ws://0.0.0.0:8080', engine: 'dtmf-det', language: 'dtmf'})
|
|
117
|
+
sip.call.start_speech_recog(ic.id, {server_url: 'ws://0.0.0.0:8080', engine: 'dtmf-det', language: 'dtmf'})
|
|
118
|
+
|
|
119
|
+
await z.wait([
|
|
120
|
+
{
|
|
121
|
+
event: 'speech_synth_complete',
|
|
122
|
+
call_id: ic.id,
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
event: 'speech_synth_complete',
|
|
126
|
+
call_id: oc.id,
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
event: 'dtmf',
|
|
130
|
+
call_id: oc.id,
|
|
131
|
+
digits: 'dcba',
|
|
132
|
+
mode: 1,
|
|
133
|
+
media_id: 0
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
event: 'dtmf',
|
|
137
|
+
call_id: ic.id,
|
|
138
|
+
digits: 'abcd',
|
|
139
|
+
mode: 1,
|
|
140
|
+
media_id: 0
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
event: 'speech',
|
|
144
|
+
call_id: oc.id,
|
|
145
|
+
transcript: 'dcba'
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
event: 'speech',
|
|
149
|
+
call_id: ic.id,
|
|
150
|
+
transcript: 'abcd'
|
|
151
|
+
},
|
|
152
|
+
], 3000)
|
|
153
|
+
|
|
154
|
+
await z.sleep(1000)
|
|
155
|
+
|
|
156
|
+
sip.call.stop_record_wav(oc.id)
|
|
157
|
+
sip.call.stop_record_wav(ic.id)
|
|
158
|
+
|
|
159
|
+
sip.call.terminate(oc.id)
|
|
160
|
+
|
|
161
|
+
await z.wait([
|
|
162
|
+
{
|
|
163
|
+
event: 'call_ended',
|
|
164
|
+
call_id: oc.id,
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
event: 'call_ended',
|
|
168
|
+
call_id: ic.id,
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
event: 'response',
|
|
172
|
+
call_id: oc.id,
|
|
173
|
+
method: 'BYE',
|
|
174
|
+
msg: sip_msg({
|
|
175
|
+
$rs: '200',
|
|
176
|
+
$rr: 'OK',
|
|
177
|
+
}),
|
|
178
|
+
},
|
|
179
|
+
], 1000)
|
|
180
|
+
|
|
181
|
+
await z.sleep(100)
|
|
182
|
+
|
|
183
|
+
console.log("Success")
|
|
184
|
+
|
|
185
|
+
sip.stop()
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
test()
|
|
190
|
+
.catch(e => {
|
|
191
|
+
console.error(e)
|
|
192
|
+
process.exit(1)
|
|
193
|
+
})
|
|
194
|
+
|
|
@@ -0,0 +1,190 @@
|
|
|
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
|
+
sip.set_codecs("PCMU/8000/1:128")
|
|
13
|
+
|
|
14
|
+
z.trap_events(sip.event_source, 'event', (evt) => {
|
|
15
|
+
var e = evt.args[0]
|
|
16
|
+
return e
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
console.log(sip.start((data) => { console.log(data)} ))
|
|
20
|
+
|
|
21
|
+
t1 = sip.transport.create({address: "127.0.0.1", type: 'tcp'})
|
|
22
|
+
t2 = sip.transport.create({address: "127.0.0.1", type: 'tcp'})
|
|
23
|
+
|
|
24
|
+
console.log("t1", t1)
|
|
25
|
+
console.log("t2", t2)
|
|
26
|
+
|
|
27
|
+
oc = sip.call.create(t1.id, {
|
|
28
|
+
from_uri: '"abc"<sip:alice@test.com>',
|
|
29
|
+
to_uri: `sip:bob@${t2.address}:${t2.port}`,
|
|
30
|
+
headers: {
|
|
31
|
+
'X-MyHeader1': 'abc',
|
|
32
|
+
'X-MyHeader2': 'def',
|
|
33
|
+
},
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
await z.wait([
|
|
37
|
+
{
|
|
38
|
+
event: "incoming_call",
|
|
39
|
+
call_id: m.collect("call_id"),
|
|
40
|
+
msg: sip_msg({
|
|
41
|
+
$rm: 'INVITE',
|
|
42
|
+
$fU: 'alice',
|
|
43
|
+
$fd: 'test.com',
|
|
44
|
+
$tU: 'bob',
|
|
45
|
+
'$hdr(X-MyHeader1)': 'abc',
|
|
46
|
+
'hdr_x_myheader2': 'def',
|
|
47
|
+
}),
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
event: 'response',
|
|
51
|
+
call_id: oc.id,
|
|
52
|
+
method: 'INVITE',
|
|
53
|
+
msg: sip_msg({
|
|
54
|
+
$rs: '100',
|
|
55
|
+
$rr: 'Trying',
|
|
56
|
+
'$(hdrcnt(via))': 1,
|
|
57
|
+
'hdr_call_id': m.collect('sip_call_id'),
|
|
58
|
+
$fU: 'alice',
|
|
59
|
+
$fd: 'test.com',
|
|
60
|
+
$tU: 'bob',
|
|
61
|
+
'$hdr(l)': '0',
|
|
62
|
+
}),
|
|
63
|
+
},
|
|
64
|
+
], 1000)
|
|
65
|
+
|
|
66
|
+
ic = {
|
|
67
|
+
id: z.store.call_id,
|
|
68
|
+
sip_call_id: z.store.sip_call_id,
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
sip.call.respond(ic.id, {
|
|
72
|
+
code: 200,
|
|
73
|
+
reason:'OK',
|
|
74
|
+
headers: {
|
|
75
|
+
'X-MyHeader3': 'ghi',
|
|
76
|
+
'X-MyHeader4': 'jkl',
|
|
77
|
+
},
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
await z.wait([
|
|
81
|
+
{
|
|
82
|
+
event: 'media_update',
|
|
83
|
+
call_id: oc.id,
|
|
84
|
+
status: 'ok',
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
event: 'media_update',
|
|
88
|
+
call_id: ic.id,
|
|
89
|
+
status: 'ok',
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
event: 'response',
|
|
93
|
+
call_id: oc.id,
|
|
94
|
+
method: 'INVITE',
|
|
95
|
+
msg: sip_msg({
|
|
96
|
+
$rs: '200',
|
|
97
|
+
$rr: 'OK',
|
|
98
|
+
'$(hdrcnt(v))': 1,
|
|
99
|
+
$fU: 'alice',
|
|
100
|
+
$fd: 'test.com',
|
|
101
|
+
$tU: 'bob',
|
|
102
|
+
'$hdr(content-type)': 'application/sdp',
|
|
103
|
+
$rb: '!{_}a=sendrecv',
|
|
104
|
+
'$hdr(X-MyHeader3)': 'ghi',
|
|
105
|
+
'$hdr(X-MyHeader4)': 'jkl',
|
|
106
|
+
}),
|
|
107
|
+
},
|
|
108
|
+
], 1000)
|
|
109
|
+
|
|
110
|
+
await z.sleep(200)
|
|
111
|
+
|
|
112
|
+
sip.call.start_record_wav(oc.id, {file: './oc.wav'})
|
|
113
|
+
sip.call.start_record_wav(ic.id, {file: './ic.wav'})
|
|
114
|
+
|
|
115
|
+
sip.call.start_speech_synth(oc.id, {server_url: 'ws://0.0.0.0:8080', engine: 'gss', voice: 'en-US-Standard-E', language: 'en-US', text: 'hello world', times: 1})
|
|
116
|
+
sip.call.start_speech_synth(ic.id, {server_url: 'ws://0.0.0.0:8080', engine: 'gss', voice: 'en-US-Standard-F', language: 'en-US', text: '<speak>Good morning<break time="2s"/>Good Afternoon</speak>', times: 1})
|
|
117
|
+
|
|
118
|
+
sip.call.start_speech_recog(oc.id, {server_url: 'ws://0.0.0.0:8080', engine: 'gsr', language: 'en-US'})
|
|
119
|
+
sip.call.start_speech_recog(ic.id, {server_url: 'ws://0.0.0.0:8080', engine: 'gsr', language: 'en-US'})
|
|
120
|
+
|
|
121
|
+
await z.wait([
|
|
122
|
+
{
|
|
123
|
+
event: 'speech_synth_complete',
|
|
124
|
+
call_id: ic.id,
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
event: 'speech_synth_complete',
|
|
128
|
+
call_id: oc.id,
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
event: 'speech',
|
|
132
|
+
call_id: oc.id,
|
|
133
|
+
transcript: 'good morning',
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
event: 'speech',
|
|
137
|
+
call_id: ic.id,
|
|
138
|
+
transcript: 'hello world',
|
|
139
|
+
},
|
|
140
|
+
], 4000)
|
|
141
|
+
|
|
142
|
+
await z.wait([
|
|
143
|
+
{
|
|
144
|
+
event: 'speech',
|
|
145
|
+
call_id: oc.id,
|
|
146
|
+
transcript: ' good afternoon',
|
|
147
|
+
},
|
|
148
|
+
], 4000)
|
|
149
|
+
|
|
150
|
+
await z.sleep(1000)
|
|
151
|
+
|
|
152
|
+
sip.call.stop_record_wav(oc.id)
|
|
153
|
+
sip.call.stop_record_wav(ic.id)
|
|
154
|
+
|
|
155
|
+
sip.call.terminate(oc.id)
|
|
156
|
+
|
|
157
|
+
await z.wait([
|
|
158
|
+
{
|
|
159
|
+
event: 'call_ended',
|
|
160
|
+
call_id: oc.id,
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
event: 'call_ended',
|
|
164
|
+
call_id: ic.id,
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
event: 'response',
|
|
168
|
+
call_id: oc.id,
|
|
169
|
+
method: 'BYE',
|
|
170
|
+
msg: sip_msg({
|
|
171
|
+
$rs: '200',
|
|
172
|
+
$rr: 'OK',
|
|
173
|
+
}),
|
|
174
|
+
},
|
|
175
|
+
], 1000)
|
|
176
|
+
|
|
177
|
+
await z.sleep(100)
|
|
178
|
+
|
|
179
|
+
console.log("Success")
|
|
180
|
+
|
|
181
|
+
sip.stop()
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
test()
|
|
186
|
+
.catch(e => {
|
|
187
|
+
console.error(e)
|
|
188
|
+
process.exit(1)
|
|
189
|
+
})
|
|
190
|
+
|
package/src/event_templates.cpp
CHANGED
|
@@ -105,16 +105,16 @@ int make_evt_end_of_file(char *dest, int size, long call_id) {
|
|
|
105
105
|
"{\"event\": \"end_of_file\", \"call_id\": %ld}", call_id);
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
-
int
|
|
108
|
+
int make_evt_speech_synth_complete(char *dest, int size, long call_id) {
|
|
109
109
|
return snprintf(
|
|
110
110
|
dest, size,
|
|
111
|
-
"{\"event\": \"
|
|
111
|
+
"{\"event\": \"speech_synth_complete\", \"call_id\": %ld}", call_id);
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
-
int
|
|
114
|
+
int make_evt_speech(char *dest, int size, long call_id, char* transcript) {
|
|
115
115
|
return snprintf(
|
|
116
116
|
dest, size,
|
|
117
|
-
"{\"event\": \"
|
|
117
|
+
"{\"event\": \"speech\", \"call_id\": %ld, \"transcript\": \"%s\"}", call_id, transcript);
|
|
118
118
|
}
|
|
119
119
|
|
|
120
120
|
int make_evt_tcp_msg(char *dest, int size, long call_id, const char *protocol, char *data, int data_len) {
|
|
@@ -122,3 +122,10 @@ int make_evt_tcp_msg(char *dest, int size, long call_id, const char *protocol, c
|
|
|
122
122
|
dest, size,
|
|
123
123
|
"{\"event\": \"%s_msg\", \"call_id\": %ld}\n%.*s", protocol, call_id, data_len, data);
|
|
124
124
|
}
|
|
125
|
+
|
|
126
|
+
int make_evt_ws_speech_event(char *dest, int size, long call_id, char *data, int data_len) {
|
|
127
|
+
return snprintf(
|
|
128
|
+
dest, size,
|
|
129
|
+
"{\"event\": \"ws_speech_event\", \"call_id\": %ld, \"data\": %.*s}", call_id, data_len, data);
|
|
130
|
+
}
|
|
131
|
+
|
package/src/event_templates.hpp
CHANGED
|
@@ -36,10 +36,12 @@ int make_evt_fax_result(char *dest, int size, long call_id, int result);
|
|
|
36
36
|
|
|
37
37
|
int make_evt_end_of_file(char *dest, int size, long call_id);
|
|
38
38
|
|
|
39
|
-
int
|
|
39
|
+
int make_evt_speech_synth_complete(char *dest, int size, long call_id);
|
|
40
40
|
|
|
41
|
-
int
|
|
41
|
+
int make_evt_speech(char *dest, int size, long call_id, char* transcript);
|
|
42
42
|
|
|
43
43
|
int make_evt_tcp_msg(char *dest, int size, long call_id, const char *protocol, char *data, int data_len);
|
|
44
44
|
|
|
45
|
+
int make_evt_ws_speech_event(char *dest, int size, long call_id, char *data, int data_len);
|
|
46
|
+
|
|
45
47
|
#endif
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
PJ_BEGIN_DECL
|
|
7
7
|
|
|
8
|
-
enum
|
|
8
|
+
enum pjmedia_flite_option
|
|
9
9
|
{
|
|
10
10
|
PJMEDIA_SPEECH_NO_LOOP = 1
|
|
11
11
|
};
|
|
@@ -25,7 +25,7 @@ PJ_DEF(pj_status_t) pjmedia_flite_port_set_eof_cb(pjmedia_port *port,
|
|
|
25
25
|
|
|
26
26
|
PJ_DEF(pj_status_t) pjmedia_flite_port_speak( pjmedia_port *port,
|
|
27
27
|
const char *text,
|
|
28
|
-
|
|
28
|
+
int times);
|
|
29
29
|
|
|
30
30
|
PJ_END_DECL
|
|
31
31
|
|