sip-lab 1.23.0 → 1.24.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
@@ -23,6 +23,7 @@
23
23
  #include "dtmfdet.h"
24
24
  #include "fax_port.h"
25
25
  #include "flite_port.h"
26
+ #include "pocketsphinx_port.h"
26
27
 
27
28
  #include <ctime>
28
29
 
@@ -265,14 +266,6 @@ pjsip_route_hdr route_set;
265
266
  pjsip_route_hdr *route;
266
267
  const pj_str_t hname = pj_str((char *)"Route");
267
268
 
268
- #define CONF_PORTS 1024
269
- //#define CLOCK_RATE 16000
270
- #define CLOCK_RATE 8000
271
- #define CHANNEL_COUNT 1
272
- #define PTIME 20
273
- #define SAMPLES_PER_FRAME (CLOCK_RATE*PTIME/1000)
274
- #define BITS_PER_SAMPLE 16
275
-
276
269
  #define MAXDIGITS 256
277
270
 
278
271
  #define DTMF_MODE_RFC2833 0
@@ -324,6 +317,10 @@ struct AudioEndpoint {
324
317
 
325
318
  pj_str_t mode;
326
319
 
320
+ pjmedia_conf *conf;
321
+ pjmedia_master_port *master_port;
322
+ pjmedia_port *null_port;
323
+
327
324
  ConfBridgePort stream_cbp;
328
325
  ConfBridgePort wav_player_cbp;
329
326
  ConfBridgePort wav_writer_cbp;
@@ -331,6 +328,7 @@ struct AudioEndpoint {
331
328
  ConfBridgePort dtmfdet_cbp;
332
329
  ConfBridgePort fax_cbp;
333
330
  ConfBridgePort flite_cbp;
331
+ ConfBridgePort pocketsphinx_cbp;
334
332
  };
335
333
 
336
334
  struct VideoEndpoint {
@@ -433,10 +431,6 @@ struct Call {
433
431
  pjmedia_sdp_session *active_remote_sdp;
434
432
 
435
433
  bool local_sdp_answer_already_set;
436
-
437
- pjmedia_conf *conf;
438
- pjmedia_master_port *master_port;
439
- pjmedia_port *null_port;
440
434
  };
441
435
 
442
436
  #define MAX_TCP_DATA 4096
@@ -472,6 +466,10 @@ PackageSet g_PackageSet;
472
466
 
473
467
  #define DEFAULT_EXPIRES 600
474
468
 
469
+ #define CONNECTION_MODE_SOURCE 0
470
+ #define CONNECTION_MODE_SINK 1
471
+ #define CONNECTION_MODE_SOURCE_AND_SINK 2
472
+
475
473
  void handle_events() {
476
474
  pj_time_val tv = {0, 1};
477
475
  pjsip_endpt_handle_events(g_sip_endpt, &tv);
@@ -618,23 +616,23 @@ static void build_stream_stat(ostringstream &oss, pjmedia_rtcp_stat *stat,
618
616
 
619
617
  bool prepare_tonegen(Call *call, AudioEndpoint *ae);
620
618
  bool prepare_dtmfdet(Call *call, AudioEndpoint *ae);
621
- bool prepare_wav_player(Call *c, AudioEndpoint *ae, const char *file, unsigned flags, bool end_of_file_event);
622
- bool prepare_wav_writer(Call *c, AudioEndpoint *ae, const char *file);
623
- bool prepare_fax(Call *c, AudioEndpoint *ae, bool is_sender, const char *file,
624
- unsigned flags);
625
- bool prepare_flite(Call *c, AudioEndpoint *ae, const char *voice, bool end_of_speech_event);
619
+ bool prepare_wav_player(Call *call, AudioEndpoint *ae, const char *file, unsigned flags, bool end_of_file_event);
620
+ bool prepare_wav_writer(Call *call, AudioEndpoint *ae, const char *file);
621
+ bool prepare_fax(Call *call, AudioEndpoint *ae, bool is_sender, const char *file, unsigned flags);
622
+ bool prepare_flite(Call *call, AudioEndpoint *ae, const char *voice, bool end_of_speech_event);
623
+ bool prepare_pocketsphinx(Call *call, AudioEndpoint *ae);
626
624
 
627
625
  void prepare_error_event(ostringstream *oss, char *scope, char *details);
628
626
  // void prepare_pjsipcall_error_event(ostringstream *oss, char *scope, char
629
627
  // *function, pj_status_t s);
630
628
  void append_status(ostringstream *oss, pj_status_t s);
631
629
 
632
- bool is_media_active(Call *c, MediaEndpoint *me);
630
+ bool is_media_active(Call *call, MediaEndpoint *me);
633
631
  void close_media_endpoint(Call *call, MediaEndpoint *me);
634
632
 
635
- void close_media(Call *c);
633
+ void close_media(Call *call);
636
634
 
637
- bool process_media(Call *c, pjsip_dialog *dlg, Document &document, bool answer);
635
+ bool process_media(Call *call, pjsip_dialog *dlg, Document &document, bool answer);
638
636
 
639
637
  typedef pj_status_t (*audio_endpoint_stop_op_t)(Call *call, AudioEndpoint *ae);
640
638
 
@@ -642,6 +640,7 @@ pj_status_t audio_endpoint_stop_play_wav(Call *call, AudioEndpoint *ae);
642
640
  pj_status_t audio_endpoint_stop_record_wav(Call *call, AudioEndpoint *ae);
643
641
  pj_status_t audio_endpoint_stop_fax(Call *call, AudioEndpoint *ae);
644
642
  pj_status_t audio_endpoint_stop_speech_synth(Call *call, AudioEndpoint *ae);
643
+ pj_status_t audio_endpoint_stop_speech_recog(Call *call, AudioEndpoint *ae);
645
644
 
646
645
  static pjsip_module mod_tester = {
647
646
  NULL,
@@ -716,23 +715,36 @@ find_endpoint_by_inband_dtmf_media_stream(Call *call,
716
715
  return -1;
717
716
  }
718
717
 
719
- pj_status_t setup_call_conf(Call *call) {
718
+ pj_status_t create_audio_endpoint_conf(Call *call, AudioEndpoint *ae, pjmedia_port *stream_port) {
720
719
  pj_status_t status;
720
+ int conf_ports = 16;
721
+
722
+ unsigned sampling_rate = PJMEDIA_PIA_SRATE(&stream_port->info);
723
+ unsigned channel_count = PJMEDIA_PIA_CCNT(&stream_port->info);
724
+ unsigned samples_per_frame = PJMEDIA_PIA_SPF(&stream_port->info);
725
+ unsigned bits_per_sample = PJMEDIA_PIA_BITS(&stream_port->info);
726
+
721
727
  status = pjmedia_conf_create(call->inv->pool,
722
- CONF_PORTS,
723
- CLOCK_RATE,
724
- CHANNEL_COUNT,
725
- SAMPLES_PER_FRAME,
726
- BITS_PER_SAMPLE,
728
+ conf_ports,
729
+ sampling_rate,
730
+ channel_count,
731
+ samples_per_frame,
732
+ bits_per_sample,
727
733
  PJMEDIA_CONF_NO_DEVICE,
728
- &call->conf);
734
+ &ae->conf);
729
735
 
730
736
  if (status != PJ_SUCCESS) {
731
737
  addon_log(L_DBG, "pjmedia_conf_create failed\n");
732
738
  return false;
733
739
  }
734
740
 
735
- status = pjmedia_null_port_create(call->inv->pool, CLOCK_RATE, CHANNEL_COUNT, SAMPLES_PER_FRAME, BITS_PER_SAMPLE, &call->null_port);
741
+ status = pjmedia_null_port_create(
742
+ call->inv->pool,
743
+ sampling_rate,
744
+ channel_count,
745
+ samples_per_frame,
746
+ bits_per_sample,
747
+ &ae->null_port);
736
748
  if (status != PJ_SUCCESS) {
737
749
  addon_log(L_DBG, "pjmedia_null_port_created failed\n");
738
750
  return false;
@@ -740,19 +752,19 @@ pj_status_t setup_call_conf(Call *call) {
740
752
 
741
753
  pjmedia_port *conf_port = NULL;
742
754
 
743
- conf_port = pjmedia_conf_get_master_port(call->conf);
755
+ conf_port = pjmedia_conf_get_master_port(ae->conf);
744
756
  if (conf_port == NULL) {
745
757
  addon_log(L_DBG, "pjmedia_conf_get_master_port failed\n");
746
758
  return false;
747
759
  }
748
760
 
749
- status = pjmedia_master_port_create(call->inv->pool, call->null_port, conf_port, 0, &call->master_port);
761
+ status = pjmedia_master_port_create(call->inv->pool, ae->null_port, conf_port, 0, &ae->master_port);
750
762
  if (status != PJ_SUCCESS) {
751
763
  addon_log(L_DBG, "pjmedia_master_port_create failed\n");
752
764
  return false;
753
765
  }
754
766
 
755
- status = pjmedia_master_port_start(call->master_port);
767
+ status = pjmedia_master_port_start(ae->master_port);
756
768
  if (status != PJ_SUCCESS) {
757
769
  addon_log(L_DBG, "pjmedia_master_port_start failed\n");
758
770
  return false;
@@ -761,38 +773,6 @@ pj_status_t setup_call_conf(Call *call) {
761
773
  return PJ_SUCCESS;
762
774
  }
763
775
 
764
- void release_call_conf(Call *call) {
765
- pj_status_t status;
766
-
767
- if (call->master_port) {
768
- status = pjmedia_master_port_stop(call->master_port);
769
- if(status != PJ_SUCCESS) {
770
- addon_log(L_DBG, "pjmedia_master_port_stop failed\n");
771
- }
772
- pjmedia_master_port_destroy(call->master_port, 0);
773
- if(status != PJ_SUCCESS) {
774
- addon_log(L_DBG, "pjmedia_master_port_destroy failed\n");
775
- }
776
- call->master_port = NULL;
777
- }
778
-
779
- if (call->conf) {
780
- status = pjmedia_conf_destroy(call->conf);
781
- if(status != PJ_SUCCESS) {
782
- addon_log(L_DBG, "pjmedia_conf_destroy failed\n");
783
- }
784
- call->conf = NULL;
785
- }
786
-
787
- if (call->null_port) {
788
- status = pjmedia_port_destroy(call->null_port);
789
- if(status != PJ_SUCCESS) {
790
- addon_log(L_DBG, "pjmedia_port_destroy(null_port) failed\n");
791
- }
792
- call->null_port = NULL;
793
- }
794
- }
795
-
796
776
  static int find_endpoint_by_inband_dtmf_media_port(Call *call,
797
777
  pjmedia_port *port) {
798
778
  for (int i = 0; i < call->media_count; i++) {
@@ -905,6 +885,22 @@ static void on_end_of_speech(pjmedia_port *port, void *user_data) {
905
885
  dispatch_event(evt);
906
886
  }
907
887
 
888
+ static void on_speech_transcript(pjmedia_port*, void *user_data, char* transcript) {
889
+ if (g_shutting_down)
890
+ return;
891
+
892
+ long call_id;
893
+ if (!g_call_ids.get_id((long)user_data, call_id)) {
894
+ addon_log(
895
+ L_DBG,
896
+ "on_speech_transcript: Failed to get call_id. Event will not be notified.\n");
897
+ return;
898
+ }
899
+
900
+ char evt[1024];
901
+ make_evt_speech_transcript(evt, sizeof(evt), call_id, transcript);
902
+ dispatch_event(evt);
903
+ }
908
904
 
909
905
  void dispatch_event(const char *evt) {
910
906
  addon_log(L_DBG, "dispach_event called with evt=%s\n", evt);
@@ -3047,12 +3043,6 @@ int call_create(Transport *t, unsigned flags, pjsip_dialog *dlg,
3047
3043
  }
3048
3044
  // addon_log(L_DBG, "pjsip_dlg_add_usage OK\n");
3049
3045
 
3050
- status = setup_call_conf(call);
3051
- if (status != PJ_SUCCESS) {
3052
- set_error("setup_call_conf failed");
3053
- return -1;
3054
- }
3055
-
3056
3046
  return call_id;
3057
3047
  }
3058
3048
 
@@ -3251,7 +3241,7 @@ out:
3251
3241
  return 0;
3252
3242
  }
3253
3243
 
3254
- pj_status_t audio_endpoint_remove_port(Call *call, ConfBridgePort *cbp) {
3244
+ pj_status_t audio_endpoint_remove_port(Call *call, AudioEndpoint *ae, ConfBridgePort *cbp) {
3255
3245
  printf("audio_endpoint_remove_port\n");
3256
3246
  pj_status_t status;
3257
3247
 
@@ -3262,7 +3252,7 @@ pj_status_t audio_endpoint_remove_port(Call *call, ConfBridgePort *cbp) {
3262
3252
  pjmedia_conf_disconnect_port_from_sinks(conf, port);
3263
3253
  */
3264
3254
 
3265
- status = pjmedia_conf_remove_port(call->conf, cbp->slot);
3255
+ status = pjmedia_conf_remove_port(ae->conf, cbp->slot);
3266
3256
  if (status != PJ_SUCCESS) {
3267
3257
  set_error("pjmedia_conf_remove_port failed");
3268
3258
  return false;
@@ -3928,6 +3918,121 @@ out:
3928
3918
  return 0;
3929
3919
  }
3930
3920
 
3921
+ pj_status_t audio_endpoint_start_speech_recog(Call *call, AudioEndpoint *ae) {
3922
+ pj_status_t status;
3923
+
3924
+ if(!ae->stream_cbp.port) {
3925
+ set_error("stream port is not ready yet");
3926
+ return -1;
3927
+ }
3928
+
3929
+ // First stop and destroy existing port.
3930
+ status = audio_endpoint_stop_speech_recog(call, ae);
3931
+ if(status != PJ_SUCCESS) {
3932
+ return -1;
3933
+ }
3934
+
3935
+ if (!prepare_pocketsphinx(call, ae)) {
3936
+ return -1;
3937
+ }
3938
+
3939
+ return PJ_SUCCESS;
3940
+ }
3941
+
3942
+ int pjw_call_start_speech_recog(long call_id, const char *json) {
3943
+ PJW_LOCK();
3944
+ clear_error();
3945
+
3946
+ long val;
3947
+ Call *call;
3948
+
3949
+ pj_status_t status;
3950
+
3951
+ MediaEndpoint *me;
3952
+ AudioEndpoint *ae;
3953
+ int ae_count;
3954
+ int res;
3955
+
3956
+ int media_id = -1;
3957
+
3958
+ char *voice;
3959
+
3960
+ char *text;
3961
+
3962
+ bool end_of_speech_event = false;
3963
+
3964
+ unsigned flags = 0;
3965
+
3966
+ bool no_loop = false;
3967
+
3968
+ char buffer[MAX_JSON_INPUT];
3969
+
3970
+ Document document;
3971
+
3972
+ const char *valid_params[] = {"media_id", ""};
3973
+
3974
+ if (!g_call_ids.get(call_id, val)) {
3975
+ set_error("Invalid call_id");
3976
+ goto out;
3977
+ }
3978
+ call = (Call *)val;
3979
+
3980
+ ae_count = count_media_by_type(call, ENDPOINT_TYPE_AUDIO);
3981
+
3982
+ if (ae_count == 0) {
3983
+ set_error("No audio endpoint");
3984
+ goto out;
3985
+ }
3986
+
3987
+ if (!parse_json(document, json, buffer, MAX_JSON_INPUT)) {
3988
+ goto out;
3989
+ }
3990
+
3991
+ if (!validate_params(document, valid_params)) {
3992
+ goto out;
3993
+ }
3994
+
3995
+ res = json_get_int_param(document, "media_id", true, &media_id);
3996
+ if (res <= 0) {
3997
+ goto out;
3998
+ }
3999
+
4000
+ if (NOT_FOUND_OPTIONAL == res) {
4001
+ // start on all audio media endpoints
4002
+ for (int i = 0; i < call->media_count; i++) {
4003
+ MediaEndpoint *me = (MediaEndpoint *)call->media[i];
4004
+ if (me->type == ENDPOINT_TYPE_AUDIO) {
4005
+ AudioEndpoint *ae = (AudioEndpoint *)me->endpoint.audio;
4006
+ status = audio_endpoint_start_speech_recog(call, ae);
4007
+ if (status != PJ_SUCCESS) goto out;
4008
+ }
4009
+ }
4010
+ } else {
4011
+ if ((int)media_id >= call->media_count) {
4012
+ set_error("invalid media_id");
4013
+ goto out;
4014
+ }
4015
+
4016
+ me = (MediaEndpoint *)call->media[media_id];
4017
+ if (ENDPOINT_TYPE_AUDIO != me->type) {
4018
+ set_error("media_endpoint is not audio endpoint");
4019
+ goto out;
4020
+ }
4021
+
4022
+ ae = (AudioEndpoint *)me->endpoint.audio;
4023
+
4024
+ audio_endpoint_start_speech_recog(call, ae);
4025
+ }
4026
+
4027
+ out:
4028
+ PJW_UNLOCK();
4029
+ if (pjw_errorstring[0]) {
4030
+ return -1;
4031
+ }
4032
+
4033
+ return 0;
4034
+ }
4035
+
3931
4036
  pj_status_t call_stop_op_on_all_audio_endpoints(Call *call,
3932
4037
  audio_endpoint_stop_op_t op) {
3933
4038
  addon_log(L_DBG, "call_stop_op_on_audio_endpoints media_count=%d\n",
@@ -4018,19 +4123,23 @@ out:
4018
4123
  }
4019
4124
 
4020
4125
  pj_status_t audio_endpoint_stop_speech_synth(Call *call, AudioEndpoint *ae) {
4021
- return audio_endpoint_remove_port(call, &ae->flite_cbp);
4126
+ return audio_endpoint_remove_port(call, ae, &ae->flite_cbp);
4127
+ }
4128
+
4129
+ pj_status_t audio_endpoint_stop_speech_recog(Call *call, AudioEndpoint *ae) {
4130
+ return audio_endpoint_remove_port(call, ae, &ae->pocketsphinx_cbp);
4022
4131
  }
4023
4132
 
4024
4133
  pj_status_t audio_endpoint_stop_play_wav(Call *call, AudioEndpoint *ae) {
4025
- return audio_endpoint_remove_port(call, &ae->wav_player_cbp);
4134
+ return audio_endpoint_remove_port(call, ae, &ae->wav_player_cbp);
4026
4135
  }
4027
4136
 
4028
4137
  pj_status_t audio_endpoint_stop_record_wav(Call *call, AudioEndpoint *ae) {
4029
- return audio_endpoint_remove_port(call, &ae->wav_writer_cbp);
4138
+ return audio_endpoint_remove_port(call, ae, &ae->wav_writer_cbp);
4030
4139
  }
4031
4140
 
4032
4141
  pj_status_t audio_endpoint_stop_fax(Call *call, AudioEndpoint *ae) {
4033
- return audio_endpoint_remove_port(call, &ae->fax_cbp);
4142
+ return audio_endpoint_remove_port(call, ae, &ae->fax_cbp);
4034
4143
  }
4035
4144
 
4036
4145
 
@@ -4039,6 +4148,10 @@ int pjw_call_stop_speech_synth(long call_id, const char *json) {
4039
4148
  return audio_endpoint_stop_op(call_id, json, audio_endpoint_stop_speech_synth);
4040
4149
  }
4041
4150
 
4151
+ int pjw_call_stop_speech_recog(long call_id, const char *json) {
4152
+ return audio_endpoint_stop_op(call_id, json, audio_endpoint_stop_speech_recog);
4153
+ }
4154
+
4042
4155
  int pjw_call_stop_play_wav(long call_id, const char *json) {
4043
4156
  return audio_endpoint_stop_op(call_id, json, audio_endpoint_stop_play_wav);
4044
4157
  }
@@ -4523,82 +4636,80 @@ bool start_tcp_media(Call *call, MediaEndpoint *me,
4523
4636
  return true;
4524
4637
  }
4525
4638
 
4639
+ void close_audio_endpoint_ports_and_conf(Call *call, AudioEndpoint *ae) {
4640
+ pj_status_t status;
4526
4641
 
4527
- bool restart_media_stream(Call *call, MediaEndpoint *me,
4528
- const pjmedia_sdp_session *local_sdp,
4529
- const pjmedia_sdp_session *remote_sdp, int idx) {
4530
- char evt[4096];
4531
- pjmedia_stream_info stream_info;
4532
-
4533
- AudioEndpoint *ae = (AudioEndpoint *)me->endpoint.audio;
4534
-
4535
- pj_status_t status;
4536
-
4537
- if(ae->stream_cbp.port) {
4538
- if(ae->tonegen_cbp.port) {
4539
- status = pjmedia_conf_disconnect_port(call->conf, ae->tonegen_cbp.slot, ae->stream_cbp.slot);
4540
- if (status != PJ_SUCCESS) {
4541
- make_evt_media_update(evt, sizeof(evt), call->id,
4542
- "setup_failed (pjmedia_conf_disconnect_port for tonegen failed)", "");
4543
- dispatch_event(evt);
4544
- return false;
4545
- }
4642
+ audio_endpoint_remove_port(call, ae, &ae->stream_cbp);
4643
+ audio_endpoint_remove_port(call, ae, &ae->wav_player_cbp);
4644
+ audio_endpoint_remove_port(call, ae, &ae->wav_writer_cbp);
4645
+ audio_endpoint_remove_port(call, ae, &ae->tonegen_cbp);
4646
+ audio_endpoint_remove_port(call, ae, &ae->dtmfdet_cbp);
4647
+ audio_endpoint_remove_port(call, ae, &ae->fax_cbp);
4648
+ audio_endpoint_remove_port(call, ae, &ae->flite_cbp);
4649
+ audio_endpoint_remove_port(call, ae, &ae->pocketsphinx_cbp);
4650
+
4651
+ if (ae->master_port) {
4652
+ status = pjmedia_master_port_stop(ae->master_port);
4653
+ if(status != PJ_SUCCESS) {
4654
+ addon_log(L_DBG, "pjmedia_master_port_stop failed\n");
4655
+ }
4656
+ pjmedia_master_port_destroy(ae->master_port, 0);
4657
+ if(status != PJ_SUCCESS) {
4658
+ addon_log(L_DBG, "pjmedia_master_port_destroy failed\n");
4659
+ }
4660
+ ae->master_port = NULL;
4546
4661
  }
4547
4662
 
4548
- if(ae->wav_player_cbp.port) {
4549
- status = pjmedia_conf_disconnect_port(call->conf, ae->wav_player_cbp.slot, ae->stream_cbp.slot);
4550
- if (status != PJ_SUCCESS) {
4551
- make_evt_media_update(evt, sizeof(evt), call->id,
4552
- "setup_failed (pjmedia_conf_disconnect_port for wav_player failed)", "");
4553
- dispatch_event(evt);
4554
- return false;
4555
- }
4663
+ if (ae->conf) {
4664
+ status = pjmedia_conf_destroy(ae->conf);
4665
+ if(status != PJ_SUCCESS) {
4666
+ addon_log(L_DBG, "pjmedia_conf_destroy failed\n");
4667
+ }
4668
+ ae->conf = NULL;
4556
4669
  }
4557
4670
 
4558
- if(ae->dtmfdet_cbp.port) {
4559
- status = pjmedia_conf_disconnect_port(call->conf, ae->stream_cbp.slot, ae->dtmfdet_cbp.slot);
4560
- if (status != PJ_SUCCESS) {
4561
- make_evt_media_update(evt, sizeof(evt), call->id,
4562
- "setup_failed (pjmedia_conf_disconnect_port for dtmfdet failed)", "");
4563
- dispatch_event(evt);
4564
- return false;
4565
- }
4671
+ if (ae->null_port) {
4672
+ status = pjmedia_port_destroy(ae->null_port);
4673
+ if(status != PJ_SUCCESS) {
4674
+ addon_log(L_DBG, "pjmedia_port_destroy(null_port) failed\n");
4675
+ }
4676
+ ae->null_port = NULL;
4566
4677
  }
4678
+ }
4567
4679
 
4568
- if(ae->fax_cbp.port) {
4569
- status = pjmedia_conf_disconnect_port(call->conf, ae->stream_cbp.slot, ae->fax_cbp.slot);
4570
- if (status != PJ_SUCCESS) {
4571
- make_evt_media_update(evt, sizeof(evt), call->id,
4572
- "setup_failed (pjmedia_conf_disconnect_port fax dst failed)", "");
4573
- dispatch_event(evt);
4574
- return false;
4575
- }
4576
-
4577
- status = pjmedia_conf_disconnect_port(call->conf, ae->fax_cbp.slot, ae->stream_cbp.slot);
4578
- if (status != PJ_SUCCESS) {
4579
- make_evt_media_update(evt, sizeof(evt), call->id,
4580
- "setup_failed (pjmedia_conf_disconnect_port for fax src failed)", "");
4581
- dispatch_event(evt);
4582
- return false;
4583
- }
4584
- }
4680
+ bool connect_feature_port_to_stream_port(Call *call, AudioEndpoint *ae, ConfBridgePort *cbp, int connection_mode) {
4681
+ pj_status_t status;
4585
4682
 
4586
- status = pjmedia_conf_remove_port(call->conf, ae->stream_cbp.slot);
4683
+ if(connection_mode == CONNECTION_MODE_SOURCE || connection_mode == CONNECTION_MODE_SOURCE_AND_SINK) {
4684
+ status = pjmedia_conf_connect_port(ae->conf, cbp->slot, ae->stream_cbp.slot, 0);
4587
4685
  if (status != PJ_SUCCESS) {
4588
- make_evt_media_update(evt, sizeof(evt), call->id,
4589
- "setup_failed (pjmedia_conf_remove_port failed)", "");
4686
+ set_error("pjmedia_conf_connect_port failed");
4590
4687
  return false;
4591
4688
  }
4592
- ae->stream_cbp.slot = 0;
4593
-
4594
- status = pjmedia_port_destroy(ae->stream_cbp.port);
4689
+ }
4690
+ if(connection_mode == CONNECTION_MODE_SINK || connection_mode == CONNECTION_MODE_SOURCE_AND_SINK) {
4691
+ status = pjmedia_conf_connect_port(ae->conf, ae->stream_cbp.slot, cbp->slot, 0);
4692
+ printf("status=%i\n" ,status);
4595
4693
  if (status != PJ_SUCCESS) {
4596
- make_evt_media_update(evt, sizeof(evt), call->id,
4597
- "setup_failed (pjmedia_port_destroy failed)", "");
4694
+ set_error("pjmedia_conf_connect_port failed");
4598
4695
  return false;
4599
4696
  }
4600
- ae->stream_cbp.port = NULL;
4601
- }
4697
+ }
4698
+ return true;
4699
+ }
4700
+
4701
+ bool restart_media_stream(Call *call, MediaEndpoint *me,
4702
+ const pjmedia_sdp_session *local_sdp,
4703
+ const pjmedia_sdp_session *remote_sdp, int idx) {
4704
+ char evt[4096];
4705
+ pjmedia_stream_info stream_info;
4706
+
4707
+ AudioEndpoint *ae = (AudioEndpoint *)me->endpoint.audio;
4708
+
4709
+ pj_status_t status;
4710
+
4711
+ pjmedia_port *old_port = ae->stream_cbp.port;
4712
+ pjmedia_port *new_port;
4602
4713
 
4603
4714
  status =
4604
4715
  pjmedia_stream_info_from_sdp(&stream_info, call->inv->dlg->pool,
@@ -4664,7 +4775,7 @@ bool restart_media_stream(Call *call, MediaEndpoint *me,
4664
4775
  return false;
4665
4776
  }
4666
4777
 
4667
- status = pjmedia_stream_get_port(ae->med_stream, &ae->stream_cbp.port);
4778
+ status = pjmedia_stream_get_port(ae->med_stream, &new_port);
4668
4779
  if (status != PJ_SUCCESS) {
4669
4780
  make_evt_media_update(evt, sizeof(evt), call->id,
4670
4781
  "setup_failed (pjmedia_stream_get_port failed)", "");
@@ -4672,73 +4783,112 @@ bool restart_media_stream(Call *call, MediaEndpoint *me,
4672
4783
  return false;
4673
4784
  }
4674
4785
 
4675
- status = pjmedia_conf_add_port(call->conf, call->inv->pool, ae->stream_cbp.port, NULL, &ae->stream_cbp.slot);
4676
- if (status != PJ_SUCCESS) {
4677
- make_evt_media_update(evt, sizeof(evt), call->id,
4678
- "setup_failed (pjmedia_conf_add_port failed)", "");
4679
- dispatch_event(evt);
4680
- return false;
4681
- }
4682
-
4683
- if(!ae->dtmfdet_cbp.port) {
4684
- if(!prepare_dtmfdet(call, ae)) {
4786
+ if(!old_port) {
4787
+ printf("call_id=%i restart_media_stream !old_port (first SDP negotiation)\n", call->id);
4788
+ status = create_audio_endpoint_conf(call, ae, new_port);
4789
+ if (status != PJ_SUCCESS) {
4685
4790
  make_evt_media_update(evt, sizeof(evt), call->id,
4686
- "setup_failed (prepare_dtmfdet failed)", "");
4791
+ "setup_failed (create_audio_endpoint_conf failed)", "");
4687
4792
  dispatch_event(evt);
4688
4793
  return false;
4689
4794
  }
4690
- }
4691
4795
 
4692
- if(ae->tonegen_cbp.port) {
4693
- status = pjmedia_conf_connect_port(call->conf, ae->tonegen_cbp.slot, ae->stream_cbp.slot, 0);
4796
+ ae->stream_cbp.port = new_port;
4797
+ status = pjmedia_conf_add_port(ae->conf, call->inv->pool, ae->stream_cbp.port, NULL, &ae->stream_cbp.slot);
4694
4798
  if (status != PJ_SUCCESS) {
4695
4799
  make_evt_media_update(evt, sizeof(evt), call->id,
4696
- "setup_failed (pjmedia_conf_connect_port for tonegen failed)", "");
4800
+ "setup_failed (pjmedia_conf_add_port failed)", "");
4697
4801
  dispatch_event(evt);
4698
4802
  return false;
4699
4803
  }
4700
- }
4701
4804
 
4702
- if(ae->wav_player_cbp.port) {
4703
- status = pjmedia_conf_connect_port(call->conf, ae->wav_player_cbp.slot, ae->stream_cbp.slot, 0);
4704
- if (status != PJ_SUCCESS) {
4805
+ // we always add dtmfdet to audio endpoints
4806
+ if(!prepare_dtmfdet(call, ae)) {
4705
4807
  make_evt_media_update(evt, sizeof(evt), call->id,
4706
- "setup_failed (pjmedia_conf_connect_port for wav_player failed)", "");
4808
+ "setup_failed (prepare_dtmfdet failed)", "");
4707
4809
  dispatch_event(evt);
4708
4810
  return false;
4709
4811
  }
4710
- }
4711
-
4712
- if(ae->dtmfdet_cbp.port) {
4713
- status = pjmedia_conf_connect_port(call->conf, ae->stream_cbp.slot, ae->dtmfdet_cbp.slot, 0);
4812
+ } else if(
4813
+ (PJMEDIA_PIA_SRATE(&old_port->info) != PJMEDIA_PIA_SRATE(&new_port->info)) ||
4814
+ (PJMEDIA_PIA_CCNT(&old_port->info) != PJMEDIA_PIA_CCNT(&new_port->info)) ||
4815
+ (PJMEDIA_PIA_SPF(&old_port->info) != PJMEDIA_PIA_SPF(&new_port->info)) ||
4816
+ (PJMEDIA_PIA_BITS(&old_port->info) != PJMEDIA_PIA_BITS(&new_port->info))) {
4817
+ // stream characteristics changed so we need to destroy old conf and ports
4818
+ printf("call_id=%i restart_media_stream: stream characteristics changed\n", call->id);
4819
+ close_audio_endpoint_ports_and_conf(call, ae);
4820
+
4821
+ // then create a new conf
4822
+ status = create_audio_endpoint_conf(call, ae, new_port);
4714
4823
  if (status != PJ_SUCCESS) {
4715
4824
  make_evt_media_update(evt, sizeof(evt), call->id,
4716
- "setup_failed (pjmedia_conf_connect_port for dtmfdet failed)", "");
4825
+ "setup_failed (create_audio_endpoint_conf failed)", "");
4717
4826
  dispatch_event(evt);
4718
4827
  return false;
4719
-
4720
4828
  }
4721
- }
4722
4829
 
4723
- if(ae->fax_cbp.port) {
4724
- status = pjmedia_conf_connect_port(call->conf, ae->stream_cbp.slot, ae->fax_cbp.slot, 0);
4830
+ ae->stream_cbp.port = new_port;
4831
+ status = pjmedia_conf_add_port(ae->conf, call->inv->pool, ae->stream_cbp.port, NULL, &ae->stream_cbp.slot);
4725
4832
  if (status != PJ_SUCCESS) {
4726
4833
  make_evt_media_update(evt, sizeof(evt), call->id,
4727
- "setup_failed (pjmedia_conf_connect_port for fax dst failed)", "");
4834
+ "setup_failed (pjmedia_conf_add_port failed)", "");
4728
4835
  dispatch_event(evt);
4729
4836
  return false;
4837
+ }
4730
4838
 
4839
+ // we always add dtmfdet to audio endpoints
4840
+ if(!prepare_dtmfdet(call, ae)) {
4841
+ make_evt_media_update(evt, sizeof(evt), call->id,
4842
+ "setup_failed (prepare_dtmfdet failed)", "");
4843
+ dispatch_event(evt);
4844
+ return false;
4731
4845
  }
4732
4846
 
4733
- status = pjmedia_conf_connect_port(call->conf, ae->fax_cbp.slot, ae->stream_cbp.slot, 0);
4847
+ // at this point we could try to recreate ports (see #91)
4848
+ } else {
4849
+ printf("call_id=%i restart_media_stream: stream characteristics no change\n", call->id);
4850
+ // stream characteristics didn't change so just replace the stream port
4851
+
4852
+ audio_endpoint_remove_port(call, ae, &ae->stream_cbp);
4853
+ ae->stream_cbp.port = new_port;
4854
+ status = pjmedia_conf_add_port(ae->conf, call->inv->pool, ae->stream_cbp.port, NULL, &ae->stream_cbp.slot);
4734
4855
  if (status != PJ_SUCCESS) {
4735
4856
  make_evt_media_update(evt, sizeof(evt), call->id,
4736
- "setup_failed (pjmedia_conf_connect_port for fax src failed)", "");
4857
+ "setup_failed (pjmedia_conf_add_port failed)", "");
4737
4858
  dispatch_event(evt);
4738
4859
  return false;
4739
4860
  }
4740
- }
4741
4861
 
4862
+ // Need to connect ports to new stream port
4863
+ if(ae->dtmfdet_cbp.port) {
4864
+ if(!connect_feature_port_to_stream_port(call, ae, &ae->dtmfdet_cbp, CONNECTION_MODE_SINK)) return false;
4865
+ }
4866
+
4867
+ if(ae->wav_writer_cbp.port) {
4868
+ if(!connect_feature_port_to_stream_port(call, ae, &ae->wav_writer_cbp, CONNECTION_MODE_SINK)) return false;
4869
+ }
4870
+
4871
+ if(ae->wav_player_cbp.port) {
4872
+ if(!connect_feature_port_to_stream_port(call, ae, &ae->wav_player_cbp, CONNECTION_MODE_SOURCE)) return false;
4873
+ }
4874
+
4875
+ if(ae->tonegen_cbp.port) {
4876
+ if(!connect_feature_port_to_stream_port(call, ae, &ae->tonegen_cbp, CONNECTION_MODE_SOURCE)) return false;
4877
+ }
4878
+
4879
+ if(ae->fax_cbp.port) {
4880
+ if(!connect_feature_port_to_stream_port(call, ae, &ae->fax_cbp, CONNECTION_MODE_SOURCE_AND_SINK)) return false;
4881
+ }
4882
+
4883
+ if(ae->flite_cbp.port) {
4884
+ if(!connect_feature_port_to_stream_port(call, ae, &ae->flite_cbp, CONNECTION_MODE_SOURCE)) return false;
4885
+ }
4886
+
4887
+ if(ae->pocketsphinx_cbp.port) {
4888
+ if(!connect_feature_port_to_stream_port(call, ae, &ae->pocketsphinx_cbp, CONNECTION_MODE_SINK)) return false;
4889
+ }
4890
+ }
4891
+
4742
4892
  return true;
4743
4893
  }
4744
4894
 
@@ -4925,8 +5075,6 @@ static void on_state_changed(pjsip_inv_session *inv, pjsip_event *e) {
4925
5075
  }
4926
5076
  }
4927
5077
 
4928
- release_call_conf(call);
4929
-
4930
5078
  long val;
4931
5079
  if (!g_call_ids.remove(call_id, val)) {
4932
5080
  addon_log(L_DBG, "g_call_ids.remove failed\n");
@@ -5317,13 +5465,6 @@ static pj_bool_t on_rx_request(pjsip_rx_data *rdata) {
5317
5465
  return PJ_TRUE;
5318
5466
  }
5319
5467
 
5320
- status = setup_call_conf(call);
5321
- if (status != PJ_SUCCESS) {
5322
- printf("setup_call_conf failed\n");
5323
- pjsip_endpt_respond_stateless(g_sip_endpt, rdata, 500, &reason, NULL, NULL);
5324
- return PJ_TRUE;
5325
- }
5326
-
5327
5468
  // TODO: check if this is really necessary as we are calling
5328
5469
  // pjsip_dlg_add_usage subsequently
5329
5470
  inv->dlg->mod_data[mod_tester.id] = call;
@@ -6511,10 +6652,10 @@ bool process_media(Call *call, pjsip_dialog *dlg, Document &document, bool answe
6511
6652
  return true;
6512
6653
  }
6513
6654
 
6514
- bool is_media_active(Call *c, MediaEndpoint *me) {
6655
+ bool is_media_active(Call *call, MediaEndpoint *me) {
6515
6656
  // check if media from call->media_neg is on call->media
6516
- for (int i = 0; i < c->media_count; ++i) {
6517
- if (me == c->media[i])
6657
+ for (int i = 0; i < call->media_count; ++i) {
6658
+ if (me == call->media[i])
6518
6659
  return true;
6519
6660
  }
6520
6661
  return false;
@@ -6522,19 +6663,14 @@ bool is_media_active(Call *c, MediaEndpoint *me) {
6522
6663
 
6523
6664
  void close_media_endpoint(Call *call, MediaEndpoint *me) {
6524
6665
  printf("close_media_endpoint %p\n", (void*)me);
6666
+
6667
+ pj_status_t status;
6668
+
6525
6669
  if(!me) return;
6526
6670
 
6527
6671
  if (ENDPOINT_TYPE_AUDIO == me->type) {
6528
6672
  AudioEndpoint *ae = (AudioEndpoint *)me->endpoint.audio;
6529
-
6530
- audio_endpoint_remove_port(call, &ae->stream_cbp);
6531
- audio_endpoint_remove_port(call, &ae->wav_player_cbp);
6532
- audio_endpoint_remove_port(call, &ae->wav_writer_cbp);
6533
- audio_endpoint_remove_port(call, &ae->tonegen_cbp);
6534
- audio_endpoint_remove_port(call, &ae->dtmfdet_cbp);
6535
- audio_endpoint_remove_port(call, &ae->fax_cbp);
6536
- audio_endpoint_remove_port(call, &ae->flite_cbp);
6537
-
6673
+ close_audio_endpoint_ports_and_conf(call, ae);
6538
6674
  close_media_transport(ae->med_transport);
6539
6675
  ae->med_transport = NULL;
6540
6676
  } else if (ENDPOINT_TYPE_MRCP == me->type) {
@@ -6558,17 +6694,17 @@ void close_media_endpoint(Call *call, MediaEndpoint *me) {
6558
6694
  me->port = 0;
6559
6695
  }
6560
6696
 
6561
- void close_media(Call *c) {
6562
- printf("close_media call_id=%i\n", c->id);
6563
- for (int i = 0; i < c->media_count; ++i) {
6564
- MediaEndpoint *me = c->media[i];
6565
- close_media_endpoint(c, me);
6697
+ void close_media(Call *call) {
6698
+ printf("close_media call_id=%i\n", call->id);
6699
+ for (int i = 0; i < call->media_count; ++i) {
6700
+ MediaEndpoint *me = call->media[i];
6701
+ close_media_endpoint(call, me);
6566
6702
  }
6567
- c->media_count = 0;
6703
+ call->media_count = 0;
6568
6704
  }
6569
6705
 
6570
- bool prepare_tonegen(Call *c, AudioEndpoint *ae) {
6571
- printf("prepare_tone_gen call.id=%i\n", c->id);
6706
+ bool prepare_tonegen(Call *call, AudioEndpoint *ae) {
6707
+ printf("prepare_tone_gen call.id=%i\n", call->id);
6572
6708
  pj_status_t status;
6573
6709
 
6574
6710
  if(ae->tonegen_cbp.port) {
@@ -6577,7 +6713,7 @@ bool prepare_tonegen(Call *c, AudioEndpoint *ae) {
6577
6713
  }
6578
6714
 
6579
6715
  status = pjmedia_tonegen_create(
6580
- c->inv->pool, PJMEDIA_PIA_SRATE(&ae->stream_cbp.port->info),
6716
+ call->inv->pool, PJMEDIA_PIA_SRATE(&ae->stream_cbp.port->info),
6581
6717
  PJMEDIA_PIA_CCNT(&ae->stream_cbp.port->info),
6582
6718
  PJMEDIA_PIA_SPF(&ae->stream_cbp.port->info),
6583
6719
  PJMEDIA_PIA_BITS(&ae->stream_cbp.port->info), 0, &ae->tonegen_cbp.port);
@@ -6586,22 +6722,16 @@ bool prepare_tonegen(Call *c, AudioEndpoint *ae) {
6586
6722
  return false;
6587
6723
  }
6588
6724
 
6589
- status = pjmedia_conf_add_port(c->conf, c->inv->pool, ae->tonegen_cbp.port, NULL, &ae->tonegen_cbp.slot);
6725
+ status = pjmedia_conf_add_port(ae->conf, call->inv->pool, ae->tonegen_cbp.port, NULL, &ae->tonegen_cbp.slot);
6590
6726
  if (status != PJ_SUCCESS) {
6591
6727
  set_error("pjmedia_conf_add_port failed");
6592
6728
  return false;
6593
6729
  }
6594
6730
 
6595
- status = pjmedia_conf_connect_port(c->conf, ae->tonegen_cbp.slot, ae->stream_cbp.slot, 0);
6596
- if (status != PJ_SUCCESS) {
6597
- set_error("pjmedia_conf_connect_port failed");
6598
- return false;
6599
- }
6600
-
6601
- return true;
6731
+ return connect_feature_port_to_stream_port(call, ae, &ae->tonegen_cbp, CONNECTION_MODE_SOURCE);
6602
6732
  }
6603
6733
 
6604
- bool prepare_wav_player(Call *c, AudioEndpoint *ae, const char *file, unsigned flags, bool end_of_file_event) {
6734
+ bool prepare_wav_player(Call *call, AudioEndpoint *ae, const char *file, unsigned flags, bool end_of_file_event) {
6605
6735
  pj_status_t status;
6606
6736
 
6607
6737
  unsigned wav_ptime;
@@ -6609,7 +6739,7 @@ bool prepare_wav_player(Call *c, AudioEndpoint *ae, const char *file, unsigned f
6609
6739
  PJMEDIA_PIA_SRATE(&ae->stream_cbp.port->info);
6610
6740
 
6611
6741
  status = pjmedia_wav_player_port_create(
6612
- c->inv->pool,
6742
+ call->inv->pool,
6613
6743
  file,
6614
6744
  wav_ptime,
6615
6745
  flags,
@@ -6623,33 +6753,27 @@ bool prepare_wav_player(Call *c, AudioEndpoint *ae, const char *file, unsigned f
6623
6753
  }
6624
6754
 
6625
6755
  if (end_of_file_event) {
6626
- status = pjmedia_wav_player_set_eof_cb2(ae->wav_player_cbp.port, (void*)c, on_end_of_file);
6756
+ status = pjmedia_wav_player_set_eof_cb2(ae->wav_player_cbp.port, (void*)call, on_end_of_file);
6627
6757
  if (status != PJ_SUCCESS) {
6628
6758
  set_error("pjmedia_wav_player_set_eof_cb2 failed");
6629
6759
  return false;
6630
6760
  }
6631
6761
  }
6632
6762
 
6633
- status = pjmedia_conf_add_port(c->conf, c->inv->pool, ae->wav_player_cbp.port, NULL, &ae->wav_player_cbp.slot);
6763
+ status = pjmedia_conf_add_port(ae->conf, call->inv->pool, ae->wav_player_cbp.port, NULL, &ae->wav_player_cbp.slot);
6634
6764
  if (status != PJ_SUCCESS) {
6635
6765
  set_error("pjmedia_conf_add_port failed");
6636
6766
  return false;
6637
6767
  }
6638
6768
 
6639
- status = pjmedia_conf_connect_port(c->conf, ae->wav_player_cbp.slot, ae->stream_cbp.slot, 0);
6640
- if (status != PJ_SUCCESS) {
6641
- set_error("pjmedia_conf_connect_port failed");
6642
- return false;
6643
- }
6644
-
6645
- return true;
6769
+ return connect_feature_port_to_stream_port(call, ae, &ae->wav_player_cbp, CONNECTION_MODE_SOURCE);
6646
6770
  }
6647
6771
 
6648
- bool prepare_wav_writer(Call *c, AudioEndpoint *ae, const char *file) {
6772
+ bool prepare_wav_writer(Call *call, AudioEndpoint *ae, const char *file) {
6649
6773
  pj_status_t status;
6650
6774
 
6651
6775
  status = pjmedia_wav_writer_port_create(
6652
- c->inv->pool, file, PJMEDIA_PIA_SRATE(&ae->stream_cbp.port->info),
6776
+ call->inv->pool, file, PJMEDIA_PIA_SRATE(&ae->stream_cbp.port->info),
6653
6777
  PJMEDIA_PIA_CCNT(&ae->stream_cbp.port->info), PJMEDIA_PIA_SPF(&ae->stream_cbp.port->info),
6654
6778
  PJMEDIA_PIA_BITS(&ae->stream_cbp.port->info), PJMEDIA_FILE_WRITE_PCM, 0,
6655
6779
  (pjmedia_port **)&ae->wav_writer_cbp.port);
@@ -6658,89 +6782,66 @@ bool prepare_wav_writer(Call *c, AudioEndpoint *ae, const char *file) {
6658
6782
  return false;
6659
6783
  }
6660
6784
 
6661
- status = pjmedia_conf_add_port(c->conf, c->inv->pool, ae->wav_writer_cbp.port, NULL, &ae->wav_writer_cbp.slot);
6785
+ status = pjmedia_conf_add_port(ae->conf, call->inv->pool, ae->wav_writer_cbp.port, NULL, &ae->wav_writer_cbp.slot);
6662
6786
  if (status != PJ_SUCCESS) {
6663
6787
  set_error("pjmedia_conf_add_port failed");
6664
6788
  return false;
6665
6789
  }
6666
6790
 
6667
- status = pjmedia_conf_connect_port(c->conf, ae->stream_cbp.slot, ae->wav_writer_cbp.slot, 0);
6668
- if (status != PJ_SUCCESS) {
6669
- set_error("pjmedia_conf_connect_port failed");
6670
- return false;
6671
- }
6672
-
6673
- return true;
6791
+ return connect_feature_port_to_stream_port(call, ae, &ae->wav_writer_cbp, CONNECTION_MODE_SINK);
6674
6792
  }
6675
6793
 
6676
- bool prepare_dtmfdet(Call *c, AudioEndpoint *ae) {
6794
+ bool prepare_dtmfdet(Call *call, AudioEndpoint *ae) {
6677
6795
  pj_status_t status;
6678
6796
  status = pjmedia_dtmfdet_create(
6679
- c->inv->pool,
6797
+ call->inv->pool,
6680
6798
  PJMEDIA_PIA_SRATE(&ae->stream_cbp.port->info),
6681
- PJMEDIA_PIA_CCNT(&ae->stream_cbp.port->info), PJMEDIA_PIA_SPF(&ae->stream_cbp.port->info),
6799
+ PJMEDIA_PIA_CCNT(&ae->stream_cbp.port->info),
6800
+ PJMEDIA_PIA_SPF(&ae->stream_cbp.port->info),
6682
6801
  PJMEDIA_PIA_BITS(&ae->stream_cbp.port->info),
6683
- on_inband_dtmf, c, &ae->dtmfdet_cbp.port);
6802
+ on_inband_dtmf, call, &ae->dtmfdet_cbp.port);
6684
6803
  if (status != PJ_SUCCESS) {
6685
6804
  set_error("pjmedia_dtmfdet_create failed");
6686
6805
  return false;
6687
6806
  }
6688
6807
 
6689
- status = pjmedia_conf_add_port(c->conf, c->inv->pool, ae->dtmfdet_cbp.port, NULL, &ae->dtmfdet_cbp.slot);
6808
+ status = pjmedia_conf_add_port(ae->conf, call->inv->pool, ae->dtmfdet_cbp.port, NULL, &ae->dtmfdet_cbp.slot);
6690
6809
  if (status != PJ_SUCCESS) {
6691
6810
  set_error("pjmedia_conf_add_port failed");
6692
6811
  return false;
6693
6812
  }
6694
6813
 
6695
- status = pjmedia_conf_connect_port(c->conf, ae->stream_cbp.slot, ae->dtmfdet_cbp.slot, 0);
6696
- if (status != PJ_SUCCESS) {
6697
- set_error("pjmedia_conf_connect_port failed");
6698
- return false;
6699
- }
6700
-
6701
- return true;
6814
+ return connect_feature_port_to_stream_port(call, ae, &ae->dtmfdet_cbp, CONNECTION_MODE_SINK);
6702
6815
  }
6703
6816
 
6704
- bool prepare_fax(Call *c, AudioEndpoint *ae, bool is_sender, const char *file,
6817
+ bool prepare_fax(Call *call, AudioEndpoint *ae, bool is_sender, const char *file,
6705
6818
  unsigned flags) {
6706
6819
  pj_status_t status;
6707
6820
 
6708
6821
  status = pjmedia_fax_port_create(
6709
- c->inv->pool,
6822
+ call->inv->pool,
6710
6823
  PJMEDIA_PIA_SRATE(&ae->stream_cbp.port->info),
6711
6824
  PJMEDIA_PIA_CCNT(&ae->stream_cbp.port->info),
6712
6825
  PJMEDIA_PIA_SPF(&ae->stream_cbp.port->info),
6713
6826
  PJMEDIA_PIA_BITS(&ae->stream_cbp.port->info),
6714
- on_fax_result, c, is_sender, file,
6827
+ on_fax_result, call, is_sender, file,
6715
6828
  flags, &ae->fax_cbp.port);
6716
6829
  if (status != PJ_SUCCESS) {
6717
6830
  set_error("pjmedia_fax_port_create failed");
6718
6831
  return false;
6719
6832
  }
6720
6833
 
6721
- status = pjmedia_conf_add_port(c->conf, c->inv->pool, ae->fax_cbp.port, NULL, &ae->fax_cbp.slot);
6834
+ status = pjmedia_conf_add_port(ae->conf, call->inv->pool, ae->fax_cbp.port, NULL, &ae->fax_cbp.slot);
6722
6835
  if (status != PJ_SUCCESS) {
6723
6836
  set_error("pjmedia_conf_add_port failed");
6724
6837
  return false;
6725
6838
  }
6726
6839
 
6727
- status = pjmedia_conf_connect_port(c->conf, ae->fax_cbp.slot, ae->stream_cbp.slot, 0);
6728
- if (status != PJ_SUCCESS) {
6729
- set_error("pjmedia_conf_connect_port failed");
6730
- return false;
6731
- }
6732
-
6733
- status = pjmedia_conf_connect_port(c->conf, ae->stream_cbp.slot, ae->fax_cbp.slot, 0);
6734
- if (status != PJ_SUCCESS) {
6735
- set_error("pjmedia_conf_connect_port failed");
6736
- return false;
6737
- }
6738
-
6739
- return true;
6840
+ return connect_feature_port_to_stream_port(call, ae, &ae->fax_cbp, CONNECTION_MODE_SOURCE_AND_SINK);
6740
6841
  }
6741
6842
 
6742
- bool prepare_flite(Call *c, AudioEndpoint *ae, const char *voice, bool end_of_speech_event) {
6743
- printf("prepare_flite call.id=%i\n", c->id);
6843
+ bool prepare_flite(Call *call, AudioEndpoint *ae, const char *voice, bool end_of_speech_event) {
6844
+ printf("prepare_flite call.id=%i\n", call->id);
6744
6845
  pj_status_t status;
6745
6846
 
6746
6847
  if(ae->flite_cbp.port) {
@@ -6749,7 +6850,7 @@ bool prepare_flite(Call *c, AudioEndpoint *ae, const char *voice, bool end_of_sp
6749
6850
  }
6750
6851
 
6751
6852
  status = pjmedia_flite_port_create(
6752
- c->inv->pool, PJMEDIA_PIA_SRATE(&ae->stream_cbp.port->info),
6853
+ call->inv->pool, PJMEDIA_PIA_SRATE(&ae->stream_cbp.port->info),
6753
6854
  PJMEDIA_PIA_CCNT(&ae->stream_cbp.port->info),
6754
6855
  PJMEDIA_PIA_SPF(&ae->stream_cbp.port->info),
6755
6856
  PJMEDIA_PIA_BITS(&ae->stream_cbp.port->info), voice, &ae->flite_cbp.port);
@@ -6759,28 +6860,52 @@ bool prepare_flite(Call *c, AudioEndpoint *ae, const char *voice, bool end_of_sp
6759
6860
  }
6760
6861
 
6761
6862
  if (end_of_speech_event) {
6762
- status = pjmedia_flite_port_set_eof_cb(ae->flite_cbp.port, (void*)c, on_end_of_speech);
6863
+ status = pjmedia_flite_port_set_eof_cb(ae->flite_cbp.port, (void*)call, on_end_of_speech);
6763
6864
  if (status != PJ_SUCCESS) {
6764
6865
  set_error("pjmedia_flite_port_set_eof_cb failed");
6765
6866
  return false;
6766
6867
  }
6767
6868
  }
6768
6869
 
6769
- status = pjmedia_conf_add_port(c->conf, c->inv->pool, ae->flite_cbp.port, NULL, &ae->flite_cbp.slot);
6870
+ status = pjmedia_conf_add_port(ae->conf, call->inv->pool, ae->flite_cbp.port, NULL, &ae->flite_cbp.slot);
6770
6871
  if (status != PJ_SUCCESS) {
6771
6872
  set_error("pjmedia_conf_add_port failed");
6772
6873
  return false;
6773
6874
  }
6774
6875
 
6775
- status = pjmedia_conf_connect_port(c->conf, ae->flite_cbp.slot, ae->stream_cbp.slot, 0);
6876
+ return connect_feature_port_to_stream_port(call, ae, &ae->flite_cbp, CONNECTION_MODE_SOURCE);
6877
+ }
6878
+
6879
+ bool prepare_pocketsphinx(Call *call, AudioEndpoint *ae) {
6880
+ printf("prepare_pocketsphinx call.id=%i\n", call->id);
6881
+ pj_status_t status;
6882
+
6883
+ if(ae->pocketsphinx_cbp.port) {
6884
+ printf("already prepared\n");
6885
+ return true;
6886
+ }
6887
+
6888
+ status = pjmedia_pocketsphinx_port_create(
6889
+ call->inv->pool, PJMEDIA_PIA_SRATE(&ae->stream_cbp.port->info),
6890
+ PJMEDIA_PIA_CCNT(&ae->stream_cbp.port->info),
6891
+ PJMEDIA_PIA_SPF(&ae->stream_cbp.port->info),
6892
+ PJMEDIA_PIA_BITS(&ae->stream_cbp.port->info),
6893
+ on_speech_transcript,
6894
+ call,
6895
+ &ae->pocketsphinx_cbp.port);
6776
6896
  if (status != PJ_SUCCESS) {
6777
- set_error("pjmedia_conf_connect_port failed");
6897
+ set_error("pjmedia_pocketsphinx_port_create failed");
6778
6898
  return false;
6779
6899
  }
6780
6900
 
6781
- return true;
6782
- }
6901
+ status = pjmedia_conf_add_port(ae->conf, call->inv->pool, ae->pocketsphinx_cbp.port, NULL, &ae->pocketsphinx_cbp.slot);
6902
+ if (status != PJ_SUCCESS) {
6903
+ set_error("pjmedia_conf_add_port failed");
6904
+ return false;
6905
+ }
6783
6906
 
6907
+ return connect_feature_port_to_stream_port(call, ae, &ae->pocketsphinx_cbp, CONNECTION_MODE_SINK);
6908
+ }
6784
6909
 
6785
6910
  void on_rx_notify(pjsip_evsub *sub, pjsip_rx_data *rdata, int *p_st_code,
6786
6911
  pj_str_t **p_st_text, pjsip_hdr *res_hdr,
@@ -8168,8 +8293,8 @@ static int g_now;
8168
8293
 
8169
8294
  void check_digit_buffer(Call *call, int mode) {
8170
8295
  // addon_log(L_DBG, "check_digit_buffer g_now=%i for call_id=%i and mode=%i
8171
- // timestamp=%i len=%i\n", g_now, c->id, mode, c->last_digit_timestamp[mode],
8172
- // c->DigitBufferLength[mode]);
8296
+ // timestamp=%i len=%i\n", g_now, call->id, mode, call->last_digit_timestamp[mode],
8297
+ // call->DigitBufferLength[mode]);
8173
8298
  char evt[1024];
8174
8299
 
8175
8300
  for (int i = 0; i < call->media_count; i++) {
@@ -8193,10 +8318,10 @@ void check_digit_buffer(Call *call, int mode) {
8193
8318
  }
8194
8319
 
8195
8320
  void check_digit_buffers(long id, long val) {
8196
- Call *c = (Call *)val;
8321
+ Call *call = (Call *)val;
8197
8322
 
8198
- check_digit_buffer(c, DTMF_MODE_RFC2833);
8199
- check_digit_buffer(c, DTMF_MODE_INBAND);
8323
+ check_digit_buffer(call, DTMF_MODE_RFC2833);
8324
+ check_digit_buffer(call, DTMF_MODE_INBAND);
8200
8325
  }
8201
8326
 
8202
8327
  static int digit_buffer_thread(void *arg) {