sip-lab 1.28.12 → 1.29.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/DEV.md +55 -0
- package/README.md +8 -2
- package/binding.gyp +1 -0
- package/index.js +7 -0
- package/package.json +1 -1
- package/prebuilds/linux-x64/node.abi102.node +0 -0
- package/prebuilds/linux-x64/node.abi108.node +0 -0
- package/prebuilds/linux-x64/node.abi111.node +0 -0
- package/prebuilds/linux-x64/node.abi115.node +0 -0
- package/prebuilds/linux-x64/node.abi120.node +0 -0
- package/prebuilds/linux-x64/node.abi88.node +0 -0
- package/prebuilds/linux-x64/node.abi93.node +0 -0
- package/samples/100_calls.js +4 -0
- package/samples/16_audio_streams.js +2 -0
- package/samples/183_session_progress.js +2 -0
- package/samples/delayed_media.js +2 -0
- package/samples/four_audio_streams_two_refused.js +7 -4
- package/samples/mrcp_and_audio.simplified_media.js +2 -0
- package/samples/multiple_audio_streams.js +2 -0
- package/samples/refuse_telephone_event.js +3 -0
- package/samples/reinvite_and_dtmf.js +3 -0
- package/samples/reinvite_audio_audio.js +2 -0
- package/samples/reinvite_with_hold_unhold.js +2 -0
- package/samples/rtp_and_srtp.js +3 -0
- package/samples/rtp_and_srtp.rtp_refused.js +3 -0
- package/samples/srtp.js +3 -0
- package/samples/tcp.js +2 -0
- package/samples/text_to_speech.js +3 -0
- package/samples/two_audio_streams.js +4 -0
- package/samples/two_audio_streams.port_zero.js +4 -0
- package/src/addon.cpp +180 -10
- package/src/event_templates.cpp +8 -0
- package/src/event_templates.hpp +3 -0
- package/src/pjmedia/include/pjmedia/bfsk_det.h +25 -0
- package/src/pjmedia/src/pjmedia/bfsk_det.c +163 -0
- package/src/sip.cpp +520 -21
- 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 = 0;
|
|
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
|
|
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,6 +641,7 @@ 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, const int min_level, const int baud_rate);
|
|
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);
|
|
@@ -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
|
|
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[
|
|
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 =
|
|
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;
|
|
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;
|
|
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;
|
|
@@ -3413,6 +3469,178 @@ out:
|
|
|
3413
3469
|
return 0;
|
|
3414
3470
|
}
|
|
3415
3471
|
|
|
3472
|
+
pj_status_t audio_endpoint_send_bfsk(Call *call, AudioEndpoint *ae,
|
|
3473
|
+
const char *bits, const int freq_zero, const int freq_one, const int level, const int baud_rate) {
|
|
3474
|
+
pj_status_t status;
|
|
3475
|
+
|
|
3476
|
+
if (!prepare_tonegen(call, ae)) {
|
|
3477
|
+
set_error("prepare_tonegen failed.");
|
|
3478
|
+
return -1;
|
|
3479
|
+
}
|
|
3480
|
+
|
|
3481
|
+
int len = strlen(bits);
|
|
3482
|
+
|
|
3483
|
+
int duration = 1000 / baud_rate; // Duration of each tone in milliseconds
|
|
3484
|
+
|
|
3485
|
+
pjmedia_tone_desc *tones = (pjmedia_tone_desc*)pj_pool_zalloc(call->inv->pool, sizeof(pjmedia_tone_desc) * len);
|
|
3486
|
+
|
|
3487
|
+
for (int i = 0; i < len; ++i) {
|
|
3488
|
+
tones[i].freq1 = bits[i] == '0' ? freq_zero : freq_one;
|
|
3489
|
+
tones[i].on_msec = duration;
|
|
3490
|
+
tones[i].off_msec = duration;
|
|
3491
|
+
tones[i].volume = level;
|
|
3492
|
+
}
|
|
3493
|
+
|
|
3494
|
+
status = pjmedia_tonegen_play((pjmedia_port *)ae->feature_cbps[FP_TONEGEN].port, len, tones, 0);
|
|
3495
|
+
if (status != PJ_SUCCESS) {
|
|
3496
|
+
set_error("pjmedia_tonegen_plays failed.");
|
|
3497
|
+
return status;
|
|
3498
|
+
}
|
|
3499
|
+
|
|
3500
|
+
return PJ_SUCCESS;
|
|
3501
|
+
}
|
|
3502
|
+
|
|
3503
|
+
pj_status_t send_bfsk(Call *call, const char *bits, const int freq_zero, const int freq_one, const int level, const int baud_rate) {
|
|
3504
|
+
for (int i = 0; i < call->media_count; i++) {
|
|
3505
|
+
MediaEndpoint *me = (MediaEndpoint *)call->media[i];
|
|
3506
|
+
if (me->type != ENDPOINT_TYPE_AUDIO)
|
|
3507
|
+
continue;
|
|
3508
|
+
|
|
3509
|
+
if(me->port == 0)
|
|
3510
|
+
continue;
|
|
3511
|
+
|
|
3512
|
+
AudioEndpoint *ae = (AudioEndpoint *)me->endpoint.audio;
|
|
3513
|
+
|
|
3514
|
+
pj_status_t status = audio_endpoint_send_bfsk(call, ae, bits, freq_zero, freq_one, level, baud_rate);
|
|
3515
|
+
if (status != PJ_SUCCESS)
|
|
3516
|
+
return status;
|
|
3517
|
+
}
|
|
3518
|
+
|
|
3519
|
+
return PJ_SUCCESS;
|
|
3520
|
+
}
|
|
3521
|
+
|
|
3522
|
+
int pjw_call_send_bfsk(long call_id, const char *json) {
|
|
3523
|
+
#define BITS_MAX_LEN 32 // pjmedia_tonegen limit
|
|
3524
|
+
|
|
3525
|
+
PJW_LOCK();
|
|
3526
|
+
clear_error();
|
|
3527
|
+
|
|
3528
|
+
Call *call;
|
|
3529
|
+
|
|
3530
|
+
pj_status_t status;
|
|
3531
|
+
|
|
3532
|
+
long val;
|
|
3533
|
+
|
|
3534
|
+
int len;
|
|
3535
|
+
|
|
3536
|
+
char *bits;
|
|
3537
|
+
int freq_zero;
|
|
3538
|
+
int freq_one;
|
|
3539
|
+
int level;
|
|
3540
|
+
int baud_rate;
|
|
3541
|
+
|
|
3542
|
+
MediaEndpoint *me;
|
|
3543
|
+
AudioEndpoint *ae;
|
|
3544
|
+
int res;
|
|
3545
|
+
|
|
3546
|
+
int media_id = -1;
|
|
3547
|
+
|
|
3548
|
+
char buffer[MAX_JSON_INPUT];
|
|
3549
|
+
|
|
3550
|
+
Document document;
|
|
3551
|
+
|
|
3552
|
+
const char *valid_params[] = {"bits", "freq_zero", "freq_one", "level", "baud_rate", "media_id", ""};
|
|
3553
|
+
|
|
3554
|
+
if (!g_call_ids.get(call_id, val)) {
|
|
3555
|
+
set_error("Invalid call_id");
|
|
3556
|
+
goto out;
|
|
3557
|
+
}
|
|
3558
|
+
call = (Call *)val;
|
|
3559
|
+
|
|
3560
|
+
if (!parse_json(document, json, buffer, MAX_JSON_INPUT)) {
|
|
3561
|
+
goto out;
|
|
3562
|
+
}
|
|
3563
|
+
|
|
3564
|
+
if (!validate_params(document, valid_params)) {
|
|
3565
|
+
goto out;
|
|
3566
|
+
}
|
|
3567
|
+
|
|
3568
|
+
if (json_get_string_param(document, "bits", false, &bits) <= 0) {
|
|
3569
|
+
goto out;
|
|
3570
|
+
}
|
|
3571
|
+
|
|
3572
|
+
if (json_get_int_param(document, "freq_zero", false, &freq_zero) <= 0) {
|
|
3573
|
+
goto out;
|
|
3574
|
+
}
|
|
3575
|
+
|
|
3576
|
+
if (json_get_int_param(document, "freq_one", false, &freq_one) <= 0) {
|
|
3577
|
+
goto out;
|
|
3578
|
+
}
|
|
3579
|
+
|
|
3580
|
+
if (json_get_int_param(document, "level", false, &level) <= 0) {
|
|
3581
|
+
goto out;
|
|
3582
|
+
}
|
|
3583
|
+
|
|
3584
|
+
if (json_get_int_param(document, "baud_rate", false, &baud_rate) <= 0) {
|
|
3585
|
+
goto out;
|
|
3586
|
+
}
|
|
3587
|
+
|
|
3588
|
+
len = strlen(bits);
|
|
3589
|
+
|
|
3590
|
+
if (len > BITS_MAX_LEN) {
|
|
3591
|
+
set_error("bits too long");
|
|
3592
|
+
goto out;
|
|
3593
|
+
}
|
|
3594
|
+
|
|
3595
|
+
for (int i = 0; i < len; ++i) {
|
|
3596
|
+
if (bits[i] != '0' && bits[i] != '1') {
|
|
3597
|
+
set_error("Invalid character");
|
|
3598
|
+
goto out;
|
|
3599
|
+
}
|
|
3600
|
+
}
|
|
3601
|
+
|
|
3602
|
+
res = json_get_int_param(document, "media_id", true, &media_id);
|
|
3603
|
+
if (res <= 0) {
|
|
3604
|
+
goto out;
|
|
3605
|
+
}
|
|
3606
|
+
|
|
3607
|
+
if (NOT_FOUND_OPTIONAL == res) {
|
|
3608
|
+
// send_bfsk_bits to all audio endpoints
|
|
3609
|
+
status = send_bfsk(call, bits, freq_zero, freq_one, level, baud_rate);
|
|
3610
|
+
if (status != PJ_SUCCESS) {
|
|
3611
|
+
goto out;
|
|
3612
|
+
}
|
|
3613
|
+
} else {
|
|
3614
|
+
// send_bfsk_bits to specified media_id
|
|
3615
|
+
|
|
3616
|
+
if (media_id >= call->media_count) {
|
|
3617
|
+
set_error("invalid media_id");
|
|
3618
|
+
goto out;
|
|
3619
|
+
}
|
|
3620
|
+
|
|
3621
|
+
me = (MediaEndpoint *)call->media[media_id];
|
|
3622
|
+
if (ENDPOINT_TYPE_AUDIO != me->type) {
|
|
3623
|
+
set_error("invalid media_id non audio");
|
|
3624
|
+
goto out;
|
|
3625
|
+
}
|
|
3626
|
+
|
|
3627
|
+
ae = (AudioEndpoint *)me->endpoint.audio;
|
|
3628
|
+
|
|
3629
|
+
status = audio_endpoint_send_bfsk(call, ae, bits, freq_one, freq_zero, level, baud_rate);
|
|
3630
|
+
if (status != PJ_SUCCESS) {
|
|
3631
|
+
goto out;
|
|
3632
|
+
}
|
|
3633
|
+
}
|
|
3634
|
+
|
|
3635
|
+
out:
|
|
3636
|
+
PJW_UNLOCK();
|
|
3637
|
+
if (pjw_errorstring[0]) {
|
|
3638
|
+
return -1;
|
|
3639
|
+
}
|
|
3640
|
+
|
|
3641
|
+
return 0;
|
|
3642
|
+
}
|
|
3643
|
+
|
|
3416
3644
|
pj_status_t audio_endpoint_remove_port(Call *call, AudioEndpoint *ae, ConfBridgePort *cbp) {
|
|
3417
3645
|
printf("audio_endpoint_remove_port\n");
|
|
3418
3646
|
pj_status_t status;
|
|
@@ -4253,6 +4481,229 @@ out:
|
|
|
4253
4481
|
return 0;
|
|
4254
4482
|
}
|
|
4255
4483
|
|
|
4484
|
+
pj_status_t audio_endpoint_start_inband_dtmf_detection(Call *call, AudioEndpoint *ae) {
|
|
4485
|
+
pj_status_t status;
|
|
4486
|
+
|
|
4487
|
+
if(!ae->stream_cbp.port) {
|
|
4488
|
+
set_error("stream port is not ready yet");
|
|
4489
|
+
return -1;
|
|
4490
|
+
}
|
|
4491
|
+
|
|
4492
|
+
if(!prepare_dtmfdet(call, ae)) {
|
|
4493
|
+
return -1;
|
|
4494
|
+
}
|
|
4495
|
+
|
|
4496
|
+
return PJ_SUCCESS;
|
|
4497
|
+
}
|
|
4498
|
+
|
|
4499
|
+
int pjw_call_start_inband_dtmf_detection(long call_id, const char *json) {
|
|
4500
|
+
printf("pjw_call_start_inband_dtmf_detection\n");
|
|
4501
|
+
PJW_LOCK();
|
|
4502
|
+
clear_error();
|
|
4503
|
+
|
|
4504
|
+
long val;
|
|
4505
|
+
Call *call;
|
|
4506
|
+
|
|
4507
|
+
pj_status_t status;
|
|
4508
|
+
|
|
4509
|
+
MediaEndpoint *me;
|
|
4510
|
+
AudioEndpoint *ae;
|
|
4511
|
+
int ae_count;
|
|
4512
|
+
int res;
|
|
4513
|
+
|
|
4514
|
+
int media_id = -1;
|
|
4515
|
+
|
|
4516
|
+
char buffer[MAX_JSON_INPUT];
|
|
4517
|
+
|
|
4518
|
+
Document document;
|
|
4519
|
+
|
|
4520
|
+
const char *valid_params[] = {"media_id", ""};
|
|
4521
|
+
|
|
4522
|
+
if (!g_call_ids.get(call_id, val)) {
|
|
4523
|
+
set_error("Invalid call_id");
|
|
4524
|
+
goto out;
|
|
4525
|
+
}
|
|
4526
|
+
call = (Call *)val;
|
|
4527
|
+
|
|
4528
|
+
ae_count = count_media_by_type(call, ENDPOINT_TYPE_AUDIO);
|
|
4529
|
+
|
|
4530
|
+
if (ae_count == 0) {
|
|
4531
|
+
set_error("No audio endpoint");
|
|
4532
|
+
goto out;
|
|
4533
|
+
}
|
|
4534
|
+
|
|
4535
|
+
if (!parse_json(document, json, buffer, MAX_JSON_INPUT)) {
|
|
4536
|
+
goto out;
|
|
4537
|
+
}
|
|
4538
|
+
|
|
4539
|
+
if (!validate_params(document, valid_params)) {
|
|
4540
|
+
goto out;
|
|
4541
|
+
}
|
|
4542
|
+
|
|
4543
|
+
res = json_get_int_param(document, "media_id", true, &media_id);
|
|
4544
|
+
if (res <= 0) {
|
|
4545
|
+
goto out;
|
|
4546
|
+
}
|
|
4547
|
+
|
|
4548
|
+
if (NOT_FOUND_OPTIONAL == res) {
|
|
4549
|
+
for (int i = 0; i < call->media_count; i++) {
|
|
4550
|
+
MediaEndpoint *me = (MediaEndpoint *)call->media[i];
|
|
4551
|
+
if (me->type == ENDPOINT_TYPE_AUDIO) {
|
|
4552
|
+
AudioEndpoint *ae = (AudioEndpoint *)me->endpoint.audio;
|
|
4553
|
+
status = audio_endpoint_start_inband_dtmf_detection(call, ae);
|
|
4554
|
+
if (status != PJ_SUCCESS) goto out;
|
|
4555
|
+
}
|
|
4556
|
+
}
|
|
4557
|
+
} else {
|
|
4558
|
+
if ((int)media_id >= call->media_count) {
|
|
4559
|
+
set_error("invalid media_id");
|
|
4560
|
+
goto out;
|
|
4561
|
+
}
|
|
4562
|
+
|
|
4563
|
+
me = (MediaEndpoint *)call->media[media_id];
|
|
4564
|
+
if (ENDPOINT_TYPE_AUDIO != me->type) {
|
|
4565
|
+
set_error("media_endpoint is not audio endpoint");
|
|
4566
|
+
goto out;
|
|
4567
|
+
}
|
|
4568
|
+
|
|
4569
|
+
ae = (AudioEndpoint *)me->endpoint.audio;
|
|
4570
|
+
|
|
4571
|
+
audio_endpoint_start_inband_dtmf_detection(call, ae);
|
|
4572
|
+
}
|
|
4573
|
+
|
|
4574
|
+
out:
|
|
4575
|
+
PJW_UNLOCK();
|
|
4576
|
+
if (pjw_errorstring[0]) {
|
|
4577
|
+
return -1;
|
|
4578
|
+
}
|
|
4579
|
+
|
|
4580
|
+
return 0;
|
|
4581
|
+
}
|
|
4582
|
+
|
|
4583
|
+
pj_status_t audio_endpoint_start_bfsk_detection(Call *call, AudioEndpoint *ae, const int freq_zero, const int freq_one, const int min_level, const int baud_rate) {
|
|
4584
|
+
pj_status_t status;
|
|
4585
|
+
|
|
4586
|
+
if(!ae->stream_cbp.port) {
|
|
4587
|
+
set_error("stream port is not ready yet");
|
|
4588
|
+
return -1;
|
|
4589
|
+
}
|
|
4590
|
+
|
|
4591
|
+
if(!prepare_bfsk_det(call, ae, freq_zero, freq_one, min_level, baud_rate)) {
|
|
4592
|
+
return -1;
|
|
4593
|
+
}
|
|
4594
|
+
|
|
4595
|
+
return PJ_SUCCESS;
|
|
4596
|
+
}
|
|
4597
|
+
|
|
4598
|
+
int pjw_call_start_bfsk_detection(long call_id, const char *json) {
|
|
4599
|
+
printf("pjw_call_start_bfsk_detection\n");
|
|
4600
|
+
PJW_LOCK();
|
|
4601
|
+
clear_error();
|
|
4602
|
+
|
|
4603
|
+
long val;
|
|
4604
|
+
Call *call;
|
|
4605
|
+
|
|
4606
|
+
pj_status_t status;
|
|
4607
|
+
|
|
4608
|
+
MediaEndpoint *me;
|
|
4609
|
+
AudioEndpoint *ae;
|
|
4610
|
+
int ae_count;
|
|
4611
|
+
int res;
|
|
4612
|
+
|
|
4613
|
+
int media_id = -1;
|
|
4614
|
+
|
|
4615
|
+
int freq_zero;
|
|
4616
|
+
int freq_one;
|
|
4617
|
+
int min_level;
|
|
4618
|
+
int baud_rate;
|
|
4619
|
+
|
|
4620
|
+
char buffer[MAX_JSON_INPUT];
|
|
4621
|
+
|
|
4622
|
+
Document document;
|
|
4623
|
+
|
|
4624
|
+
const char *valid_params[] = {"freq_zero", "freq_one", "min_level", "baud_rate", "media_id", ""};
|
|
4625
|
+
|
|
4626
|
+
if (!g_call_ids.get(call_id, val)) {
|
|
4627
|
+
set_error("Invalid call_id");
|
|
4628
|
+
goto out;
|
|
4629
|
+
}
|
|
4630
|
+
call = (Call *)val;
|
|
4631
|
+
|
|
4632
|
+
ae_count = count_media_by_type(call, ENDPOINT_TYPE_AUDIO);
|
|
4633
|
+
|
|
4634
|
+
if (ae_count == 0) {
|
|
4635
|
+
set_error("No audio endpoint");
|
|
4636
|
+
goto out;
|
|
4637
|
+
}
|
|
4638
|
+
|
|
4639
|
+
if (!parse_json(document, json, buffer, MAX_JSON_INPUT)) {
|
|
4640
|
+
goto out;
|
|
4641
|
+
}
|
|
4642
|
+
|
|
4643
|
+
if (!validate_params(document, valid_params)) {
|
|
4644
|
+
goto out;
|
|
4645
|
+
}
|
|
4646
|
+
|
|
4647
|
+
res = json_get_int_param(document, "freq_zero", false, &freq_zero);
|
|
4648
|
+
if (res <= 0) {
|
|
4649
|
+
goto out;
|
|
4650
|
+
}
|
|
4651
|
+
|
|
4652
|
+
res = json_get_int_param(document, "freq_one", false, &freq_one);
|
|
4653
|
+
if (res <= 0) {
|
|
4654
|
+
goto out;
|
|
4655
|
+
}
|
|
4656
|
+
|
|
4657
|
+
res = json_get_int_param(document, "min_level", false, &min_level);
|
|
4658
|
+
if (res <= 0) {
|
|
4659
|
+
goto out;
|
|
4660
|
+
}
|
|
4661
|
+
|
|
4662
|
+
res = json_get_int_param(document, "baud_rate", false, &baud_rate);
|
|
4663
|
+
if (res <= 0) {
|
|
4664
|
+
goto out;
|
|
4665
|
+
}
|
|
4666
|
+
|
|
4667
|
+
res = json_get_int_param(document, "media_id", true, &media_id);
|
|
4668
|
+
if (res <= 0) {
|
|
4669
|
+
goto out;
|
|
4670
|
+
}
|
|
4671
|
+
|
|
4672
|
+
if (NOT_FOUND_OPTIONAL == res) {
|
|
4673
|
+
for (int i = 0; i < call->media_count; i++) {
|
|
4674
|
+
MediaEndpoint *me = (MediaEndpoint *)call->media[i];
|
|
4675
|
+
if (me->type == ENDPOINT_TYPE_AUDIO) {
|
|
4676
|
+
AudioEndpoint *ae = (AudioEndpoint *)me->endpoint.audio;
|
|
4677
|
+
status = audio_endpoint_start_bfsk_detection(call, ae, freq_zero, freq_one, min_level, baud_rate);
|
|
4678
|
+
if (status != PJ_SUCCESS) goto out;
|
|
4679
|
+
}
|
|
4680
|
+
}
|
|
4681
|
+
} else {
|
|
4682
|
+
if ((int)media_id >= call->media_count) {
|
|
4683
|
+
set_error("invalid media_id");
|
|
4684
|
+
goto out;
|
|
4685
|
+
}
|
|
4686
|
+
|
|
4687
|
+
me = (MediaEndpoint *)call->media[media_id];
|
|
4688
|
+
if (ENDPOINT_TYPE_AUDIO != me->type) {
|
|
4689
|
+
set_error("media_endpoint is not audio endpoint");
|
|
4690
|
+
goto out;
|
|
4691
|
+
}
|
|
4692
|
+
|
|
4693
|
+
ae = (AudioEndpoint *)me->endpoint.audio;
|
|
4694
|
+
|
|
4695
|
+
audio_endpoint_start_bfsk_detection(call, ae, freq_zero, freq_one, min_level, baud_rate);
|
|
4696
|
+
}
|
|
4697
|
+
|
|
4698
|
+
out:
|
|
4699
|
+
PJW_UNLOCK();
|
|
4700
|
+
if (pjw_errorstring[0]) {
|
|
4701
|
+
return -1;
|
|
4702
|
+
}
|
|
4703
|
+
|
|
4704
|
+
return 0;
|
|
4705
|
+
}
|
|
4706
|
+
|
|
4256
4707
|
pj_status_t call_stop_op_on_all_audio_endpoints(Call *call,
|
|
4257
4708
|
audio_endpoint_stop_op_t op) {
|
|
4258
4709
|
addon_log(L_DBG, "call_stop_op_on_audio_endpoints media_count=%d\n",
|
|
@@ -4274,6 +4725,7 @@ pj_status_t call_stop_op_on_all_audio_endpoints(Call *call,
|
|
|
4274
4725
|
return PJ_SUCCESS;
|
|
4275
4726
|
}
|
|
4276
4727
|
|
|
4728
|
+
|
|
4277
4729
|
int audio_endpoint_stop_op(long call_id, const char *json, audio_endpoint_stop_op_t op) {
|
|
4278
4730
|
PJW_LOCK();
|
|
4279
4731
|
clear_error();
|
|
@@ -4362,6 +4814,14 @@ pj_status_t audio_endpoint_stop_speech_recog(Call *call, AudioEndpoint *ae) {
|
|
|
4362
4814
|
return audio_endpoint_remove_port(call, ae, &ae->feature_cbps[FP_SPEECH_RECOG]);
|
|
4363
4815
|
}
|
|
4364
4816
|
|
|
4817
|
+
pj_status_t audio_endpoint_stop_inband_dtmf_detection(Call *call, AudioEndpoint *ae) {
|
|
4818
|
+
return audio_endpoint_remove_port(call, ae, &ae->feature_cbps[FP_DTMFDET]);
|
|
4819
|
+
}
|
|
4820
|
+
|
|
4821
|
+
pj_status_t audio_endpoint_stop_bfsk_detection(Call *call, AudioEndpoint *ae) {
|
|
4822
|
+
return audio_endpoint_remove_port(call, ae, &ae->feature_cbps[FP_BFSK_DET]);
|
|
4823
|
+
}
|
|
4824
|
+
|
|
4365
4825
|
|
|
4366
4826
|
int pjw_call_stop_play_wav(long call_id, const char *json) {
|
|
4367
4827
|
return audio_endpoint_stop_op(call_id, json, audio_endpoint_stop_play_wav);
|
|
@@ -4383,6 +4843,11 @@ int pjw_call_stop_speech_recog(long call_id, const char *json) {
|
|
|
4383
4843
|
return audio_endpoint_stop_op(call_id, json, audio_endpoint_stop_speech_recog);
|
|
4384
4844
|
}
|
|
4385
4845
|
|
|
4846
|
+
int pjw_call_stop_inband_dtmf_detection(long call_id, const char *json) {
|
|
4847
|
+
return audio_endpoint_stop_op(call_id, json, audio_endpoint_stop_inband_dtmf_detection);
|
|
4848
|
+
}
|
|
4849
|
+
|
|
4850
|
+
|
|
4386
4851
|
|
|
4387
4852
|
int pjw_call_start_fax(long call_id, const char *json) {
|
|
4388
4853
|
PJW_LOCK();
|
|
@@ -5030,14 +5495,6 @@ bool restart_media_stream(Call *call, MediaEndpoint *me,
|
|
|
5030
5495
|
dispatch_event(evt);
|
|
5031
5496
|
return false;
|
|
5032
5497
|
}
|
|
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
5498
|
} else if(
|
|
5042
5499
|
(PJMEDIA_PIA_SRATE(&old_port->info) != PJMEDIA_PIA_SRATE(&new_port->info)) ||
|
|
5043
5500
|
(PJMEDIA_PIA_CCNT(&old_port->info) != PJMEDIA_PIA_CCNT(&new_port->info)) ||
|
|
@@ -5065,14 +5522,6 @@ bool restart_media_stream(Call *call, MediaEndpoint *me,
|
|
|
5065
5522
|
return false;
|
|
5066
5523
|
}
|
|
5067
5524
|
|
|
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
5525
|
// at this point we could try to recreate ports (see #91)
|
|
5077
5526
|
} else {
|
|
5078
5527
|
printf("call_id=%i restart_media_stream: stream characteristics no change\n", call->id);
|
|
@@ -7006,10 +7455,16 @@ bool prepare_wav_writer(Call *call, AudioEndpoint *ae, const char *file) {
|
|
|
7006
7455
|
}
|
|
7007
7456
|
|
|
7008
7457
|
bool prepare_dtmfdet(Call *call, AudioEndpoint *ae) {
|
|
7458
|
+
printf("DEBUG prepare_dtmfdet\n");
|
|
7009
7459
|
pj_status_t status;
|
|
7010
7460
|
|
|
7011
7461
|
ConfBridgePort *fp = &ae->feature_cbps[FP_DTMFDET];
|
|
7012
7462
|
|
|
7463
|
+
if(fp->port) {
|
|
7464
|
+
printf("already prepared\n");
|
|
7465
|
+
return true;
|
|
7466
|
+
}
|
|
7467
|
+
|
|
7013
7468
|
status = pjmedia_dtmfdet_create(
|
|
7014
7469
|
call->inv->pool,
|
|
7015
7470
|
PJMEDIA_PIA_SRATE(&ae->stream_cbp.port->info),
|
|
@@ -7033,6 +7488,41 @@ bool prepare_dtmfdet(Call *call, AudioEndpoint *ae) {
|
|
|
7033
7488
|
return connect_feature_port_to_stream_port(call, ae, fp);
|
|
7034
7489
|
}
|
|
7035
7490
|
|
|
7491
|
+
bool prepare_bfsk_det(Call *call, AudioEndpoint *ae, const int freq_zero, const int freq_one, const int min_level, const int baud_rate) {
|
|
7492
|
+
printf("DEBUG prepare_bfsk_det\n");
|
|
7493
|
+
pj_status_t status;
|
|
7494
|
+
|
|
7495
|
+
ConfBridgePort *fp = &ae->feature_cbps[FP_BFSK_DET];
|
|
7496
|
+
|
|
7497
|
+
if(fp->port) {
|
|
7498
|
+
printf("already prepared\n");
|
|
7499
|
+
return true;
|
|
7500
|
+
}
|
|
7501
|
+
|
|
7502
|
+
status = pjmedia_bfsk_det_create(
|
|
7503
|
+
call->inv->pool,
|
|
7504
|
+
PJMEDIA_PIA_SRATE(&ae->stream_cbp.port->info),
|
|
7505
|
+
PJMEDIA_PIA_CCNT(&ae->stream_cbp.port->info),
|
|
7506
|
+
PJMEDIA_PIA_SPF(&ae->stream_cbp.port->info),
|
|
7507
|
+
PJMEDIA_PIA_BITS(&ae->stream_cbp.port->info),
|
|
7508
|
+
on_bfsk_bit, call, freq_zero, freq_one, min_level, baud_rate, &fp->port);
|
|
7509
|
+
if (status != PJ_SUCCESS) {
|
|
7510
|
+
set_error("pjmedia_bfsk_det_create failed");
|
|
7511
|
+
return false;
|
|
7512
|
+
}
|
|
7513
|
+
|
|
7514
|
+
status = pjmedia_conf_add_port(ae->conf, call->inv->pool, fp->port, NULL, &fp->slot);
|
|
7515
|
+
if (status != PJ_SUCCESS) {
|
|
7516
|
+
set_error("pjmedia_conf_add_port failed");
|
|
7517
|
+
return false;
|
|
7518
|
+
}
|
|
7519
|
+
|
|
7520
|
+
fp->connection_mode = CONNECTION_MODE_SINK;
|
|
7521
|
+
|
|
7522
|
+
return connect_feature_port_to_stream_port(call, ae, fp);
|
|
7523
|
+
}
|
|
7524
|
+
|
|
7525
|
+
|
|
7036
7526
|
bool prepare_fax(Call *call, AudioEndpoint *ae, bool is_sender, const char *file, unsigned flags) {
|
|
7037
7527
|
pj_status_t status;
|
|
7038
7528
|
|
|
@@ -8616,6 +9106,15 @@ void check_digit_buffer(Call *call, int mode) {
|
|
|
8616
9106
|
*pLen = 0;
|
|
8617
9107
|
ae->last_digit_timestamp[mode] = 0;
|
|
8618
9108
|
}
|
|
9109
|
+
|
|
9110
|
+
if (ae->last_bit_timestamp > 0 &&
|
|
9111
|
+
g_now - ae->last_bit_timestamp > g_bfsk_inter_bit_timer) {
|
|
9112
|
+
int len = ae->BfskBufferLength;
|
|
9113
|
+
ae->BfskBufferLength = 0;
|
|
9114
|
+
make_evt_bfsk(evt, sizeof(evt), call->id, len, ae->BfskBuffer, i);
|
|
9115
|
+
dispatch_event(evt);
|
|
9116
|
+
ae->last_bit_timestamp = 0;
|
|
9117
|
+
}
|
|
8619
9118
|
}
|
|
8620
9119
|
}
|
|
8621
9120
|
|
package/src/sip.hpp
CHANGED
|
@@ -41,6 +41,8 @@ int pjw_call_terminate(long call_id, const char *json);
|
|
|
41
41
|
|
|
42
42
|
int pjw_call_send_dtmf(long call_id, const char *json);
|
|
43
43
|
|
|
44
|
+
int pjw_call_send_bfsk(long call_id, const char *json);
|
|
45
|
+
|
|
44
46
|
int pjw_call_reinvite(long call_id, const char *json);
|
|
45
47
|
|
|
46
48
|
int pjw_call_send_request(long call_id, const char *json);
|
|
@@ -64,6 +66,15 @@ int pjw_call_stop_speech_synth(long call_id, const char *json);
|
|
|
64
66
|
int pjw_call_start_speech_recog(long call_id, const char *json);
|
|
65
67
|
|
|
66
68
|
int pjw_call_stop_speech_recog(long call_id, const char *json);
|
|
69
|
+
|
|
70
|
+
int pjw_call_start_inband_dtmf_detection(long call_id, const char *json);
|
|
71
|
+
|
|
72
|
+
int pjw_call_stop_inband_dtmf_detection(long call_id, const char *json);
|
|
73
|
+
|
|
74
|
+
int pjw_call_start_bfsk_detection(long call_id, const char *json);
|
|
75
|
+
|
|
76
|
+
int pjw_call_stop_bfsk_detection(long call_id, const char *json);
|
|
77
|
+
|
|
67
78
|
int pjw_call_get_stream_stat(long call_id, const char *json, char *out_stats);
|
|
68
79
|
|
|
69
80
|
// int pjw_call_refer(long call_id, const char *json, long
|