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/src/event_templates.hpp
CHANGED
|
@@ -34,6 +34,10 @@ int make_evt_registration_status(char *dest, int size, long account_id,
|
|
|
34
34
|
|
|
35
35
|
int make_evt_fax_result(char *dest, int size, long call_id, int result);
|
|
36
36
|
|
|
37
|
+
int make_evt_end_of_file(char *dest, int size, long call_id);
|
|
38
|
+
|
|
39
|
+
int make_evt_end_of_speech(char *dest, int size, long call_id);
|
|
40
|
+
|
|
37
41
|
int make_evt_tcp_msg(char *dest, int size, long call_id, const char *protocol, char *data, int data_len);
|
|
38
42
|
|
|
39
43
|
#endif
|
|
@@ -5,18 +5,24 @@
|
|
|
5
5
|
|
|
6
6
|
PJ_BEGIN_DECL
|
|
7
7
|
|
|
8
|
+
enum pjmedia_filte_option
|
|
9
|
+
{
|
|
10
|
+
PJMEDIA_SPEECH_NO_LOOP = 1
|
|
11
|
+
};
|
|
12
|
+
|
|
8
13
|
PJ_DEF(pj_status_t) pjmedia_flite_port_create( pj_pool_t *pool,
|
|
9
14
|
unsigned clock_rate,
|
|
10
15
|
unsigned channel_count,
|
|
11
16
|
unsigned samples_per_frame,
|
|
12
17
|
unsigned bits_per_sample,
|
|
13
|
-
void (*cb)(pjmedia_port*,
|
|
14
|
-
void *user_data,
|
|
15
|
-
int result),
|
|
16
|
-
void *user_data,
|
|
17
18
|
const char *voice,
|
|
18
19
|
pjmedia_port **p_port);
|
|
19
20
|
|
|
21
|
+
PJ_DEF(pj_status_t) pjmedia_flite_port_set_eof_cb(pjmedia_port *port,
|
|
22
|
+
void *user_data,
|
|
23
|
+
void (*cb)(pjmedia_port *port,
|
|
24
|
+
void *usr_data));
|
|
25
|
+
|
|
20
26
|
PJ_DEF(pj_status_t) pjmedia_flite_port_speak( pjmedia_port *port,
|
|
21
27
|
const char *text,
|
|
22
28
|
unsigned options);
|
|
@@ -53,26 +53,62 @@ static struct {
|
|
|
53
53
|
|
|
54
54
|
struct flite_t {
|
|
55
55
|
struct pjmedia_port base;
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
unsigned options;
|
|
57
|
+
|
|
58
58
|
cst_voice *v;
|
|
59
|
-
|
|
59
|
+
unsigned written_samples;
|
|
60
60
|
cst_wave *w;
|
|
61
|
-
|
|
61
|
+
|
|
62
|
+
pj_bool_t subscribed;
|
|
63
|
+
void (*cb)(pjmedia_port*, void*);
|
|
62
64
|
};
|
|
63
65
|
|
|
64
66
|
#define free_wave(w) if (w) {delete_wave(w) ; w = NULL; }
|
|
65
67
|
#define FLITE_BLOCK_SIZE 1024 * 32
|
|
66
68
|
|
|
69
|
+
/*
|
|
70
|
+
* Register a callback to be called when we reach the end of speech
|
|
71
|
+
*/
|
|
72
|
+
PJ_DEF(pj_status_t) pjmedia_flite_port_set_eof_cb(pjmedia_port *port,
|
|
73
|
+
void *user_data,
|
|
74
|
+
void (*cb)(pjmedia_port *port,
|
|
75
|
+
void *usr_data))
|
|
76
|
+
{
|
|
77
|
+
struct flite_t *flite;
|
|
78
|
+
|
|
79
|
+
/* Sanity check */
|
|
80
|
+
PJ_ASSERT_RETURN(port, -PJ_EINVAL);
|
|
81
|
+
|
|
82
|
+
/* Check that this is really a flite port */
|
|
83
|
+
PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, -PJ_EINVALIDOP);
|
|
84
|
+
|
|
85
|
+
flite = (struct flite_t*) port;
|
|
86
|
+
|
|
87
|
+
flite->base.port_data.pdata = user_data;
|
|
88
|
+
flite->cb = cb;
|
|
89
|
+
|
|
90
|
+
return PJ_SUCCESS;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
static pj_status_t speech_on_event(pjmedia_event *event,
|
|
95
|
+
void *user_data)
|
|
96
|
+
{
|
|
97
|
+
struct flite_t *flite = (struct flite_t*)user_data;
|
|
98
|
+
|
|
99
|
+
if (event->type == PJMEDIA_EVENT_CALLBACK) {
|
|
100
|
+
if (flite->cb)
|
|
101
|
+
(*flite->cb)(&flite->base, flite->base.port_data.pdata);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return PJ_SUCCESS;
|
|
105
|
+
}
|
|
106
|
+
|
|
67
107
|
PJ_DEF(pj_status_t) pjmedia_flite_port_create( pj_pool_t *pool,
|
|
68
108
|
unsigned clock_rate,
|
|
69
109
|
unsigned channel_count,
|
|
70
110
|
unsigned samples_per_frame,
|
|
71
111
|
unsigned bits_per_sample,
|
|
72
|
-
void (*cb)(pjmedia_port*,
|
|
73
|
-
void *user_data,
|
|
74
|
-
int result),
|
|
75
|
-
void *user_data,
|
|
76
112
|
const char *voice,
|
|
77
113
|
pjmedia_port **p_port)
|
|
78
114
|
{
|
|
@@ -122,9 +158,6 @@ PJ_DEF(pj_status_t) pjmedia_flite_port_create( pj_pool_t *pool,
|
|
|
122
158
|
return 0;
|
|
123
159
|
}
|
|
124
160
|
|
|
125
|
-
flite->flite_cb = cb;
|
|
126
|
-
flite->flite_cb_user_data = user_data;
|
|
127
|
-
|
|
128
161
|
TRACE_((THIS_FILE, "flite_device created: %u/%u/%u/%u", clock_rate,
|
|
129
162
|
channel_count, samples_per_frame, bits_per_sample));
|
|
130
163
|
|
|
@@ -140,9 +173,12 @@ PJ_DEF(pj_status_t) pjmedia_flite_port_speak( pjmedia_port *port,
|
|
|
140
173
|
free_wave(flite->w);
|
|
141
174
|
}
|
|
142
175
|
|
|
176
|
+
flite->options = options;
|
|
177
|
+
|
|
143
178
|
flite->w = flite_text_to_wave(text, flite->v);
|
|
144
|
-
if (flite->w->sample_rate != PJMEDIA_PIA_SRATE(&port->info)) {
|
|
145
|
-
|
|
179
|
+
if ((unsigned)flite->w->sample_rate != PJMEDIA_PIA_SRATE(&port->info)) {
|
|
180
|
+
printf("resampling from %i to %i\n", flite->w->sample_rate, PJMEDIA_PIA_SRATE(&port->info));
|
|
181
|
+
cst_wave_resample(flite->w, PJMEDIA_PIA_SRATE(&port->info));
|
|
146
182
|
}
|
|
147
183
|
flite->written_samples = 0;
|
|
148
184
|
|
|
@@ -164,11 +200,36 @@ static pj_status_t flite_get_frame(pjmedia_port *port,
|
|
|
164
200
|
}
|
|
165
201
|
|
|
166
202
|
printf("written_samples=%i num_samples=%i\n", flite->written_samples, flite->w->num_samples);
|
|
167
|
-
if (flite->written_samples + PJMEDIA_PIA_SPF(&port->info) > flite->w->num_samples) {
|
|
168
|
-
printf("flite
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
203
|
+
if (flite->written_samples + PJMEDIA_PIA_SPF(&port->info) > (unsigned)flite->w->num_samples) {
|
|
204
|
+
printf("flite end of speech\n");
|
|
205
|
+
|
|
206
|
+
if(flite->cb) {
|
|
207
|
+
if (!flite->subscribed) {
|
|
208
|
+
pj_status_t status = pjmedia_event_subscribe(NULL, &speech_on_event,
|
|
209
|
+
flite, flite);
|
|
210
|
+
flite->subscribed = (status == PJ_SUCCESS)? PJ_TRUE:
|
|
211
|
+
PJ_FALSE;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (flite->subscribed) {
|
|
215
|
+
pjmedia_event event;
|
|
216
|
+
|
|
217
|
+
pjmedia_event_init(&event, PJMEDIA_EVENT_CALLBACK,
|
|
218
|
+
NULL, flite);
|
|
219
|
+
pjmedia_event_publish(NULL, flite, &event,
|
|
220
|
+
PJMEDIA_EVENT_PUBLISH_POST_EVENT);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
pj_bool_t no_loop = (flite->options & PJMEDIA_SPEECH_NO_LOOP);
|
|
225
|
+
|
|
226
|
+
if(no_loop) {
|
|
227
|
+
free_wave(flite->w);
|
|
228
|
+
frame->type = PJMEDIA_FRAME_TYPE_NONE;
|
|
229
|
+
return PJ_SUCCESS;
|
|
230
|
+
} else {
|
|
231
|
+
flite->written_samples = 0;
|
|
232
|
+
}
|
|
172
233
|
}
|
|
173
234
|
|
|
174
235
|
memcpy(frame->buf, flite->w->samples + flite->written_samples, PJMEDIA_PIA_SPF(&port->info)*2);
|
|
@@ -187,8 +248,16 @@ static pj_status_t flite_on_destroy(pjmedia_port *port)
|
|
|
187
248
|
printf("flite_on_destroy\n");
|
|
188
249
|
|
|
189
250
|
struct flite_t *flite = (struct flite_t*)port;
|
|
251
|
+
|
|
252
|
+
pj_assert(port->info.signature == SIGNATURE);
|
|
253
|
+
|
|
190
254
|
free_wave(flite->w);
|
|
191
255
|
|
|
256
|
+
if (flite->subscribed) {
|
|
257
|
+
pjmedia_event_unsubscribe(NULL, &speech_on_event, flite, flite);
|
|
258
|
+
flite->subscribed = PJ_FALSE;
|
|
259
|
+
}
|
|
260
|
+
|
|
192
261
|
return PJ_SUCCESS;
|
|
193
262
|
}
|
|
194
263
|
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/* $Id: pocketsphinx_port.c 0000 2024-03-09 mayamatakeshi $ */
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
|
|
4
|
+
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
|
|
5
|
+
*
|
|
6
|
+
* This program is free software; you can redistribute it and/or modify
|
|
7
|
+
* it under the terms of the GNU General Public License as published by
|
|
8
|
+
* the Free Software Foundation; either version 2 of the License, or
|
|
9
|
+
* (at your option) any later version.
|
|
10
|
+
*
|
|
11
|
+
* This program is distributed in the hope that it will be useful,
|
|
12
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14
|
+
* GNU General Public License for more details.
|
|
15
|
+
*
|
|
16
|
+
* You should have received a copy of the GNU General Public License
|
|
17
|
+
* along with this program; if not, write to the Free Software
|
|
18
|
+
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
#include <pjmedia/pocketsphinx.h>
|
|
22
|
+
#include <pjmedia/errno.h>
|
|
23
|
+
#include <pjmedia/port.h>
|
|
24
|
+
#include <pj/assert.h>
|
|
25
|
+
#include <pj/pool.h>
|
|
26
|
+
#include <pj/string.h>
|
|
27
|
+
|
|
28
|
+
#include <pocketsphinx.h>
|
|
29
|
+
|
|
30
|
+
#define SIGNATURE PJMEDIA_SIGNATURE('p', 'i', 'n', 'x')
|
|
31
|
+
#define THIS_FILE "pocketsphinx_port.c"
|
|
32
|
+
|
|
33
|
+
#if 0
|
|
34
|
+
# define TRACE_(expr) PJ_LOG(4,expr)
|
|
35
|
+
#else
|
|
36
|
+
# define TRACE_(expr)
|
|
37
|
+
#endif
|
|
38
|
+
|
|
39
|
+
static pj_status_t pocketsphinx_put_frame(pjmedia_port *this_port,
|
|
40
|
+
pjmedia_frame *frame);
|
|
41
|
+
static pj_status_t pocketsphinx_on_destroy(pjmedia_port *this_port);
|
|
42
|
+
|
|
43
|
+
struct pocketsphinx_t
|
|
44
|
+
{
|
|
45
|
+
struct pjmedia_port base;
|
|
46
|
+
|
|
47
|
+
pj_bool_t subscribed;
|
|
48
|
+
void (*cb)(pjmedia_port*, void*, char*);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/*
|
|
52
|
+
* Register a callback to be called when we get translation
|
|
53
|
+
*/
|
|
54
|
+
PJ_DEF(pj_status_t) pjmedia_pocketsphinx_port_set_speech_cb(pjmedia_port *port,
|
|
55
|
+
void *user_data,
|
|
56
|
+
void (*cb)(pjmedia_port *port,
|
|
57
|
+
void *usr_data, char *transcript))
|
|
58
|
+
{
|
|
59
|
+
struct pocketsphinx_t *flite;
|
|
60
|
+
|
|
61
|
+
/* Sanity check */
|
|
62
|
+
PJ_ASSERT_RETURN(port, -PJ_EINVAL);
|
|
63
|
+
|
|
64
|
+
/* Check that this is really a pocketsphinx port */
|
|
65
|
+
PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, -PJ_EINVALIDOP);
|
|
66
|
+
|
|
67
|
+
pocketsphinx = (struct pocketsphinx_t*) port;
|
|
68
|
+
|
|
69
|
+
pocketsphinx->base.port_data.pdata = user_data;
|
|
70
|
+
pocketsphinx->cb = cb;
|
|
71
|
+
|
|
72
|
+
return PJ_SUCCESS;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
static pj_status_t speech_on_event(pjmedia_event *event,
|
|
77
|
+
void *user_data)
|
|
78
|
+
{
|
|
79
|
+
struct pocketsphinx_t *pocketsphinx = (struct pocketsphinx_t*)user_data;
|
|
80
|
+
|
|
81
|
+
if (event->type == PJMEDIA_EVENT_CALLBACK) {
|
|
82
|
+
if (pocketsphinx->cb)
|
|
83
|
+
(*pocketsphinx->cb)(&flite->base, flite->base.port_data.pdata, "transcript");
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return PJ_SUCCESS;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
PJ_DEF(pj_status_t) pjmedia_pocketsphinx_port_create( pj_pool_t *pool,
|
|
90
|
+
unsigned clock_rate,
|
|
91
|
+
unsigned channel_count,
|
|
92
|
+
unsigned samples_per_frame,
|
|
93
|
+
unsigned bits_per_sample,
|
|
94
|
+
pjmedia_port **p_port)
|
|
95
|
+
{
|
|
96
|
+
struct pocketsphinx *pocketsphinx;
|
|
97
|
+
const pj_str_t name = pj_str("pocketsphinx");
|
|
98
|
+
|
|
99
|
+
PJ_ASSERT_RETURN(pool && clock_rate && channel_count &&
|
|
100
|
+
samples_per_frame && bits_per_sample == 16 &&
|
|
101
|
+
p_port != NULL, PJ_EINVAL);
|
|
102
|
+
|
|
103
|
+
PJ_ASSERT_RETURN(pool && p_port, PJ_EINVAL);
|
|
104
|
+
|
|
105
|
+
pocketsphinx = PJ_POOL_ZALLOC_T(pool, struct pocketsphinx);
|
|
106
|
+
PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
|
|
107
|
+
|
|
108
|
+
pjmedia_port_info_init(&pocketsphinx->base.info, &name, SIGNATURE, clock_rate,
|
|
109
|
+
channel_count, bits_per_sample, samples_per_frame);
|
|
110
|
+
|
|
111
|
+
pocketsphinx->base.put_frame = &pocketsphinx_put_frame;
|
|
112
|
+
pocketsphinx->base.on_destroy = &pocketsphinx_on_destroy;
|
|
113
|
+
|
|
114
|
+
pocketsphinx->dtmf_cb = cb;
|
|
115
|
+
pocketsphinx->dtmf_cb_user_data = user_data;
|
|
116
|
+
|
|
117
|
+
dtmf_rx_init(&pocketsphinx->state, NULL, NULL);
|
|
118
|
+
dtmf_rx_set_realtime_callback(&pocketsphinx->state,
|
|
119
|
+
&pocketsphinx_digit_callback,
|
|
120
|
+
(void*)pocketsphinx);
|
|
121
|
+
|
|
122
|
+
TRACE_((THIS_FILE, "pocketsphinx created: %u/%u/%u/%u", clock_rate,
|
|
123
|
+
channel_count, samples_per_frame, bits_per_sample));
|
|
124
|
+
|
|
125
|
+
*p_port = &pocketsphinx->base;
|
|
126
|
+
return PJ_SUCCESS;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
static pj_status_t pocketsphinx_put_frame(pjmedia_port *this_port,
|
|
130
|
+
pjmedia_frame *frame)
|
|
131
|
+
{
|
|
132
|
+
if(frame->type != PJMEDIA_FRAME_TYPE_AUDIO) return PJ_SUCCESS;
|
|
133
|
+
|
|
134
|
+
struct pocketsphinx *dport = (struct pocketsphinx*) this_port;
|
|
135
|
+
dtmf_rx(&dport->state, (const pj_int16_t*)frame->buf,
|
|
136
|
+
PJMEDIA_PIA_SPF(&dport->base.info));
|
|
137
|
+
|
|
138
|
+
return PJ_SUCCESS;
|
|
139
|
+
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/*
|
|
143
|
+
* Destroy port.
|
|
144
|
+
*/
|
|
145
|
+
static pj_status_t pocketsphinx_on_destroy(pjmedia_port *this_port)
|
|
146
|
+
{
|
|
147
|
+
return PJ_SUCCESS;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
|