sip-lab 1.28.12 → 1.30.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.
Files changed (47) hide show
  1. package/DEV.md +55 -0
  2. package/README.md +8 -2
  3. package/binding.gyp +1 -0
  4. package/build_deps.sh +2 -1
  5. package/index.js +7 -0
  6. package/package.json +1 -1
  7. package/prebuilds/linux-x64/node.abi102.node +0 -0
  8. package/prebuilds/linux-x64/node.abi108.node +0 -0
  9. package/prebuilds/linux-x64/node.abi111.node +0 -0
  10. package/prebuilds/linux-x64/node.abi115.node +0 -0
  11. package/prebuilds/linux-x64/node.abi120.node +0 -0
  12. package/prebuilds/linux-x64/node.abi88.node +0 -0
  13. package/prebuilds/linux-x64/node.abi93.node +0 -0
  14. package/samples/100_calls.js +4 -0
  15. package/samples/16_audio_streams.js +2 -0
  16. package/samples/183_session_progress.js +2 -0
  17. package/samples/delayed_media.js +2 -0
  18. package/samples/four_audio_streams_two_refused.js +7 -4
  19. package/samples/mrcp_and_audio.simplified_media.js +2 -0
  20. package/samples/multiple_audio_streams.js +2 -0
  21. package/samples/refuse_telephone_event.js +3 -0
  22. package/samples/reinvite_and_dtmf.js +3 -0
  23. package/samples/reinvite_audio_audio.js +2 -0
  24. package/samples/reinvite_with_hold_unhold.js +2 -0
  25. package/samples/rtp_and_srtp.js +3 -0
  26. package/samples/rtp_and_srtp.rtp_refused.js +3 -0
  27. package/samples/send_and_receive_bfsk.js.future +171 -0
  28. package/samples/srtp.js +3 -0
  29. package/samples/tcp.js +2 -0
  30. package/samples/text_to_speech.js +3 -0
  31. package/samples/two_audio_streams.js +4 -0
  32. package/samples/two_audio_streams.port_zero.js +4 -0
  33. package/samples_extra/ws_speech_server.bfsk.js +154 -0
  34. package/samples_extra/ws_speech_server.dtmf.js +5 -21
  35. package/samples_extra/ws_speech_server.google.js +8 -10
  36. package/samples_extra/ws_speech_server.send_bfsk.js +156 -0
  37. package/samples_extra/ws_speech_server.start_bfsk_detection.js.future +164 -0
  38. package/src/addon.cpp +180 -10
  39. package/src/event_templates.cpp +8 -0
  40. package/src/event_templates.hpp +3 -0
  41. package/src/pjmedia/include/pjmedia/bfsk_det.h +23 -0
  42. package/src/pjmedia/include/pjmedia/ws_speech_port.h +1 -0
  43. package/src/pjmedia/src/pjmedia/bfsk_det.c +289 -0
  44. package/src/pjmedia/src/pjmedia/ws_speech_port.cpp +8 -0
  45. package/src/sip.cpp +552 -35
  46. package/src/sip.cpp.old +9236 -0
  47. package/src/sip.hpp +11 -0
package/src/sip.cpp CHANGED
@@ -24,6 +24,7 @@
24
24
  #include "websock.h"
25
25
 
26
26
  #include "dtmfdet.h"
27
+ #include "bfsk_det.h"
27
28
  #include "fax_port.h"
28
29
  #include "flite_port.h"
29
30
  #include "pocketsphinx_port.h"
@@ -266,6 +267,7 @@ int ms_timestamp();
266
267
  bool g_shutting_down;
267
268
 
268
269
  int g_dtmf_inter_digit_timer = 0;
270
+ int g_bfsk_inter_bit_timer = 200;
269
271
 
270
272
  pj_str_t g_sip_ipaddress;
271
273
 
@@ -329,7 +331,8 @@ struct ConfBridgePort {
329
331
  #define FP_FAX 4
330
332
  #define FP_SPEECH_SYNTH 5
331
333
  #define FP_SPEECH_RECOG 6
332
- #define MAX_FP 7
334
+ #define FP_BFSK_DET 7
335
+ #define MAX_FP 8
333
336
 
334
337
  struct AudioEndpoint {
335
338
  pjmedia_transport *med_transport;
@@ -341,6 +344,10 @@ struct AudioEndpoint {
341
344
 
342
345
  pj_str_t mode;
343
346
 
347
+ char BfskBuffer[MAXDIGITS + 1];
348
+ int BfskBufferLength;
349
+ int last_bit_timestamp;
350
+
344
351
  pjmedia_conf *conf;
345
352
  pjmedia_master_port *master_port;
346
353
  pjmedia_port *null_port;
@@ -634,11 +641,12 @@ static void build_stream_stat(ostringstream &oss, pjmedia_rtcp_stat *stat,
634
641
 
635
642
  bool prepare_tonegen(Call *call, AudioEndpoint *ae);
636
643
  bool prepare_dtmfdet(Call *call, AudioEndpoint *ae);
644
+ bool prepare_bfsk_det(Call *call, AudioEndpoint *ae, const int freq_zero, const int freq_one);
637
645
  bool prepare_wav_player(Call *call, AudioEndpoint *ae, const char *file, unsigned flags, bool end_of_file_event);
638
646
  bool prepare_wav_writer(Call *call, AudioEndpoint *ae, const char *file);
639
647
  bool prepare_fax(Call *call, AudioEndpoint *ae, bool is_sender, const char *file, unsigned flags);
640
- bool prepare_speech_synth(Call *call, AudioEndpoint *ae, const char *server_url, const char *engine, const char *voice, const char *language, const char *text, int times);
641
- bool prepare_speech_recog(Call *call, AudioEndpoint *ae, const char *server_url, const char *engine, const char *language);
648
+ bool prepare_speech_synth(Call *call, AudioEndpoint *ae, const char *server_url, const char *uuid, const char *engine, const char *voice, const char *language, const char *text, int times);
649
+ bool prepare_speech_recog(Call *call, AudioEndpoint *ae, const char *server_url, const char *uuid, const char *engine, const char *language);
642
650
 
643
651
  void prepare_error_event(ostringstream *oss, char *scope, char *details);
644
652
  // void prepare_pjsipcall_error_event(ostringstream *oss, char *scope, char
@@ -659,6 +667,7 @@ pj_status_t audio_endpoint_stop_record_wav(Call *call, AudioEndpoint *ae);
659
667
  pj_status_t audio_endpoint_stop_fax(Call *call, AudioEndpoint *ae);
660
668
  pj_status_t audio_endpoint_stop_speech_synth(Call *call, AudioEndpoint *ae);
661
669
  pj_status_t audio_endpoint_stop_speech_recog(Call *call, AudioEndpoint *ae);
670
+ pj_status_t audio_endpoint_stop_inband_dtmf_detection(Call *call, AudioEndpoint *ae);
662
671
 
663
672
  static pjsip_module mod_tester = {
664
673
  NULL,
@@ -791,13 +800,13 @@ pj_status_t create_audio_endpoint_conf(Call *call, AudioEndpoint *ae, pjmedia_po
791
800
  return PJ_SUCCESS;
792
801
  }
793
802
 
794
- static int find_endpoint_by_inband_dtmf_media_port(Call *call,
795
- pjmedia_port *port) {
803
+ static int find_endpoint_by_media_port(Call *call,
804
+ pjmedia_port *port, int type) {
796
805
  for (int i = 0; i < call->media_count; i++) {
797
806
  MediaEndpoint *me = (MediaEndpoint *)call->media[i];
798
807
  if (ENDPOINT_TYPE_AUDIO == me->type) {
799
808
  AudioEndpoint *ae = (AudioEndpoint *)me->endpoint.audio;
800
- if (ae->feature_cbps[FP_DTMFDET].port && (pjmedia_port *)ae->feature_cbps[FP_DTMFDET].port == port) {
809
+ if (ae->feature_cbps[type].port && (pjmedia_port *)ae->feature_cbps[type].port == port) {
801
810
  return i;
802
811
  }
803
812
  }
@@ -825,7 +834,7 @@ static void on_inband_dtmf(pjmedia_port *port, void *user_data, char digit) {
825
834
 
826
835
  Call *call = (Call *)user_data;
827
836
 
828
- int media_id = find_endpoint_by_inband_dtmf_media_port(call, port);
837
+ int media_id = find_endpoint_by_media_port(call, port, FP_DTMFDET);
829
838
  assert(media_id >= 0);
830
839
 
831
840
  MediaEndpoint *me = (MediaEndpoint *)call->media[media_id];
@@ -855,6 +864,53 @@ static void on_inband_dtmf(pjmedia_port *port, void *user_data, char digit) {
855
864
  }
856
865
  }
857
866
 
867
+ static void on_bfsk_bit(pjmedia_port *port, void *user_data, int bit) {
868
+ printf("on_bfsk_bit: %i\n", bit);
869
+
870
+ if (g_shutting_down)
871
+ return;
872
+
873
+ long call_id;
874
+ if (!g_call_ids.get_id((long)user_data, call_id)) {
875
+ addon_log(
876
+ L_DBG,
877
+ "on_bfsk_bit: Failed to get call_id. Event will not be notified.\n");
878
+ return;
879
+ }
880
+
881
+ Call *call = (Call *)user_data;
882
+
883
+ int media_id = find_endpoint_by_media_port(call, port, FP_BFSK_DET);
884
+ assert(media_id >= 0);
885
+
886
+ MediaEndpoint *me = (MediaEndpoint *)call->media[media_id];
887
+ AudioEndpoint *ae = (AudioEndpoint *)me->endpoint.audio;
888
+
889
+ if (g_bfsk_inter_bit_timer) {
890
+
891
+ PJW_LOCK();
892
+ int len = ae->BfskBufferLength;
893
+
894
+ if (len > MAXDIGITS) {
895
+ PJW_UNLOCK();
896
+ addon_log(L_DBG, "No more space for bits in bfsk buffer\n");
897
+ return;
898
+ }
899
+
900
+ ae->BfskBuffer[len] = bit == 0 ? '0' : '1';
901
+ ae->BfskBufferLength++;
902
+
903
+ ae->last_bit_timestamp = ms_timestamp();
904
+ PJW_UNLOCK();
905
+ } else {
906
+ char evt[1024];
907
+ char the_bit[1];
908
+ the_bit[0] = bit == 0 ? '0' : '1';
909
+ make_evt_bfsk(evt, sizeof(evt), call_id, 1, the_bit, media_id);
910
+ dispatch_event(evt);
911
+ }
912
+ }
913
+
858
914
  static void on_fax_result(pjmedia_port *port, void *user_data, int result) {
859
915
  if (g_shutting_down)
860
916
  return;
@@ -1401,11 +1457,13 @@ int __pjw_init() {
1401
1457
  return 1;
1402
1458
  }
1403
1459
 
1460
+ /*
1404
1461
  status = pjsip_replaces_init_module(g_sip_endpt);
1405
1462
  if (status != PJ_SUCCESS) {
1406
1463
  addon_log(L_DBG, "pjsip_replaces_init_module failed\n");
1407
1464
  return 1;
1408
1465
  }
1466
+ */
1409
1467
 
1410
1468
  pjsip_inv_callback inv_cb;
1411
1469
  pj_bzero(&inv_cb, sizeof(inv_cb));
@@ -2367,6 +2425,8 @@ int pjw_call_respond(long call_id, const char *json) {
2367
2425
 
2368
2426
  if (code >= 200 && code < 300) {
2369
2427
  call->pending_request = -1;
2428
+
2429
+ pjsip_msg_find_remove_hdr(tdata->msg, PJSIP_H_SUPPORTED, NULL);
2370
2430
  }
2371
2431
  }
2372
2432
  } else {
@@ -2390,6 +2450,9 @@ int pjw_call_respond(long call_id, const char *json) {
2390
2450
 
2391
2451
  if (code >= 200 && code < 300) {
2392
2452
  call->pending_request = -1;
2453
+
2454
+ pjsip_msg *msg = tdata->msg;
2455
+ pjsip_msg_find_remove_hdr(msg, PJSIP_H_SUPPORTED, NULL);
2393
2456
  }
2394
2457
  }
2395
2458
 
@@ -3193,6 +3256,8 @@ int call_create(Transport *t, unsigned flags, pjsip_dialog *dlg,
3193
3256
  }
3194
3257
  addon_log(L_DBG, "inv=%p tdata=%p\n", (void*)inv, (void*)tdata);
3195
3258
 
3259
+ pjsip_msg_find_remove_hdr(tdata->msg, PJSIP_H_SUPPORTED, NULL);
3260
+
3196
3261
  status = pjsip_inv_send_msg(inv, tdata);
3197
3262
  addon_log(L_DBG, "status=%d\n", status);
3198
3263
  if (status != PJ_SUCCESS) {
@@ -3413,6 +3478,176 @@ out:
3413
3478
  return 0;
3414
3479
  }
3415
3480
 
3481
+ pj_status_t audio_endpoint_send_bfsk(Call *call, AudioEndpoint *ae,
3482
+ const char *bits, const int freq_zero, const int freq_one, const int level, const int signal_duration) {
3483
+ pj_status_t status;
3484
+
3485
+ if (!prepare_tonegen(call, ae)) {
3486
+ set_error("prepare_tonegen failed.");
3487
+ return -1;
3488
+ }
3489
+
3490
+ int len = strlen(bits);
3491
+
3492
+ pjmedia_tone_desc *tones = (pjmedia_tone_desc*)pj_pool_zalloc(call->inv->pool, sizeof(pjmedia_tone_desc) * len);
3493
+
3494
+ for (int i = 0; i < len; ++i) {
3495
+ tones[i].freq1 = bits[i] == '0' ? freq_zero : freq_one;
3496
+ tones[i].on_msec = signal_duration;
3497
+ tones[i].off_msec = signal_duration;
3498
+ tones[i].volume = level;
3499
+ }
3500
+
3501
+ status = pjmedia_tonegen_play((pjmedia_port *)ae->feature_cbps[FP_TONEGEN].port, len, tones, 0);
3502
+ if (status != PJ_SUCCESS) {
3503
+ set_error("pjmedia_tonegen_plays failed.");
3504
+ return status;
3505
+ }
3506
+
3507
+ return PJ_SUCCESS;
3508
+ }
3509
+
3510
+ pj_status_t send_bfsk(Call *call, const char *bits, const int freq_zero, const int freq_one, const int level, const int signal_duration) {
3511
+ for (int i = 0; i < call->media_count; i++) {
3512
+ MediaEndpoint *me = (MediaEndpoint *)call->media[i];
3513
+ if (me->type != ENDPOINT_TYPE_AUDIO)
3514
+ continue;
3515
+
3516
+ if(me->port == 0)
3517
+ continue;
3518
+
3519
+ AudioEndpoint *ae = (AudioEndpoint *)me->endpoint.audio;
3520
+
3521
+ pj_status_t status = audio_endpoint_send_bfsk(call, ae, bits, freq_zero, freq_one, level, signal_duration);
3522
+ if (status != PJ_SUCCESS)
3523
+ return status;
3524
+ }
3525
+
3526
+ return PJ_SUCCESS;
3527
+ }
3528
+
3529
+ int pjw_call_send_bfsk(long call_id, const char *json) {
3530
+ #define BITS_MAX_LEN 32 // pjmedia_tonegen limit
3531
+
3532
+ PJW_LOCK();
3533
+ clear_error();
3534
+
3535
+ Call *call;
3536
+
3537
+ pj_status_t status;
3538
+
3539
+ long val;
3540
+
3541
+ int len;
3542
+
3543
+ char *bits;
3544
+ int freq_zero;
3545
+ int freq_one;
3546
+ int level = 24000;
3547
+ int signal_duration = 10;
3548
+
3549
+ MediaEndpoint *me;
3550
+ AudioEndpoint *ae;
3551
+ int res;
3552
+
3553
+ int media_id = -1;
3554
+
3555
+ char buffer[MAX_JSON_INPUT];
3556
+
3557
+ Document document;
3558
+
3559
+ const char *valid_params[] = {"bits", "freq_zero", "freq_one", "level", "signal_duration", "media_id", ""};
3560
+
3561
+ if (!g_call_ids.get(call_id, val)) {
3562
+ set_error("Invalid call_id");
3563
+ goto out;
3564
+ }
3565
+ call = (Call *)val;
3566
+
3567
+ if (!parse_json(document, json, buffer, MAX_JSON_INPUT)) {
3568
+ goto out;
3569
+ }
3570
+
3571
+ if (!validate_params(document, valid_params)) {
3572
+ goto out;
3573
+ }
3574
+
3575
+ if (json_get_string_param(document, "bits", false, &bits) <= 0) {
3576
+ goto out;
3577
+ }
3578
+
3579
+ if (json_get_int_param(document, "freq_zero", false, &freq_zero) <= 0) {
3580
+ goto out;
3581
+ }
3582
+
3583
+ if (json_get_int_param(document, "freq_one", false, &freq_one) <= 0) {
3584
+ goto out;
3585
+ }
3586
+
3587
+ if (json_get_int_param(document, "level", true, &level) <= 0) {
3588
+ goto out;
3589
+ }
3590
+
3591
+ if (json_get_int_param(document, "signal_duration", true, &signal_duration) <= 0) {
3592
+ goto out;
3593
+ }
3594
+
3595
+ len = strlen(bits);
3596
+
3597
+ if (len > BITS_MAX_LEN) {
3598
+ set_error("bits too long");
3599
+ goto out;
3600
+ }
3601
+
3602
+ for (int i = 0; i < len; ++i) {
3603
+ if (bits[i] != '0' && bits[i] != '1') {
3604
+ set_error("Invalid character");
3605
+ goto out;
3606
+ }
3607
+ }
3608
+
3609
+ res = json_get_int_param(document, "media_id", true, &media_id);
3610
+ if (res <= 0) {
3611
+ goto out;
3612
+ }
3613
+
3614
+ if (NOT_FOUND_OPTIONAL == res) {
3615
+ // send_bfsk_bits to all audio endpoints
3616
+ status = send_bfsk(call, bits, freq_zero, freq_one, level, signal_duration);
3617
+ if (status != PJ_SUCCESS) {
3618
+ goto out;
3619
+ }
3620
+ } else {
3621
+ // send_bfsk_bits to specified media_id
3622
+
3623
+ if (media_id >= call->media_count) {
3624
+ set_error("invalid media_id");
3625
+ goto out;
3626
+ }
3627
+
3628
+ me = (MediaEndpoint *)call->media[media_id];
3629
+ if (ENDPOINT_TYPE_AUDIO != me->type) {
3630
+ set_error("invalid media_id non audio");
3631
+ goto out;
3632
+ }
3633
+
3634
+ ae = (AudioEndpoint *)me->endpoint.audio;
3635
+
3636
+ status = audio_endpoint_send_bfsk(call, ae, bits, freq_one, freq_zero, level, signal_duration);
3637
+ if (status != PJ_SUCCESS) {
3638
+ goto out;
3639
+ }
3640
+ }
3641
+
3642
+ out:
3643
+ PJW_UNLOCK();
3644
+ if (pjw_errorstring[0]) {
3645
+ return -1;
3646
+ }
3647
+
3648
+ return 0;
3649
+ }
3650
+
3416
3651
  pj_status_t audio_endpoint_remove_port(Call *call, AudioEndpoint *ae, ConfBridgePort *cbp) {
3417
3652
  printf("audio_endpoint_remove_port\n");
3418
3653
  pj_status_t status;
@@ -3531,6 +3766,8 @@ int pjw_call_reinvite(long call_id, const char *json) {
3531
3766
  goto out;
3532
3767
  }
3533
3768
 
3769
+ pjsip_msg_find_remove_hdr(tdata->msg, PJSIP_H_SUPPORTED, NULL);
3770
+
3534
3771
  status = pjsip_inv_send_msg(call->inv, tdata);
3535
3772
  if (status != PJ_SUCCESS) {
3536
3773
  set_error("pjsip_inv_send_msg failed");
@@ -3943,7 +4180,7 @@ out:
3943
4180
  return 0;
3944
4181
  }
3945
4182
 
3946
- pj_status_t audio_endpoint_start_speech_synth(Call *call, AudioEndpoint *ae, const char *server_url, const char *engine, const char *voice, const char *language, const char *text, int times) {
4183
+ pj_status_t audio_endpoint_start_speech_synth(Call *call, AudioEndpoint *ae, const char *server_url, const char *uuid, const char *engine, const char *voice, const char *language, const char *text, int times) {
3947
4184
  pj_status_t status;
3948
4185
 
3949
4186
  if(!ae->stream_cbp.port) {
@@ -3957,7 +4194,7 @@ pj_status_t audio_endpoint_start_speech_synth(Call *call, AudioEndpoint *ae, con
3957
4194
  return -1;
3958
4195
  }
3959
4196
 
3960
- if (!prepare_speech_synth(call, ae, server_url, engine, voice, language, text, times)) {
4197
+ if (!prepare_speech_synth(call, ae, server_url, uuid, engine, voice, language, text, times)) {
3961
4198
  return -1;
3962
4199
  }
3963
4200
 
@@ -4076,13 +4313,16 @@ int pjw_call_start_speech_synth(long call_id, const char *json) {
4076
4313
  }
4077
4314
  }
4078
4315
 
4316
+ char uuid[1024];
4317
+ sprintf(uuid, "%.*s", call->inv->dlg->call_id->id.slen, call->inv->dlg->call_id->id.ptr);
4318
+
4079
4319
  if (NOT_FOUND_OPTIONAL == res) {
4080
4320
  // start on all audio media endpoints
4081
4321
  for (int i = 0; i < call->media_count; i++) {
4082
4322
  MediaEndpoint *me = (MediaEndpoint *)call->media[i];
4083
4323
  if (me->type == ENDPOINT_TYPE_AUDIO) {
4084
4324
  AudioEndpoint *ae = (AudioEndpoint *)me->endpoint.audio;
4085
- status = audio_endpoint_start_speech_synth(call, ae, server_url, engine, voice, language, text, times);
4325
+ status = audio_endpoint_start_speech_synth(call, ae, server_url, uuid, engine, voice, language, text, times);
4086
4326
  if (status != PJ_SUCCESS) goto out;
4087
4327
  }
4088
4328
  }
@@ -4100,7 +4340,7 @@ int pjw_call_start_speech_synth(long call_id, const char *json) {
4100
4340
 
4101
4341
  ae = (AudioEndpoint *)me->endpoint.audio;
4102
4342
 
4103
- audio_endpoint_start_speech_synth(call, ae, server_url, engine, voice, language, text, times);
4343
+ audio_endpoint_start_speech_synth(call, ae, server_url, uuid, engine, voice, language, text, times);
4104
4344
  }
4105
4345
 
4106
4346
  out:
@@ -4112,7 +4352,7 @@ out:
4112
4352
  return 0;
4113
4353
  }
4114
4354
 
4115
- pj_status_t audio_endpoint_start_speech_recog(Call *call, AudioEndpoint *ae, const char *server_url, const char *engine, const char *language) {
4355
+ pj_status_t audio_endpoint_start_speech_recog(Call *call, AudioEndpoint *ae, const char *server_url, const char *uuid, const char *engine, const char *language) {
4116
4356
  pj_status_t status;
4117
4357
 
4118
4358
  if(!ae->stream_cbp.port) {
@@ -4126,7 +4366,7 @@ pj_status_t audio_endpoint_start_speech_recog(Call *call, AudioEndpoint *ae, con
4126
4366
  return -1;
4127
4367
  }
4128
4368
 
4129
- if (!prepare_speech_recog(call, ae, server_url, engine, language)) {
4369
+ if (!prepare_speech_recog(call, ae, server_url, uuid, engine, language)) {
4130
4370
  return -1;
4131
4371
  }
4132
4372
 
@@ -4217,13 +4457,16 @@ int pjw_call_start_speech_recog(long call_id, const char *json) {
4217
4457
  }
4218
4458
  }
4219
4459
 
4460
+ char uuid[1024];
4461
+ sprintf(uuid, "%.*s", call->inv->dlg->call_id->id.slen, call->inv->dlg->call_id->id.ptr);
4462
+
4220
4463
  if (NOT_FOUND_OPTIONAL == res) {
4221
4464
  // start on all audio media endpoints
4222
4465
  for (int i = 0; i < call->media_count; i++) {
4223
4466
  MediaEndpoint *me = (MediaEndpoint *)call->media[i];
4224
4467
  if (me->type == ENDPOINT_TYPE_AUDIO) {
4225
4468
  AudioEndpoint *ae = (AudioEndpoint *)me->endpoint.audio;
4226
- status = audio_endpoint_start_speech_recog(call, ae, server_url, engine, language);
4469
+ status = audio_endpoint_start_speech_recog(call, ae, server_url, uuid, engine, language);
4227
4470
  if (status != PJ_SUCCESS) goto out;
4228
4471
  }
4229
4472
  }
@@ -4241,7 +4484,218 @@ int pjw_call_start_speech_recog(long call_id, const char *json) {
4241
4484
 
4242
4485
  ae = (AudioEndpoint *)me->endpoint.audio;
4243
4486
 
4244
- audio_endpoint_start_speech_recog(call, ae, server_url, engine, language);
4487
+ audio_endpoint_start_speech_recog(call, ae, server_url, uuid, engine, language);
4488
+ }
4489
+
4490
+ out:
4491
+ PJW_UNLOCK();
4492
+ if (pjw_errorstring[0]) {
4493
+ return -1;
4494
+ }
4495
+
4496
+ return 0;
4497
+ }
4498
+
4499
+ pj_status_t audio_endpoint_start_inband_dtmf_detection(Call *call, AudioEndpoint *ae) {
4500
+ pj_status_t status;
4501
+
4502
+ if(!ae->stream_cbp.port) {
4503
+ set_error("stream port is not ready yet");
4504
+ return -1;
4505
+ }
4506
+
4507
+ if(!prepare_dtmfdet(call, ae)) {
4508
+ return -1;
4509
+ }
4510
+
4511
+ return PJ_SUCCESS;
4512
+ }
4513
+
4514
+ int pjw_call_start_inband_dtmf_detection(long call_id, const char *json) {
4515
+ printf("pjw_call_start_inband_dtmf_detection\n");
4516
+ PJW_LOCK();
4517
+ clear_error();
4518
+
4519
+ long val;
4520
+ Call *call;
4521
+
4522
+ pj_status_t status;
4523
+
4524
+ MediaEndpoint *me;
4525
+ AudioEndpoint *ae;
4526
+ int ae_count;
4527
+ int res;
4528
+
4529
+ int media_id = -1;
4530
+
4531
+ char buffer[MAX_JSON_INPUT];
4532
+
4533
+ Document document;
4534
+
4535
+ const char *valid_params[] = {"media_id", ""};
4536
+
4537
+ if (!g_call_ids.get(call_id, val)) {
4538
+ set_error("Invalid call_id");
4539
+ goto out;
4540
+ }
4541
+ call = (Call *)val;
4542
+
4543
+ ae_count = count_media_by_type(call, ENDPOINT_TYPE_AUDIO);
4544
+
4545
+ if (ae_count == 0) {
4546
+ set_error("No audio endpoint");
4547
+ goto out;
4548
+ }
4549
+
4550
+ if (!parse_json(document, json, buffer, MAX_JSON_INPUT)) {
4551
+ goto out;
4552
+ }
4553
+
4554
+ if (!validate_params(document, valid_params)) {
4555
+ goto out;
4556
+ }
4557
+
4558
+ res = json_get_int_param(document, "media_id", true, &media_id);
4559
+ if (res <= 0) {
4560
+ goto out;
4561
+ }
4562
+
4563
+ if (NOT_FOUND_OPTIONAL == res) {
4564
+ for (int i = 0; i < call->media_count; i++) {
4565
+ MediaEndpoint *me = (MediaEndpoint *)call->media[i];
4566
+ if (me->type == ENDPOINT_TYPE_AUDIO) {
4567
+ AudioEndpoint *ae = (AudioEndpoint *)me->endpoint.audio;
4568
+ status = audio_endpoint_start_inband_dtmf_detection(call, ae);
4569
+ if (status != PJ_SUCCESS) goto out;
4570
+ }
4571
+ }
4572
+ } else {
4573
+ if ((int)media_id >= call->media_count) {
4574
+ set_error("invalid media_id");
4575
+ goto out;
4576
+ }
4577
+
4578
+ me = (MediaEndpoint *)call->media[media_id];
4579
+ if (ENDPOINT_TYPE_AUDIO != me->type) {
4580
+ set_error("media_endpoint is not audio endpoint");
4581
+ goto out;
4582
+ }
4583
+
4584
+ ae = (AudioEndpoint *)me->endpoint.audio;
4585
+
4586
+ audio_endpoint_start_inband_dtmf_detection(call, ae);
4587
+ }
4588
+
4589
+ out:
4590
+ PJW_UNLOCK();
4591
+ if (pjw_errorstring[0]) {
4592
+ return -1;
4593
+ }
4594
+
4595
+ return 0;
4596
+ }
4597
+
4598
+ pj_status_t audio_endpoint_start_bfsk_detection(Call *call, AudioEndpoint *ae, const int freq_zero, const int freq_one) {
4599
+ pj_status_t status;
4600
+
4601
+ if(!ae->stream_cbp.port) {
4602
+ set_error("stream port is not ready yet");
4603
+ return -1;
4604
+ }
4605
+
4606
+ if(!prepare_bfsk_det(call, ae, freq_zero, freq_one)) {
4607
+ return -1;
4608
+ }
4609
+
4610
+ return PJ_SUCCESS;
4611
+ }
4612
+
4613
+ int pjw_call_start_bfsk_detection(long call_id, const char *json) {
4614
+ printf("pjw_call_start_bfsk_detection\n");
4615
+ PJW_LOCK();
4616
+ clear_error();
4617
+
4618
+ long val;
4619
+ Call *call;
4620
+
4621
+ pj_status_t status;
4622
+
4623
+ MediaEndpoint *me;
4624
+ AudioEndpoint *ae;
4625
+ int ae_count;
4626
+ int res;
4627
+
4628
+ int media_id = -1;
4629
+
4630
+ int freq_zero;
4631
+ int freq_one;
4632
+
4633
+ char buffer[MAX_JSON_INPUT];
4634
+
4635
+ Document document;
4636
+
4637
+ const char *valid_params[] = {"freq_zero", "freq_one", "media_id", ""};
4638
+
4639
+ if (!g_call_ids.get(call_id, val)) {
4640
+ set_error("Invalid call_id");
4641
+ goto out;
4642
+ }
4643
+ call = (Call *)val;
4644
+
4645
+ ae_count = count_media_by_type(call, ENDPOINT_TYPE_AUDIO);
4646
+
4647
+ if (ae_count == 0) {
4648
+ set_error("No audio endpoint");
4649
+ goto out;
4650
+ }
4651
+
4652
+ if (!parse_json(document, json, buffer, MAX_JSON_INPUT)) {
4653
+ goto out;
4654
+ }
4655
+
4656
+ if (!validate_params(document, valid_params)) {
4657
+ goto out;
4658
+ }
4659
+
4660
+ res = json_get_int_param(document, "freq_zero", false, &freq_zero);
4661
+ if (res <= 0) {
4662
+ goto out;
4663
+ }
4664
+
4665
+ res = json_get_int_param(document, "freq_one", false, &freq_one);
4666
+ if (res <= 0) {
4667
+ goto out;
4668
+ }
4669
+
4670
+ res = json_get_int_param(document, "media_id", true, &media_id);
4671
+ if (res <= 0) {
4672
+ goto out;
4673
+ }
4674
+
4675
+ if (NOT_FOUND_OPTIONAL == res) {
4676
+ for (int i = 0; i < call->media_count; i++) {
4677
+ MediaEndpoint *me = (MediaEndpoint *)call->media[i];
4678
+ if (me->type == ENDPOINT_TYPE_AUDIO) {
4679
+ AudioEndpoint *ae = (AudioEndpoint *)me->endpoint.audio;
4680
+ status = audio_endpoint_start_bfsk_detection(call, ae, freq_zero, freq_one);
4681
+ if (status != PJ_SUCCESS) goto out;
4682
+ }
4683
+ }
4684
+ } else {
4685
+ if ((int)media_id >= call->media_count) {
4686
+ set_error("invalid media_id");
4687
+ goto out;
4688
+ }
4689
+
4690
+ me = (MediaEndpoint *)call->media[media_id];
4691
+ if (ENDPOINT_TYPE_AUDIO != me->type) {
4692
+ set_error("media_endpoint is not audio endpoint");
4693
+ goto out;
4694
+ }
4695
+
4696
+ ae = (AudioEndpoint *)me->endpoint.audio;
4697
+
4698
+ audio_endpoint_start_bfsk_detection(call, ae, freq_zero, freq_one);
4245
4699
  }
4246
4700
 
4247
4701
  out:
@@ -4274,6 +4728,7 @@ pj_status_t call_stop_op_on_all_audio_endpoints(Call *call,
4274
4728
  return PJ_SUCCESS;
4275
4729
  }
4276
4730
 
4731
+
4277
4732
  int audio_endpoint_stop_op(long call_id, const char *json, audio_endpoint_stop_op_t op) {
4278
4733
  PJW_LOCK();
4279
4734
  clear_error();
@@ -4362,6 +4817,14 @@ pj_status_t audio_endpoint_stop_speech_recog(Call *call, AudioEndpoint *ae) {
4362
4817
  return audio_endpoint_remove_port(call, ae, &ae->feature_cbps[FP_SPEECH_RECOG]);
4363
4818
  }
4364
4819
 
4820
+ pj_status_t audio_endpoint_stop_inband_dtmf_detection(Call *call, AudioEndpoint *ae) {
4821
+ return audio_endpoint_remove_port(call, ae, &ae->feature_cbps[FP_DTMFDET]);
4822
+ }
4823
+
4824
+ pj_status_t audio_endpoint_stop_bfsk_detection(Call *call, AudioEndpoint *ae) {
4825
+ return audio_endpoint_remove_port(call, ae, &ae->feature_cbps[FP_BFSK_DET]);
4826
+ }
4827
+
4365
4828
 
4366
4829
  int pjw_call_stop_play_wav(long call_id, const char *json) {
4367
4830
  return audio_endpoint_stop_op(call_id, json, audio_endpoint_stop_play_wav);
@@ -4383,6 +4846,11 @@ int pjw_call_stop_speech_recog(long call_id, const char *json) {
4383
4846
  return audio_endpoint_stop_op(call_id, json, audio_endpoint_stop_speech_recog);
4384
4847
  }
4385
4848
 
4849
+ int pjw_call_stop_inband_dtmf_detection(long call_id, const char *json) {
4850
+ return audio_endpoint_stop_op(call_id, json, audio_endpoint_stop_inband_dtmf_detection);
4851
+ }
4852
+
4853
+
4386
4854
 
4387
4855
  int pjw_call_start_fax(long call_id, const char *json) {
4388
4856
  PJW_LOCK();
@@ -5030,14 +5498,6 @@ bool restart_media_stream(Call *call, MediaEndpoint *me,
5030
5498
  dispatch_event(evt);
5031
5499
  return false;
5032
5500
  }
5033
-
5034
- // we always add dtmfdet to audio endpoints
5035
- if(!prepare_dtmfdet(call, ae)) {
5036
- make_evt_media_update(evt, sizeof(evt), call->id,
5037
- "setup_failed (prepare_dtmfdet failed)", "");
5038
- dispatch_event(evt);
5039
- return false;
5040
- }
5041
5501
  } else if(
5042
5502
  (PJMEDIA_PIA_SRATE(&old_port->info) != PJMEDIA_PIA_SRATE(&new_port->info)) ||
5043
5503
  (PJMEDIA_PIA_CCNT(&old_port->info) != PJMEDIA_PIA_CCNT(&new_port->info)) ||
@@ -5065,14 +5525,6 @@ bool restart_media_stream(Call *call, MediaEndpoint *me,
5065
5525
  return false;
5066
5526
  }
5067
5527
 
5068
- // we always add dtmfdet to audio endpoints
5069
- if(!prepare_dtmfdet(call, ae)) {
5070
- make_evt_media_update(evt, sizeof(evt), call->id,
5071
- "setup_failed (prepare_dtmfdet failed)", "");
5072
- dispatch_event(evt);
5073
- return false;
5074
- }
5075
-
5076
5528
  // at this point we could try to recreate ports (see #91)
5077
5529
  } else {
5078
5530
  printf("call_id=%i restart_media_stream: stream characteristics no change\n", call->id);
@@ -7006,10 +7458,16 @@ bool prepare_wav_writer(Call *call, AudioEndpoint *ae, const char *file) {
7006
7458
  }
7007
7459
 
7008
7460
  bool prepare_dtmfdet(Call *call, AudioEndpoint *ae) {
7461
+ printf("DEBUG prepare_dtmfdet\n");
7009
7462
  pj_status_t status;
7010
7463
 
7011
7464
  ConfBridgePort *fp = &ae->feature_cbps[FP_DTMFDET];
7012
7465
 
7466
+ if(fp->port) {
7467
+ printf("already prepared\n");
7468
+ return true;
7469
+ }
7470
+
7013
7471
  status = pjmedia_dtmfdet_create(
7014
7472
  call->inv->pool,
7015
7473
  PJMEDIA_PIA_SRATE(&ae->stream_cbp.port->info),
@@ -7033,6 +7491,41 @@ bool prepare_dtmfdet(Call *call, AudioEndpoint *ae) {
7033
7491
  return connect_feature_port_to_stream_port(call, ae, fp);
7034
7492
  }
7035
7493
 
7494
+ bool prepare_bfsk_det(Call *call, AudioEndpoint *ae, const int freq_zero, const int freq_one) {
7495
+ printf("DEBUG prepare_bfsk_det\n");
7496
+ pj_status_t status;
7497
+
7498
+ ConfBridgePort *fp = &ae->feature_cbps[FP_BFSK_DET];
7499
+
7500
+ if(fp->port) {
7501
+ printf("already prepared\n");
7502
+ return true;
7503
+ }
7504
+
7505
+ status = pjmedia_bfsk_det_create(
7506
+ call->inv->pool,
7507
+ PJMEDIA_PIA_SRATE(&ae->stream_cbp.port->info),
7508
+ PJMEDIA_PIA_CCNT(&ae->stream_cbp.port->info),
7509
+ PJMEDIA_PIA_SPF(&ae->stream_cbp.port->info),
7510
+ PJMEDIA_PIA_BITS(&ae->stream_cbp.port->info),
7511
+ on_bfsk_bit, call, freq_zero, freq_one, &fp->port);
7512
+ if (status != PJ_SUCCESS) {
7513
+ set_error("pjmedia_bfsk_det_create failed");
7514
+ return false;
7515
+ }
7516
+
7517
+ status = pjmedia_conf_add_port(ae->conf, call->inv->pool, fp->port, NULL, &fp->slot);
7518
+ if (status != PJ_SUCCESS) {
7519
+ set_error("pjmedia_conf_add_port failed");
7520
+ return false;
7521
+ }
7522
+
7523
+ fp->connection_mode = CONNECTION_MODE_SINK;
7524
+
7525
+ return connect_feature_port_to_stream_port(call, ae, fp);
7526
+ }
7527
+
7528
+
7036
7529
  bool prepare_fax(Call *call, AudioEndpoint *ae, bool is_sender, const char *file, unsigned flags) {
7037
7530
  pj_status_t status;
7038
7531
 
@@ -7062,7 +7555,7 @@ bool prepare_fax(Call *call, AudioEndpoint *ae, bool is_sender, const char *file
7062
7555
  return connect_feature_port_to_stream_port(call, ae, fp);
7063
7556
  }
7064
7557
 
7065
- bool prepare_speech_synth(Call *call, AudioEndpoint *ae, const char *server_url, const char *engine, const char *voice, const char *language, const char *text, int times) {
7558
+ bool prepare_speech_synth(Call *call, AudioEndpoint *ae, const char *server_url, const char *uuid, const char *engine, const char *voice, const char *language, const char *text, int times) {
7066
7559
  pj_status_t status;
7067
7560
 
7068
7561
  ConfBridgePort *fp = &ae->feature_cbps[FP_SPEECH_SYNTH];
@@ -7117,6 +7610,7 @@ bool prepare_speech_synth(Call *call, AudioEndpoint *ae, const char *server_url,
7117
7610
  PJMEDIA_PIA_BITS(&ae->stream_cbp.port->info),
7118
7611
  g_ws_endpt,
7119
7612
  server_url,
7613
+ uuid,
7120
7614
  engine,
7121
7615
  voice,
7122
7616
  language,
@@ -7150,7 +7644,7 @@ bool prepare_speech_synth(Call *call, AudioEndpoint *ae, const char *server_url,
7150
7644
  return PJ_SUCCESS;
7151
7645
  }
7152
7646
 
7153
- bool prepare_speech_recog(Call *call, AudioEndpoint *ae, const char *server_url, const char *engine, const char *language) {
7647
+ bool prepare_speech_recog(Call *call, AudioEndpoint *ae, const char *server_url, const char *uuid, const char *engine, const char *language) {
7154
7648
  pj_status_t status;
7155
7649
 
7156
7650
  ConfBridgePort *fp = &ae->feature_cbps[FP_SPEECH_RECOG];
@@ -7182,6 +7676,7 @@ bool prepare_speech_recog(Call *call, AudioEndpoint *ae, const char *server_url,
7182
7676
  PJMEDIA_PIA_BITS(&ae->stream_cbp.port->info),
7183
7677
  g_ws_endpt,
7184
7678
  server_url,
7679
+ uuid,
7185
7680
  NULL,
7186
7681
  NULL,
7187
7682
  NULL,
@@ -8619,11 +9114,33 @@ void check_digit_buffer(Call *call, int mode) {
8619
9114
  }
8620
9115
  }
8621
9116
 
8622
- void check_digit_buffers(long id, long val) {
9117
+ void check_bit_buffer(Call *call) {
9118
+ char evt[1024];
9119
+
9120
+ for (int i = 0; i < call->media_count; i++) {
9121
+ MediaEndpoint *me = (MediaEndpoint *)call->media[i];
9122
+ if (ENDPOINT_TYPE_AUDIO != me->type)
9123
+ continue;
9124
+
9125
+ AudioEndpoint *ae = (AudioEndpoint *)me->endpoint.audio;
9126
+
9127
+ if (ae->last_bit_timestamp > 0 &&
9128
+ g_now - ae->last_bit_timestamp > g_bfsk_inter_bit_timer) {
9129
+ int len = ae->BfskBufferLength;
9130
+ ae->BfskBufferLength = 0;
9131
+ make_evt_bfsk(evt, sizeof(evt), call->id, len, ae->BfskBuffer, i);
9132
+ dispatch_event(evt);
9133
+ ae->last_bit_timestamp = 0;
9134
+ }
9135
+ }
9136
+ }
9137
+
9138
+ void check_buffers(long id, long val) {
8623
9139
  Call *call = (Call *)val;
8624
9140
 
8625
9141
  check_digit_buffer(call, DTMF_MODE_RFC2833);
8626
9142
  check_digit_buffer(call, DTMF_MODE_INBAND);
9143
+ check_bit_buffer(call);
8627
9144
  }
8628
9145
 
8629
9146
  static int digit_buffer_thread(void *arg) {
@@ -8638,7 +9155,7 @@ static int digit_buffer_thread(void *arg) {
8638
9155
  PJW_LOCK();
8639
9156
  if (g_dtmf_inter_digit_timer > 0) {
8640
9157
  g_now = ms_timestamp();
8641
- g_call_ids.iterate(check_digit_buffers);
9158
+ g_call_ids.iterate(check_buffers);
8642
9159
  }
8643
9160
  PJW_UNLOCK();
8644
9161