sip-lab 1.8.0 → 1.11.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/samples/simple.js CHANGED
@@ -86,175 +86,6 @@ async function test() {
86
86
  },
87
87
  ], 1000)
88
88
 
89
- sip.call.send_dtmf(oc.id, '1234', 0)
90
- sip.call.send_dtmf(ic.id, '4321', 1)
91
-
92
- await z.wait([
93
- {
94
- event: 'dtmf',
95
- call_id: ic.id,
96
- digits: '1234',
97
- mode: 0,
98
- },
99
- {
100
- event: 'dtmf',
101
- call_id: oc.id,
102
- digits: '4321',
103
- mode: 1,
104
- },
105
- ], 2000)
106
-
107
-
108
- sip.call.reinvite(oc.id, true, 0)
109
-
110
- await z.wait([
111
- {
112
- event: 'response',
113
- call_id: oc.id,
114
- method: 'INVITE',
115
- msg: sip_msg({
116
- $rs: '200',
117
- $rr: 'OK',
118
- $rb: '!{_}a=recvonly',
119
- }),
120
- },
121
- {
122
- event: 'media_status',
123
- call_id: oc.id,
124
- status: 'setup_ok',
125
- local_mode: 'sendonly',
126
- remote_mode: 'recvonly',
127
- },
128
- {
129
- event: 'media_status',
130
- call_id: ic.id,
131
- status: 'setup_ok',
132
- local_mode: 'recvonly',
133
- remote_mode: 'sendonly',
134
- },
135
- ], 500)
136
-
137
- sip.call.send_dtmf(oc.id, '1234', 0)
138
- sip.call.send_dtmf(ic.id, '4321', 1) // this will not generate event 'dtmf' as the call is on hold
139
-
140
- await z.wait([
141
- {
142
- event: 'dtmf',
143
- call_id: ic.id,
144
- digits: '1234',
145
- mode: 0,
146
- },
147
- ], 2000)
148
-
149
- sip.call.reinvite(ic.id, false, 0)
150
-
151
- await z.wait([
152
- {
153
- event: 'response',
154
- call_id: ic.id,
155
- method: 'INVITE',
156
- msg: sip_msg({
157
- $rs: '200',
158
- $rr: 'OK',
159
- $rb: '!{_}a=sendonly',
160
- }),
161
- },
162
- {
163
- event: 'media_status',
164
- call_id: oc.id,
165
- status: 'setup_ok',
166
- local_mode: 'sendonly',
167
- remote_mode: 'recvonly',
168
- },
169
- {
170
- event: 'media_status',
171
- call_id: ic.id,
172
- status: 'setup_ok',
173
- local_mode: 'recvonly',
174
- remote_mode: 'sendonly',
175
- },
176
- ], 500)
177
-
178
- sip.call.send_dtmf(oc.id, '1234', 0)
179
- sip.call.send_dtmf(ic.id, '4321', 1) // this will not generate event 'dtmf' as the call is on hold
180
-
181
- await z.wait([
182
- {
183
- event: 'dtmf',
184
- call_id: ic.id,
185
- digits: '1234',
186
- mode: 0,
187
- },
188
- ], 2000)
189
-
190
- sip.call.send_request(oc.id, 'INFO')
191
-
192
- await z.wait([
193
- {
194
- event: 'request',
195
- call_id: ic.id,
196
- msg: sip_msg({
197
- $rm: 'INFO',
198
- }),
199
- },
200
- {
201
- event: 'response',
202
- call_id: oc.id,
203
- method: 'INFO',
204
- msg: sip_msg({
205
- $rs: '200',
206
- $rr: 'OK',
207
- }),
208
- },
209
- ], 500)
210
-
211
- sip.call.reinvite(oc.id, false, 0)
212
-
213
- await z.wait([
214
- {
215
- event: 'response',
216
- call_id: oc.id,
217
- method: 'INVITE',
218
- msg: sip_msg({
219
- $rs: '200',
220
- $rr: 'OK',
221
- $rb: '!{_}a=sendrecv',
222
- }),
223
- },
224
- {
225
- event: 'media_status',
226
- call_id: oc.id,
227
- status: 'setup_ok',
228
- local_mode: 'sendrecv',
229
- remote_mode: 'sendrecv',
230
- },
231
- {
232
- event: 'media_status',
233
- call_id: ic.id,
234
- status: 'setup_ok',
235
- local_mode: 'sendrecv',
236
- remote_mode: 'sendrecv',
237
- },
238
- ], 500)
239
-
240
- sip.call.send_dtmf(oc.id, '1234', 0)
241
- sip.call.send_dtmf(ic.id, '4321', 1)
242
-
243
- await z.wait([
244
- {
245
- event: 'dtmf',
246
- call_id: ic.id,
247
- digits: '1234',
248
- mode: 0,
249
- },
250
- {
251
- event: 'dtmf',
252
- call_id: oc.id,
253
- digits: '4321',
254
- mode: 1,
255
- },
256
- ], 2000)
257
-
258
89
  sip.call.terminate(oc.id)
259
90
 
260
91
  await z.wait([
@@ -277,8 +108,6 @@ async function test() {
277
108
  },
278
109
  ], 1000)
279
110
 
280
- await z.sleep(1000)
281
-
282
111
  console.log("Success")
283
112
 
284
113
  sip.stop()
@@ -108,8 +108,6 @@ async function test() {
108
108
  },
109
109
  ], 1000)
110
110
 
111
- await z.sleep(1000)
112
-
113
111
  console.log("Success")
114
112
 
115
113
  sip.stop()
package/src/addon.cpp CHANGED
@@ -669,6 +669,47 @@ Napi::Value call_start_play_wav(const Napi::CallbackInfo& info) {
669
669
  return env.Null();
670
670
  }
671
671
 
672
+ Napi::Value call_start_fax(const Napi::CallbackInfo& info) {
673
+ Napi::Env env = info.Env();
674
+
675
+ if (info.Length() != 3) {
676
+ Napi::Error::New(env, "Wrong number of arguments. Expected: call_id, is_sender, file]").ThrowAsJavaScriptException();
677
+ return env.Null();
678
+ }
679
+
680
+ if (!info[0].IsNumber()) {
681
+ Napi::TypeError::New(env, "call_id must be number.").ThrowAsJavaScriptException();
682
+ return env.Null();
683
+ }
684
+ int call_id = info[0].As<Napi::Number>().Int32Value();
685
+
686
+ if (!info[1].IsBoolean()) {
687
+ Napi::TypeError::New(env, "is_sender must be boolean.").ThrowAsJavaScriptException();
688
+ return env.Null();
689
+ }
690
+ bool is_sender = info[1].As<Napi::Boolean>().Value();
691
+
692
+ if (!info[2].IsString()) {
693
+ Napi::TypeError::New(env, "file must be string.").ThrowAsJavaScriptException();
694
+ return env.Null();
695
+ }
696
+ string file = info[2].As<Napi::String>().Utf8Value();
697
+
698
+ if (file.length() == 0) {
699
+ Napi::Error::New(env, "input_file is invalid (blank string)").ThrowAsJavaScriptException();
700
+ return env.Null();
701
+ }
702
+
703
+ int res = pjw_call_start_fax(call_id, is_sender, file.c_str());
704
+
705
+ if(res != 0) {
706
+ Napi::Error::New(env, pjw_get_error()).ThrowAsJavaScriptException();
707
+ return env.Null();
708
+ }
709
+
710
+ return env.Null();
711
+ }
712
+
672
713
  Napi::Value call_stop_record_wav(const Napi::CallbackInfo& info) {
673
714
  Napi::Env env = info.Env();
674
715
 
@@ -717,6 +758,30 @@ Napi::Value call_stop_play_wav(const Napi::CallbackInfo& info) {
717
758
  return env.Null();
718
759
  }
719
760
 
761
+ Napi::Value call_stop_fax(const Napi::CallbackInfo& info) {
762
+ Napi::Env env = info.Env();
763
+
764
+ if (info.Length() != 1) {
765
+ Napi::Error::New(env, "Wrong number of arguments. Expected: call_id").ThrowAsJavaScriptException();
766
+ return env.Null();
767
+ }
768
+
769
+ if (!info[0].IsNumber()) {
770
+ Napi::TypeError::New(env, "call_id must be number.").ThrowAsJavaScriptException();
771
+ return env.Null();
772
+ }
773
+ int call_id = info[0].As<Napi::Number>().Int32Value();
774
+
775
+ int res = pjw_call_stop_fax(call_id);
776
+
777
+ if(res != 0) {
778
+ Napi::Error::New(env, pjw_get_error()).ThrowAsJavaScriptException();
779
+ return env.Null();
780
+ }
781
+
782
+ return env.Null();
783
+ }
784
+
720
785
  Napi::Value call_get_stream_stat(const Napi::CallbackInfo& info) {
721
786
  Napi::Env env = info.Env();
722
787
 
@@ -1381,8 +1446,10 @@ Napi::Object init(Napi::Env env, Napi::Object exports) {
1381
1446
  exports.Set("call_send_request", Napi::Function::New(env, call_send_request));
1382
1447
  exports.Set("call_start_record_wav", Napi::Function::New(env, call_start_record_wav));
1383
1448
  exports.Set("call_start_play_wav", Napi::Function::New(env, call_start_play_wav));
1449
+ exports.Set("call_start_fax", Napi::Function::New(env, call_start_fax));
1384
1450
  exports.Set("call_stop_record_wav", Napi::Function::New(env, call_stop_record_wav));
1385
1451
  exports.Set("call_stop_play_wav", Napi::Function::New(env, call_stop_play_wav));
1452
+ exports.Set("call_stop_fax", Napi::Function::New(env, call_stop_fax));
1386
1453
  exports.Set("call_get_stream_stat", Napi::Function::New(env, call_get_stream_stat));
1387
1454
  exports.Set("call_refer", Napi::Function::New(env, call_refer));
1388
1455
  exports.Set("call_get_info", Napi::Function::New(env, call_get_info));
@@ -53,3 +53,7 @@ int make_evt_registration_status(char *dest, int size, long account_id, int code
53
53
  return snprintf(dest, size, "{\"event\": \"registration_status\", \"account_id\": %i, \"code\": %i, \"reason\": \"%s\", \"expires\": %i}", account_id, code, reason, expires);
54
54
  }
55
55
 
56
+ int make_evt_fax_result(char *dest, int size, long call_id, int result) {
57
+ return snprintf(dest, size, "{\"event\": \"fax_result\", \"call_id\": %i, \"result\": %i}", call_id, result);
58
+ }
59
+
@@ -22,6 +22,8 @@ int make_evt_internal_error(char *dest, int size, char *msg);
22
22
 
23
23
  int make_evt_registration_status(char *dest, int size, long account_id, int code, char *reason, int expires);
24
24
 
25
+ int make_evt_fax_result(char *dest, int size, long call_id, int result);
26
+
25
27
  #endif
26
28
 
27
29
 
@@ -18,7 +18,7 @@ all: libchainlink.a
18
18
 
19
19
  #libchainlink.a: chainlink_wire_port.o chainlink_dtmfdet.o chainlink_tonegen.o chainlink_wav_player.o
20
20
  #libchainlink.a: chainlink_wire_port.o chainlink_dtmfdet.o chainlink_tonegen.o
21
- libchainlink.a: chainlink_wire_port.o chainlink_dtmfdet.o chainlink_wav_player.o chainlink_wav_writer.o chainlink_tonegen.o
21
+ libchainlink.a: chainlink_wire_port.o chainlink_dtmfdet.o chainlink_wav_player.o chainlink_wav_writer.o chainlink_tonegen.o chainlink_fax.o
22
22
  ar rcs $@ $^
23
23
 
24
24
  chainlink_wire_port.o:
@@ -31,6 +31,8 @@ chainlink_wav_writer.o:
31
31
 
32
32
  chainlink_tonegen.o:
33
33
 
34
+ chainlink_fax.o:
35
+
34
36
  clean:
35
37
  rm -f *.o
36
38
  rm -f *.a
@@ -0,0 +1,25 @@
1
+ #ifndef __CHAINLINK_FAX_H__
2
+ #define __CHAINLINK_FAX_H__
3
+
4
+ #include <pjmedia/port.h>
5
+
6
+ PJ_BEGIN_DECL
7
+
8
+ PJ_DECL(pj_status_t) chainlink_fax_port_create( pj_pool_t *pool,
9
+ unsigned clock_rate,
10
+ unsigned channel_count,
11
+ unsigned samples_per_frame,
12
+ unsigned bits_per_sample,
13
+ void (*cb)(pjmedia_port*,
14
+ void *user_data,
15
+ int result),
16
+ void *user_data,
17
+ int is_caller,
18
+ int is_sender,
19
+ const char *file,
20
+ pjmedia_port **p_port);
21
+
22
+
23
+ PJ_END_DECL
24
+
25
+ #endif /* __CHAINLINK_FAX_H__ */
@@ -0,0 +1,274 @@
1
+ #include "chainlink.h"
2
+ #include "chainlink_fax.h"
3
+
4
+ #include <pjmedia/errno.h>
5
+ #include <pjmedia/port.h>
6
+ #include <pj/assert.h>
7
+ #include <pj/lock.h>
8
+ #include <pj/pool.h>
9
+ #include <pj/string.h>
10
+
11
+ #define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
12
+ #include <spandsp.h>
13
+
14
+ #define SIGNATURE PJMEDIA_SIGNATURE('L', 'f', 'a', 'x')
15
+ #define THIS_FILE "chainlink_fax.c"
16
+
17
+ #if 0
18
+ # define TRACE_(expr) PJ_LOG(4,expr)
19
+ #else
20
+ # define TRACE_(expr)
21
+ #endif
22
+
23
+ #define FAX_DATA_CHUNK 320
24
+ #define T38_DATA_CHUNK 160
25
+
26
+
27
+ enum
28
+ {
29
+ /*! No compression */
30
+ T30_SUPPORT_NO_COMPRESSION = 0x01,
31
+ /*! T.1 1D compression */
32
+ T30_SUPPORT_T4_1D_COMPRESSION = 0x02,
33
+ /*! T.4 2D compression */
34
+ T30_SUPPORT_T4_2D_COMPRESSION = 0x04,
35
+ /*! T.6 2D compression */
36
+ T30_SUPPORT_T6_COMPRESSION = 0x08,
37
+ /*! T.85 monochrome JBIG compression */
38
+ T30_SUPPORT_T85_COMPRESSION = 0x10,
39
+ /*! T.43 colour JBIG compression */
40
+ T30_SUPPORT_T43_COMPRESSION = 0x20,
41
+ /*! T.45 run length colour compression */
42
+ T30_SUPPORT_T45_COMPRESSION = 0x40,
43
+ /*! T.81 + T.30 Annex E colour JPEG compression */
44
+ T30_SUPPORT_T81_COMPRESSION = 0x80,
45
+ /*! T.81 + T.30 Annex K colour sYCC-JPEG compression */
46
+ T30_SUPPORT_SYCC_T81_COMPRESSION = 0x100,
47
+ /*! T.88 monochrome JBIG2 compression */
48
+ T30_SUPPORT_T88_COMPRESSION = 0x200
49
+ };
50
+
51
+
52
+ static pj_status_t fax_get_frame(pjmedia_port *this_port,
53
+ pjmedia_frame *frame);
54
+ static pj_status_t fax_put_frame(pjmedia_port *this_port,
55
+ pjmedia_frame *frame);
56
+ static pj_status_t fax_on_destroy(pjmedia_port *this_port);
57
+
58
+ struct fax_device
59
+ {
60
+ struct chainlink link;
61
+ fax_state_t fax;
62
+ void (*fax_cb)(pjmedia_port*, void*, int);
63
+ void *fax_cb_user_data;
64
+ int is_caller;
65
+ int is_sender;
66
+
67
+ pj_lock_t *lock;
68
+ };
69
+
70
+ static int phase_b_handler(t30_state_t* s, void* user_data, int result)
71
+ {
72
+ printf("fax phase_b_handler user_data=%p result=%i\n", user_data, result);
73
+ return T30_ERR_OK;
74
+ }
75
+
76
+ static int phase_d_handler(t30_state_t* s, void* user_data, int result)
77
+ {
78
+ printf("fax phase_b_handler user_data=%p result=%i\n", user_data, result);
79
+ return T30_ERR_OK;
80
+ }
81
+
82
+ static void phase_e_handler(t30_state_t* s, void* user_data, int result)
83
+ {
84
+ printf("fax phase_e_handler user_data=%p result=%i\n", user_data, result);
85
+
86
+ if (!user_data) {
87
+ printf("not user_data\n");
88
+ return;
89
+ }
90
+
91
+ struct fax_device *fd = (struct fax_device*)user_data;
92
+ if(!fd->fax_cb) {
93
+ printf("not fax_cb\n");
94
+ return;
95
+ }
96
+
97
+ printf("sending result event\n");
98
+ fd->fax_cb((pjmedia_port*)fd, fd->fax_cb_user_data, result);
99
+ }
100
+
101
+ static int document_handler(t30_state_t* s, void* user_data, int result)
102
+ {
103
+ printf("fax document_handler user_data=%p result=%i\n", user_data, result);
104
+
105
+ if (!user_data) return 0;
106
+
107
+ struct fax_device *fd = (struct fax_device*)user_data;
108
+ if(!fd->fax_cb) return 0;
109
+
110
+ //fd->fax_cb((pjmedia_port*)fd, fd->fax_cb_user_data, result);
111
+
112
+ return 0;
113
+ }
114
+
115
+ PJ_DEF(pj_status_t) chainlink_fax_port_create( pj_pool_t *pool,
116
+ unsigned clock_rate,
117
+ unsigned channel_count,
118
+ unsigned samples_per_frame,
119
+ unsigned bits_per_sample,
120
+ void (*cb)(pjmedia_port*,
121
+ void *user_data,
122
+ int result),
123
+ void *user_data,
124
+ int is_caller,
125
+ int is_sender,
126
+ const char *file,
127
+ pjmedia_port **p_port)
128
+ {
129
+ struct fax_device *fd;
130
+ const pj_str_t name = pj_str("fax_device");
131
+
132
+ PJ_ASSERT_RETURN(pool && clock_rate && channel_count &&
133
+ samples_per_frame && bits_per_sample == 16 &&
134
+ p_port != NULL, PJ_EINVAL);
135
+
136
+ PJ_ASSERT_RETURN(pool && p_port, PJ_EINVAL);
137
+
138
+ fd = PJ_POOL_ZALLOC_T(pool, struct fax_device);
139
+ PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
140
+
141
+ pjmedia_port_info_init(&fd->link.port.info, &name, SIGNATURE, clock_rate,
142
+ channel_count, bits_per_sample, samples_per_frame);
143
+
144
+ fd->link.port.get_frame = &fax_get_frame;
145
+ fd->link.port.put_frame = &fax_put_frame;
146
+ fd->link.port.on_destroy = &fax_on_destroy;
147
+
148
+ fax_init(&fd->fax, is_caller);
149
+ //fax_set_transmit_on_idle(&fd->fax,1);
150
+
151
+ t30_state_t *t30 = fax_get_t30_state(&fd->fax);
152
+
153
+ span_log_set_level(fax_get_logging_state(&fd->fax), SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW);
154
+ span_log_set_level(t30_get_logging_state(t30), SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW);
155
+
156
+ char ident[] = "chainlink_fax";
157
+
158
+ t30_set_tx_ident(t30, ident);
159
+ t30_set_phase_b_handler(t30, &phase_b_handler, (void*)fd);
160
+ t30_set_phase_d_handler(t30, &phase_d_handler, (void*)fd);
161
+ t30_set_phase_e_handler(t30, &phase_e_handler, (void*)fd);
162
+ //printf("setting document_handler with user_data=%p\n", (void*)fd);
163
+ t30_set_document_handler(t30, &document_handler, (void*)fd);
164
+
165
+ fd->is_caller = is_caller;
166
+ fd->is_sender = is_sender;
167
+
168
+ pj_status_t status = pj_lock_create_simple_mutex(pool, "fax", &fd->lock);
169
+
170
+ if (status != PJ_SUCCESS) {
171
+ printf("failed to create lock\n");
172
+ return status;
173
+ }
174
+
175
+ if (is_sender)
176
+ t30_set_tx_file(t30,file,-1,-1);
177
+ else
178
+ t30_set_rx_file(t30,file,-1);
179
+
180
+ t30_set_ecm_capability(t30,1);
181
+ t30_set_supported_compressions(t30,T30_SUPPORT_T4_1D_COMPRESSION |
182
+ T30_SUPPORT_T4_2D_COMPRESSION | T30_SUPPORT_T6_COMPRESSION);
183
+
184
+ fax_set_transmit_on_idle(&fd->fax, 1);
185
+
186
+ fd->fax_cb = cb;
187
+ fd->fax_cb_user_data = user_data;
188
+
189
+ TRACE_((THIS_FILE, "fax_device created: %u/%u/%u/%u", clock_rate,
190
+ channel_count, samples_per_frame, bits_per_sample));
191
+
192
+ *p_port = &fd->link.port;
193
+ return PJ_SUCCESS;
194
+ }
195
+
196
+ // called when pjmedia needs data to be sent out
197
+ static pj_status_t fax_get_frame(pjmedia_port *this_port,
198
+ pjmedia_frame *frame) {
199
+
200
+ //printf("ENTER fax_get_frame frame_size=%i\n", frame->size);
201
+
202
+ PJ_ASSERT_RETURN(this_port && frame, PJ_EINVAL);
203
+ char *p = (char*)frame->buf;
204
+
205
+ struct fax_device *fd = (struct fax_device*)this_port;
206
+ pj_lock_acquire(fd->lock);
207
+
208
+ int tx = 0;
209
+
210
+ if ((tx = fax_tx(&fd->fax, (int16_t *)frame->buf, frame->size/2)) < 0) {
211
+ printf("fax_tx reported an error\n");
212
+ pj_lock_release(fd->lock);
213
+ printf("EXIT fax_get_frame\n");
214
+ return PJ_FALSE;
215
+ }
216
+ pj_lock_release(fd->lock);
217
+
218
+ frame->type = PJMEDIA_FRAME_TYPE_AUDIO;
219
+ frame->timestamp.u64 = 0;
220
+
221
+ //printf("EXIT fax_get_frame\n");
222
+ return PJ_SUCCESS;
223
+ }
224
+
225
+ // called when pjmedia has received data
226
+ static pj_status_t fax_put_frame(pjmedia_port *this_port,
227
+ pjmedia_frame *frame)
228
+ {
229
+ if(frame->type != PJMEDIA_FRAME_TYPE_AUDIO) return PJ_SUCCESS;
230
+ //printf("ENTER fax_put_frame frame->buf=%x frame->size=%i\n", frame->buf, frame->size);
231
+
232
+ struct fax_device *fd = (struct fax_device*) this_port;
233
+ pj_lock_acquire(fd->lock);
234
+
235
+ unsigned int pos = 0;
236
+
237
+ while (pos < frame->size)
238
+ {
239
+ // feed the decoder with small chunks of data (16 bytes/ms)
240
+ int len = frame->size - pos;
241
+ if (len > FAX_DATA_CHUNK) len = FAX_DATA_CHUNK;
242
+
243
+ /* Pass the new incoming audio frame to the fax_rx function */
244
+ if (fax_rx(&fd->fax, (int16_t *)(frame->buf)+pos, len/2)) {
245
+ printf("fax_rx reported an error\n");
246
+ pj_lock_release(fd->lock);
247
+ printf("EXIT fax_put_frame\n");
248
+ return 0;
249
+ }
250
+
251
+ pos += len;
252
+ }
253
+
254
+ pj_lock_release(fd->lock);
255
+
256
+ //printf("EXIT fax_put_frame\n");
257
+ return fd->link.next->put_frame(fd->link.next, frame);
258
+ }
259
+
260
+ /*
261
+ * Destroy port.
262
+ */
263
+ static pj_status_t fax_on_destroy(pjmedia_port *this_port)
264
+ {
265
+ printf("fax_on_destroy\n");
266
+
267
+ struct fax_device *fd = (struct fax_device*)this_port;
268
+
269
+ fax_release(&fd->fax);
270
+
271
+ if(fd->lock) pj_lock_destroy(fd->lock);
272
+ return PJ_SUCCESS;
273
+ }
274
+