sip-lab 1.2.4

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.
Files changed (41) hide show
  1. package/README.md +38 -0
  2. package/a.js +280 -0
  3. package/binding.gyp +101 -0
  4. package/devjournal +435 -0
  5. package/index.js +68 -0
  6. package/install.sh +32 -0
  7. package/package.json +30 -0
  8. package/samples/late_negotiation.js +278 -0
  9. package/samples/simple.js +280 -0
  10. package/samples/sip_cancel.js +111 -0
  11. package/src/Makefile +42 -0
  12. package/src/README +3 -0
  13. package/src/addon.cpp +1418 -0
  14. package/src/event_templates.cpp +55 -0
  15. package/src/event_templates.hpp +27 -0
  16. package/src/idmanager.cpp +76 -0
  17. package/src/idmanager.hpp +26 -0
  18. package/src/log.cpp +18 -0
  19. package/src/log.hpp +15 -0
  20. package/src/packetdumper.cpp +234 -0
  21. package/src/packetdumper.hpp +67 -0
  22. package/src/pjmedia/Makefile +37 -0
  23. package/src/pjmedia/devjournal +26 -0
  24. package/src/pjmedia/include/chainlink/README +3 -0
  25. package/src/pjmedia/include/chainlink/chainlink.h +11 -0
  26. package/src/pjmedia/include/chainlink/chainlink_dtmfdet.h +56 -0
  27. package/src/pjmedia/include/chainlink/chainlink_tonegen.h +178 -0
  28. package/src/pjmedia/include/chainlink/chainlink_wav_port.h +231 -0
  29. package/src/pjmedia/include/chainlink/chainlink_wire_port.h +50 -0
  30. package/src/pjmedia/include/pjmedia/README +3 -0
  31. package/src/pjmedia/include/pjmedia/dtmfdet.h +74 -0
  32. package/src/pjmedia/src/chainlink/chainlink_dtmfdet.c +125 -0
  33. package/src/pjmedia/src/chainlink/chainlink_tonegen.c +901 -0
  34. package/src/pjmedia/src/chainlink/chainlink_wav_player.c +688 -0
  35. package/src/pjmedia/src/chainlink/chainlink_wav_writer.c +442 -0
  36. package/src/pjmedia/src/chainlink/chainlink_wire_port.c +93 -0
  37. package/src/pjmedia/src/pjmedia/dtmfdet.c +129 -0
  38. package/src/pjmedia/src/pjmedia/simpleua_dtmfdet.c +753 -0
  39. package/src/pjmedia/src/pjmedia/tonegen_dtmfdet.c +263 -0
  40. package/src/sip.cpp +4891 -0
  41. package/src/sip.hpp +64 -0
@@ -0,0 +1,901 @@
1
+ #include "chainlink.h"
2
+ #include "chainlink_tonegen.h"
3
+
4
+ #include <pjmedia/errno.h>
5
+ #include <pjmedia/silencedet.h>
6
+ #include <pj/assert.h>
7
+ #include <pj/ctype.h>
8
+ #include <pj/lock.h>
9
+ #include <pj/log.h>
10
+ #include <pj/pool.h>
11
+
12
+ /* amplitude */
13
+ #define AMP PJMEDIA_TONEGEN_VOLUME
14
+
15
+ #ifndef M_PI
16
+ # define M_PI ((DATA)3.141592653589793238462643383279)
17
+ #endif
18
+
19
+ #if PJMEDIA_TONEGEN_ALG==PJMEDIA_TONEGEN_SINE
20
+ #include <math.h>
21
+ #define DATA double
22
+
23
+ /*
24
+ * This is the good old tone generator using sin().
25
+ * Speed = 1347 usec to generate 1 second, 8KHz dual-tones (2.66GHz P4).
26
+ * approx. 10.91 MIPS
27
+ *
28
+ * 506,535 usec/100.29 MIPS on ARM926EJ-S.
29
+ */
30
+ struct gen
31
+ {
32
+ DATA add;
33
+ DATA c;
34
+ DATA vol;
35
+ };
36
+
37
+ #define GEN_INIT(var,R,F,A) var.add = ((DATA)F)/R, var.c=0, var.vol=A
38
+ #define GEN_SAMP(val,var) val = (short)(sin(var.c * 2 * M_PI) * \
39
+ var.vol); \
40
+ var.c += var.add
41
+
42
+ #elif PJMEDIA_TONEGEN_ALG==PJMEDIA_TONEGEN_FLOATING_POINT
43
+ #include <math.h>
44
+ #define DATA float
45
+
46
+ /*
47
+ * Default floating-point based tone generation using sine wave
48
+ * generation from:
49
+ * http://www.musicdsp.org/showone.php?id=10.
50
+ * This produces good quality tone in relatively faster time than
51
+ * the normal sin() generator.
52
+ * Speed = 350 usec to generate 1 second, 8KHz dual-tones (2.66GHz P4).
53
+ * approx. 2.84 MIPS
54
+ *
55
+ * 18,037 usec/3.57 MIPS on ARM926EJ-S.
56
+ */
57
+ struct gen
58
+ {
59
+ DATA a, s0, s1;
60
+ };
61
+
62
+ #define GEN_INIT(var,R,F,A) var.a = (DATA) (2.0 * sin(M_PI * F / R)); \
63
+ var.s0 = 0; \
64
+ var.s1 = (DATA)(0 - (int)A)
65
+ #define GEN_SAMP(val,var) var.s0 = var.s0 - var.a * var.s1; \
66
+ var.s1 = var.s1 + var.a * var.s0; \
67
+ val = (short) var.s0
68
+
69
+ #elif PJMEDIA_TONEGEN_ALG==PJMEDIA_TONEGEN_FIXED_POINT_CORDIC
70
+ /* Cordic algorithm with 28 bit size, from:
71
+ * http://www.dcs.gla.ac.uk/~jhw/cordic/
72
+ * Speed = 742 usec to generate 1 second, 8KHz dual-tones (2.66GHz P4).
73
+ * (PJMEDIA_TONEGEN_FIXED_POINT_CORDIC_LOOP=7)
74
+ * approx. 6.01 MIPS
75
+ *
76
+ * ARM926EJ-S results:
77
+ * loop=7: 8,943 usec/1.77 MIPS
78
+ * loop=8: 9,872 usec/1.95 MIPS
79
+ * loop=10: 11,662 usec/2.31 MIPS
80
+ * loop=12: 13,561 usec/2.69 MIPS
81
+ */
82
+ #define CORDIC_1K 0x026DD3B6
83
+ #define CORDIC_HALF_PI 0x06487ED5
84
+ #define CORDIC_PI (CORDIC_HALF_PI * 2)
85
+ #define CORDIC_MUL_BITS 26
86
+ #define CORDIC_MUL (1 << CORDIC_MUL_BITS)
87
+ #define CORDIC_NTAB 28
88
+ #define CORDIC_LOOP PJMEDIA_TONEGEN_FIXED_POINT_CORDIC_LOOP
89
+
90
+ static int cordic_ctab [] =
91
+ {
92
+ 0x03243F6A, 0x01DAC670, 0x00FADBAF, 0x007F56EA, 0x003FEAB7,
93
+ 0x001FFD55, 0x000FFFAA, 0x0007FFF5, 0x0003FFFE, 0x0001FFFF,
94
+ 0x0000FFFF, 0x00007FFF, 0x00003FFF, 0x00001FFF, 0x00000FFF,
95
+ 0x000007FF, 0x000003FF, 0x000001FF, 0x000000FF, 0x0000007F,
96
+ 0x0000003F, 0x0000001F, 0x0000000F, 0x00000007, 0x00000003,
97
+ 0x00000001, 0x00000000, 0x00000000
98
+ };
99
+
100
+ static pj_int32_t cordic(pj_int32_t theta, unsigned n)
101
+ {
102
+ unsigned k;
103
+ int d;
104
+ pj_int32_t tx;
105
+ pj_int32_t x = CORDIC_1K, y = 0, z = theta;
106
+
107
+ for (k=0; k<n; ++k) {
108
+ #if 0
109
+ d = (z>=0) ? 0 : -1;
110
+ #else
111
+ /* Only slightly (~2.5%) faster, but not portable? */
112
+ d = z>>27;
113
+ #endif
114
+ tx = x - (((y>>k) ^ d) - d);
115
+ y = y + (((x>>k) ^ d) - d);
116
+ z = z - ((cordic_ctab[k] ^ d) - d);
117
+ x = tx;
118
+ }
119
+ return y;
120
+ }
121
+
122
+ /* Note: theta must be uint32 here */
123
+ static pj_int32_t cordic_sin(pj_uint32_t theta, unsigned n)
124
+ {
125
+ if (theta < CORDIC_HALF_PI)
126
+ return cordic(theta, n);
127
+ else if (theta < CORDIC_PI)
128
+ return cordic(CORDIC_HALF_PI-(theta-CORDIC_HALF_PI), n);
129
+ else if (theta < CORDIC_PI + CORDIC_HALF_PI)
130
+ return -cordic(theta - CORDIC_PI, n);
131
+ else if (theta < 2 * CORDIC_PI)
132
+ return -cordic(CORDIC_HALF_PI-(theta-3*CORDIC_HALF_PI), n);
133
+ else {
134
+ pj_assert(!"Invalid cordic_sin() value");
135
+ return 0;
136
+ }
137
+ }
138
+
139
+ struct gen
140
+ {
141
+ unsigned add;
142
+ pj_uint32_t c;
143
+ unsigned vol;
144
+ };
145
+
146
+ #define VOL(var,v) (((v) * var.vol) >> 15)
147
+ #define GEN_INIT(var,R,F,A) gen_init(&var, R, F, A)
148
+ #define GEN_SAMP(val,var) val = gen_samp(&var)
149
+
150
+ static void gen_init(struct gen *var, unsigned R, unsigned F, unsigned A)
151
+ {
152
+ var->add = 2*CORDIC_PI/R * F;
153
+ var->c = 0;
154
+ var->vol = A;
155
+ }
156
+
157
+ PJ_INLINE(short) gen_samp(struct gen *var)
158
+ {
159
+ pj_int32_t val;
160
+ val = cordic_sin(var->c, CORDIC_LOOP);
161
+ /*val = (val * 32767) / CORDIC_MUL;
162
+ *val = VOL((*var), val);
163
+ */
164
+ val = ((val >> 10) * var->vol) >> 16;
165
+ var->c += var->add;
166
+ if (var->c > 2*CORDIC_PI)
167
+ var->c -= (2 * CORDIC_PI);
168
+ return (short) val;
169
+ }
170
+
171
+ #elif PJMEDIA_TONEGEN_ALG==PJMEDIA_TONEGEN_FAST_FIXED_POINT
172
+
173
+ /*
174
+ * Fallback algorithm when floating point is disabled.
175
+ * This is a very fast fixed point tone generation using sine wave
176
+ * approximation from
177
+ * http://www.audiomulch.com/~rossb/code/sinusoids/
178
+ * Quality wise not so good, but it's blazing fast!
179
+ * Speed = 117 usec to generate 1 second, 8KHz dual-tones (2.66GHz P4).
180
+ * approx. 0.95 MIPS
181
+ *
182
+ * 1,449 usec/0.29 MIPS on ARM926EJ-S.
183
+ */
184
+ PJ_INLINE(int) approximate_sin3(unsigned x)
185
+ {
186
+ unsigned s=-(int)(x>>31);
187
+ x+=x;
188
+ x=x>>16;
189
+ x*=x^0xffff; // x=x*(2-x)
190
+ x+=x; // optional
191
+ return x^s;
192
+ }
193
+ struct gen
194
+ {
195
+ unsigned add;
196
+ unsigned c;
197
+ unsigned vol;
198
+ };
199
+
200
+ #define MAXI ((unsigned)0xFFFFFFFF)
201
+ #define SIN approximate_sin3
202
+ #define VOL(var,v) (((v) * var.vol) >> 15)
203
+ #define GEN_INIT(var,R,F,A) var.add = MAXI/R * F, var.c=0, var.vol=A
204
+ #define GEN_SAMP(val,var) val = (short) VOL(var,SIN(var.c)>>16); \
205
+ var.c += var.add
206
+
207
+ #else
208
+ #error "PJMEDIA_TONEGEN_ALG is not set correctly"
209
+ #endif
210
+
211
+ struct gen_state
212
+ {
213
+ struct gen tone1;
214
+ struct gen tone2;
215
+ pj_bool_t has_tone2;
216
+ };
217
+
218
+
219
+ static void init_generate_single_tone(struct gen_state *state,
220
+ unsigned clock_rate,
221
+ unsigned freq,
222
+ unsigned vol)
223
+ {
224
+ GEN_INIT(state->tone1,clock_rate,freq,vol);
225
+ state->has_tone2 = PJ_FALSE;
226
+ }
227
+
228
+ static void generate_single_tone(struct gen_state *state,
229
+ unsigned channel_count,
230
+ unsigned samples,
231
+ short buf[])
232
+ {
233
+ short *end = buf + samples;
234
+
235
+ if (channel_count==1) {
236
+
237
+ while (buf < end) {
238
+ GEN_SAMP(*buf++, state->tone1);
239
+ }
240
+
241
+ } else if (channel_count == 2) {
242
+
243
+ while (buf < end) {
244
+ GEN_SAMP(*buf, state->tone1);
245
+ *(buf+1) = *buf;
246
+ buf += 2;
247
+ }
248
+ }
249
+ }
250
+
251
+
252
+ static void init_generate_dual_tone(struct gen_state *state,
253
+ unsigned clock_rate,
254
+ unsigned freq1,
255
+ unsigned freq2,
256
+ unsigned vol)
257
+ {
258
+ GEN_INIT(state->tone1,clock_rate,freq1,vol);
259
+ GEN_INIT(state->tone2,clock_rate,freq2,vol);
260
+ state->has_tone2 = PJ_TRUE;
261
+ }
262
+
263
+
264
+ static void generate_dual_tone(struct gen_state *state,
265
+ unsigned channel_count,
266
+ unsigned samples,
267
+ short buf[])
268
+ {
269
+ short *end = buf + samples;
270
+
271
+ if (channel_count==1) {
272
+ int val, val2;
273
+ while (buf < end) {
274
+ GEN_SAMP(val, state->tone1);
275
+ GEN_SAMP(val2, state->tone2);
276
+ *buf++ = (short)((val+val2) >> 1);
277
+ }
278
+ } else if (channel_count == 2) {
279
+ int val, val2;
280
+ while (buf < end) {
281
+
282
+ GEN_SAMP(val, state->tone1);
283
+ GEN_SAMP(val2, state->tone2);
284
+ val = (val + val2) >> 1;
285
+
286
+ *buf++ = (short)val;
287
+ *buf++ = (short)val;
288
+ }
289
+ }
290
+ }
291
+
292
+
293
+ static void init_generate_tone(struct gen_state *state,
294
+ unsigned clock_rate,
295
+ unsigned freq1,
296
+ unsigned freq2,
297
+ unsigned vol)
298
+ {
299
+ if (freq2)
300
+ init_generate_dual_tone(state, clock_rate, freq1, freq2 ,vol);
301
+ else
302
+ init_generate_single_tone(state, clock_rate, freq1,vol);
303
+ }
304
+
305
+
306
+ static void generate_tone(struct gen_state *state,
307
+ unsigned channel_count,
308
+ unsigned samples,
309
+ short buf[])
310
+ {
311
+ if (!state->has_tone2)
312
+ generate_single_tone(state, channel_count, samples, buf);
313
+ else
314
+ generate_dual_tone(state, channel_count, samples, buf);
315
+ }
316
+
317
+
318
+ /****************************************************************************/
319
+
320
+ #define SIGNATURE PJMEDIA_SIGNATURE('L', 't', 'o', 'n')
321
+ #define THIS_FILE "chainlink_tonegen.c"
322
+
323
+ #if 0
324
+ # define TRACE_(expr) PJ_LOG(4,expr)
325
+ #else
326
+ # define TRACE_(expr)
327
+ #endif
328
+
329
+ enum flags
330
+ {
331
+ PJMEDIA_TONE_INITIALIZED = 1,
332
+ PJMEDIA_TONE_ENABLE_FADE = 2
333
+ };
334
+
335
+ struct tonegen
336
+ {
337
+ struct chainlink link;
338
+
339
+ /* options */
340
+ unsigned options;
341
+ unsigned playback_options;
342
+ unsigned fade_in_len; /* fade in for this # of samples */
343
+ unsigned fade_out_len; /* fade out for this # of samples*/
344
+
345
+ /* lock */
346
+ pj_lock_t *lock;
347
+
348
+ /* Digit map */
349
+ pjmedia_tone_digit_map *digit_map;
350
+
351
+ /* Tone generation state */
352
+ struct gen_state state;
353
+
354
+ /* Currently played digits: */
355
+ unsigned count; /* # of digits */
356
+ unsigned cur_digit; /* currently played */
357
+ unsigned dig_samples; /* sample pos in cur digit */
358
+ pjmedia_tone_desc digits[PJMEDIA_TONEGEN_MAX_DIGITS];/* array of digits*/
359
+ };
360
+
361
+
362
+ /* Default digit map is DTMF */
363
+ static pjmedia_tone_digit_map digit_map =
364
+ {
365
+ 16,
366
+ {
367
+ { '0', 941, 1336 },
368
+ { '1', 697, 1209 },
369
+ { '2', 697, 1336 },
370
+ { '3', 697, 1477 },
371
+ { '4', 770, 1209 },
372
+ { '5', 770, 1336 },
373
+ { '6', 770, 1477 },
374
+ { '7', 852, 1209 },
375
+ { '8', 852, 1336 },
376
+ { '9', 852, 1477 },
377
+ { 'a', 697, 1633 },
378
+ { 'b', 770, 1633 },
379
+ { 'c', 852, 1633 },
380
+ { 'd', 941, 1633 },
381
+ { '*', 941, 1209 },
382
+ { '#', 941, 1477 },
383
+ }
384
+ };
385
+
386
+
387
+ static pj_status_t tonegen_put_frame(pjmedia_port *this_port,
388
+ pjmedia_frame *frame);
389
+ static pj_status_t tonegen_get_frame(pjmedia_port *this_port,
390
+ pjmedia_frame *frame);
391
+ static pj_status_t tonegen_destroy(pjmedia_port *this_port);
392
+
393
+ /*
394
+ * Create an instance of tone generator with the specified parameters.
395
+ * When the tone generator is first created, it will be loaded with the
396
+ * default digit map.
397
+ */
398
+ PJ_DEF(pj_status_t) chainlink_tonegen_create2(pj_pool_t *pool,
399
+ const pj_str_t *name,
400
+ unsigned clock_rate,
401
+ unsigned channel_count,
402
+ unsigned samples_per_frame,
403
+ unsigned bits_per_sample,
404
+ unsigned options,
405
+ pjmedia_port **p_port)
406
+ {
407
+ const pj_str_t STR_TONE_GEN = pj_str("tonegen");
408
+ struct tonegen *tonegen;
409
+ pj_status_t status;
410
+
411
+ PJ_ASSERT_RETURN(pool && clock_rate && channel_count &&
412
+ samples_per_frame && bits_per_sample == 16 &&
413
+ p_port != NULL, PJ_EINVAL);
414
+
415
+ /* Only support mono and stereo */
416
+ PJ_ASSERT_RETURN(channel_count==1 || channel_count==2, PJ_EINVAL);
417
+
418
+ /* Create and initialize port */
419
+ tonegen = PJ_POOL_ZALLOC_T(pool, struct tonegen);
420
+ if (name == NULL || name->slen == 0) name = &STR_TONE_GEN;
421
+ status = pjmedia_port_info_init(&tonegen->link.port.info, name,
422
+ SIGNATURE, clock_rate, channel_count,
423
+ bits_per_sample, samples_per_frame);
424
+ if (status != PJ_SUCCESS)
425
+ return status;
426
+
427
+ tonegen->options = options;
428
+ tonegen->link.port.put_frame = &tonegen_put_frame;
429
+ tonegen->link.port.get_frame = &tonegen_get_frame;
430
+ tonegen->link.port.on_destroy = &tonegen_destroy;
431
+ tonegen->digit_map = &digit_map;
432
+
433
+ tonegen->fade_in_len = PJMEDIA_TONEGEN_FADE_IN_TIME * clock_rate / 1000;
434
+ tonegen->fade_out_len = PJMEDIA_TONEGEN_FADE_OUT_TIME * clock_rate / 1000;
435
+
436
+ /* Lock */
437
+ if (options & PJMEDIA_TONEGEN_NO_LOCK) {
438
+ status = pj_lock_create_null_mutex(pool, "tonegen", &tonegen->lock);
439
+ } else {
440
+ status = pj_lock_create_simple_mutex(pool, "tonegen", &tonegen->lock);
441
+ }
442
+
443
+ if (status != PJ_SUCCESS) {
444
+ return status;
445
+ }
446
+
447
+ TRACE_((THIS_FILE, "Chainlink_Tonegen created: %u/%u/%u/%u", clock_rate,
448
+ channel_count, samples_per_frame, bits_per_sample));
449
+
450
+ /* Done */
451
+ *p_port = &tonegen->link.port;
452
+ return PJ_SUCCESS;
453
+ }
454
+
455
+
456
+ PJ_DEF(pj_status_t) chainlink_tonegen_create( pj_pool_t *pool,
457
+ unsigned clock_rate,
458
+ unsigned channel_count,
459
+ unsigned samples_per_frame,
460
+ unsigned bits_per_sample,
461
+ unsigned options,
462
+ pjmedia_port **p_port)
463
+ {
464
+ return chainlink_tonegen_create2(pool, NULL, clock_rate, channel_count,
465
+ samples_per_frame, bits_per_sample,
466
+ options, p_port);
467
+ }
468
+
469
+
470
+ /*
471
+ * Check if the tone generator is still busy producing some tones.
472
+ */
473
+ PJ_DEF(pj_bool_t) chainlink_tonegen_is_busy(pjmedia_port *port)
474
+ {
475
+ struct tonegen *tonegen = (struct tonegen*) port;
476
+ PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, PJ_TRUE);
477
+ return tonegen->count != 0;
478
+ }
479
+
480
+
481
+ /*
482
+ * Instruct the tone generator to stop current processing.
483
+ */
484
+ PJ_DEF(pj_status_t) chainlink_tonegen_stop(pjmedia_port *port)
485
+ {
486
+ struct tonegen *tonegen = (struct tonegen*) port;
487
+ PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, PJ_EINVAL);
488
+
489
+ TRACE_((THIS_FILE, "tonegen_stop()"));
490
+
491
+ pj_lock_acquire(tonegen->lock);
492
+ tonegen->count = 0;
493
+ tonegen->cur_digit = 0;
494
+ tonegen->dig_samples = 0;
495
+ pj_lock_release(tonegen->lock);
496
+
497
+ return PJ_SUCCESS;
498
+ }
499
+
500
+
501
+ /*
502
+ * Instruct the tone generator to stop current processing.
503
+ */
504
+ PJ_DEF(pj_status_t) chainlink_tonegen_rewind(pjmedia_port *port)
505
+ {
506
+ struct tonegen *tonegen = (struct tonegen*) port;
507
+ PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, PJ_EINVAL);
508
+
509
+ TRACE_((THIS_FILE, "tonegen_rewind()"));
510
+
511
+ /* Reset back to the first tone */
512
+ pj_lock_acquire(tonegen->lock);
513
+ tonegen->cur_digit = 0;
514
+ tonegen->dig_samples = 0;
515
+ pj_lock_release(tonegen->lock);
516
+
517
+ return PJ_SUCCESS;
518
+ }
519
+
520
+
521
+ /*
522
+ * Callback to destroy tonegen
523
+ */
524
+ static pj_status_t tonegen_destroy(pjmedia_port *port)
525
+ {
526
+ struct tonegen *tonegen = (struct tonegen*) port;
527
+ PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, PJ_EINVAL);
528
+
529
+ TRACE_((THIS_FILE, "tonegen_destroy()"));
530
+
531
+ pj_lock_acquire(tonegen->lock);
532
+ pj_lock_release(tonegen->lock);
533
+
534
+ pj_lock_destroy(tonegen->lock);
535
+
536
+ return PJ_SUCCESS;
537
+ }
538
+
539
+ static pj_status_t tonegen_put_frame(pjmedia_port *this_port,
540
+ pjmedia_frame *frame)
541
+ {
542
+ PJ_ASSERT_RETURN(this_port && frame, PJ_EINVAL);
543
+
544
+ struct chainlink *link = (struct chainlink*)this_port;
545
+ PJ_ASSERT_RETURN(link->next, PJ_EINVAL);
546
+ PJ_ASSERT_RETURN(link->next->put_frame, PJ_EINVAL);
547
+
548
+ return link->next->put_frame(link->next, frame);
549
+ }
550
+
551
+ /*
552
+ * Fill a frame with tones.
553
+ */
554
+ static pj_status_t tonegen_get_frame(pjmedia_port *port,
555
+ pjmedia_frame *frame)
556
+ {
557
+ struct tonegen *tonegen = (struct tonegen*) port;
558
+ short *dst, *end;
559
+ unsigned clock_rate = PJMEDIA_PIA_SRATE(&tonegen->link.port.info);
560
+
561
+ PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, PJ_EINVAL);
562
+
563
+ pj_lock_acquire(tonegen->lock);
564
+
565
+ if (tonegen->count == 0) {
566
+ /* We don't have digits to play */
567
+
568
+ //Let's get the fram from downstream port
569
+ struct chainlink *link = (struct chainlink*)port;
570
+ PJ_ASSERT_RETURN(link->next, PJ_EINVAL);
571
+ PJ_ASSERT_RETURN(link->next->get_frame, PJ_EINVAL);
572
+
573
+ link->next->get_frame(link->next, frame);
574
+
575
+ goto on_return;
576
+ }
577
+
578
+ if (tonegen->cur_digit > tonegen->count) {
579
+ /* We have played all the digits */
580
+ if ((tonegen->options|tonegen->playback_options)&PJMEDIA_TONEGEN_LOOP)
581
+ {
582
+ /* Reset back to the first tone */
583
+ tonegen->cur_digit = 0;
584
+ tonegen->dig_samples = 0;
585
+
586
+ TRACE_((THIS_FILE, "tonegen_get_frame(): rewind"));
587
+
588
+ } else {
589
+ tonegen->count = 0;
590
+ tonegen->cur_digit = 0;
591
+ frame->type = PJMEDIA_FRAME_TYPE_NONE;
592
+ TRACE_((THIS_FILE, "tonegen_get_frame(): no more digit"));
593
+ goto on_return;
594
+ }
595
+ }
596
+
597
+ if (tonegen->dig_samples>=(tonegen->digits[tonegen->cur_digit].on_msec+
598
+ tonegen->digits[tonegen->cur_digit].off_msec)*
599
+ clock_rate / 1000)
600
+ {
601
+ /* We have finished with current digit */
602
+ tonegen->cur_digit++;
603
+ tonegen->dig_samples = 0;
604
+
605
+ TRACE_((THIS_FILE, "tonegen_get_frame(): next digit"));
606
+ }
607
+
608
+ if (tonegen->cur_digit >= tonegen->count) {
609
+ /* After we're finished with the last digit, we have played all
610
+ * the digits
611
+ */
612
+ if ((tonegen->options|tonegen->playback_options)&PJMEDIA_TONEGEN_LOOP)
613
+ {
614
+ /* Reset back to the first tone */
615
+ tonegen->cur_digit = 0;
616
+ tonegen->dig_samples = 0;
617
+
618
+ TRACE_((THIS_FILE, "tonegen_get_frame(): rewind"));
619
+
620
+ } else {
621
+ tonegen->count = 0;
622
+ tonegen->cur_digit = 0;
623
+ frame->type = PJMEDIA_FRAME_TYPE_NONE;
624
+ TRACE_((THIS_FILE, "tonegen_get_frame(): no more digit"));
625
+ goto on_return;
626
+ }
627
+ }
628
+
629
+ dst = (short*) frame->buf;
630
+ end = dst + PJMEDIA_PIA_SPF(&port->info);
631
+
632
+ while (dst < end) {
633
+ pjmedia_tone_desc *dig = &tonegen->digits[tonegen->cur_digit];
634
+ unsigned required, cnt, on_samp, off_samp;
635
+
636
+ required = end - dst;
637
+ on_samp = dig->on_msec * clock_rate / 1000;
638
+ off_samp = dig->off_msec * clock_rate / 1000;
639
+
640
+ /* Init tonegen */
641
+ if (tonegen->dig_samples == 0 &&
642
+ (tonegen->count!=1 || !(dig->flags & PJMEDIA_TONE_INITIALIZED)))
643
+ {
644
+ init_generate_tone(&tonegen->state, PJMEDIA_PIA_SRATE(&port->info),
645
+ dig->freq1, dig->freq2, dig->volume);
646
+ dig->flags |= PJMEDIA_TONE_INITIALIZED;
647
+ if (tonegen->cur_digit > 0) {
648
+ /* Clear initialized flag of previous digit */
649
+ tonegen->digits[tonegen->cur_digit-1].flags &=
650
+ (~PJMEDIA_TONE_INITIALIZED);
651
+ }
652
+ }
653
+
654
+ /* Add tone signal */
655
+ if (tonegen->dig_samples < on_samp) {
656
+ cnt = on_samp - tonegen->dig_samples;
657
+ if (cnt > required)
658
+ cnt = required;
659
+ generate_tone(&tonegen->state, PJMEDIA_PIA_CCNT(&port->info),
660
+ cnt, dst);
661
+
662
+ dst += cnt;
663
+ tonegen->dig_samples += cnt;
664
+ required -= cnt;
665
+
666
+ if ((dig->flags & PJMEDIA_TONE_ENABLE_FADE) &&
667
+ tonegen->dig_samples == cnt)
668
+ {
669
+ /* Fade in */
670
+ short *samp = (dst - cnt);
671
+ short *end;
672
+
673
+ if (cnt > tonegen->fade_in_len)
674
+ cnt = tonegen->fade_in_len;
675
+ end = samp + cnt;
676
+ if (cnt) {
677
+ const unsigned step = 0xFFFF / cnt;
678
+ unsigned scale = 0;
679
+
680
+ for (; samp < end; ++samp) {
681
+ (*samp) = (short)(((*samp) * scale) >> 16);
682
+ scale += step;
683
+ }
684
+ }
685
+ } else if ((dig->flags & PJMEDIA_TONE_ENABLE_FADE) &&
686
+ tonegen->dig_samples==on_samp)
687
+ {
688
+ /* Fade out */
689
+ if (cnt > tonegen->fade_out_len)
690
+ cnt = tonegen->fade_out_len;
691
+ if (cnt) {
692
+ short *samp = (dst - cnt);
693
+ const unsigned step = 0xFFFF / cnt;
694
+ unsigned scale = 0xFFFF - step;
695
+
696
+ for (; samp < dst; ++samp) {
697
+ (*samp) = (short)(((*samp) * scale) >> 16);
698
+ scale -= step;
699
+ }
700
+ }
701
+ }
702
+
703
+ if (dst == end)
704
+ break;
705
+ }
706
+
707
+ /* Add silence signal */
708
+ cnt = off_samp + on_samp - tonegen->dig_samples;
709
+ if (cnt > required)
710
+ cnt = required;
711
+ pjmedia_zero_samples(dst, cnt);
712
+ dst += cnt;
713
+ tonegen->dig_samples += cnt;
714
+
715
+ /* Move to next digit if we're finished with this tone */
716
+ if (tonegen->dig_samples >= on_samp + off_samp) {
717
+ tonegen->cur_digit++;
718
+ tonegen->dig_samples = 0;
719
+
720
+ if (tonegen->cur_digit >= tonegen->count) {
721
+ /* All digits have been played */
722
+ if ((tonegen->options & PJMEDIA_TONEGEN_LOOP) ||
723
+ (tonegen->playback_options & PJMEDIA_TONEGEN_LOOP))
724
+ {
725
+ tonegen->cur_digit = 0;
726
+ } else {
727
+ break;
728
+ }
729
+ }
730
+ }
731
+ }
732
+
733
+ if (dst < end)
734
+ pjmedia_zero_samples(dst, end-dst);
735
+
736
+ frame->type = PJMEDIA_FRAME_TYPE_AUDIO;
737
+ frame->size = PJMEDIA_PIA_AVG_FSZ(&port->info);
738
+
739
+ TRACE_((THIS_FILE, "tonegen_get_frame(): frame created, level=%u",
740
+ pjmedia_calc_avg_signal((pj_int16_t*)frame->buf, frame->size/2)));
741
+
742
+ if (tonegen->cur_digit >= tonegen->count) {
743
+ if ((tonegen->options|tonegen->playback_options)&PJMEDIA_TONEGEN_LOOP)
744
+ {
745
+ /* Reset back to the first tone */
746
+ tonegen->cur_digit = 0;
747
+ tonegen->dig_samples = 0;
748
+
749
+ TRACE_((THIS_FILE, "tonegen_get_frame(): rewind"));
750
+
751
+ } else {
752
+ tonegen->count = 0;
753
+ tonegen->cur_digit = 0;
754
+
755
+ TRACE_((THIS_FILE, "tonegen_get_frame(): no more digit"));
756
+ }
757
+ }
758
+
759
+ on_return:
760
+ pj_lock_release(tonegen->lock);
761
+ return PJ_SUCCESS;
762
+ }
763
+
764
+
765
+ /*
766
+ * Play tones.
767
+ */
768
+ PJ_DEF(pj_status_t) chainlink_tonegen_play( pjmedia_port *port,
769
+ unsigned count,
770
+ const pjmedia_tone_desc tones[],
771
+ unsigned options)
772
+ {
773
+ struct tonegen *tonegen = (struct tonegen*) port;
774
+ unsigned i;
775
+
776
+ PJ_ASSERT_RETURN(port && port->info.signature == SIGNATURE &&
777
+ count && tones, PJ_EINVAL);
778
+
779
+ /* Don't put more than available buffer */
780
+ PJ_ASSERT_RETURN(count+tonegen->count <= PJMEDIA_TONEGEN_MAX_DIGITS,
781
+ PJ_ETOOMANY);
782
+
783
+ pj_lock_acquire(tonegen->lock);
784
+
785
+ /* Set playback options */
786
+ tonegen->playback_options = options;
787
+
788
+ /* Copy digits */
789
+ pj_memcpy(tonegen->digits + tonegen->count,
790
+ tones, count * sizeof(pjmedia_tone_desc));
791
+
792
+ /* Normalize volume, and check if we need to disable fading.
793
+ * Disable fading if tone off time is zero. Application probably
794
+ * wants to play this tone continuously (e.g. dial tone).
795
+ */
796
+ for (i=0; i<count; ++i) {
797
+ pjmedia_tone_desc *t = &tonegen->digits[i+tonegen->count];
798
+ if (t->volume == 0)
799
+ t->volume = AMP;
800
+ else if (t->volume < 0)
801
+ t->volume = (short) -t->volume;
802
+ /* Reset flags */
803
+ t->flags = 0;
804
+ if (t->off_msec != 0)
805
+ t->flags |= PJMEDIA_TONE_ENABLE_FADE;
806
+ }
807
+
808
+ tonegen->count += count;
809
+
810
+ pj_lock_release(tonegen->lock);
811
+
812
+ return PJ_SUCCESS;
813
+ }
814
+
815
+
816
+ /*
817
+ * Play digits.
818
+ */
819
+ PJ_DEF(pj_status_t) chainlink_tonegen_play_digits( pjmedia_port *port,
820
+ unsigned count,
821
+ const pjmedia_tone_digit digits[],
822
+ unsigned options)
823
+ {
824
+ struct tonegen *tonegen = (struct tonegen*) port;
825
+ pjmedia_tone_desc tones[PJMEDIA_TONEGEN_MAX_DIGITS];
826
+ const pjmedia_tone_digit_map *map;
827
+ unsigned i;
828
+
829
+ PJ_ASSERT_RETURN(port && port->info.signature == SIGNATURE &&
830
+ count && digits, PJ_EINVAL);
831
+ PJ_ASSERT_RETURN(count < PJMEDIA_TONEGEN_MAX_DIGITS, PJ_ETOOMANY);
832
+
833
+ pj_lock_acquire(tonegen->lock);
834
+
835
+ map = tonegen->digit_map;
836
+
837
+ for (i=0; i<count; ++i) {
838
+ int d = pj_tolower(digits[i].digit);
839
+ unsigned j;
840
+
841
+ /* Translate ASCII digits with digitmap */
842
+ for (j=0; j<map->count; ++j) {
843
+ if (d == map->digits[j].digit)
844
+ break;
845
+ }
846
+ if (j == map->count) {
847
+ pj_lock_release(tonegen->lock);
848
+ return PJMEDIA_RTP_EINDTMF;
849
+ }
850
+
851
+ tones[i].freq1 = map->digits[j].freq1;
852
+ tones[i].freq2 = map->digits[j].freq2;
853
+ tones[i].on_msec = digits[i].on_msec;
854
+ tones[i].off_msec = digits[i].off_msec;
855
+ tones[i].volume = digits[i].volume;
856
+ }
857
+
858
+ pj_lock_release(tonegen->lock);
859
+
860
+ return chainlink_tonegen_play(port, count, tones, options);
861
+ }
862
+
863
+
864
+ /*
865
+ * Get the digit-map currently used by this tone generator.
866
+ */
867
+ PJ_DEF(pj_status_t) chainlink_tonegen_get_digit_map(pjmedia_port *port,
868
+ const pjmedia_tone_digit_map **m)
869
+ {
870
+ struct tonegen *tonegen = (struct tonegen*) port;
871
+
872
+ PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, PJ_EINVAL);
873
+ PJ_ASSERT_RETURN(m != NULL, PJ_EINVAL);
874
+
875
+ *m = tonegen->digit_map;
876
+
877
+ return PJ_SUCCESS;
878
+ }
879
+
880
+
881
+ /*
882
+ * Set digit map to be used by the tone generator.
883
+ */
884
+ PJ_DEF(pj_status_t) chainlink_tonegen_set_digit_map(pjmedia_port *port,
885
+ pjmedia_tone_digit_map *m)
886
+ {
887
+ struct tonegen *tonegen = (struct tonegen*) port;
888
+
889
+ PJ_ASSERT_RETURN(port->info.signature == SIGNATURE, PJ_EINVAL);
890
+ PJ_ASSERT_RETURN(m != NULL, PJ_EINVAL);
891
+
892
+ pj_lock_acquire(tonegen->lock);
893
+
894
+ tonegen->digit_map = m;
895
+
896
+ pj_lock_release(tonegen->lock);
897
+
898
+ return PJ_SUCCESS;
899
+ }
900
+
901
+