sip-lab 1.22.0 → 1.23.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/src/sip.cpp CHANGED
@@ -618,11 +618,11 @@ static void build_stream_stat(ostringstream &oss, pjmedia_rtcp_stat *stat,
618
618
 
619
619
  bool prepare_tonegen(Call *call, AudioEndpoint *ae);
620
620
  bool prepare_dtmfdet(Call *call, AudioEndpoint *ae);
621
- bool prepare_wav_player(Call *c, AudioEndpoint *ae, const char *file);
621
+ bool prepare_wav_player(Call *c, AudioEndpoint *ae, const char *file, unsigned flags, bool end_of_file_event);
622
622
  bool prepare_wav_writer(Call *c, AudioEndpoint *ae, const char *file);
623
623
  bool prepare_fax(Call *c, AudioEndpoint *ae, bool is_sender, const char *file,
624
624
  unsigned flags);
625
- bool prepare_flite(Call *c, AudioEndpoint *ae, const char *voice);
625
+ bool prepare_flite(Call *c, AudioEndpoint *ae, const char *voice, bool end_of_speech_event);
626
626
 
627
627
  void prepare_error_event(ostringstream *oss, char *scope, char *details);
628
628
  // void prepare_pjsipcall_error_event(ostringstream *oss, char *scope, char
@@ -641,7 +641,7 @@ typedef pj_status_t (*audio_endpoint_stop_op_t)(Call *call, AudioEndpoint *ae);
641
641
  pj_status_t audio_endpoint_stop_play_wav(Call *call, AudioEndpoint *ae);
642
642
  pj_status_t audio_endpoint_stop_record_wav(Call *call, AudioEndpoint *ae);
643
643
  pj_status_t audio_endpoint_stop_fax(Call *call, AudioEndpoint *ae);
644
- pj_status_t audio_endpoint_stop_flite(Call *call, AudioEndpoint *ae);
644
+ pj_status_t audio_endpoint_stop_speech_synth(Call *call, AudioEndpoint *ae);
645
645
 
646
646
  static pjsip_module mod_tester = {
647
647
  NULL,
@@ -851,7 +851,7 @@ static void on_inband_dtmf(pjmedia_port *port, void *user_data, char digit) {
851
851
  ae->last_digit_timestamp[mode] = ms_timestamp();
852
852
  PJW_UNLOCK();
853
853
  } else {
854
- char evt[256];
854
+ char evt[1024];
855
855
  make_evt_dtmf(evt, sizeof(evt), call_id, 1, &d, mode, media_id);
856
856
  dispatch_event(evt);
857
857
  }
@@ -868,11 +868,44 @@ static void on_fax_result(pjmedia_port *port, void *user_data, int result) {
868
868
  return;
869
869
  }
870
870
 
871
- char evt[256];
871
+ char evt[1024];
872
872
  make_evt_fax_result(evt, sizeof(evt), call_id, result);
873
873
  dispatch_event(evt);
874
874
  }
875
875
 
876
+ static void on_end_of_file(pjmedia_port *port, void *user_data) {
877
+ if (g_shutting_down)
878
+ return;
879
+
880
+ long call_id;
881
+ if (!g_call_ids.get_id((long)user_data, call_id)) {
882
+ printf(
883
+ "on_end_of_file: Failed to get call_id. Event will not be notified.\n");
884
+ return;
885
+ }
886
+
887
+ char evt[1024];
888
+ make_evt_end_of_file(evt, sizeof(evt), call_id);
889
+ dispatch_event(evt);
890
+ }
891
+
892
+ static void on_end_of_speech(pjmedia_port *port, void *user_data) {
893
+ if (g_shutting_down)
894
+ return;
895
+
896
+ long call_id;
897
+ if (!g_call_ids.get_id((long)user_data, call_id)) {
898
+ printf(
899
+ "on_end_of_speech: Failed to get call_id. Event will not be notified.\n");
900
+ return;
901
+ }
902
+
903
+ char evt[1024];
904
+ make_evt_end_of_speech(evt, sizeof(evt), call_id);
905
+ dispatch_event(evt);
906
+ }
907
+
908
+
876
909
  void dispatch_event(const char *evt) {
877
910
  addon_log(L_DBG, "dispach_event called with evt=%s\n", evt);
878
911
  // g_event_sink(evt);
@@ -3090,7 +3123,6 @@ pj_status_t send_dtmf(Call *call, const char *digits, int mode) {
3090
3123
  return PJ_SUCCESS;
3091
3124
  }
3092
3125
 
3093
- // int pjw_call_send_dtmf(long call_id, const char *digits, int mode)
3094
3126
  int pjw_call_send_dtmf(long call_id, const char *json) {
3095
3127
  #define MAX_LENGTH \
3096
3128
  31 // pjsip allows for 31 digits (inband allows for 32 digits)
@@ -3098,32 +3130,40 @@ int pjw_call_send_dtmf(long call_id, const char *json) {
3098
3130
  PJW_LOCK();
3099
3131
  clear_error();
3100
3132
 
3133
+ Call *call;
3134
+
3135
+ pj_status_t status;
3136
+
3101
3137
  long val;
3138
+
3102
3139
  char *digits;
3103
3140
  int mode = 0;
3104
- ;
3105
3141
 
3106
- Call *call;
3142
+ MediaEndpoint *me;
3143
+ AudioEndpoint *ae;
3144
+ int res;
3145
+
3146
+ int media_id = -1;
3107
3147
 
3108
3148
  char buffer[MAX_JSON_INPUT];
3109
3149
 
3110
3150
  Document document;
3111
3151
 
3112
- const char *valid_params[] = {"digits", "mode", ""};
3152
+ const char *valid_params[] = {"digits", "mode", "media_id", ""};
3113
3153
 
3114
- if (!parse_json(document, json, buffer, MAX_JSON_INPUT)) {
3154
+ if (!g_call_ids.get(call_id, val)) {
3155
+ set_error("Invalid call_id");
3115
3156
  goto out;
3116
3157
  }
3158
+ call = (Call *)val;
3117
3159
 
3118
- if (!validate_params(document, valid_params)) {
3160
+ if (!parse_json(document, json, buffer, MAX_JSON_INPUT)) {
3119
3161
  goto out;
3120
3162
  }
3121
3163
 
3122
- if (!g_call_ids.get(call_id, val)) {
3123
- set_error("Invalid call_id");
3164
+ if (!validate_params(document, valid_params)) {
3124
3165
  goto out;
3125
3166
  }
3126
- call = (Call *)val;
3127
3167
 
3128
3168
  if (json_get_string_param(document, "digits", false, &digits) <= 0) {
3129
3169
  goto out;
@@ -3169,7 +3209,38 @@ int pjw_call_send_dtmf(long call_id, const char *json) {
3169
3209
  adjusted_digits[len] = 0;
3170
3210
  // addon_log(L_DBG, "adjusted_digits >>%s<<\n", adjusted_digits);
3171
3211
 
3172
- send_dtmf(call, adjusted_digits, mode);
3212
+ res = json_get_int_param(document, "media_id", true, &media_id);
3213
+ if (res <= 0) {
3214
+ goto out;
3215
+ }
3216
+
3217
+ if (NOT_FOUND_OPTIONAL == res) {
3218
+ // send_dtmf to all audio endpoints
3219
+ status = send_dtmf(call, adjusted_digits, mode);
3220
+ if (status != PJ_SUCCESS) {
3221
+ goto out;
3222
+ }
3223
+ } else {
3224
+ // send_dtmf to specified media_id
3225
+
3226
+ if (media_id >= call->media_count) {
3227
+ set_error("invalid media_id");
3228
+ goto out;
3229
+ }
3230
+
3231
+ me = (MediaEndpoint *)call->media[media_id];
3232
+ if (ENDPOINT_TYPE_AUDIO != me->type) {
3233
+ set_error("invalid media_id non audio");
3234
+ goto out;
3235
+ }
3236
+
3237
+ ae = (AudioEndpoint *)me->endpoint.audio;
3238
+
3239
+ status = audio_endpoint_send_dtmf(call, ae, digits, mode);
3240
+ if (status != PJ_SUCCESS) {
3241
+ goto out;
3242
+ }
3243
+ }
3173
3244
 
3174
3245
  out:
3175
3246
  PJW_UNLOCK();
@@ -3443,7 +3514,15 @@ int count_media_by_type(Call *call, int type) {
3443
3514
  return total;
3444
3515
  }
3445
3516
 
3446
- // int pjw_call_start_record_wav(long call_id, const char *file)
3517
+ int get_first_media_id_by_type(Call *call, int type) {
3518
+ for (int i = 0; i < call->media_count; i++) {
3519
+ MediaEndpoint *me = (MediaEndpoint *)call->media[i];
3520
+ if (type == me->type)
3521
+ return i;
3522
+ }
3523
+ return -1;
3524
+ }
3525
+
3447
3526
  int pjw_call_start_record_wav(long call_id, const char *json) {
3448
3527
  PJW_LOCK();
3449
3528
  clear_error();
@@ -3452,7 +3531,7 @@ int pjw_call_start_record_wav(long call_id, const char *json) {
3452
3531
  Call *call;
3453
3532
  pj_status_t status;
3454
3533
 
3455
- unsigned media_id = 0;
3534
+ int media_id = -1;
3456
3535
 
3457
3536
  MediaEndpoint *me;
3458
3537
  AudioEndpoint *ae;
@@ -3497,7 +3576,13 @@ int pjw_call_start_record_wav(long call_id, const char *json) {
3497
3576
  }
3498
3577
 
3499
3578
  if (ae_count > 1) {
3500
- if (json_get_uint_param(document, "media_id", false, &media_id) <= 0) {
3579
+ if (json_get_int_param(document, "media_id", false, &media_id) <= 0) {
3580
+ goto out;
3581
+ }
3582
+ } else {
3583
+ media_id = get_first_media_id_by_type(call, ENDPOINT_TYPE_AUDIO);
3584
+ if(media_id < 0) {
3585
+ set_error("could not resolve media_id");
3501
3586
  goto out;
3502
3587
  }
3503
3588
  }
@@ -3541,7 +3626,7 @@ out:
3541
3626
  }
3542
3627
 
3543
3628
  pj_status_t audio_endpoint_start_play_wav(Call *call, AudioEndpoint *ae,
3544
- const char *file) {
3629
+ const char *file, unsigned flags, bool end_of_file_event) {
3545
3630
  pj_status_t status;
3546
3631
 
3547
3632
  if(!ae->stream_cbp.port) {
@@ -3555,14 +3640,34 @@ pj_status_t audio_endpoint_start_play_wav(Call *call, AudioEndpoint *ae,
3555
3640
  return -1;
3556
3641
  }
3557
3642
 
3558
- if (!prepare_wav_player(call, ae, file)) {
3643
+ if (!prepare_wav_player(call, ae, file, flags, end_of_file_event)) {
3644
+ return -1;
3645
+ }
3646
+
3647
+ return PJ_SUCCESS;
3648
+ }
3649
+
3650
+ pj_status_t audio_endpoint_start_fax(Call *call, AudioEndpoint *ae, bool is_sender, char *file, unsigned flags) {
3651
+ pj_status_t status;
3652
+
3653
+ if(!ae->stream_cbp.port) {
3654
+ set_error("stream port is not ready yet");
3655
+ return -1;
3656
+ }
3657
+
3658
+ // First stop and destroy existing port.
3659
+ status = audio_endpoint_stop_fax(call, ae);
3660
+ if(status != PJ_SUCCESS) {
3661
+ return -1;
3662
+ }
3663
+
3664
+ if (!prepare_fax(call, ae, is_sender, file, flags)) {
3559
3665
  return -1;
3560
3666
  }
3561
3667
 
3562
3668
  return PJ_SUCCESS;
3563
3669
  }
3564
3670
 
3565
- // int pjw_call_start_play_wav(long call_id, const char *file)
3566
3671
  int pjw_call_start_play_wav(long call_id, const char *json) {
3567
3672
  PJW_LOCK();
3568
3673
  clear_error();
@@ -3573,16 +3678,25 @@ int pjw_call_start_play_wav(long call_id, const char *json) {
3573
3678
  MediaEndpoint *me;
3574
3679
  AudioEndpoint *ae;
3575
3680
  int ae_count;
3681
+ int res;
3576
3682
 
3577
- unsigned media_id = 0;
3683
+ int media_id = -1;
3578
3684
 
3579
3685
  char *file;
3580
3686
 
3687
+ unsigned flags = 0;
3688
+
3689
+ bool end_of_file_event = false;
3690
+
3691
+ bool no_loop = false;
3692
+
3581
3693
  char buffer[MAX_JSON_INPUT];
3582
3694
 
3695
+ pj_status_t status;
3696
+
3583
3697
  Document document;
3584
3698
 
3585
- const char *valid_params[] = {"file", "media_id", ""};
3699
+ const char *valid_params[] = {"file", "media_id", "end_of_file_event", "no_loop", ""};
3586
3700
 
3587
3701
  if (!g_call_ids.get(call_id, val)) {
3588
3702
  set_error("Invalid call_id");
@@ -3614,26 +3728,49 @@ int pjw_call_start_play_wav(long call_id, const char *json) {
3614
3728
  goto out;
3615
3729
  }
3616
3730
 
3617
- if (ae_count > 1) {
3618
- if (json_get_uint_param(document, "media_id", false, &media_id) <= 0) {
3619
- goto out;
3620
- }
3731
+ if (json_get_bool_param(document, "end_of_file_event", true, &end_of_file_event) <= 0) {
3732
+ goto out;
3621
3733
  }
3622
3734
 
3623
- if ((int)media_id >= call->media_count) {
3624
- set_error("invalid media_id");
3735
+ if (json_get_bool_param(document, "no_loop", true, &no_loop) <= 0) {
3625
3736
  goto out;
3626
3737
  }
3627
3738
 
3628
- me = (MediaEndpoint *)call->media[media_id];
3629
- if (ENDPOINT_TYPE_AUDIO != me->type) {
3630
- set_error("media_endpoint is not audio endpoint");
3739
+ if(no_loop) {
3740
+ flags |= PJMEDIA_FILE_NO_LOOP;
3741
+ }
3742
+
3743
+ res = json_get_int_param(document, "media_id", true, &media_id);
3744
+ if (res <= 0) {
3631
3745
  goto out;
3632
3746
  }
3633
3747
 
3634
- ae = (AudioEndpoint *)me->endpoint.audio;
3748
+ if (NOT_FOUND_OPTIONAL == res) {
3749
+ // start on all audio media endpoints
3750
+ for (int i = 0; i < call->media_count; i++) {
3751
+ MediaEndpoint *me = (MediaEndpoint *)call->media[i];
3752
+ if (me->type == ENDPOINT_TYPE_AUDIO) {
3753
+ AudioEndpoint *ae = (AudioEndpoint *)me->endpoint.audio;
3754
+ status = audio_endpoint_start_play_wav(call, ae, file, flags, end_of_file_event);
3755
+ if (status != PJ_SUCCESS) goto out;
3756
+ }
3757
+ }
3758
+ } else {
3759
+ if (media_id >= call->media_count) {
3760
+ set_error("invalid media_id");
3761
+ goto out;
3762
+ }
3635
3763
 
3636
- audio_endpoint_start_play_wav(call, ae, file);
3764
+ me = (MediaEndpoint *)call->media[media_id];
3765
+ if (ENDPOINT_TYPE_AUDIO != me->type) {
3766
+ set_error("media_endpoint is not audio endpoint");
3767
+ goto out;
3768
+ }
3769
+
3770
+ ae = (AudioEndpoint *)me->endpoint.audio;
3771
+
3772
+ audio_endpoint_start_play_wav(call, ae, file, flags, end_of_file_event);
3773
+ }
3637
3774
 
3638
3775
  out:
3639
3776
  PJW_UNLOCK();
@@ -3644,7 +3781,7 @@ out:
3644
3781
  return 0;
3645
3782
  }
3646
3783
 
3647
- pj_status_t audio_endpoint_start_speech_synth(Call *call, AudioEndpoint *ae, const char * voice, const char *text) {
3784
+ pj_status_t audio_endpoint_start_speech_synth(Call *call, AudioEndpoint *ae, const char * voice, const char *text, unsigned flags, bool end_of_speech_event) {
3648
3785
  pj_status_t status;
3649
3786
 
3650
3787
  if(!ae->stream_cbp.port) {
@@ -3653,16 +3790,16 @@ pj_status_t audio_endpoint_start_speech_synth(Call *call, AudioEndpoint *ae, con
3653
3790
  }
3654
3791
 
3655
3792
  // First stop and destroy existing flite port.
3656
- status = audio_endpoint_stop_flite(call, ae);
3793
+ status = audio_endpoint_stop_speech_synth(call, ae);
3657
3794
  if(status != PJ_SUCCESS) {
3658
3795
  return -1;
3659
3796
  }
3660
3797
 
3661
- if (!prepare_flite(call, ae, voice)) {
3798
+ if (!prepare_flite(call, ae, voice, end_of_speech_event)) {
3662
3799
  return -1;
3663
3800
  }
3664
3801
 
3665
- pjmedia_flite_port_speak(ae->flite_cbp.port, text, 0);
3802
+ pjmedia_flite_port_speak(ae->flite_cbp.port, text, flags);
3666
3803
 
3667
3804
  return PJ_SUCCESS;
3668
3805
  }
@@ -3674,21 +3811,30 @@ int pjw_call_start_speech_synth(long call_id, const char *json) {
3674
3811
  long val;
3675
3812
  Call *call;
3676
3813
 
3814
+ pj_status_t status;
3815
+
3677
3816
  MediaEndpoint *me;
3678
3817
  AudioEndpoint *ae;
3679
3818
  int ae_count;
3819
+ int res;
3680
3820
 
3681
- unsigned media_id = 0;
3821
+ int media_id = -1;
3682
3822
 
3683
3823
  char *voice;
3684
3824
 
3685
3825
  char *text;
3686
3826
 
3827
+ bool end_of_speech_event = false;
3828
+
3829
+ unsigned flags = 0;
3830
+
3831
+ bool no_loop = false;
3832
+
3687
3833
  char buffer[MAX_JSON_INPUT];
3688
3834
 
3689
3835
  Document document;
3690
3836
 
3691
- const char *valid_params[] = {"voice", "text", "media_id", ""};
3837
+ const char *valid_params[] = {"voice", "text", "media_id", "end_of_speech_event", "no_loop", ""};
3692
3838
 
3693
3839
  if (!g_call_ids.get(call_id, val)) {
3694
3840
  set_error("Invalid call_id");
@@ -3729,26 +3875,49 @@ int pjw_call_start_speech_synth(long call_id, const char *json) {
3729
3875
  goto out;
3730
3876
  }
3731
3877
 
3732
- if (ae_count > 1) {
3733
- if (json_get_uint_param(document, "media_id", false, &media_id) <= 0) {
3734
- goto out;
3735
- }
3878
+ if (json_get_bool_param(document, "end_of_speech_event", true, &end_of_speech_event) <= 0) {
3879
+ goto out;
3736
3880
  }
3737
3881
 
3738
- if ((int)media_id >= call->media_count) {
3739
- set_error("invalid media_id");
3882
+ if (json_get_bool_param(document, "no_loop", true, &no_loop) <= 0) {
3740
3883
  goto out;
3741
3884
  }
3742
3885
 
3743
- me = (MediaEndpoint *)call->media[media_id];
3744
- if (ENDPOINT_TYPE_AUDIO != me->type) {
3745
- set_error("media_endpoint is not audio endpoint");
3886
+ if(no_loop) {
3887
+ flags |= PJMEDIA_SPEECH_NO_LOOP;
3888
+ }
3889
+
3890
+ res = json_get_int_param(document, "media_id", true, &media_id);
3891
+ if (res <= 0) {
3746
3892
  goto out;
3747
3893
  }
3748
3894
 
3749
- ae = (AudioEndpoint *)me->endpoint.audio;
3895
+ if (NOT_FOUND_OPTIONAL == res) {
3896
+ // start on all audio media endpoints
3897
+ for (int i = 0; i < call->media_count; i++) {
3898
+ MediaEndpoint *me = (MediaEndpoint *)call->media[i];
3899
+ if (me->type == ENDPOINT_TYPE_AUDIO) {
3900
+ AudioEndpoint *ae = (AudioEndpoint *)me->endpoint.audio;
3901
+ status = audio_endpoint_start_speech_synth(call, ae, voice, text, flags, end_of_speech_event);
3902
+ if (status != PJ_SUCCESS) goto out;
3903
+ }
3904
+ }
3905
+ } else {
3906
+ if ((int)media_id >= call->media_count) {
3907
+ set_error("invalid media_id");
3908
+ goto out;
3909
+ }
3910
+
3911
+ me = (MediaEndpoint *)call->media[media_id];
3912
+ if (ENDPOINT_TYPE_AUDIO != me->type) {
3913
+ set_error("media_endpoint is not audio endpoint");
3914
+ goto out;
3915
+ }
3916
+
3917
+ ae = (AudioEndpoint *)me->endpoint.audio;
3750
3918
 
3751
- audio_endpoint_start_speech_synth(call, ae, voice, text);
3919
+ audio_endpoint_start_speech_synth(call, ae, voice, text, flags, end_of_speech_event);
3920
+ }
3752
3921
 
3753
3922
  out:
3754
3923
  PJW_UNLOCK();
@@ -3759,13 +3928,9 @@ out:
3759
3928
  return 0;
3760
3929
  }
3761
3930
 
3762
- pj_status_t audio_endpoint_stop_flite(Call *call, AudioEndpoint *ae) {
3763
- return audio_endpoint_remove_port(call, &ae->flite_cbp);
3764
- }
3765
-
3766
- pj_status_t call_stop_audio_endpoints_op(Call *call,
3931
+ pj_status_t call_stop_op_on_all_audio_endpoints(Call *call,
3767
3932
  audio_endpoint_stop_op_t op) {
3768
- addon_log(L_DBG, "call_stop_audio_endpoints_op media_count=%d\n",
3933
+ addon_log(L_DBG, "call_stop_op_on_audio_endpoints media_count=%d\n",
3769
3934
  call->media_count);
3770
3935
  pj_status_t status;
3771
3936
  for (int i = 0; i < call->media_count; i++) {
@@ -3784,11 +3949,7 @@ pj_status_t call_stop_audio_endpoints_op(Call *call,
3784
3949
  return PJ_SUCCESS;
3785
3950
  }
3786
3951
 
3787
- pj_status_t audio_endpoint_stop_play_wav(Call *call, AudioEndpoint *ae) {
3788
- return audio_endpoint_remove_port(call, &ae->wav_player_cbp);
3789
- }
3790
-
3791
- int pjw_call_stop_play_wav(long call_id, const char *json) {
3952
+ int audio_endpoint_stop_op(long call_id, const char *json, audio_endpoint_stop_op_t op) {
3792
3953
  PJW_LOCK();
3793
3954
  clear_error();
3794
3955
 
@@ -3802,7 +3963,7 @@ int pjw_call_stop_play_wav(long call_id, const char *json) {
3802
3963
  AudioEndpoint *ae;
3803
3964
  int res;
3804
3965
 
3805
- unsigned media_id = 0;
3966
+ int media_id = -1;
3806
3967
 
3807
3968
  char buffer[MAX_JSON_INPUT];
3808
3969
 
@@ -3818,21 +3979,19 @@ int pjw_call_stop_play_wav(long call_id, const char *json) {
3818
3979
  goto out;
3819
3980
  }
3820
3981
 
3821
- res = json_get_uint_param(document, "media_id", true, &media_id);
3982
+ res = json_get_int_param(document, "media_id", true, &media_id);
3822
3983
  if (res <= 0) {
3823
3984
  goto out;
3824
3985
  }
3825
3986
 
3826
3987
  if (NOT_FOUND_OPTIONAL == res) {
3827
- // Stop play wav in all audio endpoints
3828
- status = call_stop_audio_endpoints_op(call, audio_endpoint_stop_play_wav);
3829
- if (status != PJ_SUCCESS) {
3830
- goto out;
3831
- }
3988
+ // Stop op on all audio endpoints
3989
+ status = call_stop_op_on_all_audio_endpoints(call, op);
3990
+ if (status != PJ_SUCCESS) goto out;
3832
3991
  } else {
3833
- // Stop play wav on specified media_id
3992
+ // Stop op on specified media
3834
3993
 
3835
- if ((int)media_id >= call->media_count) {
3994
+ if (media_id >= call->media_count) {
3836
3995
  set_error("invalid media_id");
3837
3996
  goto out;
3838
3997
  }
@@ -3845,10 +4004,8 @@ int pjw_call_stop_play_wav(long call_id, const char *json) {
3845
4004
 
3846
4005
  ae = (AudioEndpoint *)me->endpoint.audio;
3847
4006
 
3848
- status = audio_endpoint_stop_play_wav(call, ae);
3849
- if (status != PJ_SUCCESS) {
3850
- goto out;
3851
- }
4007
+ status = op(call, ae);
4008
+ if (status != PJ_SUCCESS) goto out;
3852
4009
  }
3853
4010
 
3854
4011
  out:
@@ -3860,84 +4017,41 @@ out:
3860
4017
  return 0;
3861
4018
  }
3862
4019
 
3863
- pj_status_t audio_endpoint_stop_record_wav(Call *call, AudioEndpoint *ae) {
3864
- return audio_endpoint_remove_port(call, &ae->wav_writer_cbp);
4020
+ pj_status_t audio_endpoint_stop_speech_synth(Call *call, AudioEndpoint *ae) {
4021
+ return audio_endpoint_remove_port(call, &ae->flite_cbp);
3865
4022
  }
3866
4023
 
3867
- int pjw_call_stop_record_wav(long call_id, const char *json) {
3868
- PJW_LOCK();
3869
- clear_error();
3870
-
3871
- long val;
3872
- Call *call = (Call *)val;
3873
- pj_status_t status;
3874
-
3875
- MediaEndpoint *me;
3876
- AudioEndpoint *ae;
3877
- int res;
3878
-
3879
- unsigned media_id = 0;
3880
-
3881
- char buffer[MAX_JSON_INPUT];
3882
-
3883
- Document document;
3884
-
3885
- if (!g_call_ids.get(call_id, val)) {
3886
- set_error("Invalid call_id");
3887
- goto out;
3888
- }
3889
- call = (Call *)val;
3890
-
3891
- if (!parse_json(document, json, buffer, MAX_JSON_INPUT)) {
3892
- goto out;
3893
- }
3894
-
3895
- res = json_get_uint_param(document, "media_id", true, &media_id);
3896
- if (res <= 0) {
3897
- goto out;
3898
- }
3899
-
3900
- if (NOT_FOUND_OPTIONAL == res) {
3901
- // Stop record wav in all audio endpoints
3902
- status = call_stop_audio_endpoints_op(call, audio_endpoint_stop_record_wav);
3903
- if (status != PJ_SUCCESS) {
3904
- goto out;
3905
- }
3906
- } else {
3907
- // Stop record wav on specified media_id
4024
+ pj_status_t audio_endpoint_stop_play_wav(Call *call, AudioEndpoint *ae) {
4025
+ return audio_endpoint_remove_port(call, &ae->wav_player_cbp);
4026
+ }
3908
4027
 
3909
- if ((int)media_id >= call->media_count) {
3910
- set_error("invalid media_id");
3911
- goto out;
3912
- }
4028
+ pj_status_t audio_endpoint_stop_record_wav(Call *call, AudioEndpoint *ae) {
4029
+ return audio_endpoint_remove_port(call, &ae->wav_writer_cbp);
4030
+ }
3913
4031
 
3914
- me = (MediaEndpoint *)call->media[media_id];
3915
- if (ENDPOINT_TYPE_AUDIO != me->type) {
3916
- set_error("invalid media_id non audio");
3917
- goto out;
3918
- }
4032
+ pj_status_t audio_endpoint_stop_fax(Call *call, AudioEndpoint *ae) {
4033
+ return audio_endpoint_remove_port(call, &ae->fax_cbp);
4034
+ }
3919
4035
 
3920
- ae = (AudioEndpoint *)me->endpoint.audio;
3921
4036
 
3922
- status = audio_endpoint_stop_record_wav(call, ae);
3923
- if (status != PJ_SUCCESS) {
3924
- goto out;
3925
- }
3926
- }
3927
4037
 
3928
- out:
3929
- PJW_UNLOCK();
3930
- if (pjw_errorstring[0]) {
3931
- return -1;
3932
- }
4038
+ int pjw_call_stop_speech_synth(long call_id, const char *json) {
4039
+ return audio_endpoint_stop_op(call_id, json, audio_endpoint_stop_speech_synth);
4040
+ }
3933
4041
 
3934
- return 0;
4042
+ int pjw_call_stop_play_wav(long call_id, const char *json) {
4043
+ return audio_endpoint_stop_op(call_id, json, audio_endpoint_stop_play_wav);
4044
+ }
4045
+
4046
+ int pjw_call_stop_record_wav(long call_id, const char *json) {
4047
+ return audio_endpoint_stop_op(call_id, json, audio_endpoint_stop_record_wav);
3935
4048
  }
3936
4049
 
3937
- pj_status_t audio_endpoint_stop_fax(Call *call, AudioEndpoint *ae) {
3938
- return audio_endpoint_remove_port(call, &ae->fax_cbp);
4050
+ int pjw_call_stop_fax(long call_id, const char *json) {
4051
+ return audio_endpoint_stop_op(call_id, json, audio_endpoint_stop_fax);
3939
4052
  }
3940
4053
 
4054
+
3941
4055
  int pjw_call_start_fax(long call_id, const char *json) {
3942
4056
  PJW_LOCK();
3943
4057
  clear_error();
@@ -3954,8 +4068,9 @@ int pjw_call_start_fax(long call_id, const char *json) {
3954
4068
  MediaEndpoint *me;
3955
4069
  AudioEndpoint *ae;
3956
4070
  int ae_count;
4071
+ int res;
3957
4072
 
3958
- unsigned media_id = 0;
4073
+ int media_id = -1;
3959
4074
 
3960
4075
  char buffer[MAX_JSON_INPUT];
3961
4076
 
@@ -3994,46 +4109,10 @@ int pjw_call_start_fax(long call_id, const char *json) {
3994
4109
  goto out;
3995
4110
  }
3996
4111
 
3997
- if (ae_count > 1) {
3998
- if (json_get_uint_param(document, "media_id", false, &media_id) <= 0) {
3999
- goto out;
4000
- }
4001
- }
4002
-
4003
- if ((int)media_id >= call->media_count) {
4004
- set_error("invalid media_id");
4005
- goto out;
4006
- }
4007
-
4008
- me = (MediaEndpoint *)call->media[media_id];
4009
- if (ENDPOINT_TYPE_AUDIO != me->type) {
4010
- set_error("media_endpoint is not audio endpoint");
4011
- goto out;
4012
- }
4013
-
4014
- ae = (AudioEndpoint *)me->endpoint.audio;
4015
-
4016
- if (!parse_json(document, json, buffer, MAX_JSON_INPUT)) {
4017
- goto out;
4018
- }
4019
-
4020
- if (!validate_params(document, valid_params)) {
4021
- goto out;
4022
- }
4023
-
4024
4112
  if (json_get_bool_param(document, "is_sender", false, &is_sender) <= 0) {
4025
4113
  goto out;
4026
4114
  }
4027
4115
 
4028
- if (json_get_string_param(document, "file", false, &file) <= 0) {
4029
- goto out;
4030
- }
4031
-
4032
- if (!file[0]) {
4033
- set_error("file cannot be blank string");
4034
- goto out;
4035
- }
4036
-
4037
4116
  flag = false;
4038
4117
  if (json_get_bool_param(document, "transmit_on_idle", true, &flag) <= 0) {
4039
4118
  goto out;
@@ -4042,73 +4121,50 @@ int pjw_call_start_fax(long call_id, const char *json) {
4042
4121
  flags |= FAX_FLAG_TRANSMIT_ON_IDLE;
4043
4122
  }
4044
4123
 
4045
- // First stop and destroy existing fax port.
4046
- status = audio_endpoint_stop_fax(call, ae);
4047
- if(status != PJ_SUCCESS) {
4048
- set_error("audio_endpoint_stop_fax failed");
4049
- return -1;
4050
- }
4051
-
4052
- if (!prepare_fax(call, ae, is_sender, file, flags)) {
4053
- set_error("prepare_fax failed");
4054
- goto out;
4055
- }
4056
-
4057
- out:
4058
- PJW_UNLOCK();
4059
- if (pjw_errorstring[0]) {
4060
- return -1;
4061
- }
4062
-
4063
- return 0;
4064
- }
4065
-
4066
- int pjw_call_stop_fax(long call_id, const char *json) {
4067
- PJW_LOCK();
4068
- clear_error();
4069
-
4070
- long val;
4071
- Call *call;
4072
-
4073
- pj_status_t status;
4074
-
4075
- MediaEndpoint *me;
4076
- AudioEndpoint *ae;
4077
- int res;
4078
-
4079
- unsigned media_id = 0;
4080
-
4081
- char buffer[MAX_JSON_INPUT];
4082
-
4083
- Document document;
4084
-
4085
- if (!g_call_ids.get(call_id, val)) {
4086
- set_error("Invalid call_id");
4087
- goto out;
4088
- }
4089
- call = (Call *)val;
4124
+ if(is_sender) {
4125
+ // if we are sender we can do fax operaton to all media streams
4126
+ res = json_get_int_param(document, "media_id", true, &media_id);
4127
+ if (res <= 0) goto out;
4128
+
4129
+ if (NOT_FOUND_OPTIONAL == res) {
4130
+ // start fax on all audio endpoints
4131
+ for (int i = 0; i < call->media_count; i++) {
4132
+ MediaEndpoint *me = (MediaEndpoint *)call->media[i];
4133
+ if (ENDPOINT_TYPE_AUDIO == me->type) {
4134
+ me = (MediaEndpoint *)call->media[i];
4135
+ ae = (AudioEndpoint *)me->endpoint.audio;
4136
+ status = audio_endpoint_start_fax(call, ae, is_sender, file, flags);
4137
+ if(status != PJ_SUCCESS) goto out;
4138
+ }
4139
+ }
4140
+ } else {
4141
+ if ((int)media_id >= call->media_count) {
4142
+ set_error("invalid media_id");
4143
+ goto out;
4144
+ }
4090
4145
 
4091
- if (!parse_json(document, json, buffer, MAX_JSON_INPUT)) {
4092
- goto out;
4093
- }
4146
+ me = (MediaEndpoint *)call->media[media_id];
4147
+ if (ENDPOINT_TYPE_AUDIO != me->type) {
4148
+ set_error("invalid media_id non audio");
4149
+ goto out;
4150
+ }
4094
4151
 
4095
- res = json_get_uint_param(document, "media_id", true, &media_id);
4096
- if (res <= 0) {
4097
- goto out;
4098
- }
4152
+ ae = (AudioEndpoint *)me->endpoint.audio;
4099
4153
 
4100
- if (NOT_FOUND_OPTIONAL == res) {
4101
- // Stop fax in all audio endpoints
4102
- status = call_stop_audio_endpoints_op(call, audio_endpoint_stop_fax);
4103
- if (status != PJ_SUCCESS) {
4104
- goto out;
4154
+ status = audio_endpoint_start_fax(call, ae, is_sender, file, flags);
4155
+ if (status != PJ_SUCCESS) goto out;
4105
4156
  }
4106
4157
  } else {
4107
- // Stop fax on specified media_id
4108
-
4109
- if ((int)media_id >= call->media_count) {
4110
- set_error("invalid media_id");
4111
- goto out;
4158
+ // if we are not sender we can only start fax operation in a single media endpoint (otherwise, there would be more than one fax process writing to the same fax file)
4159
+ res = json_get_int_param(document, "media_id", true, &media_id);
4160
+ if (res <= 0) goto out;
4161
+
4162
+ if (NOT_FOUND_OPTIONAL == res) {
4163
+ media_id = get_first_media_id_by_type(call, ENDPOINT_TYPE_AUDIO);
4164
+ if(media_id < 0) {
4165
+ set_error("could not resolve media_id");
4166
+ goto out;
4167
+ }
4112
4168
  }
4113
4169
 
4114
4170
  me = (MediaEndpoint *)call->media[media_id];
@@ -4119,10 +4175,11 @@ int pjw_call_stop_fax(long call_id, const char *json) {
4119
4175
 
4120
4176
  ae = (AudioEndpoint *)me->endpoint.audio;
4121
4177
 
4178
+ // First stop and destroy existing fax port.
4122
4179
  status = audio_endpoint_stop_fax(call, ae);
4123
- if (status != PJ_SUCCESS) {
4124
- goto out;
4125
- }
4180
+ if(status != PJ_SUCCESS) goto out;
4181
+
4182
+ if (!prepare_fax(call, ae, is_sender, file, flags)) goto out;
4126
4183
  }
4127
4184
 
4128
4185
  out:
@@ -4889,6 +4946,7 @@ static void on_state_changed(pjsip_inv_session *inv, pjsip_event *e) {
4889
4946
  sip_msg = e->body.rx_msg.rdata->msg_info.msg_buf;
4890
4947
  }
4891
4948
 
4949
+ printf("call_id=%li sip_msg_len=%i sip_msg=%p\n", call_id, sip_msg_len, sip_msg);
4892
4950
  make_evt_call_ended(evt, sizeof(evt), call_id, sip_msg_len, sip_msg);
4893
4951
  dispatch_event(evt);
4894
4952
  }
@@ -6475,6 +6533,7 @@ void close_media_endpoint(Call *call, MediaEndpoint *me) {
6475
6533
  audio_endpoint_remove_port(call, &ae->tonegen_cbp);
6476
6534
  audio_endpoint_remove_port(call, &ae->dtmfdet_cbp);
6477
6535
  audio_endpoint_remove_port(call, &ae->fax_cbp);
6536
+ audio_endpoint_remove_port(call, &ae->flite_cbp);
6478
6537
 
6479
6538
  close_media_transport(ae->med_transport);
6480
6539
  ae->med_transport = NULL;
@@ -6500,7 +6559,7 @@ void close_media_endpoint(Call *call, MediaEndpoint *me) {
6500
6559
  }
6501
6560
 
6502
6561
  void close_media(Call *c) {
6503
- printf("close_media call_id=%li\n", c->id);
6562
+ printf("close_media call_id=%i\n", c->id);
6504
6563
  for (int i = 0; i < c->media_count; ++i) {
6505
6564
  MediaEndpoint *me = c->media[i];
6506
6565
  close_media_endpoint(c, me);
@@ -6542,7 +6601,7 @@ bool prepare_tonegen(Call *c, AudioEndpoint *ae) {
6542
6601
  return true;
6543
6602
  }
6544
6603
 
6545
- bool prepare_wav_player(Call *c, AudioEndpoint *ae, const char *file) {
6604
+ bool prepare_wav_player(Call *c, AudioEndpoint *ae, const char *file, unsigned flags, bool end_of_file_event) {
6546
6605
  pj_status_t status;
6547
6606
 
6548
6607
  unsigned wav_ptime;
@@ -6553,7 +6612,7 @@ bool prepare_wav_player(Call *c, AudioEndpoint *ae, const char *file) {
6553
6612
  c->inv->pool,
6554
6613
  file,
6555
6614
  wav_ptime,
6556
- 0, /* flags */
6615
+ flags,
6557
6616
  -1, /* buf size */
6558
6617
  &ae->wav_player_cbp.port
6559
6618
  );
@@ -6563,6 +6622,14 @@ bool prepare_wav_player(Call *c, AudioEndpoint *ae, const char *file) {
6563
6622
  return false;
6564
6623
  }
6565
6624
 
6625
+ if (end_of_file_event) {
6626
+ status = pjmedia_wav_player_set_eof_cb2(ae->wav_player_cbp.port, (void*)c, on_end_of_file);
6627
+ if (status != PJ_SUCCESS) {
6628
+ set_error("pjmedia_wav_player_set_eof_cb2 failed");
6629
+ return false;
6630
+ }
6631
+ }
6632
+
6566
6633
  status = pjmedia_conf_add_port(c->conf, c->inv->pool, ae->wav_player_cbp.port, NULL, &ae->wav_player_cbp.slot);
6567
6634
  if (status != PJ_SUCCESS) {
6568
6635
  set_error("pjmedia_conf_add_port failed");
@@ -6672,7 +6739,7 @@ bool prepare_fax(Call *c, AudioEndpoint *ae, bool is_sender, const char *file,
6672
6739
  return true;
6673
6740
  }
6674
6741
 
6675
- bool prepare_flite(Call *c, AudioEndpoint *ae, const char *voice) {
6742
+ bool prepare_flite(Call *c, AudioEndpoint *ae, const char *voice, bool end_of_speech_event) {
6676
6743
  printf("prepare_flite call.id=%i\n", c->id);
6677
6744
  pj_status_t status;
6678
6745
 
@@ -6685,12 +6752,20 @@ bool prepare_flite(Call *c, AudioEndpoint *ae, const char *voice) {
6685
6752
  c->inv->pool, PJMEDIA_PIA_SRATE(&ae->stream_cbp.port->info),
6686
6753
  PJMEDIA_PIA_CCNT(&ae->stream_cbp.port->info),
6687
6754
  PJMEDIA_PIA_SPF(&ae->stream_cbp.port->info),
6688
- PJMEDIA_PIA_BITS(&ae->stream_cbp.port->info), NULL, 0, voice, &ae->flite_cbp.port);
6755
+ PJMEDIA_PIA_BITS(&ae->stream_cbp.port->info), voice, &ae->flite_cbp.port);
6689
6756
  if (status != PJ_SUCCESS) {
6690
6757
  set_error("pjmedia_flite_port_create failed");
6691
6758
  return false;
6692
6759
  }
6693
6760
 
6761
+ if (end_of_speech_event) {
6762
+ status = pjmedia_flite_port_set_eof_cb(ae->flite_cbp.port, (void*)c, on_end_of_speech);
6763
+ if (status != PJ_SUCCESS) {
6764
+ set_error("pjmedia_flite_port_set_eof_cb failed");
6765
+ return false;
6766
+ }
6767
+ }
6768
+
6694
6769
  status = pjmedia_conf_add_port(c->conf, c->inv->pool, ae->flite_cbp.port, NULL, &ae->flite_cbp.slot);
6695
6770
  if (status != PJ_SUCCESS) {
6696
6771
  set_error("pjmedia_conf_add_port failed");
@@ -8012,7 +8087,7 @@ int pjw_call_send_tcp_msg(long call_id, const char *json) {
8012
8087
  MediaEndpoint *me;
8013
8088
  int res;
8014
8089
 
8015
- unsigned media_id = 0;
8090
+ int media_id = -1;
8016
8091
 
8017
8092
  char buffer[MAX_JSON_INPUT];
8018
8093
 
@@ -8036,7 +8111,7 @@ int pjw_call_send_tcp_msg(long call_id, const char *json) {
8036
8111
  }
8037
8112
  size = strlen(msg);
8038
8113
 
8039
- res = json_get_uint_param(document, "media_id", true, &media_id);
8114
+ res = json_get_int_param(document, "media_id", true, &media_id);
8040
8115
  if (res <= 0) {
8041
8116
  goto out;
8042
8117
  }
@@ -8050,7 +8125,7 @@ int pjw_call_send_tcp_msg(long call_id, const char *json) {
8050
8125
  } else {
8051
8126
  // Send msg to specified media_id
8052
8127
 
8053
- if ((int)media_id >= call->media_count) {
8128
+ if (media_id >= call->media_count) {
8054
8129
  set_error("invalid media_id");
8055
8130
  goto out;
8056
8131
  }