sip-lab 1.32.0 → 1.33.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 CHANGED
@@ -8,6 +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
+ - send/receive [BFSK](https://en.wikipedia.org/wiki/Frequency-shift_keying) bits.
11
12
  - play/record audio on a call from/to a wav file
12
13
  - send/receive fax (T.30 only)
13
14
  - send/receive MRCPv2 messages (TCP only, no TLS)
@@ -87,4 +88,8 @@ Although the code in written in *.cpp/*.hpp named files, this is not actually a
87
88
 
88
89
  It is mostly written in C using some C++ facilities.
89
90
 
91
+ ### Release Notes
92
+
93
+ [ReleaseNotes](https://github.com/MayamaTakeshi/sip-lab/blob/master/RELEASE_NOTES.md)
94
+
90
95
 
package/binding.gyp CHANGED
@@ -120,6 +120,7 @@
120
120
  'src/addon.cpp',
121
121
  'src/pjmedia/src/pjmedia/dtmfdet.c',
122
122
  'src/pjmedia/src/pjmedia/bfsk_det.c',
123
+ 'src/pjmedia/src/pjmedia/bfsk_det2.c',
123
124
  'src/pjmedia/src/pjmedia/fax_port.c',
124
125
  'src/pjmedia/src/pjmedia/flite_port.c',
125
126
  'src/pjmedia/src/pjmedia/pocketsphinx_port.c',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sip-lab",
3
- "version": "1.32.0",
3
+ "version": "1.33.0",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "engines": {
Binary file
Binary file
@@ -80,6 +80,11 @@ async function test() {
80
80
 
81
81
  await z.wait(events, 50000)
82
82
 
83
+ ocs.forEach(oc => {
84
+ sip.call.start_inband_dtmf_detection(oc.id)
85
+ })
86
+
87
+ // first send RFC2833 DTMF digits
83
88
  ocs.forEach(oc => {
84
89
  sip.call.send_dtmf(oc.id, {digits: '1234', mode: 0})
85
90
  })
@@ -92,10 +97,7 @@ async function test() {
92
97
  media_id: 0,
93
98
  })).value(), 50000)
94
99
 
95
- ocs.forEach(oc => {
96
- sip.call.start_inband_dtmf_detection(oc.id)
97
- })
98
-
100
+ // now send inband DTMF digits
99
101
  z.store.ic_ids.forEach(ic_id => {
100
102
  sip.call.send_dtmf(ic_id, {digits: '4321', mode: 1})
101
103
  })
@@ -71,11 +71,9 @@ async function test() {
71
71
  {
72
72
  type: 'audio',
73
73
  local: {
74
- port: 10000,
75
74
  mode: 'sendrecv'
76
75
  },
77
76
  remote: {
78
- port: 10002,
79
77
  mode: 'sendrecv'
80
78
  },
81
79
  },
@@ -89,11 +87,9 @@ async function test() {
89
87
  {
90
88
  type: 'audio',
91
89
  local: {
92
- port: 10002,
93
90
  mode: 'sendrecv'
94
91
  },
95
92
  remote: {
96
- port: 10000,
97
93
  mode: 'sendrecv'
98
94
  },
99
95
  }
@@ -104,33 +100,34 @@ async function test() {
104
100
  sip.call.start_record_wav(oc.id, {file: 'oc.wav'})
105
101
  sip.call.start_record_wav(ic.id, {file: 'ic.wav'})
106
102
 
107
- await z.sleep(100)
108
-
109
- sip.call.start_bfsk_detection(oc.id, {freq_zero: 880, freq_one: 1280})
110
- //sip.call.start_bfsk_detection(ic.id, {freq_zero: 880, freq_one: 1280})
103
+ sip.call.start_bfsk_detection(oc.id, {freq_zero: 500, freq_one: 2000})
104
+ sip.call.start_bfsk_detection(ic.id, {freq_zero: 500, freq_one: 2000})
111
105
 
112
106
  oc_bits = '1010'
113
107
  ic_bits = '1100'
114
108
 
115
- sip.call.send_bfsk(ic.id, {bits: ic_bits, freq_zero: 880, freq_one: 1280})
116
- //sip.call.send_bfsk(oc.id, {bits: oc_bits, freq_zero: 880, freq_one: 1280})
117
-
118
- await z.wait([
119
- {
120
- event: 'bfsk',
121
- call_id: ic.id,
122
- bits: oc_bits,
123
- media_id: 0
124
- },
125
- {
126
- event: 'bfsk',
127
- call_id: oc.id,
128
- bits: ic_bits,
129
- media_id: 0
130
- },
131
- ], 10000)
132
-
133
- await z.sleep(1000)
109
+ // wait a little for voice path to open
110
+ await z.sleep(50)
111
+
112
+ for(var i=0 ; i<5 ; i++) {
113
+ sip.call.send_bfsk(ic.id, {bits: ic_bits, freq_zero: 500, freq_one: 2000})
114
+ sip.call.send_bfsk(oc.id, {bits: oc_bits, freq_zero: 500, freq_one: 2000})
115
+
116
+ await z.wait([
117
+ {
118
+ event: 'bfsk',
119
+ call_id: ic.id,
120
+ bits: oc_bits,
121
+ media_id: 0
122
+ },
123
+ {
124
+ event: 'bfsk',
125
+ call_id: oc.id,
126
+ bits: ic_bits,
127
+ media_id: 0
128
+ },
129
+ ], 10000)
130
+ }
134
131
 
135
132
  sip.call.stop_record_wav(oc.id)
136
133
  sip.call.stop_record_wav(ic.id)
@@ -122,6 +122,13 @@ test()
122
122
  .catch(e => {
123
123
  console.error(e)
124
124
  sip.stop(true)
125
- process.exit(0)
125
+
126
+ if(e == "SOME ERROR") {
127
+ console.log("Expected error catched")
128
+ process.exit(0)
129
+ } else {
130
+ console.log("Unexpected error catched")
131
+ process.exit(1)
132
+ }
126
133
  })
127
134
 
@@ -0,0 +1,23 @@
1
+ #ifndef __PJMEDIA_BFSK_DET2_H__
2
+ #define __PJMEDIA_BFSK_DET2_H__
3
+
4
+ #include <pjmedia/port.h>
5
+
6
+ PJ_BEGIN_DECL
7
+
8
+ PJ_DEF(pj_status_t) pjmedia_bfsk_det2_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 bit),
16
+ void *user_data,
17
+ int freq_zero,
18
+ int freq_one,
19
+ pjmedia_port **p_port);
20
+
21
+ PJ_END_DECL
22
+
23
+ #endif /* __PJMEDIA_BFSK_DET2_H__ */
@@ -36,88 +36,106 @@
36
36
  # define TRACE_(expr)
37
37
  #endif
38
38
 
39
- // Adapted https://github.com/ericksc/goertzel/blob/master/main.cpp
39
+ #include <math.h>
40
+ #include <stdio.h>
41
+ #include <stdlib.h>
42
+ #include <stdbool.h>
40
43
 
41
- #define PI 3.14159265358979
44
+ // Converted by ChatGPT from https://github.com/hackergrrl/goertzel/blob/master/index.js
42
45
 
43
46
  typedef struct {
44
- float coeff;
45
- int fix_coeff;
46
- int Q1;
47
- int Q2;
48
- double sine;
49
- double cosine;
47
+ int freq;
48
+ int sampleRate;
49
+ int samplesPerFrame;
50
+ double targetMagnitude; // Store the precomputed magnitude
50
51
  } goertzel_t;
51
52
 
52
- //Para definir punto fijo de 32 bits.
53
- int FIXED_POINT_16 = 16;
54
- int ONE_16 = 1 << 16;
53
+ #define CHUNK_SIZE 16
54
+ #define THRESHOLD 0.9
55
55
 
56
- int FIXED_POINT_30 = 30;
57
- int ONE_30 = 1 << 30;
56
+ double precalcMagnitude(int freq, double rate) {
57
+ double t = 0.0;
58
+ double tstep = 1.0 / rate;
59
+ double samples[CHUNK_SIZE];
60
+ for (int i = 0; i < CHUNK_SIZE; i++) {
61
+ samples[i] = sin(2 * M_PI * freq * t);
62
+ t += tstep;
63
+ }
58
64
 
59
- int toFix( float val, int ONE ) {
60
- // Escalamiento
61
- return (int) (val * ONE);
62
- }
65
+ int k = (int)(0.5 + (CHUNK_SIZE * freq) / rate);
66
+ double w = (2 * M_PI / CHUNK_SIZE) * k;
67
+ double c = cos(w);
68
+ double s = sin(w);
69
+ double coeff = 2.0 * c;
70
+
71
+ double q0 = 0.0, q1 = 0.0, q2 = 0.0;
72
+ for (int i = 0; i < CHUNK_SIZE; i++) {
73
+ q0 = coeff * q1 - q2 + samples[i];
74
+ q2 = q1;
75
+ q1 = q0;
76
+ }
63
77
 
64
- float floatVal( int fix, int ONE ) {
65
- return ((float) fix) / ONE;
66
- }
78
+ double real = q1 - q2 * c;
79
+ double imaginary = q2 * s;
80
+ double magSquared = real * real + imaginary * imaginary;
67
81
 
68
- int intVal( int fix, int FIXED_POINT ) {
69
- return fix >> FIXED_POINT;
82
+ return magSquared;
70
83
  }
71
84
 
72
- int mul(int fix_coeff, int Q1, int FIXED_POINT_mixed) {
73
- // Manejo de 64 bit para el resultado inmedianto de la multiplicación
74
- // Conversion a 32 bits para posterior uso
75
- return (int)((long long int)fix_coeff * (long long int)Q1 >> FIXED_POINT_mixed);
76
- }
85
+ void goertzel_det_init(goertzel_t *g, int freq, int sample_rate) {
86
+ g->freq = freq;
87
+ g->sampleRate = sample_rate;
88
+ g->samplesPerFrame = CHUNK_SIZE;
77
89
 
78
- /* Call this routine before every "block" (size=N) of samples. */
79
- void goertzel_det_reset(goertzel_t *g)
80
- {
81
- g->Q2 = 0;
82
- g->Q1 = 0;
83
- }
84
- /* Call this once, to precompute the constants. */
85
- void goertzel_det_init(goertzel_t *g, float frequency, float sampling_rate, int samples_per_frame)
86
- {
87
- int k;
88
- double floatN;
89
- double omega;
90
- floatN = (double)samples_per_frame;
91
- k = (int)(0.5 + ((floatN * frequency) / sampling_rate));
92
- omega = (2.0 * PI * k) / floatN;
93
- g->sine = sin(omega);
94
- g->cosine = cos(omega);
95
- g->coeff = 2.0 * g->cosine;
96
- g->fix_coeff = toFix(g->coeff, ONE_30);
97
- printf("For sampling_rate = %f", sampling_rate);
98
- printf("samples_per_frame = %d", samples_per_frame);
99
- printf(" and frequency = %f,\n", frequency);
100
- printf("k = %d and coeff = %f\n\n", k, g->coeff);
101
- goertzel_det_reset(g);
90
+ assert(g->sampleRate >= g->freq * 2);
91
+
92
+ g->samplesPerFrame = (int)floor(g->samplesPerFrame);
93
+
94
+ // Precompute the target magnitude and store it in the struct
95
+ g->targetMagnitude = precalcMagnitude(g->freq, g->sampleRate);
96
+ // printf("Target Magnitude: %f\n", g->targetMagnitude);
102
97
  }
103
98
 
104
- float goertzel_mag(goertzel_t *g, int *buf, int size)
105
- {
106
- for (int index = 0; index < size; index++)
107
- {
108
- // Punto fijo 32. INT
109
- int Q0;
110
- Q0 = mul(g->fix_coeff, g->Q1, 30) - g->Q2 + toFix(buf[index], ONE_16);
111
- g->Q2 = g->Q1;
112
- g->Q1 = Q0;
99
+ float goertzel_mag(goertzel_t *g, void *samples) {
100
+ // Allocate an array of floats to hold normalized samples
101
+ float float_samples[CHUNK_SIZE];
102
+ uint8_t *byteBuffer = (uint8_t *)samples; // Cast the void* to a byte array (uint8_t *)
103
+ for (int i = 0; i < CHUNK_SIZE ; i++) {
104
+ // Combine two consecutive bytes into a 16-bit signed integer (little-endian)
105
+ int16_t sample = byteBuffer[i * 2] | (byteBuffer[i * 2 + 1] << 8);
106
+ float_samples[i] = sample * 2.0f / 0x7FFF;
113
107
  }
114
108
 
115
- float result;
116
- result = floatVal(g->Q1, ONE_16) * floatVal(g->Q1,ONE_16) + floatVal(g->Q2,ONE_16) * floatVal(g->Q2,ONE_16) - floatVal(g->Q1,ONE_16) * floatVal(g->Q2,ONE_16) * g->coeff;
117
- goertzel_det_reset(g);
118
- return result;
119
- }
109
+ /*
110
+ for (int i = 0; i < CHUNK_SIZE; i++) {
111
+ printf("%f,", float_samples[i]);
112
+ }
113
+ printf("\n");
114
+ */
115
+
116
+
117
+ int k = (int)(0.5f + (CHUNK_SIZE * g->freq) / g->sampleRate);
118
+ float w = (2.0f * M_PI / CHUNK_SIZE) * k;
119
+ float c = cosf(w);
120
+ float s = sinf(w);
121
+ float coeff = 2.0f * c;
122
+
123
+ float q0 = 0.0f, q1 = 0.0f, q2 = 0.0f;
124
+
125
+ for (int i = 0; i < CHUNK_SIZE; i++) {
126
+ q0 = coeff * q1 - q2 + float_samples[i];
127
+ q2 = q1;
128
+ q1 = q0;
129
+ }
120
130
 
131
+ float real = q1 - q2 * c;
132
+ float imaginary = q2 * s;
133
+ float magSquared = real * real + imaginary * imaginary;
134
+
135
+ float per = magSquared / g->targetMagnitude;
136
+ //printf("(freq=%i) MagSquared=%f targetMagnitude=%f per=%f\n", g->freq, magSquared, g->targetMagnitude, per);
137
+ return per;
138
+ }
121
139
 
122
140
 
123
141
  static pj_status_t bfsk_det_put_frame(pjmedia_port *this_port,
@@ -141,24 +159,6 @@ struct bfsk_det
141
159
  void *bfsk_cb_user_data;
142
160
  };
143
161
 
144
- /*
145
- static void bfsk_det_bit_callback(void *user_data, int bit)
146
- {
147
- printf("bfsk_det_bit_callback got bit=%i\n", bit);
148
- if(bit != 0 && bit != 1) return;
149
-
150
- struct bfsk_det *dport = (struct bfsk_det*)user_data;
151
-
152
- TRACE_((THIS_FILE, "bfsk_det bit detected: %c", bit));
153
-
154
- if(!dport->bfsk_cb) return;
155
-
156
- dport->bfsk_cb((pjmedia_port*)dport,
157
- dport->bfsk_cb_user_data,
158
- bit);
159
- }
160
- */
161
-
162
162
  PJ_DEF(pj_status_t) pjmedia_bfsk_det_create( pj_pool_t *pool,
163
163
  unsigned clock_rate,
164
164
  unsigned channel_count,
@@ -172,10 +172,9 @@ PJ_DEF(pj_status_t) pjmedia_bfsk_det_create( pj_pool_t *pool,
172
172
  int freq_one,
173
173
  pjmedia_port **p_port)
174
174
  {
175
- printf("pjmedia_bfsk_det_create\n");
175
+ //printf("pjmedia_bfsk_det_create\n");
176
176
  struct bfsk_det *det;
177
177
 
178
- printf("p1\n");
179
178
  const pj_str_t name = pj_str("bfsk_det");
180
179
 
181
180
  PJ_ASSERT_RETURN(pool && clock_rate && channel_count &&
@@ -184,11 +183,8 @@ PJ_DEF(pj_status_t) pjmedia_bfsk_det_create( pj_pool_t *pool,
184
183
 
185
184
  PJ_ASSERT_RETURN(pool && p_port, PJ_EINVAL);
186
185
 
187
- printf("p2\n");
188
-
189
186
  det = PJ_POOL_ZALLOC_T(pool, struct bfsk_det);
190
187
  PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
191
- printf("p3\n");
192
188
 
193
189
  pjmedia_port_info_init(&det->base.info, &name, SIGNATURE, clock_rate,
194
190
  channel_count, bits_per_sample, samples_per_frame);
@@ -196,13 +192,9 @@ PJ_DEF(pj_status_t) pjmedia_bfsk_det_create( pj_pool_t *pool,
196
192
  det->base.put_frame = &bfsk_det_put_frame;
197
193
  det->base.on_destroy = &bfsk_det_on_destroy;
198
194
 
199
- printf("p5\n");
200
-
201
195
  det->bfsk_cb = cb;
202
196
  det->bfsk_cb_user_data = user_data;
203
197
 
204
- printf("p6\n");
205
-
206
198
  det->clock_rate = clock_rate;
207
199
  det->freq_zero = freq_zero;
208
200
  det->freq_one = freq_one;
@@ -217,15 +209,10 @@ PJ_DEF(pj_status_t) pjmedia_bfsk_det_create( pj_pool_t *pool,
217
209
 
218
210
  int sample_rate = clock_rate;
219
211
 
220
- goertzel_det_init(det->goertzel_zero, det->freq_zero, sample_rate, samples_per_frame);
221
- goertzel_det_init(det->goertzel_one, det->freq_one, sample_rate, samples_per_frame);
222
-
223
- printf("p7\n");
224
-
225
- TRACE_((THIS_FILE, "bfsk_det created: clock_rate=%u channel_count=%u samples_per_frame=%u bits_per_frame=%u", clock_rate,
226
- channel_count, samples_per_frame, bits_per_sample));
212
+ //printf("bfsk_det: clock_rate=%u channel_count=%u samples_per_frame=%u bits_per_frame=%u", clock_rate, channel_count, samples_per_frame, bits_per_sample);
227
213
 
228
- printf("fsk_rx_init done\n");
214
+ goertzel_det_init(det->goertzel_zero, det->freq_zero, sample_rate);
215
+ goertzel_det_init(det->goertzel_one, det->freq_one, sample_rate);
229
216
 
230
217
  *p_port = &det->base;
231
218
  return PJ_SUCCESS;
@@ -234,50 +221,56 @@ PJ_DEF(pj_status_t) pjmedia_bfsk_det_create( pj_pool_t *pool,
234
221
  static pj_status_t bfsk_det_put_frame(pjmedia_port *this_port,
235
222
  pjmedia_frame *frame)
236
223
  {
237
- printf("bfsk_det_put_frame\n");
224
+ //printf("bfsk_det put_frame\n");
238
225
  if(frame->type != PJMEDIA_FRAME_TYPE_AUDIO) return PJ_SUCCESS;
239
226
 
240
227
  struct bfsk_det *dport = (struct bfsk_det*) this_port;
241
228
 
242
- int size = PJMEDIA_PIA_SPF(&dport->base.info);
229
+ int size = frame->size;
243
230
  int bps = PJMEDIA_PIA_BITS(&dport->base.info);
244
231
 
245
- printf("p=%x, size=%i clock_rate=%i bits_per_sample=%i\n", frame->buf, size, dport->clock_rate, bps);
232
+ //printf("p=%x, size=%i clock_rate=%i bits_per_sample=%i\n", frame->buf, size, dport->clock_rate, bps);
246
233
 
247
234
  int16_t * samples = (int16_t*)frame->buf;
248
235
 
236
+ /*
249
237
  printf("Buffer contents:\n");
250
238
  for (int i = 0; i < size; i++) {
251
- printf("%04x ", samples[i] & 0xFFFF);
239
+ printf("%02x", samples[i] & 0xFF);
240
+ printf("%02x", samples[i] >> 8 & 0xFF);
252
241
  }
253
242
  printf("\n");
254
-
255
- float zero_power = goertzel_mag(dport->goertzel_zero, frame->buf, size);
256
- float one_power = goertzel_mag(dport->goertzel_one, frame->buf, size);
257
-
258
- int zero = zero_power > 1000000000.0;
259
- int one = one_power > 1000000000.0;
260
-
261
- printf("zero_power=%f zero_in_progress=%i zero=%i\n", zero_power, dport->zero_in_progress, zero);
262
- printf("one_power=%f one_in_progress=%i one=%i\n", one_power, dport->one_in_progress, one);
263
-
264
-
265
- // Check for zero signal extinction
266
- if(dport->zero_in_progress && zero == 0) {
267
- printf("notifying bit=0\n");
268
- dport->bfsk_cb((pjmedia_port*)dport, dport->bfsk_cb_user_data, 0);
269
- dport->zero_in_progress = 0;
270
- } else {
271
- dport->zero_in_progress = zero;
272
- }
273
-
274
- // Check for one signal extinction
275
- if(dport->one_in_progress && one == 0) {
276
- printf("notifying bit=1\n");
277
- dport->bfsk_cb((pjmedia_port*)dport, dport->bfsk_cb_user_data, 1);
278
- dport->one_in_progress = 0;
279
- } else {
280
- dport->one_in_progress = one;
243
+ */
244
+
245
+ for(int i=0 ; i<size/2/CHUNK_SIZE; i++) {
246
+ double zero_power = goertzel_mag(dport->goertzel_zero, &frame->buf[i*2*CHUNK_SIZE]);
247
+ double one_power = goertzel_mag(dport->goertzel_one, &frame->buf[i*2*CHUNK_SIZE]);
248
+
249
+ int zero = zero_power > THRESHOLD;
250
+ int one = one_power > THRESHOLD;
251
+
252
+ /*
253
+ printf("zero_power=%f zero_in_progress=%i zero=%i threshold=%f\n", zero_power, dport->zero_in_progress, zero, THRESHOLD);
254
+ printf(" one_power=%f one_in_progress=%i one=%i threshold=%f\n", one_power, dport->one_in_progress, one, THRESHOLD);
255
+ */
256
+
257
+ // Check for zero signal extinction
258
+ if(dport->zero_in_progress && zero == 0) {
259
+ printf("notifying bit=0\n");
260
+ dport->bfsk_cb((pjmedia_port*)dport, dport->bfsk_cb_user_data, 0);
261
+ dport->zero_in_progress = 0;
262
+ } else {
263
+ dport->zero_in_progress = zero;
264
+ }
265
+
266
+ // Check for one signal extinction
267
+ if(dport->one_in_progress && one == 0) {
268
+ printf("notifying bit=1\n");
269
+ dport->bfsk_cb((pjmedia_port*)dport, dport->bfsk_cb_user_data, 1);
270
+ dport->one_in_progress = 0;
271
+ } else {
272
+ dport->one_in_progress = one;
273
+ }
281
274
  }
282
275
 
283
276
  return PJ_SUCCESS;
@@ -0,0 +1,226 @@
1
+ /* $Id: bfsk_det2.c 0000 2024-09-29 09:41:55Z 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/bfsk_det2.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 <spandsp.h>
29
+ #include <spandsp/expose.h>
30
+ #include <spandsp/tone_detect.h>
31
+
32
+ #include <math.h>
33
+
34
+ #define SIGNATURE PJMEDIA_SIGNATURE('b', 'f', 'd', '2')
35
+ #define THIS_FILE "bfsk_det2.c"
36
+
37
+ #if 0
38
+ # define TRACE_(expr) PJ_LOG(4,expr)
39
+ #else
40
+ # define TRACE_(expr)
41
+ #endif
42
+
43
+ #include <stdio.h>
44
+ #include <stdlib.h>
45
+ #include <stdbool.h>
46
+
47
+ static pj_status_t bfsk_det2_put_frame(pjmedia_port *this_port,
48
+ pjmedia_frame *frame);
49
+ static pj_status_t bfsk_det2_on_destroy(pjmedia_port *this_port);
50
+
51
+ struct bfsk_det2
52
+ {
53
+ struct pjmedia_port base;
54
+ int clock_rate;
55
+ int freq_zero;
56
+ int freq_one;
57
+
58
+ int zero_in_progress;
59
+ int one_in_progress;
60
+
61
+ int32_t threshold;
62
+ int32_t energy;
63
+
64
+ goertzel_descriptor_t desc_zero;
65
+ goertzel_descriptor_t desc_one;
66
+
67
+ goertzel_state_t *goertzel_zero;
68
+ goertzel_state_t *goertzel_one;
69
+
70
+ void (*bfsk_cb)(pjmedia_port*, void*, int);
71
+ void *bfsk_cb_user_data;
72
+ };
73
+
74
+ #define DTMF_SAMPLES_PER_BLOCK 102
75
+
76
+ PJ_DEF(pj_status_t) pjmedia_bfsk_det2_create( pj_pool_t *pool,
77
+ unsigned clock_rate,
78
+ unsigned channel_count,
79
+ unsigned samples_per_frame,
80
+ unsigned bits_per_sample,
81
+ void (*cb)(pjmedia_port*,
82
+ void *user_data,
83
+ int bit),
84
+ void *user_data,
85
+ int freq_zero,
86
+ int freq_one,
87
+ pjmedia_port **p_port)
88
+ {
89
+ //printf("pjmedia_bfsk_det2_create\n");
90
+ struct bfsk_det2 *det;
91
+
92
+ const pj_str_t name = pj_str("bfsk_det2");
93
+
94
+ PJ_ASSERT_RETURN(pool && clock_rate && channel_count &&
95
+ samples_per_frame && bits_per_sample == 16 &&
96
+ p_port != NULL, PJ_EINVAL);
97
+
98
+ PJ_ASSERT_RETURN(pool && p_port, PJ_EINVAL);
99
+
100
+ det = PJ_POOL_ZALLOC_T(pool, struct bfsk_det2);
101
+ PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
102
+
103
+ pjmedia_port_info_init(&det->base.info, &name, SIGNATURE, clock_rate,
104
+ channel_count, bits_per_sample, samples_per_frame);
105
+
106
+ det->base.put_frame = &bfsk_det2_put_frame;
107
+ det->base.on_destroy = &bfsk_det2_on_destroy;
108
+
109
+ det->bfsk_cb = cb;
110
+ det->bfsk_cb_user_data = user_data;
111
+
112
+ det->clock_rate = clock_rate;
113
+ det->freq_zero = freq_zero;
114
+ det->freq_one = freq_one;
115
+
116
+ make_goertzel_descriptor(&det->desc_zero, freq_zero, DTMF_SAMPLES_PER_BLOCK);
117
+ make_goertzel_descriptor(&det->desc_one, freq_one, DTMF_SAMPLES_PER_BLOCK);
118
+
119
+ goertzel_init(&det->goertzel_zero, &det->desc_zero);
120
+ goertzel_init(&det->goertzel_one, &det->desc_one);
121
+
122
+ int sample_rate = clock_rate;
123
+
124
+ //printf("bfsk_det2: clock_rate=%u channel_count=%u samples_per_frame=%u bits_per_frame=%u", clock_rate, channel_count, samples_per_frame, bits_per_sample);
125
+
126
+ goertzel_det_init(&det->goertzel_zero, det->freq_zero, sample_rate);
127
+ goertzel_det_init(&det->goertzel_one, det->freq_one, sample_rate);
128
+
129
+ *p_port = &det->base;
130
+ return PJ_SUCCESS;
131
+ }
132
+
133
+ static pj_status_t bfsk_det2_put_frame(pjmedia_port *this_port,
134
+ pjmedia_frame *frame)
135
+ {
136
+ //printf("bfsk_det2 put_frame\n");
137
+ if(frame->type != PJMEDIA_FRAME_TYPE_AUDIO) return PJ_SUCCESS;
138
+
139
+ struct bfsk_det2 *dport = (struct bfsk_det2*) this_port;
140
+
141
+ int size = frame->size;
142
+ int bps = PJMEDIA_PIA_BITS(&dport->base.info);
143
+
144
+ //printf("p=%x, size=%i clock_rate=%i bits_per_sample=%i\n", frame->buf, size, dport->clock_rate, bps);
145
+
146
+ int16_t * samples = (int16_t*)frame->buf;
147
+ int16_t * num_samples = frame->size/2;
148
+
149
+ /*
150
+ printf("Buffer contents:\n");
151
+ for (int i = 0; i < size; i++) {
152
+ printf("%02x", samples[i] & 0xFF);
153
+ printf("%02x", samples[i] >> 8 & 0xFF);
154
+ }
155
+ printf("\n");
156
+ */
157
+
158
+ #if defined(SPANDSP_USE_FIXED_POINT)
159
+ int32_t row_energy[4];
160
+ int32_t col_energy[4];
161
+ int16_t xamp;
162
+ float famp;
163
+ #else
164
+ float row_energy[4];
165
+ float col_energy[4];
166
+ float xamp;
167
+ float famp;
168
+ #endif
169
+
170
+ float v1;
171
+ int i;
172
+ int j;
173
+ int sample;
174
+ int limit;
175
+ uint8_t hit;
176
+
177
+ for (sample = 0; sample < num_samples; sample = limit)
178
+ {
179
+ limit = num_samples;
180
+ for (j = sample; j < limit; j++)
181
+ {
182
+ xamp = samples[j];
183
+ xamp = goertzel_preadjust_amp(xamp);
184
+ #if defined(SPANDSP_USE_FIXED_POINT)
185
+ dport->energy += ((int32_t) xamp*xamp);
186
+ #else
187
+ dport->energy += xamp*xamp;
188
+ #endif
189
+ goertzel_samplex(&dport->goertzel_zero, xamp);
190
+ goertzel_samplex(&dport->goertzel_one, xamp);
191
+ }
192
+ }
193
+ int32_t zero_power = goertzel_result(&dport->goertzel_zero);
194
+ int32_t one_power = goertzel_result(&dport->goertzel_one);
195
+
196
+ int zero = zero_power > dport->threshold;
197
+ int one = one_power > dport->threshold;
198
+
199
+ printf("zero_power=%f zero_in_progress=%i zero=%i threshold=%f\n", zero_power, dport->zero_in_progress, zero, dport->threshold);
200
+ printf(" one_power=%f one_in_progress=%i one=%i threshold=%f\n", one_power, dport->one_in_progress, one, dport->threshold);
201
+
202
+ // Check for zero signal extinction
203
+ if(dport->zero_in_progress && zero == 0) {
204
+ printf("notifying bit=0\n");
205
+ dport->bfsk_cb((pjmedia_port*)dport, dport->bfsk_cb_user_data, 0);
206
+ dport->zero_in_progress = 0;
207
+ } else {
208
+ dport->zero_in_progress = zero;
209
+ }
210
+
211
+ // Check for one signal extinction
212
+ if(dport->one_in_progress && one == 0) {
213
+ printf("notifying bit=1\n");
214
+ dport->bfsk_cb((pjmedia_port*)dport, dport->bfsk_cb_user_data, 1);
215
+ dport->one_in_progress = 0;
216
+ } else {
217
+ dport->one_in_progress = one;
218
+ }
219
+
220
+ return PJ_SUCCESS;
221
+ }
222
+
223
+ static pj_status_t bfsk_det2_on_destroy(pjmedia_port *this_port)
224
+ {
225
+ return PJ_SUCCESS;
226
+ }
@@ -338,10 +338,25 @@ PJ_DEF(pj_status_t) pjmedia_ws_speech_port_create(pj_pool_t *pool,
338
338
  }
339
339
 
340
340
  static pj_status_t put_frame(pjmedia_port *this_port, pjmedia_frame *frame) {
341
+ printf("ws_speech_port put_frame\n");
341
342
  if(frame->type != PJMEDIA_FRAME_TYPE_AUDIO) return PJ_SUCCESS;
342
343
 
343
344
  struct ws_speech_t *port = (struct ws_speech_t*) this_port;
344
345
 
346
+ int size = PJMEDIA_PIA_SPF(&port->base.info);
347
+ int bps = PJMEDIA_PIA_BITS(&port->base.info);
348
+
349
+ printf("p=%x, size=%i bits_per_sample=%i\n", frame->buf, size, bps);
350
+
351
+ int16_t * samples = (int16_t*)frame->buf;
352
+
353
+ printf("Buffer contents:\n");
354
+ for (int i = 0; i < size; i++) {
355
+ printf("%02x", samples[i] & 0xFF);
356
+ printf("%02x", samples[i] >> 8 & 0xFF);
357
+ }
358
+ printf("\n");
359
+
345
360
  if(port->wc && port->connected) {
346
361
  pj_websock_send(port->wc, PJ_WEBSOCK_OP_BIN, PJ_TRUE, PJ_TRUE, frame->buf, frame->size);
347
362
  }
@@ -364,7 +379,7 @@ static pj_status_t get_frame(pjmedia_port *this_port, pjmedia_frame *frame) {
364
379
  int len = PJMEDIA_PIA_SPF(&this_port->info)*2;
365
380
 
366
381
  if(port->buffering_count >= MINIMAl_BUFFERING && port->buffer_top > 0 && port->buffer_top >= len) {
367
- printf("get_frame top=%i\n", port->buffer_top);
382
+ //printf("get_frame top=%i\n", port->buffer_top);
368
383
  memcpy(frame->buf, port->buffer, len);
369
384
  port->buffer_top -= len;
370
385
  memcpy(port->buffer, port->buffer + len, port->buffer_top);
package/src/sip.cpp CHANGED
@@ -267,7 +267,7 @@ int ms_timestamp();
267
267
  bool g_shutting_down;
268
268
 
269
269
  int g_dtmf_inter_digit_timer = 0;
270
- int g_bfsk_inter_bit_timer = 200;
270
+ int g_bfsk_inter_bit_timer = 50;
271
271
 
272
272
  pj_str_t g_sip_ipaddress;
273
273
 
@@ -6642,7 +6642,7 @@ int pjw_enable_telephone_event() {
6642
6642
  }
6643
6643
 
6644
6644
  int __pjw_shutdown(int clean_up) {
6645
- addon_log(L_DBG, "pjw_shutdown thread_id=%i\n", syscall(SYS_gettid));
6645
+ //addon_log(L_DBG, "pjw_shutdown thread_id=%i\n", syscall(SYS_gettid));
6646
6646
 
6647
6647
  g_shutting_down = true;
6648
6648