sip-lab 1.24.0 → 1.27.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sip-lab",
3
- "version": "1.24.0",
3
+ "version": "1.27.0",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "engines": {
@@ -45,6 +45,7 @@
45
45
  "DEV.md",
46
46
  "samples",
47
47
  "prebuilds",
48
- "pocketsphinx"
48
+ "pocketsphinx",
49
+ "runtests"
49
50
  ]
50
51
  }
Binary file
package/runtests ADDED
@@ -0,0 +1,80 @@
1
+ #!/bin/bash
2
+
3
+ set -o nounset
4
+
5
+ function usage() {
6
+ cat <<EOF
7
+ Usage: $0 [-g]
8
+
9
+ Details:
10
+ -g : run each test inside gdb
11
+ EOF
12
+ }
13
+
14
+ use_gdb=0
15
+
16
+ while getopts "gh" o; do
17
+ case "${o}" in
18
+ g)
19
+ use_gdb=1
20
+ ;;
21
+ h)
22
+ usage
23
+ exit 0
24
+ ;;
25
+ *)
26
+ usage
27
+ exit 1
28
+ ;;
29
+ esac
30
+ done
31
+ shift $((OPTIND-1))
32
+
33
+ successful_tests=()
34
+
35
+ function output_successful_tests() {
36
+ echo "Successful tests:"
37
+ for t in "${successful_tests[@]}"
38
+ do
39
+ echo " - $t"
40
+ done
41
+ }
42
+
43
+ echo
44
+
45
+ for i in $(ls samples/*.js)
46
+ do
47
+ start_time=$(date +%s.%N)
48
+
49
+ if [[ $use_gdb -eq 0 ]]
50
+ then
51
+ node $i
52
+ else
53
+ gdb -ex "handle SIGSEGV stop" -ex "run" -ex "bt" -ex "quit" --args node $i
54
+ fi
55
+
56
+ if [[ $? -ne 0 ]]
57
+ then
58
+ echo "$i failed"
59
+ echo
60
+ output_successful_tests
61
+ exit 1
62
+ else
63
+ end_time=$(date +%s.%N)
64
+ duration=$(echo "$end_time - $start_time" | bc)
65
+ formatted_duration=$(printf "%.2f seconds" $duration)
66
+ successful_tests+=("$i: duration=$formatted_duration")
67
+
68
+ echo
69
+ echo "$i failed"
70
+ fi
71
+ done
72
+
73
+ echo
74
+
75
+ echo "Success. All tests passed"
76
+ echo
77
+ output_successful_tests
78
+ echo
79
+ echo "Everything OK"
80
+ echo
package/src/sip.cpp CHANGED
@@ -1,4 +1,5 @@
1
1
  #include <arpa/inet.h>
2
+ #include <netdb.h>
2
3
 
3
4
  #include "sip.hpp"
4
5
 
@@ -305,8 +306,18 @@ struct Subscription {
305
306
  struct ConfBridgePort {
306
307
  unsigned slot;
307
308
  pjmedia_port *port;
309
+ short connection_mode;
308
310
  };
309
311
 
312
+ #define FP_DTMFDET 0
313
+ #define FP_WAV_PLAYER 1
314
+ #define FP_WAV_WRITER 2
315
+ #define FP_TONEGEN 3
316
+ #define FP_FAX 4
317
+ #define FP_SPEECH_SYNTH 5
318
+ #define FP_SPEECH_RECOG 6
319
+ #define MAX_FP 7
320
+
310
321
  struct AudioEndpoint {
311
322
  pjmedia_transport *med_transport;
312
323
  pjmedia_stream *med_stream;
@@ -322,13 +333,7 @@ struct AudioEndpoint {
322
333
  pjmedia_port *null_port;
323
334
 
324
335
  ConfBridgePort stream_cbp;
325
- ConfBridgePort wav_player_cbp;
326
- ConfBridgePort wav_writer_cbp;
327
- ConfBridgePort tonegen_cbp;
328
- ConfBridgePort dtmfdet_cbp;
329
- ConfBridgePort fax_cbp;
330
- ConfBridgePort flite_cbp;
331
- ConfBridgePort pocketsphinx_cbp;
336
+ ConfBridgePort feature_cbps[MAX_FP];
332
337
  };
333
338
 
334
339
  struct VideoEndpoint {
@@ -779,7 +784,7 @@ static int find_endpoint_by_inband_dtmf_media_port(Call *call,
779
784
  MediaEndpoint *me = (MediaEndpoint *)call->media[i];
780
785
  if (ENDPOINT_TYPE_AUDIO == me->type) {
781
786
  AudioEndpoint *ae = (AudioEndpoint *)me->endpoint.audio;
782
- if (ae->dtmfdet_cbp.port && (pjmedia_port *)ae->dtmfdet_cbp.port == port) {
787
+ if (ae->feature_cbps[FP_DTMFDET].port && (pjmedia_port *)ae->feature_cbps[FP_DTMFDET].port == port) {
783
788
  return i;
784
789
  }
785
790
  }
@@ -2796,9 +2801,47 @@ bool dlg_set_transport_by_t(Transport *t, pjsip_dialog *dlg) {
2796
2801
  return true;
2797
2802
  }
2798
2803
 
2799
- void build_transport_tag(char *dest, const char *type, const char *address,
2804
+ bool is_ip_address(const char *hostname) {
2805
+ struct sockaddr_in sa;
2806
+ return inet_pton(AF_INET, hostname, &(sa.sin_addr)) != 0;
2807
+ }
2808
+
2809
+ void build_transport_tag(char *dest, const char *type, const char *hostname,
2800
2810
  int port) {
2801
- sprintf(dest, "%s:%s:%d", type, address, port);
2811
+ struct addrinfo hints, * res, *p;
2812
+
2813
+ if(is_ip_address(hostname)) {
2814
+ sprintf(dest, "%s:%s:%d", type, hostname, port);
2815
+ return;
2816
+ }
2817
+
2818
+ memset(&hints, 0, sizeof(hints));
2819
+ hints.ai_family = AF_UNSPEC; // AF_INET or AF_INET6 to force version
2820
+ hints.ai_socktype = SOCK_STREAM;
2821
+
2822
+ // Resolve the domain name
2823
+ int status = getaddrinfo(hostname, NULL, &hints, &res);
2824
+ if (status != 0) {
2825
+ printf("build_transport_tag getaddrinfo: %s\n", gai_strerror(status));
2826
+ sprintf(dest, "%s:%s:%d", type, hostname, port);
2827
+ } else {
2828
+ for (p = res; p != NULL; p = p->ai_next) {
2829
+ void *addr;
2830
+ if (p->ai_family == AF_INET) { // IPv4
2831
+ struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
2832
+ addr = &(ipv4->sin_addr);
2833
+ } else { // IPv6
2834
+ struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;
2835
+ addr = &(ipv6->sin6_addr);
2836
+ }
2837
+ char ipstr[INET6_ADDRSTRLEN];
2838
+ inet_ntop(p->ai_family, addr, ipstr, sizeof(ipstr));
2839
+ sprintf(dest, "%s:%s:%d", type, ipstr, port);
2840
+ break;
2841
+ }
2842
+ }
2843
+
2844
+ freeaddrinfo(res);
2802
2845
  }
2803
2846
 
2804
2847
  void build_transport_tag_from_pjsip_transport(char *dest, pjsip_transport *t) {
@@ -2810,6 +2853,7 @@ void build_transport_tag_from_pjsip_transport(char *dest, pjsip_transport *t) {
2810
2853
  assert(t->local_name.host.slen < 16);
2811
2854
  strncpy(address, t->local_name.host.ptr, t->local_name.host.slen);
2812
2855
  address[t->local_name.host.slen] = 0;
2856
+ printf("build_transport_tag_from_pjsip_transport address=%s\n", address);
2813
2857
 
2814
2858
  if (t->key.type == PJSIP_TRANSPORT_UDP) {
2815
2859
  type = "udp";
@@ -3082,7 +3126,7 @@ pj_status_t audio_endpoint_send_dtmf(Call *call, AudioEndpoint *ae,
3082
3126
  tone.on_msec = ON_DURATION;
3083
3127
  tone.off_msec = OFF_DURATION;
3084
3128
  tone.volume = 0;
3085
- status = pjmedia_tonegen_play_digits((pjmedia_port *)ae->tonegen_cbp.port, 1,
3129
+ status = pjmedia_tonegen_play_digits((pjmedia_port *)ae->feature_cbps[FP_TONEGEN].port, 1,
3086
3130
  &tone, 0);
3087
3131
  if (status != PJ_SUCCESS) {
3088
3132
  set_error("pjmedia_tonegen_play_digits failed.");
@@ -3789,7 +3833,7 @@ pj_status_t audio_endpoint_start_speech_synth(Call *call, AudioEndpoint *ae, con
3789
3833
  return -1;
3790
3834
  }
3791
3835
 
3792
- pjmedia_flite_port_speak(ae->flite_cbp.port, text, flags);
3836
+ pjmedia_flite_port_speak(ae->feature_cbps[FP_SPEECH_SYNTH].port, text, flags);
3793
3837
 
3794
3838
  return PJ_SUCCESS;
3795
3839
  }
@@ -4122,36 +4166,27 @@ out:
4122
4166
  return 0;
4123
4167
  }
4124
4168
 
4125
- pj_status_t audio_endpoint_stop_speech_synth(Call *call, AudioEndpoint *ae) {
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);
4131
- }
4132
-
4133
4169
  pj_status_t audio_endpoint_stop_play_wav(Call *call, AudioEndpoint *ae) {
4134
- return audio_endpoint_remove_port(call, ae, &ae->wav_player_cbp);
4170
+ return audio_endpoint_remove_port(call, ae, &ae->feature_cbps[FP_WAV_PLAYER]);
4135
4171
  }
4136
4172
 
4137
4173
  pj_status_t audio_endpoint_stop_record_wav(Call *call, AudioEndpoint *ae) {
4138
- return audio_endpoint_remove_port(call, ae, &ae->wav_writer_cbp);
4174
+ return audio_endpoint_remove_port(call, ae, &ae->feature_cbps[FP_WAV_WRITER]);
4139
4175
  }
4140
4176
 
4141
4177
  pj_status_t audio_endpoint_stop_fax(Call *call, AudioEndpoint *ae) {
4142
- return audio_endpoint_remove_port(call, ae, &ae->fax_cbp);
4178
+ return audio_endpoint_remove_port(call, ae, &ae->feature_cbps[FP_FAX]);
4143
4179
  }
4144
4180
 
4145
-
4146
-
4147
- int pjw_call_stop_speech_synth(long call_id, const char *json) {
4148
- return audio_endpoint_stop_op(call_id, json, audio_endpoint_stop_speech_synth);
4181
+ pj_status_t audio_endpoint_stop_speech_synth(Call *call, AudioEndpoint *ae) {
4182
+ return audio_endpoint_remove_port(call, ae, &ae->feature_cbps[FP_SPEECH_SYNTH]);
4149
4183
  }
4150
4184
 
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);
4185
+ pj_status_t audio_endpoint_stop_speech_recog(Call *call, AudioEndpoint *ae) {
4186
+ return audio_endpoint_remove_port(call, ae, &ae->feature_cbps[FP_SPEECH_RECOG]);
4153
4187
  }
4154
4188
 
4189
+
4155
4190
  int pjw_call_stop_play_wav(long call_id, const char *json) {
4156
4191
  return audio_endpoint_stop_op(call_id, json, audio_endpoint_stop_play_wav);
4157
4192
  }
@@ -4164,6 +4199,14 @@ int pjw_call_stop_fax(long call_id, const char *json) {
4164
4199
  return audio_endpoint_stop_op(call_id, json, audio_endpoint_stop_fax);
4165
4200
  }
4166
4201
 
4202
+ int pjw_call_stop_speech_synth(long call_id, const char *json) {
4203
+ return audio_endpoint_stop_op(call_id, json, audio_endpoint_stop_speech_synth);
4204
+ }
4205
+
4206
+ int pjw_call_stop_speech_recog(long call_id, const char *json) {
4207
+ return audio_endpoint_stop_op(call_id, json, audio_endpoint_stop_speech_recog);
4208
+ }
4209
+
4167
4210
 
4168
4211
  int pjw_call_start_fax(long call_id, const char *json) {
4169
4212
  PJW_LOCK();
@@ -4640,13 +4683,10 @@ void close_audio_endpoint_ports_and_conf(Call *call, AudioEndpoint *ae) {
4640
4683
  pj_status_t status;
4641
4684
 
4642
4685
  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);
4686
+
4687
+ for(int i=0 ; i<MAX_FP ; i++) {
4688
+ audio_endpoint_remove_port(call, ae, &ae->feature_cbps[i]);
4689
+ }
4650
4690
 
4651
4691
  if (ae->master_port) {
4652
4692
  status = pjmedia_master_port_stop(ae->master_port);
@@ -4677,17 +4717,17 @@ void close_audio_endpoint_ports_and_conf(Call *call, AudioEndpoint *ae) {
4677
4717
  }
4678
4718
  }
4679
4719
 
4680
- bool connect_feature_port_to_stream_port(Call *call, AudioEndpoint *ae, ConfBridgePort *cbp, int connection_mode) {
4720
+ bool connect_feature_port_to_stream_port(Call *call, AudioEndpoint *ae, ConfBridgePort *cbp) {
4681
4721
  pj_status_t status;
4682
4722
 
4683
- if(connection_mode == CONNECTION_MODE_SOURCE || connection_mode == CONNECTION_MODE_SOURCE_AND_SINK) {
4723
+ if(cbp->connection_mode == CONNECTION_MODE_SOURCE || cbp->connection_mode == CONNECTION_MODE_SOURCE_AND_SINK) {
4684
4724
  status = pjmedia_conf_connect_port(ae->conf, cbp->slot, ae->stream_cbp.slot, 0);
4685
4725
  if (status != PJ_SUCCESS) {
4686
4726
  set_error("pjmedia_conf_connect_port failed");
4687
4727
  return false;
4688
4728
  }
4689
4729
  }
4690
- if(connection_mode == CONNECTION_MODE_SINK || connection_mode == CONNECTION_MODE_SOURCE_AND_SINK) {
4730
+ if(cbp->connection_mode == CONNECTION_MODE_SINK || cbp->connection_mode == CONNECTION_MODE_SOURCE_AND_SINK) {
4691
4731
  status = pjmedia_conf_connect_port(ae->conf, ae->stream_cbp.slot, cbp->slot, 0);
4692
4732
  printf("status=%i\n" ,status);
4693
4733
  if (status != PJ_SUCCESS) {
@@ -4860,32 +4900,10 @@ bool restart_media_stream(Call *call, MediaEndpoint *me,
4860
4900
  }
4861
4901
 
4862
4902
  // 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;
4903
+ for(int i=0 ; i<MAX_FP ; i++) {
4904
+ if(ae->feature_cbps[i].port) {
4905
+ if(!connect_feature_port_to_stream_port(call, ae, &ae->feature_cbps[i])) return false;
4906
+ }
4889
4907
  }
4890
4908
  }
4891
4909
 
@@ -5379,7 +5397,7 @@ static pj_bool_t on_rx_request(pjsip_rx_data *rdata) {
5379
5397
 
5380
5398
  long transport_id;
5381
5399
 
5382
- // printf("tag=%s\n", tag);
5400
+ //printf("on_rx_request transport_tag=%s\n", tag);
5383
5401
 
5384
5402
  TransportMap::iterator iter = g_TransportMap.find(tag);
5385
5403
  if (iter != g_TransportMap.end()) {
@@ -5490,7 +5508,7 @@ static pj_bool_t on_rx_request(pjsip_rx_data *rdata) {
5490
5508
 
5491
5509
  long transport_id;
5492
5510
 
5493
- // printf("tag=%s\n", tag);
5511
+ printf("on_rx_request INVITE transport_tag=%s\n", tag);
5494
5512
 
5495
5513
  TransportMap::iterator iter = g_TransportMap.find(tag);
5496
5514
  if (iter != g_TransportMap.end()) {
@@ -6707,7 +6725,9 @@ bool prepare_tonegen(Call *call, AudioEndpoint *ae) {
6707
6725
  printf("prepare_tone_gen call.id=%i\n", call->id);
6708
6726
  pj_status_t status;
6709
6727
 
6710
- if(ae->tonegen_cbp.port) {
6728
+ ConfBridgePort *fp = &ae->feature_cbps[FP_TONEGEN];
6729
+
6730
+ if(fp->port) {
6711
6731
  printf("already prepared\n");
6712
6732
  return true;
6713
6733
  }
@@ -6716,24 +6736,28 @@ bool prepare_tonegen(Call *call, AudioEndpoint *ae) {
6716
6736
  call->inv->pool, PJMEDIA_PIA_SRATE(&ae->stream_cbp.port->info),
6717
6737
  PJMEDIA_PIA_CCNT(&ae->stream_cbp.port->info),
6718
6738
  PJMEDIA_PIA_SPF(&ae->stream_cbp.port->info),
6719
- PJMEDIA_PIA_BITS(&ae->stream_cbp.port->info), 0, &ae->tonegen_cbp.port);
6739
+ PJMEDIA_PIA_BITS(&ae->stream_cbp.port->info), 0, &fp->port);
6720
6740
  if (status != PJ_SUCCESS) {
6721
6741
  set_error("pjmedia_tonegen_create failed");
6722
6742
  return false;
6723
6743
  }
6724
6744
 
6725
- status = pjmedia_conf_add_port(ae->conf, call->inv->pool, ae->tonegen_cbp.port, NULL, &ae->tonegen_cbp.slot);
6745
+ status = pjmedia_conf_add_port(ae->conf, call->inv->pool, fp->port, NULL, &fp->slot);
6726
6746
  if (status != PJ_SUCCESS) {
6727
6747
  set_error("pjmedia_conf_add_port failed");
6728
6748
  return false;
6729
6749
  }
6730
6750
 
6731
- return connect_feature_port_to_stream_port(call, ae, &ae->tonegen_cbp, CONNECTION_MODE_SOURCE);
6751
+ fp->connection_mode = CONNECTION_MODE_SOURCE;
6752
+
6753
+ return connect_feature_port_to_stream_port(call, ae, fp);
6732
6754
  }
6733
6755
 
6734
6756
  bool prepare_wav_player(Call *call, AudioEndpoint *ae, const char *file, unsigned flags, bool end_of_file_event) {
6735
6757
  pj_status_t status;
6736
6758
 
6759
+ ConfBridgePort *fp = &ae->feature_cbps[FP_WAV_PLAYER];
6760
+
6737
6761
  unsigned wav_ptime;
6738
6762
  wav_ptime = PJMEDIA_PIA_SPF(&ae->stream_cbp.port->info) * 1000 /
6739
6763
  PJMEDIA_PIA_SRATE(&ae->stream_cbp.port->info);
@@ -6744,7 +6768,7 @@ bool prepare_wav_player(Call *call, AudioEndpoint *ae, const char *file, unsigne
6744
6768
  wav_ptime,
6745
6769
  flags,
6746
6770
  -1, /* buf size */
6747
- &ae->wav_player_cbp.port
6771
+ &fp->port
6748
6772
  );
6749
6773
 
6750
6774
  if (status != PJ_SUCCESS) {
@@ -6753,71 +6777,83 @@ bool prepare_wav_player(Call *call, AudioEndpoint *ae, const char *file, unsigne
6753
6777
  }
6754
6778
 
6755
6779
  if (end_of_file_event) {
6756
- status = pjmedia_wav_player_set_eof_cb2(ae->wav_player_cbp.port, (void*)call, on_end_of_file);
6780
+ status = pjmedia_wav_player_set_eof_cb2(fp->port, (void*)call, on_end_of_file);
6757
6781
  if (status != PJ_SUCCESS) {
6758
6782
  set_error("pjmedia_wav_player_set_eof_cb2 failed");
6759
6783
  return false;
6760
6784
  }
6761
6785
  }
6762
6786
 
6763
- status = pjmedia_conf_add_port(ae->conf, call->inv->pool, ae->wav_player_cbp.port, NULL, &ae->wav_player_cbp.slot);
6787
+ status = pjmedia_conf_add_port(ae->conf, call->inv->pool, fp->port, NULL, &fp->slot);
6764
6788
  if (status != PJ_SUCCESS) {
6765
6789
  set_error("pjmedia_conf_add_port failed");
6766
6790
  return false;
6767
6791
  }
6768
6792
 
6769
- return connect_feature_port_to_stream_port(call, ae, &ae->wav_player_cbp, CONNECTION_MODE_SOURCE);
6793
+ fp->connection_mode = CONNECTION_MODE_SOURCE;
6794
+
6795
+ return connect_feature_port_to_stream_port(call, ae, fp);
6770
6796
  }
6771
6797
 
6772
6798
  bool prepare_wav_writer(Call *call, AudioEndpoint *ae, const char *file) {
6773
6799
  pj_status_t status;
6774
6800
 
6801
+ ConfBridgePort *fp = &ae->feature_cbps[FP_WAV_WRITER];
6802
+
6775
6803
  status = pjmedia_wav_writer_port_create(
6776
6804
  call->inv->pool, file, PJMEDIA_PIA_SRATE(&ae->stream_cbp.port->info),
6777
6805
  PJMEDIA_PIA_CCNT(&ae->stream_cbp.port->info), PJMEDIA_PIA_SPF(&ae->stream_cbp.port->info),
6778
6806
  PJMEDIA_PIA_BITS(&ae->stream_cbp.port->info), PJMEDIA_FILE_WRITE_PCM, 0,
6779
- (pjmedia_port **)&ae->wav_writer_cbp.port);
6807
+ (pjmedia_port **)&fp->port);
6780
6808
  if (status != PJ_SUCCESS) {
6781
6809
  set_error("pjmedia_wav_write_port_create failed");
6782
6810
  return false;
6783
6811
  }
6784
6812
 
6785
- status = pjmedia_conf_add_port(ae->conf, call->inv->pool, ae->wav_writer_cbp.port, NULL, &ae->wav_writer_cbp.slot);
6813
+ status = pjmedia_conf_add_port(ae->conf, call->inv->pool, fp->port, NULL, &fp->slot);
6786
6814
  if (status != PJ_SUCCESS) {
6787
6815
  set_error("pjmedia_conf_add_port failed");
6788
6816
  return false;
6789
6817
  }
6790
6818
 
6791
- return connect_feature_port_to_stream_port(call, ae, &ae->wav_writer_cbp, CONNECTION_MODE_SINK);
6819
+ fp->connection_mode = CONNECTION_MODE_SINK;
6820
+
6821
+ return connect_feature_port_to_stream_port(call, ae, fp);
6792
6822
  }
6793
6823
 
6794
6824
  bool prepare_dtmfdet(Call *call, AudioEndpoint *ae) {
6795
6825
  pj_status_t status;
6826
+
6827
+ ConfBridgePort *fp = &ae->feature_cbps[FP_DTMFDET];
6828
+
6796
6829
  status = pjmedia_dtmfdet_create(
6797
6830
  call->inv->pool,
6798
6831
  PJMEDIA_PIA_SRATE(&ae->stream_cbp.port->info),
6799
6832
  PJMEDIA_PIA_CCNT(&ae->stream_cbp.port->info),
6800
6833
  PJMEDIA_PIA_SPF(&ae->stream_cbp.port->info),
6801
6834
  PJMEDIA_PIA_BITS(&ae->stream_cbp.port->info),
6802
- on_inband_dtmf, call, &ae->dtmfdet_cbp.port);
6835
+ on_inband_dtmf, call, &fp->port);
6803
6836
  if (status != PJ_SUCCESS) {
6804
6837
  set_error("pjmedia_dtmfdet_create failed");
6805
6838
  return false;
6806
6839
  }
6807
6840
 
6808
- status = pjmedia_conf_add_port(ae->conf, call->inv->pool, ae->dtmfdet_cbp.port, NULL, &ae->dtmfdet_cbp.slot);
6841
+ status = pjmedia_conf_add_port(ae->conf, call->inv->pool, fp->port, NULL, &fp->slot);
6809
6842
  if (status != PJ_SUCCESS) {
6810
6843
  set_error("pjmedia_conf_add_port failed");
6811
6844
  return false;
6812
6845
  }
6813
6846
 
6814
- return connect_feature_port_to_stream_port(call, ae, &ae->dtmfdet_cbp, CONNECTION_MODE_SINK);
6847
+ fp->connection_mode = CONNECTION_MODE_SINK;
6848
+
6849
+ return connect_feature_port_to_stream_port(call, ae, fp);
6815
6850
  }
6816
6851
 
6817
- bool prepare_fax(Call *call, AudioEndpoint *ae, bool is_sender, const char *file,
6818
- unsigned flags) {
6852
+ bool prepare_fax(Call *call, AudioEndpoint *ae, bool is_sender, const char *file, unsigned flags) {
6819
6853
  pj_status_t status;
6820
6854
 
6855
+ ConfBridgePort *fp = &ae->feature_cbps[FP_FAX];
6856
+
6821
6857
  status = pjmedia_fax_port_create(
6822
6858
  call->inv->pool,
6823
6859
  PJMEDIA_PIA_SRATE(&ae->stream_cbp.port->info),
@@ -6825,26 +6861,29 @@ bool prepare_fax(Call *call, AudioEndpoint *ae, bool is_sender, const char *file
6825
6861
  PJMEDIA_PIA_SPF(&ae->stream_cbp.port->info),
6826
6862
  PJMEDIA_PIA_BITS(&ae->stream_cbp.port->info),
6827
6863
  on_fax_result, call, is_sender, file,
6828
- flags, &ae->fax_cbp.port);
6864
+ flags, &fp->port);
6829
6865
  if (status != PJ_SUCCESS) {
6830
6866
  set_error("pjmedia_fax_port_create failed");
6831
6867
  return false;
6832
6868
  }
6833
6869
 
6834
- status = pjmedia_conf_add_port(ae->conf, call->inv->pool, ae->fax_cbp.port, NULL, &ae->fax_cbp.slot);
6870
+ status = pjmedia_conf_add_port(ae->conf, call->inv->pool, fp->port, NULL, &fp->slot);
6835
6871
  if (status != PJ_SUCCESS) {
6836
6872
  set_error("pjmedia_conf_add_port failed");
6837
6873
  return false;
6838
6874
  }
6839
6875
 
6840
- return connect_feature_port_to_stream_port(call, ae, &ae->fax_cbp, CONNECTION_MODE_SOURCE_AND_SINK);
6876
+ fp->connection_mode = CONNECTION_MODE_SOURCE_AND_SINK;
6877
+
6878
+ return connect_feature_port_to_stream_port(call, ae, fp);
6841
6879
  }
6842
6880
 
6843
6881
  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);
6845
6882
  pj_status_t status;
6846
6883
 
6847
- if(ae->flite_cbp.port) {
6884
+ ConfBridgePort *fp = &ae->feature_cbps[FP_SPEECH_SYNTH];
6885
+
6886
+ if(fp->port) {
6848
6887
  printf("already prepared\n");
6849
6888
  return true;
6850
6889
  }
@@ -6853,34 +6892,39 @@ bool prepare_flite(Call *call, AudioEndpoint *ae, const char *voice, bool end_of
6853
6892
  call->inv->pool, PJMEDIA_PIA_SRATE(&ae->stream_cbp.port->info),
6854
6893
  PJMEDIA_PIA_CCNT(&ae->stream_cbp.port->info),
6855
6894
  PJMEDIA_PIA_SPF(&ae->stream_cbp.port->info),
6856
- PJMEDIA_PIA_BITS(&ae->stream_cbp.port->info), voice, &ae->flite_cbp.port);
6895
+ PJMEDIA_PIA_BITS(&ae->stream_cbp.port->info),
6896
+ voice,
6897
+ &fp->port);
6857
6898
  if (status != PJ_SUCCESS) {
6858
6899
  set_error("pjmedia_flite_port_create failed");
6859
6900
  return false;
6860
6901
  }
6861
6902
 
6862
6903
  if (end_of_speech_event) {
6863
- status = pjmedia_flite_port_set_eof_cb(ae->flite_cbp.port, (void*)call, on_end_of_speech);
6904
+ status = pjmedia_flite_port_set_eof_cb(fp->port, (void*)call, on_end_of_speech);
6864
6905
  if (status != PJ_SUCCESS) {
6865
6906
  set_error("pjmedia_flite_port_set_eof_cb failed");
6866
6907
  return false;
6867
6908
  }
6868
6909
  }
6869
6910
 
6870
- status = pjmedia_conf_add_port(ae->conf, call->inv->pool, ae->flite_cbp.port, NULL, &ae->flite_cbp.slot);
6911
+ status = pjmedia_conf_add_port(ae->conf, call->inv->pool, fp->port, NULL, &fp->slot);
6871
6912
  if (status != PJ_SUCCESS) {
6872
6913
  set_error("pjmedia_conf_add_port failed");
6873
6914
  return false;
6874
6915
  }
6875
6916
 
6876
- return connect_feature_port_to_stream_port(call, ae, &ae->flite_cbp, CONNECTION_MODE_SOURCE);
6917
+ fp->connection_mode = CONNECTION_MODE_SOURCE;
6918
+
6919
+ return connect_feature_port_to_stream_port(call, ae, fp);
6877
6920
  }
6878
6921
 
6879
6922
  bool prepare_pocketsphinx(Call *call, AudioEndpoint *ae) {
6880
- printf("prepare_pocketsphinx call.id=%i\n", call->id);
6881
6923
  pj_status_t status;
6882
6924
 
6883
- if(ae->pocketsphinx_cbp.port) {
6925
+ ConfBridgePort *fp = &ae->feature_cbps[FP_SPEECH_RECOG];
6926
+
6927
+ if(fp->port) {
6884
6928
  printf("already prepared\n");
6885
6929
  return true;
6886
6930
  }
@@ -6892,19 +6936,21 @@ bool prepare_pocketsphinx(Call *call, AudioEndpoint *ae) {
6892
6936
  PJMEDIA_PIA_BITS(&ae->stream_cbp.port->info),
6893
6937
  on_speech_transcript,
6894
6938
  call,
6895
- &ae->pocketsphinx_cbp.port);
6939
+ &fp->port);
6896
6940
  if (status != PJ_SUCCESS) {
6897
6941
  set_error("pjmedia_pocketsphinx_port_create failed");
6898
6942
  return false;
6899
6943
  }
6900
6944
 
6901
- status = pjmedia_conf_add_port(ae->conf, call->inv->pool, ae->pocketsphinx_cbp.port, NULL, &ae->pocketsphinx_cbp.slot);
6945
+ status = pjmedia_conf_add_port(ae->conf, call->inv->pool, fp->port, NULL, &fp->slot);
6902
6946
  if (status != PJ_SUCCESS) {
6903
6947
  set_error("pjmedia_conf_add_port failed");
6904
6948
  return false;
6905
6949
  }
6906
6950
 
6907
- return connect_feature_port_to_stream_port(call, ae, &ae->pocketsphinx_cbp, CONNECTION_MODE_SINK);
6951
+ fp->connection_mode = CONNECTION_MODE_SINK;
6952
+
6953
+ return connect_feature_port_to_stream_port(call, ae, fp);
6908
6954
  }
6909
6955
 
6910
6956
  void on_rx_notify(pjsip_evsub *sub, pjsip_rx_data *rdata, int *p_st_code,