From a0e9ddf58943171a9031159919e99ef20147a11e Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Wed, 4 Jun 2014 11:53:34 +0000 Subject: [PATCH 001/231] Convert esl_true and esl_false to functions Prior to this commit, an expression such as: esl_true("true") ? 42 : 0 ...would return 1 rather than 42. --- libs/esl/src/include/esl_config.h | 34 ++++++++++++++++--------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/libs/esl/src/include/esl_config.h b/libs/esl/src/include/esl_config.h index 0a2dffb42a..34c67ca219 100644 --- a/libs/esl/src/include/esl_config.h +++ b/libs/esl/src/include/esl_config.h @@ -81,28 +81,30 @@ extern "C" { \param expr a string expression \return true or false */ -#define esl_true(expr)\ -(expr && ( !strcasecmp(expr, "yes") ||\ -!strcasecmp(expr, "on") ||\ -!strcasecmp(expr, "true") ||\ -!strcasecmp(expr, "enabled") ||\ -!strcasecmp(expr, "active") ||\ -!strcasecmp(expr, "allow") ||\ -atoi(expr))) ? 1 : 0 +static inline int esl_true(const char *expr) { + return (expr && (!strcasecmp(expr, "yes") + || !strcasecmp(expr, "on") + || !strcasecmp(expr, "true") + || !strcasecmp(expr, "enabled") + || !strcasecmp(expr, "active") + || !strcasecmp(expr, "allow") + || atoi(expr))); +} /*! \brief Evaluate the falsefullness of a string expression \param expr a string expression \return true or false */ -#define esl_false(expr)\ -(expr && ( !strcasecmp(expr, "no") ||\ -!strcasecmp(expr, "off") ||\ -!strcasecmp(expr, "false") ||\ -!strcasecmp(expr, "disabled") ||\ -!strcasecmp(expr, "inactive") ||\ -!strcasecmp(expr, "disallow") ||\ -!atoi(expr))) ? 1 : 0 +static inline int esl_false(const char *expr) { + return (expr && (!strcasecmp(expr, "no") + || !strcasecmp(expr, "off") + || !strcasecmp(expr, "false") + || !strcasecmp(expr, "disabled") + || !strcasecmp(expr, "inactive") + || !strcasecmp(expr, "disallow") + || !atoi(expr))); +} typedef struct esl_config esl_config_t; From c015013e5fe785b76083c9f75a28b977ac6b9b18 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Wed, 4 Jun 2014 11:07:36 +0000 Subject: [PATCH 002/231] Add log-uuid-short option to fs_cli If log-uuid-short is set, or -S is passed to fs_cli, we only display the first 8 hex digits of the UUID. The log-uuid-chars option may instead be set to specify some other truncation length for the UUID. --- libs/esl/fs_cli.c | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/libs/esl/fs_cli.c b/libs/esl/fs_cli.c index 6e4446524b..135759d004 100644 --- a/libs/esl/fs_cli.c +++ b/libs/esl/fs_cli.c @@ -59,6 +59,7 @@ typedef struct { const char *console_fnkeys[12]; char loglevel[128]; int log_uuid; + int log_uuid_chars; int quiet; int batch_mode; char prompt_color[12]; @@ -66,6 +67,7 @@ typedef struct { char output_text_color[12]; } cli_profile_t; +static const int log_uuid_short_chars = 8; static int is_color = 1; static int warn_stop = 0; static int connected = 0; @@ -604,6 +606,7 @@ static const char *usage_str = " -x, --execute=command Execute Command and Exit\n" " -l, --loglevel=command Log Level\n" " -U, --log-uuid Include UUID in log output\n" + " -S, --log-uuid-short Include shortened UUID in log output\n" " -q, --quiet Disable logging\n" " -r, --retry Retry connection on failure\n" " -R, --reconnect Reconnect if disconnected\n" @@ -742,7 +745,14 @@ static void *msg_thread_run(esl_thread_t *me, void *obj) printf("%s", colors[level]); } if (global_profile->log_uuid && !esl_strlen_zero(userdata)) { - printf("%s ", userdata); + if (global_profile->log_uuid_chars) { + int len = strlen(userdata); + int i = (global_profile->log_uuid_chars < len) ? global_profile->log_uuid_chars : len; + fwrite(userdata, sizeof(char), i, stdout); + printf(" "); + } else { + printf("%s ", userdata); + } } if (strcmp("\n",handle->last_event->body)) { char *c = handle->last_event->body; @@ -1235,6 +1245,14 @@ static void read_config(const char *dft_cfile, const char *cfile) { esl_set_string(profiles[pcount-1].loglevel, val); } else if(!strcasecmp(var, "log-uuid")) { profiles[pcount-1].log_uuid = esl_true(val); + } else if(!strcasecmp(var, "log-uuid-short")) { + profiles[pcount-1].log_uuid = esl_true(val); + profiles[pcount-1].log_uuid_chars = (esl_true(val) ? log_uuid_short_chars : 0); + } else if(!strcasecmp(var, "log-uuid-chars")) { + int i; + if ((i = atoi(val)) > -1) { + profiles[pcount-1].log_uuid_chars = i; + } } else if(!strcasecmp(var, "quiet")) { profiles[pcount-1].quiet = esl_true(val); } else if(!strcasecmp(var, "prompt-color")) { @@ -1301,6 +1319,7 @@ int main(int argc, char *argv[]) {"execute", 1, 0, 'x'}, {"loglevel", 1, 0, 'l'}, {"log-uuid", 0, 0, 'U'}, + {"log-uuid-short", 0, 0, 'S'}, {"quiet", 0, 0, 'q'}, {"batchmode", 0, 0, 'b'}, {"retry", 0, 0, 'r'}, @@ -1324,6 +1343,7 @@ int main(int argc, char *argv[]) char argv_command[1024] = ""; char argv_loglevel[128] = ""; int argv_log_uuid = 0; + int argv_log_uuid_short = 0; int argv_quiet = 0; int argv_batch = 0; int loops = 2, reconnect = 0; @@ -1373,7 +1393,7 @@ int main(int argc, char *argv[]) esl_global_set_default_logger(6); /* default debug level to 6 (info) */ for(;;) { int option_index = 0; - opt = getopt_long(argc, argv, "H:P:S:u:p:d:x:l:Ut:T:qrRhib?n", options, &option_index); + opt = getopt_long(argc, argv, "H:P:u:p:d:x:l:USt:T:qrRhib?n", options, &option_index); if (opt == -1) break; switch (opt) { case 'H': @@ -1419,6 +1439,9 @@ int main(int argc, char *argv[]) case 'U': argv_log_uuid = 1; break; + case 'S': + argv_log_uuid_short = 1; + break; case 'q': argv_quiet = 1; break; @@ -1487,6 +1510,10 @@ int main(int argc, char *argv[]) if (argv_log_uuid) { profile->log_uuid = 1; } + if (argv_log_uuid_short) { + profile->log_uuid = 1; + profile->log_uuid_chars = log_uuid_short_chars; + } esl_log(ESL_LOG_DEBUG, "Using profile %s [%s]\n", profile->name, profile->host); esl_set_string(prompt_color, profile->prompt_color); esl_set_string(input_text_color, profile->input_text_color); From 37a194d9565df2ceeadd6465b24fb9df4c3dce29 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Wed, 4 Jun 2014 20:43:26 +0500 Subject: [PATCH 003/231] FS-6555: move -w to the right place so it silences the warnings in generated code instead of using gnu makeisms that didn't actually fix the problem --- src/mod/languages/mod_perl/Makefile.am | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/mod/languages/mod_perl/Makefile.am b/src/mod/languages/mod_perl/Makefile.am index 6a8f56a9fd..600cd2e43c 100644 --- a/src/mod/languages/mod_perl/Makefile.am +++ b/src/mod/languages/mod_perl/Makefile.am @@ -3,21 +3,20 @@ MODNAME=mod_perl PERL = perl PERL_LIBDIR =-L`perl -MConfig -e 'print $$Config{archlib}'`/CORE PERL_LIBS =`perl -MConfig -e 'print $$Config{libs}'` -CFLAGS_FILTER := -ansi -pedantic perldir=$(prefix)/perl mod_LTLIBRARIES = mod_perl.la perl_LTLIBRARIES = freeswitch.la mod_perl_la_SOURCES = mod_perl.c freeswitch_perl.cpp mod_perl_wrap.cpp perlxsi.c -mod_perl_la_CFLAGS = $(filter-out $(CFLAGS_FILTER),$(AM_CFLAGS)) -w -mod_perl_la_CXXFLAGS = $(filter-out $(CFLAGS_FILTER),$(AM_CXXFLAGS)) -w -mod_perl_la_CPPFLAGS = -DMULTIPLICITY `$(PERL) -MExtUtils::Embed -e ccopts` -DEMBED_PERL -I$(switch_srcdir)/libs/libteletone/src/ +mod_perl_la_CFLAGS = $(AM_CFLAGS) +mod_perl_la_CXXFLAGS = $(AM_CXXFLAGS) +mod_perl_la_CPPFLAGS = -w -DMULTIPLICITY `$(PERL) -MExtUtils::Embed -e ccopts` -DEMBED_PERL -I$(switch_srcdir)/libs/libteletone/src/ mod_perl_la_LIBADD = $(switch_builddir)/libfreeswitch.la mod_perl_la_LDFLAGS = -avoid-version -module -no-undefined -shared `$(PERL) -MExtUtils::Embed -e ldopts` `$(PERL) -MConfig -e 'print $$Config{libs}'` freeswitch_la_SOURCES = freeswitch_perl.cpp mod_perl_wrap.cpp perlxsi.c freeswitch_la_LDFLAGS = -avoid-version -module -no-undefined -shared $(LDFLAGS) -freeswitch_la_CPPFLAGS = -DMULTIPLICITY `$(PERL) -MExtUtils::Embed -e ccopts` -DEMBED_PERL -I$(switch_srcdir)/libs/libteletone/src/ +freeswitch_la_CPPFLAGS = -w -DMULTIPLICITY `$(PERL) -MExtUtils::Embed -e ccopts` -DEMBED_PERL -I$(switch_srcdir)/libs/libteletone/src/ reswig: swigclean mod_perl_wrap.cpp swigclean: clean From 3549488e8eb56fe230db92728c895c68a0c91004 Mon Sep 17 00:00:00 2001 From: Steve Underwood Date: Wed, 4 Jun 2014 23:54:03 +0800 Subject: [PATCH 004/231] Fixed a problem in FAX where a received handshake, delayed so much it is received as we queue a retry, causes the retry frame to remain queued in the HDLC entity. --- libs/spandsp/spandsp/fax-tests.xml | 41 +++++++++++++++++++++++ libs/spandsp/src/adsi.c | 6 ++-- libs/spandsp/src/at_interpreter.c | 2 +- libs/spandsp/src/fax_modems.c | 5 ++- libs/spandsp/src/hdlc.c | 38 ++++++++++++++++++++-- libs/spandsp/src/plc.c | 12 +++---- libs/spandsp/src/queue.c | 32 +++++++++--------- libs/spandsp/src/spandsp/hdlc.h | 25 +++++++++++++- libs/spandsp/src/t30.c | 43 ++++++++++++++++--------- libs/spandsp/src/t30_api.c | 6 ++-- libs/spandsp/src/t31.c | 2 +- libs/spandsp/src/t38_core.c | 2 +- libs/spandsp/src/t38_terminal.c | 28 ++++++++++------ libs/spandsp/src/time_scale.c | 18 +++++------ libs/spandsp/src/v42.c | 2 +- libs/spandsp/tests/fax_decode.c | 43 ++++++++++++++++++------- libs/spandsp/tests/fax_tester.c | 2 +- libs/spandsp/tests/power_meter_tests.c | 2 +- libs/spandsp/tests/t43_tests.c | 4 +-- libs/spandsp/tests/tsb85_extra_tests.sh | 2 +- libs/spandsp/tests/tsb85_tests.c | 2 +- 21 files changed, 228 insertions(+), 89 deletions(-) diff --git a/libs/spandsp/spandsp/fax-tests.xml b/libs/spandsp/spandsp/fax-tests.xml index 23f333a396..495eadec7e 100644 --- a/libs/spandsp/spandsp/fax-tests.xml +++ b/libs/spandsp/spandsp/fax-tests.xml @@ -184,5 +184,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libs/spandsp/src/adsi.c b/libs/spandsp/src/adsi.c index 1f711bf44f..72d85319c1 100644 --- a/libs/spandsp/src/adsi.c +++ b/libs/spandsp/src/adsi.c @@ -1029,13 +1029,13 @@ SPAN_DECLARE(int) adsi_add_field(adsi_tx_state_t *s, uint8_t *msg, int len, uint msg[len++] = (uint8_t) field_len; if (field_len == DLE) msg[len++] = (uint8_t) field_len; - memcpy(msg + len, field_body, field_len); + memcpy(&msg[len], field_body, field_len); len += field_len; } else { /* No field type or length, for restricted single message formats */ - memcpy(msg + len, field_body, field_len); + memcpy(&msg[len], field_body, field_len); len += field_len; } } @@ -1080,7 +1080,7 @@ SPAN_DECLARE(int) adsi_add_field(adsi_tx_state_t *s, uint8_t *msg, int len, uint x = msg[--len]; if (field_type != CLIP_DTMF_HASH_UNSPECIFIED) msg[len++] = field_type; - memcpy(msg + len, field_body, field_len); + memcpy(&msg[len], field_body, field_len); msg[len + field_len] = (uint8_t) x; len += (field_len + 1); } diff --git a/libs/spandsp/src/at_interpreter.c b/libs/spandsp/src/at_interpreter.c index 9bebde6272..5d6dc42043 100644 --- a/libs/spandsp/src/at_interpreter.c +++ b/libs/spandsp/src/at_interpreter.c @@ -5411,7 +5411,7 @@ static int command_search(const char *u, int *matched) entry = 0; /* Loop over the length of the string to search the trie... */ - for (i = 0, ptr = 0; ptr < COMMAND_TRIE_LEN; i++) + for (i = 0, ptr = 0; ptr < COMMAND_TRIE_LEN - 2; i++) { /* The character in u we are processing... */ /* V.250 5.4.1 says upper and lower case are equivalent in commands */ diff --git a/libs/spandsp/src/fax_modems.c b/libs/spandsp/src/fax_modems.c index a09b0c9506..df89b088c2 100644 --- a/libs/spandsp/src/fax_modems.c +++ b/libs/spandsp/src/fax_modems.c @@ -172,7 +172,10 @@ SPAN_DECLARE_NONSTD(void) fax_modems_hdlc_tx_frame(void *user_data, const uint8_ s = (fax_modems_state_t *) user_data; - hdlc_tx_frame(&s->hdlc_tx, msg, len); + if (len == -1) + hdlc_tx_restart(&s->hdlc_tx); + else + hdlc_tx_frame(&s->hdlc_tx, msg, len); } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/hdlc.c b/libs/spandsp/src/hdlc.c index 7a20bf2451..74b2760e70 100644 --- a/libs/spandsp/src/hdlc.c +++ b/libs/spandsp/src/hdlc.c @@ -311,6 +311,20 @@ SPAN_DECLARE(void) hdlc_rx_set_octet_counting_report_interval(hdlc_rx_state_t *s } /*- End of function --------------------------------------------------------*/ +SPAN_DECLARE(int) hdlc_rx_restart(hdlc_rx_state_t *s) +{ + s->framing_ok_announced = false; + s->flags_seen = 0; + s->raw_bit_stream = 0; + s->byte_in_progress = 0; + s->num_bits = 0; + s->octet_counting_mode = false; + s->octet_count = 0; + s->len = 0; + return 0; +} +/*- End of function --------------------------------------------------------*/ + SPAN_DECLARE(hdlc_rx_state_t *) hdlc_rx_init(hdlc_rx_state_t *s, bool crc32, bool report_bad_frames, @@ -375,7 +389,7 @@ SPAN_DECLARE(int) hdlc_rx_get_stats(hdlc_rx_state_t *s, SPAN_DECLARE(int) hdlc_tx_frame(hdlc_tx_state_t *s, const uint8_t *frame, size_t len) { - if (len <= 0) + if (len == 0) { s->tx_end = true; return 0; @@ -394,7 +408,7 @@ SPAN_DECLARE(int) hdlc_tx_frame(hdlc_tx_state_t *s, const uint8_t *frame, size_t if (s->len) return -1; } - memcpy(s->buffer + s->len, frame, len); + memcpy(&s->buffer[s->len], frame, len); if (s->crc_bytes == 2) s->crc = crc_itu16_calc(frame, len, (uint16_t) s->crc); else @@ -589,6 +603,24 @@ SPAN_DECLARE(void) hdlc_tx_set_max_frame_len(hdlc_tx_state_t *s, size_t max_len) } /*- End of function --------------------------------------------------------*/ +SPAN_DECLARE(int) hdlc_tx_restart(hdlc_tx_state_t *s) +{ + s->octets_in_progress = 0; + s->num_bits = 0; + s->idle_octet = 0x7E; + s->flag_octets = 0; + s->abort_octets = 0; + s->report_flag_underflow = false; + s->len = 0; + s->pos = 0; + s->crc = 0; + s->byte = 0; + s->bits = 0; + s->tx_end = false; + return 0; +} +/*- End of function --------------------------------------------------------*/ + SPAN_DECLARE(hdlc_tx_state_t *) hdlc_tx_init(hdlc_tx_state_t *s, bool crc32, int inter_frame_flags, @@ -602,7 +634,6 @@ SPAN_DECLARE(hdlc_tx_state_t *) hdlc_tx_init(hdlc_tx_state_t *s, return NULL; } memset(s, 0, sizeof(*s)); - s->idle_octet = 0x7E; s->underflow_handler = handler; s->user_data = user_data; s->inter_frame_flags = (inter_frame_flags < 1) ? 1 : inter_frame_flags; @@ -616,6 +647,7 @@ SPAN_DECLARE(hdlc_tx_state_t *) hdlc_tx_init(hdlc_tx_state_t *s, s->crc_bytes = 2; s->crc = 0xFFFF; } + s->idle_octet = 0x7E; s->progressive = progressive; s->max_frame_len = HDLC_MAXFRAME_LEN; return s; diff --git a/libs/spandsp/src/plc.c b/libs/spandsp/src/plc.c index cb40ea88e0..52f4e24044 100644 --- a/libs/spandsp/src/plc.c +++ b/libs/spandsp/src/plc.c @@ -58,21 +58,21 @@ static void save_history(plc_state_t *s, int16_t *buf, int len) if (len >= PLC_HISTORY_LEN) { /* Just keep the last part of the new data, starting at the beginning of the buffer */ - memcpy(s->history, buf + len - PLC_HISTORY_LEN, sizeof(int16_t)*PLC_HISTORY_LEN); + memcpy(s->history, &buf[len - PLC_HISTORY_LEN], sizeof(int16_t)*PLC_HISTORY_LEN); s->buf_ptr = 0; return; } if (s->buf_ptr + len > PLC_HISTORY_LEN) { /* Wraps around - must break into two sections */ - memcpy(s->history + s->buf_ptr, buf, sizeof(int16_t)*(PLC_HISTORY_LEN - s->buf_ptr)); + memcpy(&s->history[s->buf_ptr], buf, sizeof(int16_t)*(PLC_HISTORY_LEN - s->buf_ptr)); len -= (PLC_HISTORY_LEN - s->buf_ptr); - memcpy(s->history, buf + (PLC_HISTORY_LEN - s->buf_ptr), sizeof(int16_t)*len); + memcpy(s->history, &buf[PLC_HISTORY_LEN - s->buf_ptr], sizeof(int16_t)*len); s->buf_ptr = len; return; } /* Can use just one section */ - memcpy(s->history + s->buf_ptr, buf, sizeof(int16_t)*len); + memcpy(&s->history[s->buf_ptr], buf, sizeof(int16_t)*len); s->buf_ptr += len; } /*- End of function --------------------------------------------------------*/ @@ -84,8 +84,8 @@ static __inline__ void normalise_history(plc_state_t *s) if (s->buf_ptr == 0) return; memcpy(tmp, s->history, sizeof(int16_t)*s->buf_ptr); - memmove(s->history, s->history + s->buf_ptr, sizeof(int16_t)*(PLC_HISTORY_LEN - s->buf_ptr)); - memcpy(s->history + PLC_HISTORY_LEN - s->buf_ptr, tmp, sizeof(int16_t)*s->buf_ptr); + memmove(s->history, &s->history[s->buf_ptr], sizeof(int16_t)*(PLC_HISTORY_LEN - s->buf_ptr)); + memcpy(&s->history[PLC_HISTORY_LEN - s->buf_ptr], tmp, sizeof(int16_t)*s->buf_ptr); s->buf_ptr = 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/queue.c b/libs/spandsp/src/queue.c index d569039969..98f19e3962 100644 --- a/libs/spandsp/src/queue.c +++ b/libs/spandsp/src/queue.c @@ -119,8 +119,8 @@ SPAN_DECLARE(int) queue_view(queue_state_t *s, uint8_t *buf, int len) /* A two step process */ if (buf) { - memcpy(buf, s->data + optr, to_end); - memcpy(buf + to_end, s->data, real_len - to_end); + memcpy(buf, &s->data[optr], to_end); + memcpy(&buf[to_end], s->data, real_len - to_end); } /*endif*/ } @@ -128,7 +128,7 @@ SPAN_DECLARE(int) queue_view(queue_state_t *s, uint8_t *buf, int len) { /* A one step process */ if (buf) - memcpy(buf, s->data + optr, real_len); + memcpy(buf, &s->data[optr], real_len); /*endif*/ } /*endif*/ @@ -170,8 +170,8 @@ SPAN_DECLARE(int) queue_read(queue_state_t *s, uint8_t *buf, int len) /* A two step process */ if (buf) { - memcpy(buf, s->data + optr, to_end); - memcpy(buf + to_end, s->data, real_len - to_end); + memcpy(buf, &s->data[optr], to_end); + memcpy(&buf[to_end], s->data, real_len - to_end); } /*endif*/ new_optr = real_len - to_end; @@ -180,7 +180,7 @@ SPAN_DECLARE(int) queue_read(queue_state_t *s, uint8_t *buf, int len) { /* A one step process */ if (buf) - memcpy(buf, s->data + optr, real_len); + memcpy(buf, &s->data[optr], real_len); /*endif*/ new_optr = optr + real_len; if (new_optr >= s->len) @@ -253,7 +253,7 @@ SPAN_DECLARE(int) queue_write(queue_state_t *s, const uint8_t *buf, int len) if (iptr < optr || to_end >= real_len) { /* A one step process */ - memcpy(s->data + iptr, buf, real_len); + memcpy(&s->data[iptr], buf, real_len); new_iptr = iptr + real_len; if (new_iptr >= s->len) new_iptr = 0; @@ -262,8 +262,8 @@ SPAN_DECLARE(int) queue_write(queue_state_t *s, const uint8_t *buf, int len) else { /* A two step process */ - memcpy(s->data + iptr, buf, to_end); - memcpy(s->data, buf + to_end, real_len - to_end); + memcpy(&s->data[iptr], buf, to_end); + memcpy(s->data, &buf[to_end], real_len - to_end); new_iptr = real_len - to_end; } /*endif*/ @@ -367,8 +367,8 @@ SPAN_DECLARE(int) queue_write_msg(queue_state_t *s, const uint8_t *buf, int len) if (iptr < optr || to_end >= real_len) { /* A one step process */ - memcpy(s->data + iptr, &lenx, sizeof(uint16_t)); - memcpy(s->data + iptr + sizeof(uint16_t), buf, len); + memcpy(&s->data[iptr], &lenx, sizeof(uint16_t)); + memcpy(&s->data[iptr + sizeof(uint16_t)], buf, len); new_iptr = iptr + real_len; if (new_iptr >= s->len) new_iptr = 0; @@ -380,16 +380,16 @@ SPAN_DECLARE(int) queue_write_msg(queue_state_t *s, const uint8_t *buf, int len) if (to_end >= sizeof(uint16_t)) { /* The actual message wraps around the end of the buffer */ - memcpy(s->data + iptr, &lenx, sizeof(uint16_t)); - memcpy(s->data + iptr + sizeof(uint16_t), buf, to_end - sizeof(uint16_t)); - memcpy(s->data, buf + to_end - sizeof(uint16_t), real_len - to_end); + memcpy(&s->data[iptr], &lenx, sizeof(uint16_t)); + memcpy(&s->data[iptr + sizeof(uint16_t)], buf, to_end - sizeof(uint16_t)); + memcpy(s->data, &buf[to_end - sizeof(uint16_t)], real_len - to_end); } else { /* The message length wraps around the end of the buffer */ - memcpy(s->data + iptr, (uint8_t *) &lenx, to_end); + memcpy(&s->data[iptr], (uint8_t *) &lenx, to_end); memcpy(s->data, ((uint8_t *) &lenx) + to_end, sizeof(uint16_t) - to_end); - memcpy(s->data + sizeof(uint16_t) - to_end, buf, len); + memcpy(&s->data[sizeof(uint16_t) - to_end], buf, len); } new_iptr = real_len - to_end; } diff --git a/libs/spandsp/src/spandsp/hdlc.h b/libs/spandsp/src/spandsp/hdlc.h index a0916d1d5f..52f68505b1 100644 --- a/libs/spandsp/src/spandsp/hdlc.h +++ b/libs/spandsp/src/spandsp/hdlc.h @@ -99,6 +99,13 @@ SPAN_DECLARE(hdlc_rx_state_t *) hdlc_rx_init(hdlc_rx_state_t *s, hdlc_frame_handler_t handler, void *user_data); +/*! Re-initialise an HDLC receiver context. This does not reset the usage statistics. + \brief Re-initialise an HDLC receiver context. + \param s A pointer to an HDLC receiver context. + \return 0 for success. +*/ +SPAN_DECLARE(int) hdlc_rx_restart(hdlc_rx_state_t *s); + /*! Change the put_bit function associated with an HDLC receiver context. \brief Change the put_bit function associated with an HDLC receiver context. \param s A pointer to an HDLC receiver context. @@ -167,7 +174,8 @@ SPAN_DECLARE_NONSTD(void) hdlc_rx_put_byte(hdlc_rx_state_t *s, int new_byte); */ SPAN_DECLARE_NONSTD(void) hdlc_rx_put(hdlc_rx_state_t *s, const uint8_t buf[], int len); -/*! \brief Initialise an HDLC transmitter context. +/*! Initialise an HDLC transmitter context. + \brief Initialise an HDLC transmitter context. \param s A pointer to an HDLC transmitter context. \param crc32 True to use ITU CRC32. False to use ITU CRC16. \param inter_frame_flags The minimum flag octets to insert between frames (usually one). @@ -183,8 +191,23 @@ SPAN_DECLARE(hdlc_tx_state_t *) hdlc_tx_init(hdlc_tx_state_t *s, hdlc_underflow_handler_t handler, void *user_data); +/*! Re-initialise an HDLC transmitter context. + \brief Re-initialise an HDLC transmitter context. + \param s A pointer to an HDLC transmitter context. + \return 0 for success. +*/ +SPAN_DECLARE(int) hdlc_tx_restart(hdlc_tx_state_t *s); + +/*! Release an HDLC transmitter context. + \brief Release an HDLC transmitter context. + \param s A pointer to an HDLC transmitter context. + \return 0 for OK */ SPAN_DECLARE(int) hdlc_tx_release(hdlc_tx_state_t *s); +/*! Free an HDLC transmitter context. + \brief Free an HDLC transmitter context. + \param s A pointer to an HDLC transmitter context. + \return 0 for OK */ SPAN_DECLARE(int) hdlc_tx_free(hdlc_tx_state_t *s); /*! \brief Set the maximum frame length for an HDLC transmitter context. diff --git a/libs/spandsp/src/t30.c b/libs/spandsp/src/t30.c index 8a9c1cd193..e7f958552c 100644 --- a/libs/spandsp/src/t30.c +++ b/libs/spandsp/src/t30.c @@ -5109,20 +5109,34 @@ static void queue_phase(t30_state_t *s, int phase) if (s->rx_signal_present) { /* We need to wait for that signal to go away */ + if (s->next_phase != T30_PHASE_IDLE) + { + span_log(&s->logging, SPAN_LOG_FLOW, "Flushing queued phase %s\n", phase_names[s->next_phase]); + /* Ensure nothing has been left in the queue that was scheduled to go out in the previous next + phase */ + if (s->send_hdlc_handler) + s->send_hdlc_handler(s->send_hdlc_user_data, NULL, -1); + } s->next_phase = phase; } else { + /* We don't need to queue the new phase. We can change to it immediately. */ set_phase(s, phase); - s->next_phase = T30_PHASE_IDLE; } } /*- End of function --------------------------------------------------------*/ static void set_phase(t30_state_t *s, int phase) { - //if (phase = s->phase) - // return; + if (phase != s->next_phase && s->next_phase != T30_PHASE_IDLE) + { + span_log(&s->logging, SPAN_LOG_FLOW, "Flushing queued phase %s\n", phase_names[s->next_phase]); + /* Ensure nothing has been left in the queue that was scheduled to go out in the previous next + phase */ + if (s->send_hdlc_handler) + s->send_hdlc_handler(s->send_hdlc_user_data, NULL, -1); + } span_log(&s->logging, SPAN_LOG_FLOW, "Changing from phase %s to %s\n", phase_names[s->phase], phase_names[phase]); /* We may be killing a receiver before it has declared the end of the signal. Force the signal present indicator to off, because the @@ -5132,6 +5146,7 @@ static void set_phase(t30_state_t *s, int phase) s->rx_trained = false; s->rx_frame_received = false; s->phase = phase; + s->next_phase = T30_PHASE_IDLE; switch (phase) { case T30_PHASE_A_CED: @@ -5470,6 +5485,14 @@ static void timer_t1_expired(t30_state_t *s) } /*- End of function --------------------------------------------------------*/ +static void timer_t1a_expired(t30_state_t *s) +{ + span_log(&s->logging, SPAN_LOG_FLOW, "T1A expired in phase %s, state %s. An HDLC frame lasted too long.\n", phase_names[s->phase], state_names[s->state]); + t30_set_status(s, T30_ERR_HDLC_CARRIER); + disconnect(s); +} +/*- End of function --------------------------------------------------------*/ + static void timer_t2_expired(t30_state_t *s) { if (s->timer_t2_t4_is != TIMER_IS_T2B) @@ -5541,14 +5564,6 @@ static void timer_t2_expired(t30_state_t *s) } /*- End of function --------------------------------------------------------*/ -static void timer_t1a_expired(t30_state_t *s) -{ - span_log(&s->logging, SPAN_LOG_FLOW, "T1A expired in phase %s, state %s. An HDLC frame lasted too long.\n", phase_names[s->phase], state_names[s->state]); - t30_set_status(s, T30_ERR_HDLC_CARRIER); - disconnect(s); -} -/*- End of function --------------------------------------------------------*/ - static void timer_t2a_expired(t30_state_t *s) { span_log(&s->logging, SPAN_LOG_FLOW, "T2A expired in phase %s, state %s. An HDLC frame lasted too long.\n", phase_names[s->phase], state_names[s->state]); @@ -5680,7 +5695,7 @@ static int decode_nsf_nss_nsc(t30_state_t *s, uint8_t *msg[], const uint8_t *pkt if ((t = span_alloc(len - 1)) == NULL) return 0; - memcpy(t, pkt + 1, len - 1); + memcpy(t, &pkt[1], len - 1); *msg = t; return len - 1; } @@ -5777,10 +5792,7 @@ static void t30_non_ecm_rx_status(void *user_data, int status) break; } if (s->next_phase != T30_PHASE_IDLE) - { set_phase(s, s->next_phase); - s->next_phase = T30_PHASE_IDLE; - } break; default: span_log(&s->logging, SPAN_LOG_WARNING, "Unexpected non-ECM rx status - %d!\n", status); @@ -6012,7 +6024,6 @@ static void t30_hdlc_rx_status(void *user_data, int status) { /* The appropriate timer for the next phase should already be in progress */ set_phase(s, s->next_phase); - s->next_phase = T30_PHASE_IDLE; } else { diff --git a/libs/spandsp/src/t30_api.c b/libs/spandsp/src/t30_api.c index 6d0bca3840..5bf164b998 100644 --- a/libs/spandsp/src/t30_api.c +++ b/libs/spandsp/src/t30_api.c @@ -282,7 +282,7 @@ SPAN_DECLARE(int) t30_set_tx_nsf(t30_state_t *s, const uint8_t *nsf, int len) span_free(s->tx_info.nsf); if (nsf && len > 0 && (s->tx_info.nsf = span_alloc(len + 3))) { - memcpy(s->tx_info.nsf + 3, nsf, len); + memcpy(&s->tx_info.nsf[3], nsf, len); s->tx_info.nsf_len = len; } else @@ -316,7 +316,7 @@ SPAN_DECLARE(int) t30_set_tx_nsc(t30_state_t *s, const uint8_t *nsc, int len) span_free(s->tx_info.nsc); if (nsc && len > 0 && (s->tx_info.nsc = span_alloc(len + 3))) { - memcpy(s->tx_info.nsc + 3, nsc, len); + memcpy(&s->tx_info.nsc[3], nsc, len); s->tx_info.nsc_len = len; } else @@ -350,7 +350,7 @@ SPAN_DECLARE(int) t30_set_tx_nss(t30_state_t *s, const uint8_t *nss, int len) span_free(s->tx_info.nss); if (nss && len > 0 && (s->tx_info.nss = span_alloc(len + 3))) { - memcpy(s->tx_info.nss + 3, nss, len); + memcpy(&s->tx_info.nss[3], nss, len); s->tx_info.nss_len = len; } else diff --git a/libs/spandsp/src/t31.c b/libs/spandsp/src/t31.c index 47f26c9e49..ef8dcd16f6 100644 --- a/libs/spandsp/src/t31.c +++ b/libs/spandsp/src/t31.c @@ -1877,7 +1877,7 @@ static void hdlc_accept_frame(void *user_data, const uint8_t *msg, int len, int buf[0] = (ok) ? AT_RESPONSE_CODE_OK : AT_RESPONSE_CODE_ERROR; /* It is safe to look at the two bytes beyond the length of the message, and expect to find the FCS there. */ - memcpy(buf + 1, msg, len + 2); + memcpy(&buf[1], msg, len + 2); queue_write_msg(s->rx_queue, buf, len + 3); } /*endif*/ diff --git a/libs/spandsp/src/t38_core.c b/libs/spandsp/src/t38_core.c index 5fb57bbc82..c310ebbd95 100644 --- a/libs/spandsp/src/t38_core.c +++ b/libs/spandsp/src/t38_core.c @@ -842,7 +842,7 @@ static int t38_encode_data(t38_core_state_t *s, uint8_t buf[], int data_type, co return -1; buf[len++] = (uint8_t) (((q->field_len - 1) >> 8) & 0xFF); buf[len++] = (uint8_t) ((q->field_len - 1) & 0xFF); - memcpy(buf + len, q->field, q->field_len); + memcpy(&buf[len], q->field, q->field_len); len += q->field_len; } data_field_no++; diff --git a/libs/spandsp/src/t38_terminal.c b/libs/spandsp/src/t38_terminal.c index 0349eb4283..03f8ede658 100644 --- a/libs/spandsp/src/t38_terminal.c +++ b/libs/spandsp/src/t38_terminal.c @@ -616,20 +616,28 @@ static void send_hdlc(void *user_data, const uint8_t *msg, int len) t38_terminal_state_t *s; s = (t38_terminal_state_t *) user_data; - if (len <= 0) + if (len == 0) { + /* A length of zero means shut down the HDLC transmission */ + /* Setting len to -1 makes HDLC shut down */ s->t38_fe.hdlc_tx.len = -1; - } - else - { - if (s->t38_fe.us_per_tx_chunk) - s->t38_fe.hdlc_tx.extra_bits = extra_bits_in_stuffed_frame(msg, len); - /*endif*/ - bit_reverse(s->t38_fe.hdlc_tx.buf, msg, len); - s->t38_fe.hdlc_tx.len = len; - s->t38_fe.hdlc_tx.ptr = 0; + return; } /*endif*/ + if (len == -1) + { + /* A length of -1 means flush any buffered HDLC data */ + s->t38_fe.hdlc_tx.len = 0; + s->t38_fe.hdlc_tx.ptr = 0; + return; + } + /*endif*/ + if (s->t38_fe.us_per_tx_chunk) + s->t38_fe.hdlc_tx.extra_bits = extra_bits_in_stuffed_frame(msg, len); + /*endif*/ + bit_reverse(s->t38_fe.hdlc_tx.buf, msg, len); + s->t38_fe.hdlc_tx.len = len; + s->t38_fe.hdlc_tx.ptr = 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/time_scale.c b/libs/spandsp/src/time_scale.c index 6006333674..2378b4f1c8 100644 --- a/libs/spandsp/src/time_scale.c +++ b/libs/spandsp/src/time_scale.c @@ -190,12 +190,12 @@ SPAN_DECLARE(int) time_scale(time_scale_state_t *s, int16_t out[], int16_t in[], if (s->fill + len < s->buf_len) { /* Cannot continue without more samples */ - memcpy(s->buf + s->fill, in, sizeof(int16_t)*len); + memcpy(&s->buf[s->fill], in, sizeof(int16_t)*len); s->fill += len; return out_len; } k = s->buf_len - s->fill; - memcpy(s->buf + s->fill, in, sizeof(int16_t)*k); + memcpy(&s->buf[s->fill], in, sizeof(int16_t)*k); in_len += k; s->fill = s->buf_len; while (s->fill == s->buf_len) @@ -207,12 +207,12 @@ SPAN_DECLARE(int) time_scale(time_scale_state_t *s, int16_t out[], int16_t in[], if (len - in_len < s->buf_len) { /* Cannot continue without more samples */ - memcpy(s->buf, in + in_len, sizeof(int16_t)*(len - in_len)); + memcpy(s->buf, &in[in_len], sizeof(int16_t)*(len - in_len)); s->fill = len - in_len; s->lcp -= s->buf_len; return out_len; } - memcpy(s->buf, in + in_len, sizeof(int16_t)*s->buf_len); + memcpy(s->buf, &in[in_len], sizeof(int16_t)*s->buf_len); in_len += s->buf_len; s->lcp -= s->buf_len; } @@ -220,16 +220,16 @@ SPAN_DECLARE(int) time_scale(time_scale_state_t *s, int16_t out[], int16_t in[], { memcpy(&out[out_len], s->buf, sizeof(int16_t)*s->lcp); out_len += s->lcp; - memcpy(s->buf, s->buf + s->lcp, sizeof(int16_t)*(s->buf_len - s->lcp)); + memcpy(s->buf, &s->buf[s->lcp], sizeof(int16_t)*(s->buf_len - s->lcp)); if (len - in_len < s->lcp) { /* Cannot continue without more samples */ - memcpy(s->buf + (s->buf_len - s->lcp), in + in_len, sizeof(int16_t)*(len - in_len)); + memcpy(&s->buf[s->buf_len - s->lcp], &in[in_len], sizeof(int16_t)*(len - in_len)); s->fill = s->buf_len - s->lcp + len - in_len; s->lcp = 0; return out_len; } - memcpy(s->buf + (s->buf_len - s->lcp), in + in_len, sizeof(int16_t)*s->lcp); + memcpy(&s->buf[s->buf_len - s->lcp], &in[in_len], sizeof(int16_t)*s->lcp); in_len += s->lcp; s->lcp = 0; } @@ -263,11 +263,11 @@ SPAN_DECLARE(int) time_scale(time_scale_state_t *s, int16_t out[], int16_t in[], if (len - in_len < pitch) { /* Cannot continue without more samples */ - memcpy(s->buf + s->buf_len - pitch, in + in_len, sizeof(int16_t)*(len - in_len)); + memcpy(&s->buf[s->buf_len - pitch], &in[in_len], sizeof(int16_t)*(len - in_len)); s->fill += (len - in_len - pitch); return out_len; } - memcpy(s->buf + s->buf_len - pitch, in + in_len, sizeof(int16_t)*pitch); + memcpy(&s->buf[s->buf_len - pitch], &in[in_len], sizeof(int16_t)*pitch); in_len += pitch; } else diff --git a/libs/spandsp/src/v42.c b/libs/spandsp/src/v42.c index fb54fa5b39..806f7aa212 100644 --- a/libs/spandsp/src/v42.c +++ b/libs/spandsp/src/v42.c @@ -238,7 +238,7 @@ static int tx_unnumbered_frame(lapm_state_t *s, uint8_t addr, uint8_t ctrl, uint f->len = 2; if (info && len) { - memcpy(buf + f->len, info, len); + memcpy(&buf[f->len], info, len); f->len += len; } return 0; diff --git a/libs/spandsp/tests/fax_decode.c b/libs/spandsp/tests/fax_decode.c index 9fedc23c66..12cc11bb92 100644 --- a/libs/spandsp/tests/fax_decode.c +++ b/libs/spandsp/tests/fax_decode.c @@ -211,12 +211,24 @@ static int check_rx_dcs(const uint8_t *msg, int len) } octets_per_ecm_frame = (dcs_frame[6] & DISBIT4) ? 256 : 64; + if ((dcs_frame[8] & DISBIT1)) y_resolution = T4_Y_RESOLUTION_SUPERFINE; else if (dcs_frame[4] & DISBIT7) y_resolution = T4_Y_RESOLUTION_FINE; else y_resolution = T4_Y_RESOLUTION_STANDARD; + + if ((dcs_frame[8] & DISBIT3)) + { + x_resolution = T4_X_RESOLUTION_R16; + y_resolution = T4_Y_RESOLUTION_SUPERFINE; + } + else + { + x_resolution = T4_X_RESOLUTION_R8; + } + image_width = widths[(dcs_frame[8] & DISBIT3) ? 2 : 1][dcs_frame[5] & (DISBIT2 | DISBIT1)]; /* Check which compression we will use. */ @@ -344,9 +356,9 @@ static void v21_put_bit(void *user_data, int bit) } return; } + fprintf(stderr, "V.21 Rx bit %d - %d\n", rx_bits++, bit); if (fast_trained == FAX_NONE) hdlc_rx_put_bit(&hdlcrx, bit); - //printf("V.21 Rx bit %d - %d\n", rx_bits++, bit); } /*- End of function --------------------------------------------------------*/ @@ -501,8 +513,10 @@ int main(int argc, char *argv[]) } memset(&t30_dummy, 0, sizeof(t30_dummy)); - span_log_init(&t30_dummy.logging, SPAN_LOG_FLOW, NULL); - span_log_set_protocol(&t30_dummy.logging, "T.30"); + logging = t30_get_logging_state(&t30_dummy); + span_log_init(logging, SPAN_LOG_NONE, NULL); + span_log_set_protocol(logging, "T.30"); + span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW); hdlc_rx_init(&hdlcrx, false, true, 5, hdlc_accept, NULL); fsk = fsk_rx_init(NULL, &preset_fsk_specs[FSK_V21CH2], FSK_FRAME_MODE_SYNC, v21_put_bit, NULL); @@ -520,24 +534,20 @@ int main(int argc, char *argv[]) #if 1 logging = v17_rx_get_logging_state(v17); - span_log_init(logging, SPAN_LOG_FLOW, NULL); span_log_set_protocol(logging, "V.17"); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_FLOW); + span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW); logging = v29_rx_get_logging_state(v29); - span_log_init(logging, SPAN_LOG_FLOW, NULL); span_log_set_protocol(logging, "V.29"); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_FLOW); + span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW); logging = v27ter_rx_get_logging_state(v27ter_4800); - span_log_init(logging, SPAN_LOG_FLOW, NULL); span_log_set_protocol(logging, "V.27ter-4800"); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_FLOW); + span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW); logging = v27ter_rx_get_logging_state(v27ter_2400); - span_log_init(logging, SPAN_LOG_FLOW, NULL); span_log_set_protocol(logging, "V.27ter-2400"); - span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_FLOW); + span_log_set_level(logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW); #endif if (t4_rx_init(&t4_rx_state, "fax_decode.tif", T4_COMPRESSION_T4_2D) == NULL) @@ -556,6 +566,17 @@ int main(int argc, char *argv[]) v29_rx(v29, amp, len); v27ter_rx(v27ter_4800, amp, len); v27ter_rx(v27ter_2400, amp, len); + + logging = t30_get_logging_state(&t30_dummy); + span_log_bump_samples(logging, len); + logging = v17_rx_get_logging_state(v17); + span_log_bump_samples(logging, len); + logging = v29_rx_get_logging_state(v29); + span_log_bump_samples(logging, len); + logging = v27ter_rx_get_logging_state(v27ter_4800); + span_log_bump_samples(logging, len); + logging = v27ter_rx_get_logging_state(v27ter_2400); + span_log_bump_samples(logging, len); } t4_rx_release(&t4_rx_state); diff --git a/libs/spandsp/tests/fax_tester.c b/libs/spandsp/tests/fax_tester.c index df6aeeaf60..4cd85d68a7 100644 --- a/libs/spandsp/tests/fax_tester.c +++ b/libs/spandsp/tests/fax_tester.c @@ -112,7 +112,7 @@ static void hdlc_underflow_handler(void *user_data) buf[1] = 0x03; buf[2] = 0x06; buf[3] = s->image_ptr/s->ecm_frame_size; - memcpy(buf + 4, &s->image_buffer[s->image_ptr], s->ecm_frame_size); + memcpy(&buf[4], &s->image_buffer[s->image_ptr], s->ecm_frame_size); hdlc_tx_frame(&s->modems.hdlc_tx, buf, 4 + s->ecm_frame_size); if (s->corrupt_crc >= 0 && s->corrupt_crc == s->image_ptr/s->ecm_frame_size) hdlc_tx_corrupt_frame(&s->modems.hdlc_tx); diff --git a/libs/spandsp/tests/power_meter_tests.c b/libs/spandsp/tests/power_meter_tests.c index da04372778..518fa3a694 100644 --- a/libs/spandsp/tests/power_meter_tests.c +++ b/libs/spandsp/tests/power_meter_tests.c @@ -168,7 +168,7 @@ static int power_surge_detector_file_test(const char *file) if ((inhandle = sf_open_telephony_read(file, 1)) == NULL) { - printf(" Cannot open audio file '%s'\n", file); + fprintf(stderr, " Cannot open audio file '%s'\n", file); exit(2); } diff --git a/libs/spandsp/tests/t43_tests.c b/libs/spandsp/tests/t43_tests.c index 76946b94b3..bc9242d044 100644 --- a/libs/spandsp/tests/t43_tests.c +++ b/libs/spandsp/tests/t43_tests.c @@ -68,7 +68,7 @@ typedef struct static const TIFFFieldInfo tiff_fx_tiff_field_info[] = { {TIFFTAG_INDEXED, 1, 1, TIFF_SHORT, FIELD_CUSTOM, false, false, (char *) "Indexed"}, - {TIFFTAG_GLOBALPARAMETERSIFD, 1, 1, TIFF_IFD8, FIELD_CUSTOM, false, false, (char *) "GlobalParametersIFD"}, + {TIFFTAG_GLOBALPARAMETERSIFD, 1, 1, TIFF_IFD8, FIELD_CUSTOM, false, false, (char *) "GlobalParametersIFD"}, {TIFFTAG_PROFILETYPE, 1, 1, TIFF_LONG, FIELD_CUSTOM, false, false, (char *) "ProfileType"}, {TIFFTAG_FAXPROFILE, 1, 1, TIFF_BYTE, FIELD_CUSTOM, false, false, (char *) "FaxProfile"}, {TIFFTAG_CODINGMETHODS, 1, 1, TIFF_LONG, FIELD_CUSTOM, false, false, (char *) "CodingMethods"}, @@ -86,7 +86,7 @@ static TIFFFieldArray tifffxFieldArray; static TIFFField tiff_fx_tiff_fields[] = { { TIFFTAG_INDEXED, 1, 1, TIFF_SHORT, 0, TIFF_SETGET_UINT16, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, (char *) "Indexed" }, - { TIFFTAG_GLOBALPARAMETERSIFD, 1, 1, TIFF_IFD8, 0, TIFF_SETGET_IFD8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, (char *) "GlobalParametersIFD", &tifffxFieldArray }, + { TIFFTAG_GLOBALPARAMETERSIFD, 1, 1, TIFF_IFD8, 0, TIFF_SETGET_IFD8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 0, 0, (char *) "GlobalParametersIFD", &tifffxFieldArray }, { TIFFTAG_PROFILETYPE, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, (char *) "ProfileType", NULL }, { TIFFTAG_FAXPROFILE, 1, 1, TIFF_BYTE, 0, TIFF_SETGET_UINT8, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, (char *) "FaxProfile", NULL }, { TIFFTAG_CODINGMETHODS, 1, 1, TIFF_LONG, 0, TIFF_SETGET_UINT32, TIFF_SETGET_UNDEFINED, FIELD_CUSTOM, 1, 0, (char *) "CodingMethods", NULL }, diff --git a/libs/spandsp/tests/tsb85_extra_tests.sh b/libs/spandsp/tests/tsb85_extra_tests.sh index 8aa3b24740..08d8336eee 100755 --- a/libs/spandsp/tests/tsb85_extra_tests.sh +++ b/libs/spandsp/tests/tsb85_extra_tests.sh @@ -28,7 +28,7 @@ run_tsb85_test() fi } -for TEST in PPS-MPS-lost-PPS V17-12000-V29-9600 +for TEST in PPS-MPS-lost-PPS V17-12000-V29-9600 Phase-D-collision do run_tsb85_test done diff --git a/libs/spandsp/tests/tsb85_tests.c b/libs/spandsp/tests/tsb85_tests.c index 221c70634b..f383eb8f47 100644 --- a/libs/spandsp/tests/tsb85_tests.c +++ b/libs/spandsp/tests/tsb85_tests.c @@ -299,7 +299,7 @@ static int document_handler(void *user_data, int event) ch = 'A'; s = (t30_state_t *) user_data; - fprintf(stderr, "%d: Document handler on channel %d - event %d\n", ch, ch, event); + fprintf(stderr, "%c: Document handler on channel %c - event %d\n", ch, ch, event); if (next_tx_file[0]) { t30_set_tx_file(s, next_tx_file, -1, -1); From 31186d815bae388fca3c4e6a72ba6ccbb63101bc Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Wed, 4 Jun 2014 16:04:20 +0000 Subject: [PATCH 005/231] Improve a parameter name for fs_cli What we momentarily called log-uuid-chars is now better called log-uuid-length. Setting log-uuid-length will specify a truncation length for UUIDs displayed by setting log-uuid. --- libs/esl/fs_cli.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/libs/esl/fs_cli.c b/libs/esl/fs_cli.c index 135759d004..311c6f5993 100644 --- a/libs/esl/fs_cli.c +++ b/libs/esl/fs_cli.c @@ -59,7 +59,7 @@ typedef struct { const char *console_fnkeys[12]; char loglevel[128]; int log_uuid; - int log_uuid_chars; + int log_uuid_length; int quiet; int batch_mode; char prompt_color[12]; @@ -67,7 +67,7 @@ typedef struct { char output_text_color[12]; } cli_profile_t; -static const int log_uuid_short_chars = 8; +static const int log_uuid_short_length = 8; static int is_color = 1; static int warn_stop = 0; static int connected = 0; @@ -745,9 +745,9 @@ static void *msg_thread_run(esl_thread_t *me, void *obj) printf("%s", colors[level]); } if (global_profile->log_uuid && !esl_strlen_zero(userdata)) { - if (global_profile->log_uuid_chars) { + if (global_profile->log_uuid_length) { int len = strlen(userdata); - int i = (global_profile->log_uuid_chars < len) ? global_profile->log_uuid_chars : len; + int i = (global_profile->log_uuid_length < len) ? global_profile->log_uuid_length : len; fwrite(userdata, sizeof(char), i, stdout); printf(" "); } else { @@ -1247,11 +1247,11 @@ static void read_config(const char *dft_cfile, const char *cfile) { profiles[pcount-1].log_uuid = esl_true(val); } else if(!strcasecmp(var, "log-uuid-short")) { profiles[pcount-1].log_uuid = esl_true(val); - profiles[pcount-1].log_uuid_chars = (esl_true(val) ? log_uuid_short_chars : 0); - } else if(!strcasecmp(var, "log-uuid-chars")) { + profiles[pcount-1].log_uuid_length = (esl_true(val) ? log_uuid_short_length : 0); + } else if(!strcasecmp(var, "log-uuid-length")) { int i; if ((i = atoi(val)) > -1) { - profiles[pcount-1].log_uuid_chars = i; + profiles[pcount-1].log_uuid_length = i; } } else if(!strcasecmp(var, "quiet")) { profiles[pcount-1].quiet = esl_true(val); @@ -1512,7 +1512,7 @@ int main(int argc, char *argv[]) } if (argv_log_uuid_short) { profile->log_uuid = 1; - profile->log_uuid_chars = log_uuid_short_chars; + profile->log_uuid_length = log_uuid_short_length; } esl_log(ESL_LOG_DEBUG, "Using profile %s [%s]\n", profile->name, profile->host); esl_set_string(prompt_color, profile->prompt_color); From 9847b2a6f4f2b076d48c5d5752741167b3498895 Mon Sep 17 00:00:00 2001 From: Brian West Date: Thu, 5 Jun 2014 08:37:09 -0500 Subject: [PATCH 006/231] CVE-2014-0224 --- build/Makefile.centos5 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/Makefile.centos5 b/build/Makefile.centos5 index 0fee662b2c..a3e7d7d73b 100644 --- a/build/Makefile.centos5 +++ b/build/Makefile.centos5 @@ -10,7 +10,7 @@ FSPREFIX=/usr/local/freeswitch PREFIX=/opt/fs-libs JPEG=v8d -OPENSSL=1.0.1g +OPENSSL=1.0.1h SQLITE=autoconf-3080403 PCRE=8.35 CURL=7.36.0 From 36e72b86ca37e7cf40f16ad1aebb162781bf0fc8 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Thu, 5 Jun 2014 22:07:08 +0500 Subject: [PATCH 007/231] force spandsp rebuild --- libs/spandsp/.update | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/spandsp/.update b/libs/spandsp/.update index 8822907a94..81f030be2b 100644 --- a/libs/spandsp/.update +++ b/libs/spandsp/.update @@ -1 +1 @@ -Tue Dec 6 17:55:59 CST 2011 +Thu Jun 5 22:07:01 CDT 2014 From 49ee6781a56f990ae624b7a60b1aaf30e45cf36e Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Thu, 5 Jun 2014 23:49:50 +0500 Subject: [PATCH 008/231] FS-6540 please test --- src/mod/endpoints/mod_sofia/mod_sofia.h | 1 + src/mod/endpoints/mod_sofia/sofia.c | 34 +++++++++++++++++++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index 4d971d1438..35cce381cd 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -276,6 +276,7 @@ typedef enum { PFLAG_TCP_ALWAYS_NAT, PFLAG_ENABLE_CHAT, PFLAG_AUTH_SUBSCRIPTIONS, + PFLAG_PROXY_REFER_REPLACES, /* No new flags below this line */ PFLAG_MAX } PFLAGS; diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 0ae369dfda..85e29de7cb 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -4087,6 +4087,12 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) } else if (!strcasecmp(var, "tcp-ping2pong") && !zstr(val)) { profile->tcp_ping2pong = atoi(val); sofia_set_pflag(profile, PFLAG_TCP_PING2PONG); + } else if (!strcasecmp(var, "proxy-refer-replaces") && !zstr(val)) { + if (switch_true(val)) { + sofia_set_pflag(profile, PFLAG_PROXY_REFER_REPLACES); + } else { + sofia_clear_pflag(profile, PFLAG_PROXY_REFER_REPLACES); + } } else if (!strcasecmp(var, "sip-messages-respond-200-ok") && !zstr(val)) { if (switch_true(val)) { sofia_set_pflag(profile, PFLAG_MESSAGES_RESPOND_200_OK); @@ -7310,6 +7316,31 @@ void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t goto done; } + if ((refer_to = sip->sip_refer_to)) { + full_ref_to = sip_header_as_string(home, (void *) sip->sip_refer_to); + } + + + if (sofia_test_pflag(profile, PFLAG_PROXY_REFER_REPLACES)) { + switch_core_session_t *other_session; + + if (switch_stristr("replaces=", full_ref_to) && switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) { + switch_core_session_message_t *msg; + + msg = switch_core_session_alloc(other_session, sizeof(*msg)); + MESSAGE_STAMP_FFL(msg); + msg->message_id = SWITCH_MESSAGE_INDICATE_DEFLECT; + msg->string_arg = switch_core_session_strdup(other_session, full_ref_to); + msg->from = __FILE__; + switch_core_session_queue_message(other_session, msg); + switch_core_session_rwunlock(other_session); + + nua_respond(nh, SIP_202_ACCEPTED, NUTAG_WITH_THIS_MSG(de->data->e_msg), SIPTAG_EXPIRES_STR("60"), TAG_END()); + goto done; + } + } + + from = sip->sip_from; //to = sip->sip_to; @@ -7325,9 +7356,8 @@ void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t full_ref_by = sip_header_as_string(home, (void *) sip->sip_referred_by); } - if ((refer_to = sip->sip_refer_to)) { + if (refer_to) { char *rep = NULL; - full_ref_to = sip_header_as_string(home, (void *) sip->sip_refer_to); if (sofia_test_pflag(profile, PFLAG_FULL_ID)) { exten = switch_core_session_sprintf(session, "%s@%s", (char *) refer_to->r_url->url_user, (char *) refer_to->r_url->url_host); From a607c20a94abea27801cfced37adbb4ff2b78ffb Mon Sep 17 00:00:00 2001 From: Jeff Lenk Date: Sun, 8 Jun 2014 16:06:32 -0500 Subject: [PATCH 009/231] windows fix for a0e9ddf58943171a9031159919e99ef20147a11e --- libs/esl/src/include/esl_config.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/esl/src/include/esl_config.h b/libs/esl/src/include/esl_config.h index 34c67ca219..03bbe9719b 100644 --- a/libs/esl/src/include/esl_config.h +++ b/libs/esl/src/include/esl_config.h @@ -81,7 +81,7 @@ extern "C" { \param expr a string expression \return true or false */ -static inline int esl_true(const char *expr) { +static __inline__ int esl_true(const char *expr) { return (expr && (!strcasecmp(expr, "yes") || !strcasecmp(expr, "on") || !strcasecmp(expr, "true") @@ -96,7 +96,7 @@ static inline int esl_true(const char *expr) { \param expr a string expression \return true or false */ -static inline int esl_false(const char *expr) { +static __inline__ int esl_false(const char *expr) { return (expr && (!strcasecmp(expr, "no") || !strcasecmp(expr, "off") || !strcasecmp(expr, "false") From 31a181a4b53cd52059062e804f9b2ff09b3bf51a Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Thu, 5 Jun 2014 14:39:05 +0200 Subject: [PATCH 010/231] mod_skinny: implement digit timeout for dialing For numbers with variable length, there should be a timeout to wait for further digits before routing the number. This has been prepared with the skinny-wait target, which waited forever. This patch implements the digit timeout which routes the call after the timeout has elapsed. The timeout can be configured in the mod_skinny XML settings ("digit-timeout") and defaults to 2 seconds. This implementation has been requested and sponsored by Blackned GmbH. Signed-off-by: Simon Wunderlich Signed-off-by: Nathan Neulinger --- src/mod/endpoints/mod_skinny/mod_skinny.c | 60 ++++++++++++++++++- src/mod/endpoints/mod_skinny/mod_skinny.h | 2 + .../endpoints/mod_skinny/skinny_protocol.c | 6 ++ 3 files changed, 65 insertions(+), 3 deletions(-) diff --git a/src/mod/endpoints/mod_skinny/mod_skinny.c b/src/mod/endpoints/mod_skinny/mod_skinny.c index 3d6c52dd38..ce7d4c4e9b 100644 --- a/src/mod/endpoints/mod_skinny/mod_skinny.c +++ b/src/mod/endpoints/mod_skinny/mod_skinny.c @@ -158,6 +158,7 @@ switch_status_t skinny_profile_dump(const skinny_profile_t *profile, switch_stre stream->write_function(stream, "Patterns-Dialplan \t%s\n", profile->patterns_dialplan); stream->write_function(stream, "Patterns-Context \t%s\n", profile->patterns_context); stream->write_function(stream, "Keep-Alive \t%d\n", profile->keep_alive); + stream->write_function(stream, "Digit-Timeout \t%s\n", profile->digit_timeout); stream->write_function(stream, "Date-Format \t%s\n", profile->date_format); stream->write_function(stream, "DBName \t%s\n", profile->dbname ? profile->dbname : switch_str_nil(profile->odbc_dsn)); stream->write_function(stream, "Debug \t%d\n", profile->debug); @@ -777,9 +778,19 @@ switch_status_t channel_on_routing(switch_core_session_t *session) case SKINNY_ACTION_WAIT: /* for now, wait forever */ switch_channel_set_state(channel, CS_HIBERNATE); - if (!zstr(data)) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "skinny-wait doesn't support timeout yet (See #FS-477)"); + skinny_profile_find_listener_by_device_name_and_instance(tech_pvt->profile, + switch_channel_get_variable(channel, "skinny_device_name"), + atoi(switch_channel_get_variable(channel, "skinny_device_instance")), &listener); + + if (listener) { + listener->digit_timeout_time = switch_mono_micro_time_now() + listener->profile->digit_timeout * 1000; + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Could not find listener %s:%s for Channel %s\n", + switch_channel_get_variable(channel, "skinny_device_name"), switch_channel_get_variable(channel, "skinny_device_instance"), + switch_channel_get_name(channel)); + } + break; case SKINNY_ACTION_DROP: default: @@ -952,6 +963,7 @@ int channel_on_hangup_callback(void *pArg, int argc, char **argv, char **columnN skinny_line_set_state(listener, line_instance, call_id, SKINNY_ON_HOOK); send_select_soft_keys(listener, line_instance, call_id, SKINNY_KEY_SET_ON_HOOK, 0xffff); send_define_current_time_date(listener); + listener->digit_timeout_time = 0; skinny_log_ls(listener, helper->tech_pvt->session, SWITCH_LOG_DEBUG, "channel_on_hangup_callback - cause=%s [%d], call_state = %s [%d]\n", @@ -1641,6 +1653,39 @@ switch_status_t keepalive_listener(listener_t *listener, void *pvt) return SWITCH_STATUS_SUCCESS; } +switch_status_t listener_digit_timeout(listener_t *listener) +{ + switch_core_session_t *session = NULL; + uint32_t line_instance = 1; + uint32_t call_id = 0; + switch_channel_t *channel = NULL; + private_t *tech_pvt = NULL; + + listener->digit_timeout_time = 0; + + session = skinny_profile_find_session(listener->profile, listener, &line_instance, call_id); + if ( !session ) + { + line_instance = 0; + session = skinny_profile_find_session(listener->profile, listener, &line_instance, 0); + } + + if ( !session) + return SWITCH_STATUS_FALSE; + + + channel = switch_core_session_get_channel(session); + tech_pvt = switch_core_session_get_private(session); + + if (channel && tech_pvt->session) { + switch_set_flag_locked(tech_pvt, TFLAG_FORCE_ROUTE); + switch_channel_set_state(channel, CS_ROUTING); + listener->digit_timeout_time = 0; + } + + return SWITCH_STATUS_SUCCESS; +} + static void *SWITCH_THREAD_FUNC listener_run(switch_thread_t *thread, void *obj) { listener_t *listener = (listener_t *) obj; @@ -1664,7 +1709,8 @@ static void *SWITCH_THREAD_FUNC listener_run(switch_thread_t *thread, void *obj) switch_socket_opt_set(listener->sock, SWITCH_SO_NONBLOCK, TRUE); #else switch_socket_opt_set(listener->sock, SWITCH_SO_NONBLOCK, FALSE); - switch_socket_timeout_set(listener->sock, 5000000); + /* 200 ms to allow reasonably fast reaction on digit timeout */ + switch_socket_timeout_set(listener->sock, 200000); #endif if (listener->profile->debug > 0) { skinny_log_l_msg(listener, SWITCH_LOG_DEBUG, "Connection Open\n"); @@ -1681,6 +1727,11 @@ static void *SWITCH_THREAD_FUNC listener_run(switch_thread_t *thread, void *obj) if (status != SWITCH_STATUS_SUCCESS) { switch(status) { case SWITCH_STATUS_TIMEOUT: + if (listener->digit_timeout_time && listener->digit_timeout_time < switch_mono_micro_time_now()) { + listener_digit_timeout(listener); + continue; + } + skinny_log_l_msg(listener, SWITCH_LOG_DEBUG, "Communication Time Out\n"); if(listener->expire_time < switch_epoch_time_now(NULL)) { @@ -1954,6 +2005,8 @@ switch_status_t skinny_profile_set(skinny_profile_t *profile, const char *var, c profile->context = switch_core_strdup(profile->pool, val); } else if (!strcasecmp(var, "keep-alive")) { profile->keep_alive = atoi(val); + } else if (!strcasecmp(var, "digit-timeout")) { + profile->digit_timeout = atoi(val); } else if (!strcasecmp(var, "date-format")) { strncpy(profile->date_format, val, 6); } else if (!strcasecmp(var, "odbc-dsn") && !zstr(val)) { @@ -2035,6 +2088,7 @@ static switch_status_t load_skinny_config(void) profile->pool = profile_pool; profile->name = switch_core_strdup(profile->pool, profile_name); profile->auto_restart = SWITCH_TRUE; + profile->digit_timeout = 2000; /* 2 seconds */ switch_mutex_init(&profile->sql_mutex, SWITCH_MUTEX_NESTED, profile->pool); switch_mutex_init(&profile->listener_mutex, SWITCH_MUTEX_NESTED, profile->pool); switch_mutex_init(&profile->sock_mutex, SWITCH_MUTEX_NESTED, profile->pool); diff --git a/src/mod/endpoints/mod_skinny/mod_skinny.h b/src/mod/endpoints/mod_skinny/mod_skinny.h index a98be960a9..09641452ce 100644 --- a/src/mod/endpoints/mod_skinny/mod_skinny.h +++ b/src/mod/endpoints/mod_skinny/mod_skinny.h @@ -120,6 +120,7 @@ struct skinny_profile { char *patterns_dialplan; char *patterns_context; uint32_t keep_alive; + uint32_t digit_timeout; char date_format[6]; int debug; int auto_restart; @@ -195,6 +196,7 @@ struct listener { switch_mutex_t *flag_mutex; uint32_t flags; time_t expire_time; + switch_time_t digit_timeout_time; struct listener *next; char *ext_voicemail; char *ext_redial; diff --git a/src/mod/endpoints/mod_skinny/skinny_protocol.c b/src/mod/endpoints/mod_skinny/skinny_protocol.c index ee8c8b73e3..d33d3369f2 100644 --- a/src/mod/endpoints/mod_skinny/skinny_protocol.c +++ b/src/mod/endpoints/mod_skinny/skinny_protocol.c @@ -183,6 +183,12 @@ switch_status_t skinny_read_packet(listener_t *listener, skinny_message_t **req) } } } + + if (listener->digit_timeout_time && listener->digit_timeout_time < switch_mono_micro_time_now()) { + switch_safe_free(request); + return SWITCH_STATUS_TIMEOUT; + } + if (do_sleep) { switch_cond_next(); } From 8b6fd66f34999f286463e996ee45956c0deff27a Mon Sep 17 00:00:00 2001 From: Nathan Neulinger Date: Mon, 9 Jun 2014 10:56:52 -0500 Subject: [PATCH 011/231] FS-477 default to 10 seconds to avoid noticeable impact on current users until variable timeout support re-added --- src/mod/endpoints/mod_skinny/mod_skinny.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mod/endpoints/mod_skinny/mod_skinny.c b/src/mod/endpoints/mod_skinny/mod_skinny.c index ce7d4c4e9b..9bb1cd5339 100644 --- a/src/mod/endpoints/mod_skinny/mod_skinny.c +++ b/src/mod/endpoints/mod_skinny/mod_skinny.c @@ -2088,7 +2088,7 @@ static switch_status_t load_skinny_config(void) profile->pool = profile_pool; profile->name = switch_core_strdup(profile->pool, profile_name); profile->auto_restart = SWITCH_TRUE; - profile->digit_timeout = 2000; /* 2 seconds */ + profile->digit_timeout = 10000; /* 10 seconds */ switch_mutex_init(&profile->sql_mutex, SWITCH_MUTEX_NESTED, profile->pool); switch_mutex_init(&profile->listener_mutex, SWITCH_MUTEX_NESTED, profile->pool); switch_mutex_init(&profile->sock_mutex, SWITCH_MUTEX_NESTED, profile->pool); From 2974734479aa2f1e0a26f5a4096e3b4f72848bce Mon Sep 17 00:00:00 2001 From: Nathan Neulinger Date: Mon, 9 Jun 2014 12:29:47 -0500 Subject: [PATCH 012/231] FS-477 mod_skinny: re-add ability to set digit timeout in patterns, update example configs --- conf/vanilla/dialplan/skinny-patterns.xml | 6 +++--- conf/vanilla/skinny_profiles/internal.xml | 3 +++ .../mod_skinny/conf/dialplan/skinny-patterns.xml | 6 +++--- .../mod_skinny/conf/skinny_profiles/internal.xml | 1 + src/mod/endpoints/mod_skinny/mod_skinny.c | 11 ++++++++++- 5 files changed, 20 insertions(+), 7 deletions(-) diff --git a/conf/vanilla/dialplan/skinny-patterns.xml b/conf/vanilla/dialplan/skinny-patterns.xml index b37d8eed82..a6571b792e 100644 --- a/conf/vanilla/dialplan/skinny-patterns.xml +++ b/conf/vanilla/dialplan/skinny-patterns.xml @@ -7,17 +7,17 @@ The special applications: - skinny-process tells skinny to process the call (route, set call forwarding, ...) - skinny-drop tells skinny to drop the call - - skinny-wait tells skinny to wait for more digits + - skinny-wait tells skinny to wait 'data' seconds for more numbers before drop --> - + diff --git a/conf/vanilla/skinny_profiles/internal.xml b/conf/vanilla/skinny_profiles/internal.xml index 0ca4ed0c46..cf93f4a065 100644 --- a/conf/vanilla/skinny_profiles/internal.xml +++ b/conf/vanilla/skinny_profiles/internal.xml @@ -12,6 +12,9 @@ + + + diff --git a/src/mod/endpoints/mod_skinny/conf/dialplan/skinny-patterns.xml b/src/mod/endpoints/mod_skinny/conf/dialplan/skinny-patterns.xml index 69419f36c2..abc81a43cb 100644 --- a/src/mod/endpoints/mod_skinny/conf/dialplan/skinny-patterns.xml +++ b/src/mod/endpoints/mod_skinny/conf/dialplan/skinny-patterns.xml @@ -7,17 +7,17 @@ The special applications: - skinny-process tells skinny to process the call (route, set call forwarding, ...) - skinny-drop tells skinny to drop the call - - skinny-wait tells skinny to wait for more digits + - skinny-wait tells skinny to wait 'data' seconds for more numbers before drop --> - + diff --git a/src/mod/endpoints/mod_skinny/conf/skinny_profiles/internal.xml b/src/mod/endpoints/mod_skinny/conf/skinny_profiles/internal.xml index b042c0553c..98da04abe6 100644 --- a/src/mod/endpoints/mod_skinny/conf/skinny_profiles/internal.xml +++ b/src/mod/endpoints/mod_skinny/conf/skinny_profiles/internal.xml @@ -15,6 +15,7 @@ + --> diff --git a/src/mod/endpoints/mod_skinny/mod_skinny.c b/src/mod/endpoints/mod_skinny/mod_skinny.c index 9bb1cd5339..70c96f8deb 100644 --- a/src/mod/endpoints/mod_skinny/mod_skinny.c +++ b/src/mod/endpoints/mod_skinny/mod_skinny.c @@ -751,6 +751,7 @@ switch_status_t channel_on_routing(switch_core_session_t *session) char *data = NULL; listener_t *listener = NULL; struct channel_on_routing_helper helper = {0}; + int digit_timeout; if(switch_test_flag(tech_pvt, TFLAG_FORCE_ROUTE)) { action = SKINNY_ACTION_PROCESS; @@ -783,7 +784,15 @@ switch_status_t channel_on_routing(switch_core_session_t *session) atoi(switch_channel_get_variable(channel, "skinny_device_instance")), &listener); if (listener) { - listener->digit_timeout_time = switch_mono_micro_time_now() + listener->profile->digit_timeout * 1000; + digit_timeout = listener->profile->digit_timeout; + if (!zstr(data)) { + digit_timeout = atoi(data); + if ( digit_timeout < 100 ) { + digit_timeout *= 1000; + } + } + + listener->digit_timeout_time = switch_mono_micro_time_now() + digit_timeout * 1000; } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Could not find listener %s:%s for Channel %s\n", switch_channel_get_variable(channel, "skinny_device_name"), switch_channel_get_variable(channel, "skinny_device_instance"), From 148c21c6b2efe985a82baf3227cb6ed85a4cfb0f Mon Sep 17 00:00:00 2001 From: Nathan Neulinger Date: Mon, 9 Jun 2014 12:34:52 -0500 Subject: [PATCH 013/231] FS-477 mod_skinny fix leaked lock --- src/mod/endpoints/mod_skinny/mod_skinny.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mod/endpoints/mod_skinny/mod_skinny.c b/src/mod/endpoints/mod_skinny/mod_skinny.c index 70c96f8deb..10c1fede9a 100644 --- a/src/mod/endpoints/mod_skinny/mod_skinny.c +++ b/src/mod/endpoints/mod_skinny/mod_skinny.c @@ -1682,7 +1682,6 @@ switch_status_t listener_digit_timeout(listener_t *listener) if ( !session) return SWITCH_STATUS_FALSE; - channel = switch_core_session_get_channel(session); tech_pvt = switch_core_session_get_private(session); @@ -1692,6 +1691,8 @@ switch_status_t listener_digit_timeout(listener_t *listener) listener->digit_timeout_time = 0; } + switch_core_session_rwunlock(session); + return SWITCH_STATUS_SUCCESS; } From 0685027bd8fd2018d53259bb617ec61a0e0eb292 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Mon, 9 Jun 2014 14:29:08 -0400 Subject: [PATCH 014/231] FS-6574 --resolve --- libs/sofia-sip/.update | 2 +- libs/sofia-sip/libsofia-sip-ua/tport/tport_type_ws.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/sofia-sip/.update b/libs/sofia-sip/.update index f85032292f..cb4397f41e 100644 --- a/libs/sofia-sip/.update +++ b/libs/sofia-sip/.update @@ -1 +1 @@ -Thu May 22 15:39:33 UTC 2014 +Mon Jun 9 14:22:59 EDT 2014 diff --git a/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_ws.c b/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_ws.c index 265eef2383..ab8ea1c731 100644 --- a/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_ws.c +++ b/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_ws.c @@ -217,7 +217,7 @@ int tport_recv_stream_ws(tport_t *self) N = ws_read_frame(&wstp->ws, &oc, &data); if (N == -2) { - return 2; + return 1; } if ((N == -1000) || (N == 0)) { From 10647be5a0492b685b059a909b3970b584391e2a Mon Sep 17 00:00:00 2001 From: Steve Underwood Date: Wed, 11 Jun 2014 01:49:29 +0800 Subject: [PATCH 015/231] Fixed incorrect T.30 CTC messages. Fixed reseting of the CRC generator in the HDLC tx code --- libs/spandsp/src/hdlc.c | 5 ++++- libs/spandsp/src/t30.c | 9 +++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/libs/spandsp/src/hdlc.c b/libs/spandsp/src/hdlc.c index 74b2760e70..d96609b319 100644 --- a/libs/spandsp/src/hdlc.c +++ b/libs/spandsp/src/hdlc.c @@ -613,7 +613,10 @@ SPAN_DECLARE(int) hdlc_tx_restart(hdlc_tx_state_t *s) s->report_flag_underflow = false; s->len = 0; s->pos = 0; - s->crc = 0; + if (s->crc_bytes == 2) + s->crc = 0xFFFF; + else + s->crc = 0xFFFFFFFF; s->byte = 0; s->bits = 0; s->tx_end = false; diff --git a/libs/spandsp/src/t30.c b/libs/spandsp/src/t30.c index e7f958552c..ecf86efd53 100644 --- a/libs/spandsp/src/t30.c +++ b/libs/spandsp/src/t30.c @@ -3070,7 +3070,7 @@ static void process_rx_ppr(t30_state_t *s, const uint8_t *msg, int len) int i; int j; int frame_no; - uint8_t frame[4]; + uint8_t frame[5]; if (len != 3 + 256/8) { @@ -3120,7 +3120,12 @@ static void process_rx_ppr(t30_state_t *s, const uint8_t *msg, int len) s->ecm_progress = 0; queue_phase(s, T30_PHASE_D_TX); set_state(s, T30_STATE_IV_CTC); - send_simple_frame(s, T30_CTC); + frame[0] = ADDRESS_FIELD; + frame[1] = CONTROL_FIELD_FINAL_FRAME; + frame[2] = (uint8_t) (T30_CTC | s->dis_received); + frame[3] = 0; + frame[4] = fallback_sequence[s->current_fallback].dcs_code; + send_frame(s, frame, 5); } else { From d94e393480016ca9194fa6a4345a9759f3e087b2 Mon Sep 17 00:00:00 2001 From: Chris Rienzo Date: Tue, 10 Jun 2014 15:01:47 -0400 Subject: [PATCH 016/231] freeswitch-config-rayo.spec remove some dependencies to high def audio and specific fs version --- freeswitch-config-rayo.spec | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/freeswitch-config-rayo.spec b/freeswitch-config-rayo.spec index 92f504c058..ee56e44893 100644 --- a/freeswitch-config-rayo.spec +++ b/freeswitch-config-rayo.spec @@ -1,7 +1,7 @@ ###################################################################################################################### # # freeswitch-config-rayo for FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application -# Copyright (C) 2013, Grasshopper +# Copyright (C) 2013-2014, Grasshopper # # Version: MPL 1.1 # @@ -75,7 +75,7 @@ Group: System/Libraries Packager: Chris Rienzo URL: http://www.freeswitch.org/ Source0: freeswitch-%{version}.tar.bz2 -Requires: freeswitch = %{version} +Requires: freeswitch Requires: freeswitch-application-conference Requires: freeswitch-application-esf Requires: freeswitch-application-expr @@ -94,14 +94,8 @@ Requires: freeswitch-format-mod-shout Requires: freeswitch-format-shell-stream Requires: freeswitch-format-ssml Requires: freeswitch-sounds-music-8000 -Requires: freeswitch-sounds-music-16000 -Requires: freeswitch-sounds-music-32000 -Requires: freeswitch-sounds-music-48000 Requires: freeswitch-lang-en Requires: freeswitch-sounds-en-us-callie-8000 -Requires: freeswitch-sounds-en-us-callie-16000 -Requires: freeswitch-sounds-en-us-callie-32000 -Requires: freeswitch-sounds-en-us-callie-48000 BuildRequires: bash BuildArch: noarch BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) @@ -171,6 +165,9 @@ FreeSWITCH rayo server implementation. # ###################################################################################################################### %changelog +* Tue Jun 10 2014 crienzo@grasshopper.com +- Remove dependency to high resolution music and sounds files +- Remove dependency to specific FreeSWITCH package version * Mon Jun 03 2013 - crienzo@grasshopper.com - Added users and internal profile for softphone testing * Wed May 08 2013 - crienzo@grasshopper.com From 03202e3017a904643a80a15ee347a86f0b956524 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Tue, 10 Jun 2014 22:21:38 +0000 Subject: [PATCH 017/231] Add fsctl command to summon reincarnation If you start freeswitch with -reincarnate or -reincarnate-reexec, FS will restart automatically in the event of an unexpected exit. Currently, you can cause FS to immediately call exit(0) with `fsctl shutdown now`, or you can have it call abort() with `fsctl crash`. Which are both nice, but if you have reincarnation engaged, you really might want FS to call exit([non-zero]) so the great supervisor immediately breathes life back into your system. This is now available via `fsctl shutdown reincarnate now`. --- src/include/switch_types.h | 1 + src/mod/applications/mod_commands/mod_commands.c | 5 +++++ src/switch_core.c | 4 ++++ 3 files changed, 10 insertions(+) diff --git a/src/include/switch_types.h b/src/include/switch_types.h index d7f5bc747e..e90abe2dd3 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -1994,6 +1994,7 @@ typedef enum { SCSC_DEBUG_LEVEL, SCSC_FLUSH_DB_HANDLES, SCSC_SHUTDOWN_NOW, + SCSC_REINCARNATE_NOW, SCSC_CALIBRATE_CLOCK, SCSC_SAVE_HISTORY, SCSC_CRASH, diff --git a/src/mod/applications/mod_commands/mod_commands.c b/src/mod/applications/mod_commands/mod_commands.c index 0d826f3c2a..e418b1b297 100644 --- a/src/mod/applications/mod_commands/mod_commands.c +++ b/src/mod/applications/mod_commands/mod_commands.c @@ -2268,6 +2268,10 @@ SWITCH_STANDARD_API(ctl_function) command = SCSC_SHUTDOWN_NOW; } else if (!strcasecmp(argv[x], "asap")) { command = SCSC_SHUTDOWN_ASAP; + } else if (!strcasecmp(argv[x], "reincarnate") + && (x+1 < argc) && argv[x+1] && !strcasecmp(argv[x+1], "now")) { + ++x; + command = SCSC_REINCARNATE_NOW; } else if (!strcasecmp(argv[x], "restart")) { arg = 1; } @@ -6746,6 +6750,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load) switch_console_set_complete("add fsctl shutdown cancel"); switch_console_set_complete("add fsctl shutdown elegant"); switch_console_set_complete("add fsctl shutdown elegant restart"); + switch_console_set_complete("add fsctl shutdown reincarnate now"); switch_console_set_complete("add fsctl shutdown restart"); switch_console_set_complete("add fsctl shutdown restart asap"); switch_console_set_complete("add fsctl shutdown restart elegant"); diff --git a/src/switch_core.c b/src/switch_core.c index 9a72a5a78d..321bd0dd75 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -2421,6 +2421,10 @@ SWITCH_DECLARE(int32_t) switch_core_session_ctl(switch_session_ctl_t cmd, void * switch_console_save_history(); exit(0); break; + case SCSC_REINCARNATE_NOW: + switch_console_save_history(); + exit(SWITCH_STATUS_RESTART); + break; case SCSC_SHUTDOWN_ELEGANT: case SCSC_SHUTDOWN_ASAP: { From 12da85ef61c43476e36a05fb91410f1c91ff5232 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Tue, 10 Jun 2014 23:36:56 +0000 Subject: [PATCH 018/231] Check for execv(3) errors when reincarnating When -reincarnate-reexec is given we run execv to restart FS. If argv[0] isn't a full pathname then execv is going to fail. While not common for a FS system started by init, this is a common occurrence when FS is started from the shell. Now if execv fails, we'll try execvp. If that fails too then we'll fall back on the normal reincarnation behavior. Previously what would happen in that case is god would descend from the heavens and become mortal. Leaving heaven absent, all hope for reincarnation was lost. (That is, we'd simply return from reincarnate_protect and the supervisor process would become the new instance of FS, so the trick would only work once.) --- src/switch.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/switch.c b/src/switch.c index 6c2ef2a827..4523bd0589 100644 --- a/src/switch.c +++ b/src/switch.c @@ -399,7 +399,19 @@ static void reincarnate_protect(char **argv) { sigaction(SIGTERM, &sa15_prev, NULL); sigaction(SIGCHLD, &sa17_prev, NULL); if (argv) { - execv(argv[0], argv); return; + if (execv(argv[0], argv) == -1) { + char buf[256]; + fprintf(stderr, "Reincarnate execv() failed: %d %s\n", errno, + strerror_r(errno, buf, sizeof(buf))); + } + fprintf(stderr, "Trying reincarnate-reexec plan B...\n"); + if (execvp(argv[0], argv) == -1) { + char buf[256]; + fprintf(stderr, "Reincarnate execvp() failed: %d %s\n", errno, + strerror_r(errno, buf, sizeof(buf))); + } + fprintf(stderr, "Falling back to normal reincarnate behavior...\n"); + goto refork; } else goto refork; } goto rewait; From 8a4a8f6fb857cb66a9f386659be92c627c4accbf Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Wed, 11 Jun 2014 00:52:12 +0000 Subject: [PATCH 019/231] Retry the cowbuilder create operation on failure Sometimes while the debian repositories are updating there are sporadic signature failures. It's annoying to have these break the build, and the only thing to do is to retry, so we'll retry here automatically. We were already retrying on the update operation that can fail in a similar manner. --- debian/util.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/debian/util.sh b/debian/util.sh index f73b6187f0..14dcddb77d 100755 --- a/debian/util.sh +++ b/debian/util.sh @@ -295,7 +295,10 @@ build_debs () { } if ! [ -d $cow_img ]; then announce "Creating base $distro-$arch image..." - cow --create + local x=5 + while ! cow --create; do + [ $x -lt 1 ] && break; sleep 60; x=$((x-1)) + done fi announce "Updating base $distro-$arch image..." local x=5 From afb4a20090c97203d165e4236914b7e49f2daa86 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Wed, 11 Jun 2014 00:55:06 +0000 Subject: [PATCH 020/231] Retry for longer on failed cowbuilder operations There's really nothing to do but retry. --- debian/util.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/debian/util.sh b/debian/util.sh index 14dcddb77d..b01cf0a3e8 100755 --- a/debian/util.sh +++ b/debian/util.sh @@ -295,15 +295,15 @@ build_debs () { } if ! [ -d $cow_img ]; then announce "Creating base $distro-$arch image..." - local x=5 + local x=30 while ! cow --create; do - [ $x -lt 1 ] && break; sleep 60; x=$((x-1)) + [ $x -lt 1 ] && break; sleep 120; x=$((x-1)) done fi announce "Updating base $distro-$arch image..." - local x=5 + local x=30 while ! cow --update; do - [ $x -lt 1 ] && break; sleep 60; x=$((x-1)) + [ $x -lt 1 ] && break; sleep 120; x=$((x-1)) done announce "Building $distro-$arch DEBs from $dsc..." if $debug_hook; then From 4ccdc1def3a01759884d21d30a69948bd6dec2f8 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Wed, 11 Jun 2014 01:05:36 +0000 Subject: [PATCH 021/231] Override config on cowbuilder update This allows new settings, e.g. new mirrors, to propagate into the chroot images. --- debian/util.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/util.sh b/debian/util.sh index b01cf0a3e8..61e10633c7 100755 --- a/debian/util.sh +++ b/debian/util.sh @@ -302,7 +302,7 @@ build_debs () { fi announce "Updating base $distro-$arch image..." local x=30 - while ! cow --update; do + while ! cow --update --override-config; do [ $x -lt 1 ] && break; sleep 120; x=$((x-1)) done announce "Building $distro-$arch DEBs from $dsc..." From 94ab52cd01ce273fc143b8b6c688a079a2f9e452 Mon Sep 17 00:00:00 2001 From: Steve Underwood Date: Wed, 11 Jun 2014 10:52:54 +0800 Subject: [PATCH 022/231] Improved FAX disconnect handling --- libs/spandsp/spandsp/tsb85.xml | 6 +- libs/spandsp/src/t30.c | 120 +++++++++++++++++++-------------- 2 files changed, 72 insertions(+), 54 deletions(-) diff --git a/libs/spandsp/spandsp/tsb85.xml b/libs/spandsp/spandsp/tsb85.xml index 482e18b989..4286b77a45 100644 --- a/libs/spandsp/spandsp/tsb85.xml +++ b/libs/spandsp/spandsp/tsb85.xml @@ -1528,7 +1528,7 @@ - + @@ -5330,7 +5330,7 @@ - + @@ -5442,7 +5442,7 @@ - + diff --git a/libs/spandsp/src/t30.c b/libs/spandsp/src/t30.c index ecf86efd53..39c972a350 100644 --- a/libs/spandsp/src/t30.c +++ b/libs/spandsp/src/t30.c @@ -370,7 +370,8 @@ enum #define DEFAULT_TIMER_T8 10000 /*! Final time we allow for things to flush through the system, before we disconnect, in milliseconds. - 200ms should be fine for a PSTN call. For a T.38 call something longer is desirable. */ + 200ms should be fine for a PSTN call. For a T.38 call something longer is desirable. This delay is + to allow sufficient time for the last message to be flushed all the way through to the far end. */ #define FINAL_FLUSH_TIME 1000 /*! The number of PPRs received before CTC or EOR is sent in ECM mode. T.30 defines this as 4, @@ -432,7 +433,8 @@ static void send_frame(t30_state_t *s, const uint8_t *fr, int frlen); static void send_simple_frame(t30_state_t *s, int type); static void send_dcn(t30_state_t *s); static void repeat_last_command(t30_state_t *s); -static void disconnect(t30_state_t *s); +static void terminate_call(t30_state_t *s); +static void start_final_pause(t30_state_t *s); static void decode_20digit_msg(t30_state_t *s, char *msg, const uint8_t *pkt, int len); static void decode_url_msg(t30_state_t *s, char *msg, const uint8_t *pkt, int len); static int decode_nsf_nss_nsc(t30_state_t *s, uint8_t *msg[], const uint8_t *pkt, int len); @@ -2440,9 +2442,7 @@ static int send_cfr_sequence(t30_state_t *s, int start) /* CFR is usually a simple frame, but can become a sequence with Internet FAXing. */ if (start) - { s->step = 0; - } switch (s->step) { case 0: @@ -2465,9 +2465,32 @@ static int send_cfr_sequence(t30_state_t *s, int start) } /*- End of function --------------------------------------------------------*/ -static void disconnect(t30_state_t *s) +static void terminate_call(t30_state_t *s) { - span_log(&s->logging, SPAN_LOG_FLOW, "Disconnecting\n"); + /* Make sure any FAX in progress is tidied up. If the tidying up has + already happened, repeating it here is harmless. */ + terminate_operation_in_progress(s); + s->timer_t0_t1 = 0; + s->timer_t2_t4 = 0; + s->timer_t3 = 0; + s->timer_t5 = 0; + if (s->phase_e_handler) + s->phase_e_handler(s->phase_e_user_data, s->current_status); + set_state(s, T30_STATE_CALL_FINISHED); + set_phase(s, T30_PHASE_CALL_FINISHED); + release_resources(s); + span_log(&s->logging, SPAN_LOG_FLOW, "Call completed\n"); +} +/*- End of function --------------------------------------------------------*/ + +static void start_final_pause(t30_state_t *s) +{ + /* We need to allow some time for the last part of our FAX signalling to flush through + to the far end before we declare the call finished. If we say it is finished too soon, + the call disconnect message could cause buffers downstream to be flushed, rather than + played out to completion. If that clips the final message, the far end might declare + that the call prematrurely terminated. */ + span_log(&s->logging, SPAN_LOG_FLOW, "Starting final pause before disconnecting\n"); /* Make sure any FAX in progress is tidied up. If the tidying up has already happened, repeating it here is harmless. */ terminate_operation_in_progress(s); @@ -3079,7 +3102,7 @@ static void process_rx_ppr(t30_state_t *s, const uint8_t *msg, int len) and there is little possibility that causing a retransmission will help. It is best to just give up. */ t30_set_status(s, T30_ERR_TX_ECMPHD); - disconnect(s); + terminate_call(s); return; } /* Check which frames are OK, and mark them as OK. */ @@ -3315,7 +3338,7 @@ static void process_state_answering(t30_state_t *s, const uint8_t *msg, int len) break; case T30_DCN: t30_set_status(s, T30_ERR_TX_GOTDCN); - disconnect(s); + terminate_call(s); break; default: /* We don't know what to do with this. */ @@ -3383,7 +3406,7 @@ static void process_state_d(t30_state_t *s, const uint8_t *msg, int len) { case T30_DCN: t30_set_status(s, T30_ERR_TX_BADDCS); - disconnect(s); + terminate_call(s); break; case T30_CRP: repeat_last_command(s); @@ -3409,7 +3432,7 @@ static void process_state_d_tcf(t30_state_t *s, const uint8_t *msg, int len) { case T30_DCN: t30_set_status(s, T30_ERR_TX_BADDCS); - disconnect(s); + terminate_call(s); break; case T30_CRP: repeat_last_command(s); @@ -3480,7 +3503,7 @@ static void process_state_d_post_tcf(t30_state_t *s, const uint8_t *msg, int len break; case T30_DCN: t30_set_status(s, T30_ERR_TX_BADDCS); - disconnect(s); + terminate_call(s); break; case T30_CRP: repeat_last_command(s); @@ -3633,7 +3656,7 @@ static void process_state_f_doc_non_ecm(t30_state_t *s, const uint8_t *msg, int break; case T30_DCN: t30_set_status(s, T30_ERR_RX_DCNDATA); - disconnect(s); + terminate_call(s); break; case T30_CRP: repeat_last_command(s); @@ -3740,7 +3763,7 @@ static void process_state_f_post_doc_non_ecm(t30_state_t *s, const uint8_t *msg, break; case T30_DCN: t30_set_status(s, T30_ERR_RX_DCNFAX); - disconnect(s); + terminate_call(s); break; case T30_CRP: repeat_last_command(s); @@ -3824,7 +3847,7 @@ static void process_state_f_doc_and_post_doc_ecm(t30_state_t *s, const uint8_t * break; case T30_DCN: t30_set_status(s, T30_ERR_RX_DCNDATA); - disconnect(s); + terminate_call(s); break; case T30_CRP: repeat_last_command(s); @@ -3855,7 +3878,7 @@ static void process_state_f_post_rcp_mcf(t30_state_t *s, const uint8_t *msg, int process_rx_fnv(s, msg, len); break; case T30_DCN: - disconnect(s); + terminate_call(s); break; default: /* We don't know what to do with this. */ @@ -3947,7 +3970,7 @@ static void process_state_r(t30_state_t *s, const uint8_t *msg, int len) case T30_DCN: /* Received a DCN while waiting for a DIS or DCN */ t30_set_status(s, T30_ERR_RX_DCNWHY); - disconnect(s); + terminate_call(s); break; case T30_CRP: repeat_last_command(s); @@ -3975,7 +3998,7 @@ static void process_state_t(t30_state_t *s, const uint8_t *msg, int len) break; case T30_DCN: t30_set_status(s, T30_ERR_TX_GOTDCN); - disconnect(s); + terminate_call(s); break; case T30_CRP: repeat_last_command(s); @@ -4230,7 +4253,7 @@ static void process_state_ii_q(t30_state_t *s, const uint8_t *msg, int len) t30_set_status(s, T30_ERR_TX_BADPG); break; } - disconnect(s); + terminate_call(s); break; case T30_CRP: repeat_last_command(s); @@ -4274,7 +4297,7 @@ static void process_state_iii_q_mcf(t30_state_t *s, const uint8_t *msg, int len) process_rx_fnv(s, msg, len); break; case T30_DCN: - disconnect(s); + terminate_call(s); break; default: /* We don't know what to do with this. */ @@ -4346,7 +4369,7 @@ static void process_state_iii_q_rtn(t30_state_t *s, const uint8_t *msg, int len) break; case T30_DCN: t30_set_status(s, T30_ERR_RX_DCNNORTN); - disconnect(s); + terminate_call(s); break; default: /* We don't know what to do with this. */ @@ -4453,7 +4476,7 @@ static void process_state_iv_pps_null(t30_state_t *s, const uint8_t *msg, int le break; case T30_DCN: t30_set_status(s, T30_ERR_TX_BADPG); - disconnect(s); + terminate_call(s); break; case T30_CRP: repeat_last_command(s); @@ -4557,7 +4580,7 @@ static void process_state_iv_pps_q(t30_state_t *s, const uint8_t *msg, int len) break; case T30_DCN: t30_set_status(s, T30_ERR_TX_BADPG); - disconnect(s); + terminate_call(s); break; case T30_CRP: repeat_last_command(s); @@ -4669,7 +4692,7 @@ static void process_state_iv_pps_rnr(t30_state_t *s, const uint8_t *msg, int len break; case T30_DCN: t30_set_status(s, T30_ERR_RX_DCNRRD); - disconnect(s); + terminate_call(s); break; case T30_CRP: repeat_last_command(s); @@ -4793,7 +4816,7 @@ static void process_state_iv_eor_rnr(t30_state_t *s, const uint8_t *msg, int len break; case T30_DCN: t30_set_status(s, T30_ERR_RX_DCNRRD); - disconnect(s); + terminate_call(s); break; case T30_CRP: repeat_last_command(s); @@ -5227,9 +5250,8 @@ static void set_phase(t30_state_t *s, int phase) s->set_tx_type_handler(s->set_tx_type_user_data, fallback_sequence[s->current_fallback].modem_type, fallback_sequence[s->current_fallback].bit_rate, s->short_train, true); break; case T30_PHASE_E: - /* Send a little silence before ending things, to ensure the - buffers are all flushed through, and the far end has seen - the last message we sent. */ + /* Send a little silence before ending things, to ensure the buffers are flushed all they way + through to the far end, and the far end has been able to see the last message we sent. */ s->tcf_test_bits = 0; s->tcf_current_zeros = 0; s->tcf_most_zeros = 0; @@ -5278,7 +5300,7 @@ static void repeat_last_command(t30_state_t *s) t30_set_status(s, T30_ERR_TX_PHDDEAD); break; default: - /* Disconnected after permitted retries */ + /* Disconnect after permitted retries */ t30_set_status(s, T30_ERR_RETRYDCN); break; } @@ -5462,7 +5484,7 @@ static void timer_t0_expired(t30_state_t *s) span_log(&s->logging, SPAN_LOG_FLOW, "T0 expired in state %s\n", state_names[s->state]); t30_set_status(s, T30_ERR_T0_EXPIRED); /* Just end the call */ - disconnect(s); + terminate_call(s); } /*- End of function --------------------------------------------------------*/ @@ -5477,7 +5499,7 @@ static void timer_t1_expired(t30_state_t *s) { case T30_STATE_T: /* Just end the call */ - disconnect(s); + terminate_call(s); break; case T30_STATE_R: /* Send disconnect, and then end the call. Since we have not @@ -5494,7 +5516,7 @@ static void timer_t1a_expired(t30_state_t *s) { span_log(&s->logging, SPAN_LOG_FLOW, "T1A expired in phase %s, state %s. An HDLC frame lasted too long.\n", phase_names[s->phase], state_names[s->state]); t30_set_status(s, T30_ERR_HDLC_CARRIER); - disconnect(s); + terminate_call(s); } /*- End of function --------------------------------------------------------*/ @@ -5573,7 +5595,7 @@ static void timer_t2a_expired(t30_state_t *s) { span_log(&s->logging, SPAN_LOG_FLOW, "T2A expired in phase %s, state %s. An HDLC frame lasted too long.\n", phase_names[s->phase], state_names[s->state]); t30_set_status(s, T30_ERR_HDLC_CARRIER); - disconnect(s); + terminate_call(s); } /*- End of function --------------------------------------------------------*/ @@ -5588,7 +5610,7 @@ static void timer_t3_expired(t30_state_t *s) { span_log(&s->logging, SPAN_LOG_FLOW, "T3 expired in phase %s, state %s\n", phase_names[s->phase], state_names[s->state]); t30_set_status(s, T30_ERR_T3_EXPIRED); - disconnect(s); + terminate_call(s); } /*- End of function --------------------------------------------------------*/ @@ -5612,7 +5634,7 @@ static void timer_t4a_expired(t30_state_t *s) { span_log(&s->logging, SPAN_LOG_FLOW, "T4A expired in phase %s, state %s. An HDLC frame lasted too long.\n", phase_names[s->phase], state_names[s->state]); t30_set_status(s, T30_ERR_HDLC_CARRIER); - disconnect(s); + terminate_call(s); } /*- End of function --------------------------------------------------------*/ @@ -6253,7 +6275,7 @@ SPAN_DECLARE(void) t30_front_end_status(void *user_data, int status) break; default: span_log(&s->logging, SPAN_LOG_FLOW, "Unknown next rx step - %d\n", s->next_rx_step); - disconnect(s); + terminate_call(s); break; } } @@ -6282,11 +6304,7 @@ SPAN_DECLARE(void) t30_front_end_status(void *user_data, int status) case T30_STATE_B: /* We have now allowed time for the last message to flush through the system, so it is safe to report the end of the call. */ - if (s->phase_e_handler) - s->phase_e_handler(s->phase_e_user_data, s->current_status); - set_state(s, T30_STATE_CALL_FINISHED); - set_phase(s, T30_PHASE_CALL_FINISHED); - release_resources(s); + terminate_call(s); break; case T30_STATE_C: if (s->step == 0) @@ -6296,8 +6314,9 @@ SPAN_DECLARE(void) t30_front_end_status(void *user_data, int status) } else { - /* We just sent the disconnect message. Now it is time to disconnect. */ - disconnect(s); + /* We just sent the disconnect message. Now it is time to clean up and + end the call. */ + start_final_pause(s); } break; case T30_STATE_D: @@ -6527,14 +6546,17 @@ SPAN_DECLARE(void) t30_terminate(t30_state_t *s) { case T30_STATE_C: /* We were sending the final disconnect, so just hussle things along. */ - disconnect(s); break; case T30_STATE_B: - /* We were in the final wait for everything to flush through, so just - hussle things along. */ + /* We were in the final pause, waiting for everything to flush through, + so just hussle things along. */ break; default: - /* If we have seen a genuine EOP or PRI_EOP, that's good enough. */ + /* If we have seen a genuine EOP or PRI_EOP, and that's good enough for us. + The far end might not agree, as it might not have seen the MCF we sent + in response to EOP or PRI_EOP. This might cause it to say the call did + not complete properly. However, if this function has been called we can + do no more. */ if (!s->end_of_procedure_detected) { /* The call terminated prematurely. */ @@ -6542,11 +6564,7 @@ SPAN_DECLARE(void) t30_terminate(t30_state_t *s) } break; } - if (s->phase_e_handler) - s->phase_e_handler(s->phase_e_user_data, s->current_status); - set_state(s, T30_STATE_CALL_FINISHED); - set_phase(s, T30_PHASE_CALL_FINISHED); - release_resources(s); + terminate_call(s); } } /*- End of function --------------------------------------------------------*/ From 1ffb1ee0d07f3366376e6e2f7e720039684a09d0 Mon Sep 17 00:00:00 2001 From: Michael Jerris Date: Wed, 11 Jun 2014 12:48:46 -0500 Subject: [PATCH 023/231] WIP --- build/modules.conf.in | 1 + configure.ac | 1 + src/mod/endpoints/mod_verto/Makefile.am | 38 + src/mod/endpoints/mod_verto/mcast/.gitignore | 2 + src/mod/endpoints/mod_verto/mcast/MCAST.i | 24 + src/mod/endpoints/mod_verto/mcast/MCAST.pm | 108 + src/mod/endpoints/mod_verto/mcast/mcast.c | 173 + src/mod/endpoints/mod_verto/mcast/mcast.h | 78 + .../endpoints/mod_verto/mcast/mcast_cpp.cpp | 69 + src/mod/endpoints/mod_verto/mcast/mcast_cpp.h | 59 + .../endpoints/mod_verto/mcast/mcast_wrap.cpp | 2254 +++++++++ src/mod/endpoints/mod_verto/mcast/perlxsi.c | 16 + src/mod/endpoints/mod_verto/mcast/test.c | 29 + src/mod/endpoints/mod_verto/mcast/test.pl | 19 + src/mod/endpoints/mod_verto/mcast/test2.pl | 23 + .../endpoints/mod_verto/mod_verto.2008.vcproj | 287 ++ .../mod_verto/mod_verto.2010.vcxproj | 131 + .../mod_verto/mod_verto.2012.vcxproj | 135 + src/mod/endpoints/mod_verto/mod_verto.c | 4485 +++++++++++++++++ src/mod/endpoints/mod_verto/mod_verto.h | 272 + src/mod/endpoints/mod_verto/ws.c | 879 ++++ src/mod/endpoints/mod_verto/ws.h | 120 + 22 files changed, 9203 insertions(+) create mode 100644 src/mod/endpoints/mod_verto/Makefile.am create mode 100644 src/mod/endpoints/mod_verto/mcast/.gitignore create mode 100644 src/mod/endpoints/mod_verto/mcast/MCAST.i create mode 100644 src/mod/endpoints/mod_verto/mcast/MCAST.pm create mode 100644 src/mod/endpoints/mod_verto/mcast/mcast.c create mode 100644 src/mod/endpoints/mod_verto/mcast/mcast.h create mode 100644 src/mod/endpoints/mod_verto/mcast/mcast_cpp.cpp create mode 100644 src/mod/endpoints/mod_verto/mcast/mcast_cpp.h create mode 100644 src/mod/endpoints/mod_verto/mcast/mcast_wrap.cpp create mode 100644 src/mod/endpoints/mod_verto/mcast/perlxsi.c create mode 100644 src/mod/endpoints/mod_verto/mcast/test.c create mode 100644 src/mod/endpoints/mod_verto/mcast/test.pl create mode 100644 src/mod/endpoints/mod_verto/mcast/test2.pl create mode 100644 src/mod/endpoints/mod_verto/mod_verto.2008.vcproj create mode 100644 src/mod/endpoints/mod_verto/mod_verto.2010.vcxproj create mode 100644 src/mod/endpoints/mod_verto/mod_verto.2012.vcxproj create mode 100644 src/mod/endpoints/mod_verto/mod_verto.c create mode 100644 src/mod/endpoints/mod_verto/mod_verto.h create mode 100644 src/mod/endpoints/mod_verto/ws.c create mode 100644 src/mod/endpoints/mod_verto/ws.h diff --git a/build/modules.conf.in b/build/modules.conf.in index 34e16be048..7368cc8f01 100644 --- a/build/modules.conf.in +++ b/build/modules.conf.in @@ -83,6 +83,7 @@ dialplans/mod_dialplan_xml #endpoints/mod_h323 #endpoints/mod_khomp endpoints/mod_rtc +endpoints/mod_verto endpoints/mod_loopback #endpoints/mod_opal #endpoints/mod_portaudio diff --git a/configure.ac b/configure.ac index 4da80f2105..294f6b469d 100644 --- a/configure.ac +++ b/configure.ac @@ -1500,6 +1500,7 @@ AC_CONFIG_FILES([Makefile src/mod/endpoints/mod_sofia/Makefile src/mod/endpoints/mod_unicall/Makefile src/mod/endpoints/mod_rtc/Makefile + src/mod/endpoints/mod_verto/Makefile src/mod/event_handlers/mod_cdr_csv/Makefile src/mod/event_handlers/mod_cdr_mongodb/Makefile src/mod/event_handlers/mod_cdr_pg_csv/Makefile diff --git a/src/mod/endpoints/mod_verto/Makefile.am b/src/mod/endpoints/mod_verto/Makefile.am new file mode 100644 index 0000000000..08b82bd32c --- /dev/null +++ b/src/mod/endpoints/mod_verto/Makefile.am @@ -0,0 +1,38 @@ +include $(top_srcdir)/build/modmake.rulesam +MODNAME=mod_verto + +mod_LTLIBRARIES = mod_verto.la +mod_verto_la_SOURCES = mod_verto.c ws.c mcast/mcast.c +mod_verto_la_CFLAGS = -D__EXTENSIONS__ -D_GNU_SOURCE $(AM_CFLAGS) +mod_verto_la_CPPFLAGS = -I. -Imcast +mod_verto_la_LIBADD = $(switch_builddir)/libfreeswitch.la +mod_verto_la_LDFLAGS = -avoid-version -module -no-undefined -shared + +if HAVE_PERL +perldir = $(PERL_SITEDIR) +perl_LTLIBRARIES = MCAST.la +MCAST_la_SOURCES = mcast/mcast_wrap.cpp mcast/perlxsi.c mcast/mcast.c mcast/mcast_cpp.cpp +MCAST_la_CFLAGS = $(CC_CFLAGS) $(CFLAGS) $(SWITCH_AM_CFLAGS) $(PERL_CFLAGS) +MCAST_la_CXXFLAGS = $(SWITCH_AM_CXXFLAGS) $(CXXFLAGS) -w $(PERL_INC) +MCAST_la_CPPFLAGS = -I$(switch_srcdir)/src/mod/endpoints/mod_verto/mcast +MCAST_la_LDFLAGS = -avoid-version -module -no-undefined -shared $(PERL_LDFLAGS) + +install-data-local: perlmod-install + +perlmod-install: install-perlLTLIBRARIES + install -m 755 MCAST.pm $(PERL_SITEDIR) +endif + +mcast/esl_wrap.cpp: + cd mcast && swig -module MCAST -shadow -perl5 -c++ -DMULTIPLICITY -I../src/include -o mcast_wrap.cpp ../MCAST.i + +mcast/perlxsi.c: + $(PERL) -MExtUtils::Embed -e xsinit -- -o perlxsi.c + +clean-data-local: + rm -f *.o *.so *~ + +swigclean: + rm -f mcast/mcast_wrap.* mcast/MCAST.so mcast/MCAST.pm mcast/perlxsi.* + +reswig: swigclean mcast/mcast_wrap.cpp mcast/perlxsi.c diff --git a/src/mod/endpoints/mod_verto/mcast/.gitignore b/src/mod/endpoints/mod_verto/mcast/.gitignore new file mode 100644 index 0000000000..9d22eb46a9 --- /dev/null +++ b/src/mod/endpoints/mod_verto/mcast/.gitignore @@ -0,0 +1,2 @@ +*.o +*.so diff --git a/src/mod/endpoints/mod_verto/mcast/MCAST.i b/src/mod/endpoints/mod_verto/mcast/MCAST.i new file mode 100644 index 0000000000..097a52bc77 --- /dev/null +++ b/src/mod/endpoints/mod_verto/mcast/MCAST.i @@ -0,0 +1,24 @@ +%{ +#include "mcast.h" +#include "mcast_cpp.h" +%} + +%newobject McastHANDLE::recv; + +%include "mcast_cpp.h" + +%perlcode %{ +use constant { + MCAST_SEND => (1 << 0), + MCAST_RECV => (1 << 1), + MCAST_TTL_HOST => (1 << 2), + MCAST_TTL_SUBNET => (1 << 3), + MCAST_TTL_SITE => (1 << 4), + MCAST_TTL_REGION => (1 << 5), + MCAST_TTL_CONTINENT => (1 << 6), + MCAST_TTL_UNIVERSE => (1 << 7) +}; +%} + + + diff --git a/src/mod/endpoints/mod_verto/mcast/MCAST.pm b/src/mod/endpoints/mod_verto/mcast/MCAST.pm new file mode 100644 index 0000000000..531665035b --- /dev/null +++ b/src/mod/endpoints/mod_verto/mcast/MCAST.pm @@ -0,0 +1,108 @@ +# This file was automatically generated by SWIG (http://www.swig.org). +# Version 1.3.35 +# +# Don't modify this file, modify the SWIG interface instead. + +package MCAST; +require Exporter; +require DynaLoader; +@ISA = qw(Exporter DynaLoader); +package MCASTc; +bootstrap MCAST; +package MCAST; +@EXPORT = qw( ); + +# ---------- BASE METHODS ------------- + +package MCAST; + +sub TIEHASH { + my ($classname,$obj) = @_; + return bless $obj, $classname; +} + +sub CLEAR { } + +sub FIRSTKEY { } + +sub NEXTKEY { } + +sub FETCH { + my ($self,$field) = @_; + my $member_func = "swig_${field}_get"; + $self->$member_func(); +} + +sub STORE { + my ($self,$field,$newval) = @_; + my $member_func = "swig_${field}_set"; + $self->$member_func($newval); +} + +sub this { + my $ptr = shift; + return tied(%$ptr); +} + + +# ------- FUNCTION WRAPPERS -------- + +package MCAST; + + +############# Class : MCAST::McastHandle ############## + +package MCAST::McastHandle; +use vars qw(@ISA %OWNER %ITERATORS %BLESSEDMEMBERS); +@ISA = qw( MCAST ); +%OWNER = (); +%ITERATORS = (); +sub new { + my $pkg = shift; + my $self = MCASTc::new_McastHandle(@_); + bless $self, $pkg if defined($self); +} + +sub DESTROY { + return unless $_[0]->isa('HASH'); + my $self = tied(%{$_[0]}); + return unless defined $self; + delete $ITERATORS{$self}; + if (exists $OWNER{$self}) { + MCASTc::delete_McastHandle($self); + delete $OWNER{$self}; + } +} + +*send = *MCASTc::McastHandle_send; +*recv = *MCASTc::McastHandle_recv; +*fileno = *MCASTc::McastHandle_fileno; +sub DISOWN { + my $self = shift; + my $ptr = tied(%$self); + delete $OWNER{$ptr}; +} + +sub ACQUIRE { + my $self = shift; + my $ptr = tied(%$self); + $OWNER{$ptr} = 1; +} + + +# ------- VARIABLE STUBS -------- + +package MCAST; + + +use constant { + MCAST_SEND => (1 << 0), + MCAST_RECV => (1 << 1), + MCAST_TTL_HOST => (1 << 2), + MCAST_TTL_SUBNET => (1 << 3), + MCAST_TTL_SITE => (1 << 4), + MCAST_TTL_REGION => (1 << 5), + MCAST_TTL_CONTINENT => (1 << 6), + MCAST_TTL_UNIVERSE => (1 << 7) +}; +1; diff --git a/src/mod/endpoints/mod_verto/mcast/mcast.c b/src/mod/endpoints/mod_verto/mcast/mcast.c new file mode 100644 index 0000000000..a3234d743f --- /dev/null +++ b/src/mod/endpoints/mod_verto/mcast/mcast.c @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2011, Anthony Minessale II + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of the original author; nor the names of any contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mcast.h" +#include + +int mcast_socket_create(const char *host, int16_t port, mcast_handle_t *handle, mcast_flag_t flags) +{ + uint32_t one = 1; + + memset(handle, 0, sizeof(*handle)); + + if ((!(flags & MCAST_SEND) && !(flags & MCAST_RECV)) || !(handle->sock = socket(AF_INET, SOCK_DGRAM, 0))) { + return -1; + } + + handle->send_addr.sin_family = AF_INET; + handle->send_addr.sin_addr.s_addr = inet_addr(host); + handle->send_addr.sin_port = htons(port); + + setsockopt(handle->sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); + + + if ((flags & MCAST_RECV)) { + struct ip_mreq mreq; + + handle->recv_addr.sin_family = AF_INET; + handle->recv_addr.sin_addr.s_addr = htonl(INADDR_ANY); + handle->recv_addr.sin_port = htons(port); + + mreq.imr_multiaddr.s_addr = inet_addr(host); + mreq.imr_interface.s_addr = htonl(INADDR_ANY); + + if (setsockopt(handle->sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) { + close(handle->sock); + handle->sock = -1; + return -1; + } + + if (bind(handle->sock, (struct sockaddr *) &handle->recv_addr, sizeof(handle->recv_addr)) < 0) { + close(handle->sock); + handle->sock = -1; + return -1; + } + + + } + + handle->ttl = 1; + + if ((flags & MCAST_TTL_HOST)) { + handle->ttl = 0; + } + + if ((flags & MCAST_TTL_SUBNET)) { + handle->ttl = 1; + } + + if ((flags & MCAST_TTL_SITE)) { + handle->ttl = 32; + } + + if ((flags & MCAST_TTL_REGION)) { + handle->ttl = 64; + } + + if ((flags & MCAST_TTL_CONTINENT)) { + handle->ttl = 128; + } + + if ((flags & MCAST_TTL_UNIVERSE)) { + handle->ttl = 255; + } + + setsockopt(handle->sock, IPPROTO_IP, IP_MULTICAST_TTL, &handle->ttl, sizeof(handle->ttl)); + + handle->ready = 1; + + return 0; +} + + +void mcast_socket_close(mcast_handle_t *handle) +{ + if (handle->sock > -1) { + close(handle->sock); + handle->sock = -1; + } +} + +ssize_t mcast_socket_send(mcast_handle_t *handle, void *data, size_t datalen) +{ + if (handle->sock <= -1) { + return -1; + } + + if (data == NULL || datalen == 0) { + data = handle->buffer; + datalen = sizeof(handle->buffer); + } + + return sendto(handle->sock, data, datalen, 0, (struct sockaddr *) &handle->send_addr, sizeof(handle->send_addr)); +} + +ssize_t mcast_socket_recv(mcast_handle_t *handle, void *data, size_t datalen, int ms) +{ + socklen_t addrlen = sizeof(handle->recv_addr); + int r; + + if (data == NULL || datalen == 0) { + data = handle->buffer; + datalen = sizeof(handle->buffer); + } + + if (ms > 0) { + struct pollfd pfds[1]; + + pfds[0].fd = handle->sock; + pfds[0].events = POLLIN|POLLERR; + + if ((r = poll(pfds, 1, ms)) <= 0) { + return r; + } + + if (pfds[0].revents & POLLERR) { + return -1; + } + } + + + return recvfrom(handle->sock, data, datalen, 0, (struct sockaddr *) &handle->recv_addr, &addrlen); +} diff --git a/src/mod/endpoints/mod_verto/mcast/mcast.h b/src/mod/endpoints/mod_verto/mcast/mcast.h new file mode 100644 index 0000000000..38afa951e9 --- /dev/null +++ b/src/mod/endpoints/mod_verto/mcast/mcast.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2011, Anthony Minessale II + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of the original author; nor the names of any contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MCAST_H +#define __MCAST_H + +#ifdef __cplusplus +extern "C" { +#endif /* defined(__cplusplus) */ +#if EMACS_WORKS +} +#endif + +#include +#include +#include +#include + +typedef struct { + int sock; + unsigned char ttl; + struct sockaddr_in send_addr; + struct sockaddr_in recv_addr; + unsigned char buffer[65536]; + int ready; +} mcast_handle_t; + +typedef enum { + MCAST_SEND = (1 << 0), + MCAST_RECV = (1 << 1), + MCAST_TTL_HOST = (1 << 2), + MCAST_TTL_SUBNET = (1 << 3), + MCAST_TTL_SITE = (1 << 4), + MCAST_TTL_REGION = (1 << 5), + MCAST_TTL_CONTINENT = (1 << 6), + MCAST_TTL_UNIVERSE = (1 << 7) +} mcast_flag_t; + +int mcast_socket_create(const char *host, int16_t port, mcast_handle_t *handle, mcast_flag_t flags); +void mcast_socket_close(mcast_handle_t *handle); +ssize_t mcast_socket_send(mcast_handle_t *handle, void *data, size_t datalen); +ssize_t mcast_socket_recv(mcast_handle_t *handle, void *data, size_t datalen, int ms); + +#ifdef __cplusplus +} +#endif /* defined(__cplusplus) */ + +#endif diff --git a/src/mod/endpoints/mod_verto/mcast/mcast_cpp.cpp b/src/mod/endpoints/mod_verto/mcast/mcast_cpp.cpp new file mode 100644 index 0000000000..2e3eca6c6d --- /dev/null +++ b/src/mod/endpoints/mod_verto/mcast/mcast_cpp.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2011, Anthony Minessale II + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of the original author; nor the names of any contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "mcast.h" +#include "mcast_cpp.h" +#include +#include + +McastHandle::McastHandle(const char *host, int port, int flags) +{ + mcast_socket_create(host, port, &handle, (mcast_flag_t) flags); +} + +McastHandle::~McastHandle() +{ + mcast_socket_close(&handle); +} + +int McastHandle::send(const char *data) +{ + return (int) mcast_socket_send(&handle, (void *)data, strlen(data) + 1); +} + +char *McastHandle::recv(int ms) +{ + int r; + + if ((r = mcast_socket_recv(&handle, NULL, 0, ms)) > 0) { + *((char *)handle.buffer + r) = '\0'; + return (char *) handle.buffer; + } + + return NULL; +} + +int McastHandle::fileno(void) +{ + return handle.sock; +} diff --git a/src/mod/endpoints/mod_verto/mcast/mcast_cpp.h b/src/mod/endpoints/mod_verto/mcast/mcast_cpp.h new file mode 100644 index 0000000000..5990871a0f --- /dev/null +++ b/src/mod/endpoints/mod_verto/mcast/mcast_cpp.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2011, Anthony Minessale II + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of the original author; nor the names of any contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __MCAST_CPP_H +#define __MCAST_CPP_H + +#ifdef __cplusplus +extern "C" { +#endif /* defined(__cplusplus) */ +#if EMACS_WORKS +} +#endif + +class McastHandle { + private: + mcast_handle_t handle; + public: + McastHandle(const char *host, int port, int flags); + virtual ~McastHandle(); + int send(const char *data); + char *recv(int ms = 0); + int fileno(void); +}; + +#ifdef __cplusplus +} +#endif /* defined(__cplusplus) */ + +#endif diff --git a/src/mod/endpoints/mod_verto/mcast/mcast_wrap.cpp b/src/mod/endpoints/mod_verto/mcast/mcast_wrap.cpp new file mode 100644 index 0000000000..77725cf4bd --- /dev/null +++ b/src/mod/endpoints/mod_verto/mcast/mcast_wrap.cpp @@ -0,0 +1,2254 @@ +/* ---------------------------------------------------------------------------- + * This file was automatically generated by SWIG (http://www.swig.org). + * Version 1.3.35 + * + * This file is not intended to be easily readable and contains a number of + * coding conventions designed to improve portability and efficiency. Do not make + * changes to this file unless you know what you are doing--modify the SWIG + * interface file instead. + * ----------------------------------------------------------------------------- */ + +#define SWIGPERL +#define SWIG_CASTRANK_MODE + +#ifdef __cplusplus +template class SwigValueWrapper { + T *tt; +public: + SwigValueWrapper() : tt(0) { } + SwigValueWrapper(const SwigValueWrapper& rhs) : tt(new T(*rhs.tt)) { } + SwigValueWrapper(const T& t) : tt(new T(t)) { } + ~SwigValueWrapper() { delete tt; } + SwigValueWrapper& operator=(const T& t) { delete tt; tt = new T(t); return *this; } + operator T&() const { return *tt; } + T *operator&() { return tt; } +private: + SwigValueWrapper& operator=(const SwigValueWrapper& rhs); +}; + +template T SwigValueInit() { + return T(); +} +#endif + +/* ----------------------------------------------------------------------------- + * This section contains generic SWIG labels for method/variable + * declarations/attributes, and other compiler dependent labels. + * ----------------------------------------------------------------------------- */ + +/* template workaround for compilers that cannot correctly implement the C++ standard */ +#ifndef SWIGTEMPLATEDISAMBIGUATOR +# if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x560) +# define SWIGTEMPLATEDISAMBIGUATOR template +# elif defined(__HP_aCC) +/* Needed even with `aCC -AA' when `aCC -V' reports HP ANSI C++ B3910B A.03.55 */ +/* If we find a maximum version that requires this, the test would be __HP_aCC <= 35500 for A.03.55 */ +# define SWIGTEMPLATEDISAMBIGUATOR template +# else +# define SWIGTEMPLATEDISAMBIGUATOR +# endif +#endif + +/* inline attribute */ +#ifndef SWIGINLINE +# if defined(__cplusplus) || (defined(__GNUC__) && !defined(__STRICT_ANSI__)) +# define SWIGINLINE inline +# else +# define SWIGINLINE +# endif +#endif + +/* attribute recognised by some compilers to avoid 'unused' warnings */ +#ifndef SWIGUNUSED +# if defined(__GNUC__) +# if !(defined(__cplusplus)) || (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) +# define SWIGUNUSED __attribute__ ((__unused__)) +# else +# define SWIGUNUSED +# endif +# elif defined(__ICC) +# define SWIGUNUSED __attribute__ ((__unused__)) +# else +# define SWIGUNUSED +# endif +#endif + +#ifndef SWIGUNUSEDPARM +# ifdef __cplusplus +# define SWIGUNUSEDPARM(p) +# else +# define SWIGUNUSEDPARM(p) p SWIGUNUSED +# endif +#endif + +/* internal SWIG method */ +#ifndef SWIGINTERN +# define SWIGINTERN static SWIGUNUSED +#endif + +/* internal inline SWIG method */ +#ifndef SWIGINTERNINLINE +# define SWIGINTERNINLINE SWIGINTERN SWIGINLINE +#endif + +/* exporting methods */ +#if (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) +# ifndef GCC_HASCLASSVISIBILITY +# define GCC_HASCLASSVISIBILITY +# endif +#endif + +#ifndef SWIGEXPORT +# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) +# if defined(STATIC_LINKED) +# define SWIGEXPORT +# else +# define SWIGEXPORT __declspec(dllexport) +# endif +# else +# if defined(__GNUC__) && defined(GCC_HASCLASSVISIBILITY) +# define SWIGEXPORT __attribute__ ((visibility("default"))) +# else +# define SWIGEXPORT +# endif +# endif +#endif + +/* calling conventions for Windows */ +#ifndef SWIGSTDCALL +# if defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) +# define SWIGSTDCALL __stdcall +# else +# define SWIGSTDCALL +# endif +#endif + +/* Deal with Microsoft's attempt at deprecating C standard runtime functions */ +#if !defined(SWIG_NO_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE) +# define _CRT_SECURE_NO_DEPRECATE +#endif + +/* Deal with Microsoft's attempt at deprecating methods in the standard C++ library */ +#if !defined(SWIG_NO_SCL_SECURE_NO_DEPRECATE) && defined(_MSC_VER) && !defined(_SCL_SECURE_NO_DEPRECATE) +# define _SCL_SECURE_NO_DEPRECATE +#endif + + +/* ----------------------------------------------------------------------------- + * swigrun.swg + * + * This file contains generic CAPI SWIG runtime support for pointer + * type checking. + * ----------------------------------------------------------------------------- */ + +/* This should only be incremented when either the layout of swig_type_info changes, + or for whatever reason, the runtime changes incompatibly */ +#define SWIG_RUNTIME_VERSION "4" + +/* define SWIG_TYPE_TABLE_NAME as "SWIG_TYPE_TABLE" */ +#ifdef SWIG_TYPE_TABLE +# define SWIG_QUOTE_STRING(x) #x +# define SWIG_EXPAND_AND_QUOTE_STRING(x) SWIG_QUOTE_STRING(x) +# define SWIG_TYPE_TABLE_NAME SWIG_EXPAND_AND_QUOTE_STRING(SWIG_TYPE_TABLE) +#else +# define SWIG_TYPE_TABLE_NAME +#endif + +/* + You can use the SWIGRUNTIME and SWIGRUNTIMEINLINE macros for + creating a static or dynamic library from the swig runtime code. + In 99.9% of the cases, swig just needs to declare them as 'static'. + + But only do this if is strictly necessary, ie, if you have problems + with your compiler or so. +*/ + +#ifndef SWIGRUNTIME +# define SWIGRUNTIME SWIGINTERN +#endif + +#ifndef SWIGRUNTIMEINLINE +# define SWIGRUNTIMEINLINE SWIGRUNTIME SWIGINLINE +#endif + +/* Generic buffer size */ +#ifndef SWIG_BUFFER_SIZE +# define SWIG_BUFFER_SIZE 1024 +#endif + +/* Flags for pointer conversions */ +#define SWIG_POINTER_DISOWN 0x1 +#define SWIG_CAST_NEW_MEMORY 0x2 + +/* Flags for new pointer objects */ +#define SWIG_POINTER_OWN 0x1 + + +/* + Flags/methods for returning states. + + The swig conversion methods, as ConvertPtr, return and integer + that tells if the conversion was successful or not. And if not, + an error code can be returned (see swigerrors.swg for the codes). + + Use the following macros/flags to set or process the returning + states. + + In old swig versions, you usually write code as: + + if (SWIG_ConvertPtr(obj,vptr,ty.flags) != -1) { + // success code + } else { + //fail code + } + + Now you can be more explicit as: + + int res = SWIG_ConvertPtr(obj,vptr,ty.flags); + if (SWIG_IsOK(res)) { + // success code + } else { + // fail code + } + + that seems to be the same, but now you can also do + + Type *ptr; + int res = SWIG_ConvertPtr(obj,(void **)(&ptr),ty.flags); + if (SWIG_IsOK(res)) { + // success code + if (SWIG_IsNewObj(res) { + ... + delete *ptr; + } else { + ... + } + } else { + // fail code + } + + I.e., now SWIG_ConvertPtr can return new objects and you can + identify the case and take care of the deallocation. Of course that + requires also to SWIG_ConvertPtr to return new result values, as + + int SWIG_ConvertPtr(obj, ptr,...) { + if () { + if () { + *ptr = ; + return SWIG_NEWOBJ; + } else { + *ptr = ; + return SWIG_OLDOBJ; + } + } else { + return SWIG_BADOBJ; + } + } + + Of course, returning the plain '0(success)/-1(fail)' still works, but you can be + more explicit by returning SWIG_BADOBJ, SWIG_ERROR or any of the + swig errors code. + + Finally, if the SWIG_CASTRANK_MODE is enabled, the result code + allows to return the 'cast rank', for example, if you have this + + int food(double) + int fooi(int); + + and you call + + food(1) // cast rank '1' (1 -> 1.0) + fooi(1) // cast rank '0' + + just use the SWIG_AddCast()/SWIG_CheckState() + + + */ +#define SWIG_OK (0) +#define SWIG_ERROR (-1) +#define SWIG_IsOK(r) (r >= 0) +#define SWIG_ArgError(r) ((r != SWIG_ERROR) ? r : SWIG_TypeError) + +/* The CastRankLimit says how many bits are used for the cast rank */ +#define SWIG_CASTRANKLIMIT (1 << 8) +/* The NewMask denotes the object was created (using new/malloc) */ +#define SWIG_NEWOBJMASK (SWIG_CASTRANKLIMIT << 1) +/* The TmpMask is for in/out typemaps that use temporal objects */ +#define SWIG_TMPOBJMASK (SWIG_NEWOBJMASK << 1) +/* Simple returning values */ +#define SWIG_BADOBJ (SWIG_ERROR) +#define SWIG_OLDOBJ (SWIG_OK) +#define SWIG_NEWOBJ (SWIG_OK | SWIG_NEWOBJMASK) +#define SWIG_TMPOBJ (SWIG_OK | SWIG_TMPOBJMASK) +/* Check, add and del mask methods */ +#define SWIG_AddNewMask(r) (SWIG_IsOK(r) ? (r | SWIG_NEWOBJMASK) : r) +#define SWIG_DelNewMask(r) (SWIG_IsOK(r) ? (r & ~SWIG_NEWOBJMASK) : r) +#define SWIG_IsNewObj(r) (SWIG_IsOK(r) && (r & SWIG_NEWOBJMASK)) +#define SWIG_AddTmpMask(r) (SWIG_IsOK(r) ? (r | SWIG_TMPOBJMASK) : r) +#define SWIG_DelTmpMask(r) (SWIG_IsOK(r) ? (r & ~SWIG_TMPOBJMASK) : r) +#define SWIG_IsTmpObj(r) (SWIG_IsOK(r) && (r & SWIG_TMPOBJMASK)) + + +/* Cast-Rank Mode */ +#if defined(SWIG_CASTRANK_MODE) +# ifndef SWIG_TypeRank +# define SWIG_TypeRank unsigned long +# endif +# ifndef SWIG_MAXCASTRANK /* Default cast allowed */ +# define SWIG_MAXCASTRANK (2) +# endif +# define SWIG_CASTRANKMASK ((SWIG_CASTRANKLIMIT) -1) +# define SWIG_CastRank(r) (r & SWIG_CASTRANKMASK) +SWIGINTERNINLINE int SWIG_AddCast(int r) { + return SWIG_IsOK(r) ? ((SWIG_CastRank(r) < SWIG_MAXCASTRANK) ? (r + 1) : SWIG_ERROR) : r; +} +SWIGINTERNINLINE int SWIG_CheckState(int r) { + return SWIG_IsOK(r) ? SWIG_CastRank(r) + 1 : 0; +} +#else /* no cast-rank mode */ +# define SWIG_AddCast +# define SWIG_CheckState(r) (SWIG_IsOK(r) ? 1 : 0) +#endif + + + + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void *(*swig_converter_func)(void *, int *); +typedef struct swig_type_info *(*swig_dycast_func)(void **); + +/* Structure to store information on one type */ +typedef struct swig_type_info { + const char *name; /* mangled name of this type */ + const char *str; /* human readable name of this type */ + swig_dycast_func dcast; /* dynamic cast function down a hierarchy */ + struct swig_cast_info *cast; /* linked list of types that can cast into this type */ + void *clientdata; /* language specific type data */ + int owndata; /* flag if the structure owns the clientdata */ +} swig_type_info; + +/* Structure to store a type and conversion function used for casting */ +typedef struct swig_cast_info { + swig_type_info *type; /* pointer to type that is equivalent to this type */ + swig_converter_func converter; /* function to cast the void pointers */ + struct swig_cast_info *next; /* pointer to next cast in linked list */ + struct swig_cast_info *prev; /* pointer to the previous cast */ +} swig_cast_info; + +/* Structure used to store module information + * Each module generates one structure like this, and the runtime collects + * all of these structures and stores them in a circularly linked list.*/ +typedef struct swig_module_info { + swig_type_info **types; /* Array of pointers to swig_type_info structures that are in this module */ + size_t size; /* Number of types in this module */ + struct swig_module_info *next; /* Pointer to next element in circularly linked list */ + swig_type_info **type_initial; /* Array of initially generated type structures */ + swig_cast_info **cast_initial; /* Array of initially generated casting structures */ + void *clientdata; /* Language specific module data */ +} swig_module_info; + +/* + Compare two type names skipping the space characters, therefore + "char*" == "char *" and "Class" == "Class", etc. + + Return 0 when the two name types are equivalent, as in + strncmp, but skipping ' '. +*/ +SWIGRUNTIME int +SWIG_TypeNameComp(const char *f1, const char *l1, + const char *f2, const char *l2) { + for (;(f1 != l1) && (f2 != l2); ++f1, ++f2) { + while ((*f1 == ' ') && (f1 != l1)) ++f1; + while ((*f2 == ' ') && (f2 != l2)) ++f2; + if (*f1 != *f2) return (*f1 > *f2) ? 1 : -1; + } + return (int)((l1 - f1) - (l2 - f2)); +} + +/* + Check type equivalence in a name list like ||... + Return 0 if not equal, 1 if equal +*/ +SWIGRUNTIME int +SWIG_TypeEquiv(const char *nb, const char *tb) { + int equiv = 0; + const char* te = tb + strlen(tb); + const char* ne = nb; + while (!equiv && *ne) { + for (nb = ne; *ne; ++ne) { + if (*ne == '|') break; + } + equiv = (SWIG_TypeNameComp(nb, ne, tb, te) == 0) ? 1 : 0; + if (*ne) ++ne; + } + return equiv; +} + +/* + Check type equivalence in a name list like ||... + Return 0 if equal, -1 if nb < tb, 1 if nb > tb +*/ +SWIGRUNTIME int +SWIG_TypeCompare(const char *nb, const char *tb) { + int equiv = 0; + const char* te = tb + strlen(tb); + const char* ne = nb; + while (!equiv && *ne) { + for (nb = ne; *ne; ++ne) { + if (*ne == '|') break; + } + equiv = (SWIG_TypeNameComp(nb, ne, tb, te) == 0) ? 1 : 0; + if (*ne) ++ne; + } + return equiv; +} + + +/* think of this as a c++ template<> or a scheme macro */ +#define SWIG_TypeCheck_Template(comparison, ty) \ + if (ty) { \ + swig_cast_info *iter = ty->cast; \ + while (iter) { \ + if (comparison) { \ + if (iter == ty->cast) return iter; \ + /* Move iter to the top of the linked list */ \ + iter->prev->next = iter->next; \ + if (iter->next) \ + iter->next->prev = iter->prev; \ + iter->next = ty->cast; \ + iter->prev = 0; \ + if (ty->cast) ty->cast->prev = iter; \ + ty->cast = iter; \ + return iter; \ + } \ + iter = iter->next; \ + } \ + } \ + return 0 + +/* + Check the typename +*/ +SWIGRUNTIME swig_cast_info * +SWIG_TypeCheck(const char *c, swig_type_info *ty) { + SWIG_TypeCheck_Template(strcmp(iter->type->name, c) == 0, ty); +} + +/* Same as previous function, except strcmp is replaced with a pointer comparison */ +SWIGRUNTIME swig_cast_info * +SWIG_TypeCheckStruct(swig_type_info *from, swig_type_info *into) { + SWIG_TypeCheck_Template(iter->type == from, into); +} + +/* + Cast a pointer up an inheritance hierarchy +*/ +SWIGRUNTIMEINLINE void * +SWIG_TypeCast(swig_cast_info *ty, void *ptr, int *newmemory) { + return ((!ty) || (!ty->converter)) ? ptr : (*ty->converter)(ptr, newmemory); +} + +/* + Dynamic pointer casting. Down an inheritance hierarchy +*/ +SWIGRUNTIME swig_type_info * +SWIG_TypeDynamicCast(swig_type_info *ty, void **ptr) { + swig_type_info *lastty = ty; + if (!ty || !ty->dcast) return ty; + while (ty && (ty->dcast)) { + ty = (*ty->dcast)(ptr); + if (ty) lastty = ty; + } + return lastty; +} + +/* + Return the name associated with this type +*/ +SWIGRUNTIMEINLINE const char * +SWIG_TypeName(const swig_type_info *ty) { + return ty->name; +} + +/* + Return the pretty name associated with this type, + that is an unmangled type name in a form presentable to the user. +*/ +SWIGRUNTIME const char * +SWIG_TypePrettyName(const swig_type_info *type) { + /* The "str" field contains the equivalent pretty names of the + type, separated by vertical-bar characters. We choose + to print the last name, as it is often (?) the most + specific. */ + if (!type) return NULL; + if (type->str != NULL) { + const char *last_name = type->str; + const char *s; + for (s = type->str; *s; s++) + if (*s == '|') last_name = s+1; + return last_name; + } + else + return type->name; +} + +/* + Set the clientdata field for a type +*/ +SWIGRUNTIME void +SWIG_TypeClientData(swig_type_info *ti, void *clientdata) { + swig_cast_info *cast = ti->cast; + /* if (ti->clientdata == clientdata) return; */ + ti->clientdata = clientdata; + + while (cast) { + if (!cast->converter) { + swig_type_info *tc = cast->type; + if (!tc->clientdata) { + SWIG_TypeClientData(tc, clientdata); + } + } + cast = cast->next; + } +} +SWIGRUNTIME void +SWIG_TypeNewClientData(swig_type_info *ti, void *clientdata) { + SWIG_TypeClientData(ti, clientdata); + ti->owndata = 1; +} + +/* + Search for a swig_type_info structure only by mangled name + Search is a O(log #types) + + We start searching at module start, and finish searching when start == end. + Note: if start == end at the beginning of the function, we go all the way around + the circular list. +*/ +SWIGRUNTIME swig_type_info * +SWIG_MangledTypeQueryModule(swig_module_info *start, + swig_module_info *end, + const char *name) { + swig_module_info *iter = start; + do { + if (iter->size) { + register size_t l = 0; + register size_t r = iter->size - 1; + do { + /* since l+r >= 0, we can (>> 1) instead (/ 2) */ + register size_t i = (l + r) >> 1; + const char *iname = iter->types[i]->name; + if (iname) { + register int compare = strcmp(name, iname); + if (compare == 0) { + return iter->types[i]; + } else if (compare < 0) { + if (i) { + r = i - 1; + } else { + break; + } + } else if (compare > 0) { + l = i + 1; + } + } else { + break; /* should never happen */ + } + } while (l <= r); + } + iter = iter->next; + } while (iter != end); + return 0; +} + +/* + Search for a swig_type_info structure for either a mangled name or a human readable name. + It first searches the mangled names of the types, which is a O(log #types) + If a type is not found it then searches the human readable names, which is O(#types). + + We start searching at module start, and finish searching when start == end. + Note: if start == end at the beginning of the function, we go all the way around + the circular list. +*/ +SWIGRUNTIME swig_type_info * +SWIG_TypeQueryModule(swig_module_info *start, + swig_module_info *end, + const char *name) { + /* STEP 1: Search the name field using binary search */ + swig_type_info *ret = SWIG_MangledTypeQueryModule(start, end, name); + if (ret) { + return ret; + } else { + /* STEP 2: If the type hasn't been found, do a complete search + of the str field (the human readable name) */ + swig_module_info *iter = start; + do { + register size_t i = 0; + for (; i < iter->size; ++i) { + if (iter->types[i]->str && (SWIG_TypeEquiv(iter->types[i]->str, name))) + return iter->types[i]; + } + iter = iter->next; + } while (iter != end); + } + + /* neither found a match */ + return 0; +} + +/* + Pack binary data into a string +*/ +SWIGRUNTIME char * +SWIG_PackData(char *c, void *ptr, size_t sz) { + static const char hex[17] = "0123456789abcdef"; + register const unsigned char *u = (unsigned char *) ptr; + register const unsigned char *eu = u + sz; + for (; u != eu; ++u) { + register unsigned char uu = *u; + *(c++) = hex[(uu & 0xf0) >> 4]; + *(c++) = hex[uu & 0xf]; + } + return c; +} + +/* + Unpack binary data from a string +*/ +SWIGRUNTIME const char * +SWIG_UnpackData(const char *c, void *ptr, size_t sz) { + register unsigned char *u = (unsigned char *) ptr; + register const unsigned char *eu = u + sz; + for (; u != eu; ++u) { + register char d = *(c++); + register unsigned char uu; + if ((d >= '0') && (d <= '9')) + uu = ((d - '0') << 4); + else if ((d >= 'a') && (d <= 'f')) + uu = ((d - ('a'-10)) << 4); + else + return (char *) 0; + d = *(c++); + if ((d >= '0') && (d <= '9')) + uu |= (d - '0'); + else if ((d >= 'a') && (d <= 'f')) + uu |= (d - ('a'-10)); + else + return (char *) 0; + *u = uu; + } + return c; +} + +/* + Pack 'void *' into a string buffer. +*/ +SWIGRUNTIME char * +SWIG_PackVoidPtr(char *buff, void *ptr, const char *name, size_t bsz) { + char *r = buff; + if ((2*sizeof(void *) + 2) > bsz) return 0; + *(r++) = '_'; + r = SWIG_PackData(r,&ptr,sizeof(void *)); + if (strlen(name) + 1 > (bsz - (r - buff))) return 0; + strcpy(r,name); + return buff; +} + +SWIGRUNTIME const char * +SWIG_UnpackVoidPtr(const char *c, void **ptr, const char *name) { + if (*c != '_') { + if (strcmp(c,"NULL") == 0) { + *ptr = (void *) 0; + return name; + } else { + return 0; + } + } + return SWIG_UnpackData(++c,ptr,sizeof(void *)); +} + +SWIGRUNTIME char * +SWIG_PackDataName(char *buff, void *ptr, size_t sz, const char *name, size_t bsz) { + char *r = buff; + size_t lname = (name ? strlen(name) : 0); + if ((2*sz + 2 + lname) > bsz) return 0; + *(r++) = '_'; + r = SWIG_PackData(r,ptr,sz); + if (lname) { + strncpy(r,name,lname+1); + } else { + *r = 0; + } + return buff; +} + +SWIGRUNTIME const char * +SWIG_UnpackDataName(const char *c, void *ptr, size_t sz, const char *name) { + if (*c != '_') { + if (strcmp(c,"NULL") == 0) { + memset(ptr,0,sz); + return name; + } else { + return 0; + } + } + return SWIG_UnpackData(++c,ptr,sz); +} + +#ifdef __cplusplus +} +#endif + +/* Errors in SWIG */ +#define SWIG_UnknownError -1 +#define SWIG_IOError -2 +#define SWIG_RuntimeError -3 +#define SWIG_IndexError -4 +#define SWIG_TypeError -5 +#define SWIG_DivisionByZero -6 +#define SWIG_OverflowError -7 +#define SWIG_SyntaxError -8 +#define SWIG_ValueError -9 +#define SWIG_SystemError -10 +#define SWIG_AttributeError -11 +#define SWIG_MemoryError -12 +#define SWIG_NullReferenceError -13 + + + +#ifdef __cplusplus +/* Needed on some windows machines---since MS plays funny games with the header files under C++ */ +#include +#include +extern "C" { +#endif +#include "EXTERN.h" +#include "perl.h" +#include "XSUB.h" + +/* Add in functionality missing in older versions of Perl. Much of this is based on Devel-PPPort on cpan. */ + +/* Add PERL_REVISION, PERL_VERSION, PERL_SUBVERSION if missing */ +#ifndef PERL_REVISION +# if !defined(__PATCHLEVEL_H_INCLUDED__) && !(defined(PATCHLEVEL) && defined(SUBVERSION)) +# define PERL_PATCHLEVEL_H_IMPLICIT +# include +# endif +# if !(defined(PERL_VERSION) || (defined(SUBVERSION) && defined(PATCHLEVEL))) +# include +# endif +# ifndef PERL_REVISION +# define PERL_REVISION (5) +# define PERL_VERSION PATCHLEVEL +# define PERL_SUBVERSION SUBVERSION +# endif +#endif + +#if defined(WIN32) && defined(PERL_OBJECT) && !defined(PerlIO_exportFILE) +#define PerlIO_exportFILE(fh,fl) (FILE*)(fh) +#endif + +#ifndef SvIOK_UV +# define SvIOK_UV(sv) (SvIOK(sv) && (SvUVX(sv) == SvIVX(sv))) +#endif + +#ifndef SvUOK +# define SvUOK(sv) SvIOK_UV(sv) +#endif + +#if ((PERL_VERSION < 4) || ((PERL_VERSION == 4) && (PERL_SUBVERSION <= 5))) +# define PL_sv_undef sv_undef +# define PL_na na +# define PL_errgv errgv +# define PL_sv_no sv_no +# define PL_sv_yes sv_yes +# define PL_markstack_ptr markstack_ptr +#endif + +#ifndef IVSIZE +# ifdef LONGSIZE +# define IVSIZE LONGSIZE +# else +# define IVSIZE 4 /* A bold guess, but the best we can make. */ +# endif +#endif + +#ifndef INT2PTR +# if (IVSIZE == PTRSIZE) && (UVSIZE == PTRSIZE) +# define PTRV UV +# define INT2PTR(any,d) (any)(d) +# else +# if PTRSIZE == LONGSIZE +# define PTRV unsigned long +# else +# define PTRV unsigned +# endif +# define INT2PTR(any,d) (any)(PTRV)(d) +# endif + +# define NUM2PTR(any,d) (any)(PTRV)(d) +# define PTR2IV(p) INT2PTR(IV,p) +# define PTR2UV(p) INT2PTR(UV,p) +# define PTR2NV(p) NUM2PTR(NV,p) + +# if PTRSIZE == LONGSIZE +# define PTR2ul(p) (unsigned long)(p) +# else +# define PTR2ul(p) INT2PTR(unsigned long,p) +# endif +#endif /* !INT2PTR */ + +#ifndef SvPV_nolen +# define SvPV_nolen(x) SvPV(x,PL_na) +#endif + +#ifndef get_sv +# define get_sv perl_get_sv +#endif + +#ifndef ERRSV +# define ERRSV get_sv("@",FALSE) +#endif + +#ifndef pTHX_ +#define pTHX_ +#endif + +#include +#ifdef __cplusplus +} +#endif + +/* ----------------------------------------------------------------------------- + * error manipulation + * ----------------------------------------------------------------------------- */ + +SWIGINTERN const char* +SWIG_Perl_ErrorType(int code) { + const char* type = 0; + switch(code) { + case SWIG_MemoryError: + type = "MemoryError"; + break; + case SWIG_IOError: + type = "IOError"; + break; + case SWIG_RuntimeError: + type = "RuntimeError"; + break; + case SWIG_IndexError: + type = "IndexError"; + break; + case SWIG_TypeError: + type = "TypeError"; + break; + case SWIG_DivisionByZero: + type = "ZeroDivisionError"; + break; + case SWIG_OverflowError: + type = "OverflowError"; + break; + case SWIG_SyntaxError: + type = "SyntaxError"; + break; + case SWIG_ValueError: + type = "ValueError"; + break; + case SWIG_SystemError: + type = "SystemError"; + break; + case SWIG_AttributeError: + type = "AttributeError"; + break; + default: + type = "RuntimeError"; + } + return type; +} + + + + +/* ----------------------------------------------------------------------------- + * perlrun.swg + * + * This file contains the runtime support for Perl modules + * and includes code for managing global variables and pointer + * type checking. + * ----------------------------------------------------------------------------- */ + +#ifdef PERL_OBJECT +#define SWIG_PERL_OBJECT_DECL CPerlObj *SWIGUNUSEDPARM(pPerl), +#define SWIG_PERL_OBJECT_CALL pPerl, +#else +#define SWIG_PERL_OBJECT_DECL +#define SWIG_PERL_OBJECT_CALL +#endif + +/* Common SWIG API */ + +/* for raw pointers */ +#define SWIG_ConvertPtr(obj, pp, type, flags) SWIG_Perl_ConvertPtr(SWIG_PERL_OBJECT_CALL obj, pp, type, flags) +#define SWIG_NewPointerObj(p, type, flags) SWIG_Perl_NewPointerObj(SWIG_PERL_OBJECT_CALL p, type, flags) + +/* for raw packed data */ +#define SWIG_ConvertPacked(obj, p, s, type) SWIG_Perl_ConvertPacked(SWIG_PERL_OBJECT_CALL obj, p, s, type) +#define SWIG_NewPackedObj(p, s, type) SWIG_Perl_NewPackedObj(SWIG_PERL_OBJECT_CALL p, s, type) + +/* for class or struct pointers */ +#define SWIG_ConvertInstance(obj, pptr, type, flags) SWIG_ConvertPtr(obj, pptr, type, flags) +#define SWIG_NewInstanceObj(ptr, type, flags) SWIG_NewPointerObj(ptr, type, flags) + +/* for C or C++ function pointers */ +#define SWIG_ConvertFunctionPtr(obj, pptr, type) SWIG_ConvertPtr(obj, pptr, type, 0) +#define SWIG_NewFunctionPtrObj(ptr, type) SWIG_NewPointerObj(ptr, type, 0) + +/* for C++ member pointers, ie, member methods */ +#define SWIG_ConvertMember(obj, ptr, sz, ty) SWIG_ConvertPacked(obj, ptr, sz, ty) +#define SWIG_NewMemberObj(ptr, sz, type) SWIG_NewPackedObj(ptr, sz, type) + + +/* Runtime API */ + +#define SWIG_GetModule(clientdata) SWIG_Perl_GetModule() +#define SWIG_SetModule(clientdata, pointer) SWIG_Perl_SetModule(pointer) + + +/* Error manipulation */ + +#define SWIG_ErrorType(code) SWIG_Perl_ErrorType(code) +#define SWIG_Error(code, msg) sv_setpvf(GvSV(PL_errgv),"%s %s\n", SWIG_ErrorType(code), msg) +#define SWIG_fail goto fail + +/* Perl-specific SWIG API */ + +#define SWIG_MakePtr(sv, ptr, type, flags) SWIG_Perl_MakePtr(SWIG_PERL_OBJECT_CALL sv, ptr, type, flags) +#define SWIG_MakePackedObj(sv, p, s, type) SWIG_Perl_MakePackedObj(SWIG_PERL_OBJECT_CALL sv, p, s, type) +#define SWIG_SetError(str) SWIG_Error(SWIG_RuntimeError, str) + + +#define SWIG_PERL_DECL_ARGS_1(arg1) (SWIG_PERL_OBJECT_DECL arg1) +#define SWIG_PERL_CALL_ARGS_1(arg1) (SWIG_PERL_OBJECT_CALL arg1) +#define SWIG_PERL_DECL_ARGS_2(arg1, arg2) (SWIG_PERL_OBJECT_DECL arg1, arg2) +#define SWIG_PERL_CALL_ARGS_2(arg1, arg2) (SWIG_PERL_OBJECT_CALL arg1, arg2) + +/* ----------------------------------------------------------------------------- + * pointers/data manipulation + * ----------------------------------------------------------------------------- */ + +/* For backward compatibility only */ +#define SWIG_POINTER_EXCEPTION 0 + +#ifdef __cplusplus +extern "C" { +#endif + +#define SWIG_OWNER SWIG_POINTER_OWN +#define SWIG_SHADOW SWIG_OWNER << 1 + +#define SWIG_MAYBE_PERL_OBJECT SWIG_PERL_OBJECT_DECL + +/* SWIG Perl macros */ + +/* Macro to declare an XS function */ +#ifndef XSPROTO +# define XSPROTO(name) void name(pTHX_ CV* cv) +#endif + +/* Macro to call an XS function */ +#ifdef PERL_OBJECT +# define SWIG_CALLXS(_name) _name(cv,pPerl) +#else +# ifndef MULTIPLICITY +# define SWIG_CALLXS(_name) _name(cv) +# else +# define SWIG_CALLXS(_name) _name(PERL_GET_THX, cv) +# endif +#endif + +#ifdef PERL_OBJECT +#define MAGIC_PPERL CPerlObj *pPerl = (CPerlObj *) this; + +#ifdef __cplusplus +extern "C" { +#endif +typedef int (CPerlObj::*SwigMagicFunc)(SV *, MAGIC *); +#ifdef __cplusplus +} +#endif + +#define SWIG_MAGIC(a,b) (SV *a, MAGIC *b) +#define SWIGCLASS_STATIC + +#else /* PERL_OBJECT */ + +#define MAGIC_PPERL +#define SWIGCLASS_STATIC static SWIGUNUSED + +#ifndef MULTIPLICITY +#define SWIG_MAGIC(a,b) (SV *a, MAGIC *b) + +#ifdef __cplusplus +extern "C" { +#endif +typedef int (*SwigMagicFunc)(SV *, MAGIC *); +#ifdef __cplusplus +} +#endif + +#else /* MULTIPLICITY */ + +#define SWIG_MAGIC(a,b) (struct interpreter *interp, SV *a, MAGIC *b) + +#ifdef __cplusplus +extern "C" { +#endif +typedef int (*SwigMagicFunc)(struct interpreter *, SV *, MAGIC *); +#ifdef __cplusplus +} +#endif + +#endif /* MULTIPLICITY */ +#endif /* PERL_OBJECT */ + +/* Workaround for bug in perl 5.6.x croak and earlier */ +#if (PERL_VERSION < 8) +# ifdef PERL_OBJECT +# define SWIG_croak_null() SWIG_Perl_croak_null(pPerl) +static void SWIG_Perl_croak_null(CPerlObj *pPerl) +# else +static void SWIG_croak_null() +# endif +{ + SV *err=ERRSV; +# if (PERL_VERSION < 6) + croak("%_", err); +# else + if (SvOK(err) && !SvROK(err)) croak("%_", err); + croak(Nullch); +# endif +} +#else +# define SWIG_croak_null() croak(Nullch) +#endif + + +/* + Define how strict is the cast between strings and integers/doubles + when overloading between these types occurs. + + The default is making it as strict as possible by using SWIG_AddCast + when needed. + + You can use -DSWIG_PERL_NO_STRICT_STR2NUM at compilation time to + disable the SWIG_AddCast, making the casting between string and + numbers less strict. + + In the end, we try to solve the overloading between strings and + numerical types in the more natural way, but if you can avoid it, + well, avoid it using %rename, for example. +*/ +#ifndef SWIG_PERL_NO_STRICT_STR2NUM +# ifndef SWIG_PERL_STRICT_STR2NUM +# define SWIG_PERL_STRICT_STR2NUM +# endif +#endif +#ifdef SWIG_PERL_STRICT_STR2NUM +/* string takes precedence */ +#define SWIG_Str2NumCast(x) SWIG_AddCast(x) +#else +/* number takes precedence */ +#define SWIG_Str2NumCast(x) x +#endif + + + +#include + +SWIGRUNTIME const char * +SWIG_Perl_TypeProxyName(const swig_type_info *type) { + if (!type) return NULL; + if (type->clientdata != NULL) { + return (const char*) type->clientdata; + } + else { + return type->name; + } +} + +SWIGRUNTIME swig_cast_info * +SWIG_TypeProxyCheck(const char *c, swig_type_info *ty) { + SWIG_TypeCheck_Template(( (!iter->type->clientdata && (strcmp(iter->type->name, c) == 0)) + || (iter->type->clientdata && (strcmp((char*)iter->type->clientdata, c) == 0))), ty); +} + + +/* Function for getting a pointer value */ + +SWIGRUNTIME int +SWIG_Perl_ConvertPtr(SWIG_MAYBE_PERL_OBJECT SV *sv, void **ptr, swig_type_info *_t, int flags) { + swig_cast_info *tc; + void *voidptr = (void *)0; + SV *tsv = 0; + /* If magical, apply more magic */ + if (SvGMAGICAL(sv)) + mg_get(sv); + + /* Check to see if this is an object */ + if (sv_isobject(sv)) { + IV tmp = 0; + tsv = (SV*) SvRV(sv); + if ((SvTYPE(tsv) == SVt_PVHV)) { + MAGIC *mg; + if (SvMAGICAL(tsv)) { + mg = mg_find(tsv,'P'); + if (mg) { + sv = mg->mg_obj; + if (sv_isobject(sv)) { + tsv = (SV*)SvRV(sv); + tmp = SvIV(tsv); + } + } + } else { + return SWIG_ERROR; + } + } else { + tmp = SvIV(tsv); + } + voidptr = INT2PTR(void *,tmp); + } else if (! SvOK(sv)) { /* Check for undef */ + *(ptr) = (void *) 0; + return SWIG_OK; + } else if (SvTYPE(sv) == SVt_RV) { /* Check for NULL pointer */ + if (!SvROK(sv)) { + *(ptr) = (void *) 0; + return SWIG_OK; + } else { + return SWIG_ERROR; + } + } else { /* Don't know what it is */ + return SWIG_ERROR; + } + if (_t) { + /* Now see if the types match */ + char *_c = HvNAME(SvSTASH(SvRV(sv))); + tc = SWIG_TypeProxyCheck(_c,_t); + if (!tc) { + return SWIG_ERROR; + } + { + int newmemory = 0; + *ptr = SWIG_TypeCast(tc,voidptr,&newmemory); + assert(!newmemory); /* newmemory handling not yet implemented */ + } + } else { + *ptr = voidptr; + } + + /* + * DISOWN implementation: we need a perl guru to check this one. + */ + if (tsv && (flags & SWIG_POINTER_DISOWN)) { + /* + * almost copy paste code from below SWIG_POINTER_OWN setting + */ + SV *obj = sv; + HV *stash = SvSTASH(SvRV(obj)); + GV *gv = *(GV**) hv_fetch(stash, "OWNER", 5, TRUE); + if (isGV(gv)) { + HV *hv = GvHVn(gv); + /* + * To set ownership (see below), a newSViv(1) entry is added. + * Hence, to remove ownership, we delete the entry. + */ + if (hv_exists_ent(hv, obj, 0)) { + hv_delete_ent(hv, obj, 0, 0); + } + } + } + return SWIG_OK; +} + +SWIGRUNTIME void +SWIG_Perl_MakePtr(SWIG_MAYBE_PERL_OBJECT SV *sv, void *ptr, swig_type_info *t, int flags) { + if (ptr && (flags & SWIG_SHADOW)) { + SV *self; + SV *obj=newSV(0); + HV *hash=newHV(); + HV *stash; + sv_setref_pv(obj, (char *) SWIG_Perl_TypeProxyName(t), ptr); + stash=SvSTASH(SvRV(obj)); + if (flags & SWIG_POINTER_OWN) { + HV *hv; + GV *gv=*(GV**)hv_fetch(stash, "OWNER", 5, TRUE); + if (!isGV(gv)) + gv_init(gv, stash, "OWNER", 5, FALSE); + hv=GvHVn(gv); + hv_store_ent(hv, obj, newSViv(1), 0); + } + sv_magic((SV *)hash, (SV *)obj, 'P', Nullch, 0); + SvREFCNT_dec(obj); + self=newRV_noinc((SV *)hash); + sv_setsv(sv, self); + SvREFCNT_dec((SV *)self); + sv_bless(sv, stash); + } + else { + sv_setref_pv(sv, (char *) SWIG_Perl_TypeProxyName(t), ptr); + } +} + +SWIGRUNTIMEINLINE SV * +SWIG_Perl_NewPointerObj(SWIG_MAYBE_PERL_OBJECT void *ptr, swig_type_info *t, int flags) { + SV *result = sv_newmortal(); + SWIG_MakePtr(result, ptr, t, flags); + return result; +} + +SWIGRUNTIME void +SWIG_Perl_MakePackedObj(SWIG_MAYBE_PERL_OBJECT SV *sv, void *ptr, int sz, swig_type_info *type) { + char result[1024]; + char *r = result; + if ((2*sz + 1 + strlen(SWIG_Perl_TypeProxyName(type))) > 1000) return; + *(r++) = '_'; + r = SWIG_PackData(r,ptr,sz); + strcpy(r,SWIG_Perl_TypeProxyName(type)); + sv_setpv(sv, result); +} + +SWIGRUNTIME SV * +SWIG_Perl_NewPackedObj(SWIG_MAYBE_PERL_OBJECT void *ptr, int sz, swig_type_info *type) { + SV *result = sv_newmortal(); + SWIG_Perl_MakePackedObj(result, ptr, sz, type); + return result; +} + +/* Convert a packed value value */ +SWIGRUNTIME int +SWIG_Perl_ConvertPacked(SWIG_MAYBE_PERL_OBJECT SV *obj, void *ptr, int sz, swig_type_info *ty) { + swig_cast_info *tc; + const char *c = 0; + + if ((!obj) || (!SvOK(obj))) return SWIG_ERROR; + c = SvPV_nolen(obj); + /* Pointer values must start with leading underscore */ + if (*c != '_') return SWIG_ERROR; + c++; + c = SWIG_UnpackData(c,ptr,sz); + if (ty) { + tc = SWIG_TypeCheck(c,ty); + if (!tc) return SWIG_ERROR; + } + return SWIG_OK; +} + + +/* Macros for low-level exception handling */ +#define SWIG_croak(x) { SWIG_Error(SWIG_RuntimeError, x); SWIG_fail; } + + +typedef XSPROTO(SwigPerlWrapper); +typedef SwigPerlWrapper *SwigPerlWrapperPtr; + +/* Structure for command table */ +typedef struct { + const char *name; + SwigPerlWrapperPtr wrapper; +} swig_command_info; + +/* Information for constant table */ + +#define SWIG_INT 1 +#define SWIG_FLOAT 2 +#define SWIG_STRING 3 +#define SWIG_POINTER 4 +#define SWIG_BINARY 5 + +/* Constant information structure */ +typedef struct swig_constant_info { + int type; + const char *name; + long lvalue; + double dvalue; + void *pvalue; + swig_type_info **ptype; +} swig_constant_info; + + +/* Structure for variable table */ +typedef struct { + const char *name; + SwigMagicFunc set; + SwigMagicFunc get; + swig_type_info **type; +} swig_variable_info; + +/* Magic variable code */ +#ifndef PERL_OBJECT +#define swig_create_magic(s,a,b,c) _swig_create_magic(s,a,b,c) + #ifndef MULTIPLICITY + SWIGRUNTIME void _swig_create_magic(SV *sv, char *name, int (*set)(SV *, MAGIC *), int (*get)(SV *,MAGIC *)) + #else + SWIGRUNTIME void _swig_create_magic(SV *sv, char *name, int (*set)(struct interpreter*, SV *, MAGIC *), int (*get)(struct interpreter*, SV *,MAGIC *)) + #endif +#else +# define swig_create_magic(s,a,b,c) _swig_create_magic(pPerl,s,a,b,c) +SWIGRUNTIME void _swig_create_magic(CPerlObj *pPerl, SV *sv, const char *name, int (CPerlObj::*set)(SV *, MAGIC *), int (CPerlObj::*get)(SV *, MAGIC *)) +#endif +{ + MAGIC *mg; + sv_magic(sv,sv,'U',(char *) name,strlen(name)); + mg = mg_find(sv,'U'); + mg->mg_virtual = (MGVTBL *) malloc(sizeof(MGVTBL)); + mg->mg_virtual->svt_get = (SwigMagicFunc) get; + mg->mg_virtual->svt_set = (SwigMagicFunc) set; + mg->mg_virtual->svt_len = 0; + mg->mg_virtual->svt_clear = 0; + mg->mg_virtual->svt_free = 0; +} + + +SWIGRUNTIME swig_module_info * +SWIG_Perl_GetModule(void) { + static void *type_pointer = (void *)0; + SV *pointer; + + /* first check if pointer already created */ + if (!type_pointer) { + pointer = get_sv("swig_runtime_data::type_pointer" SWIG_RUNTIME_VERSION SWIG_TYPE_TABLE_NAME, FALSE | GV_ADDMULTI); + if (pointer && SvOK(pointer)) { + type_pointer = INT2PTR(swig_type_info **, SvIV(pointer)); + } + } + + return (swig_module_info *) type_pointer; +} + +SWIGRUNTIME void +SWIG_Perl_SetModule(swig_module_info *module) { + SV *pointer; + + /* create a new pointer */ + pointer = get_sv("swig_runtime_data::type_pointer" SWIG_RUNTIME_VERSION SWIG_TYPE_TABLE_NAME, TRUE | GV_ADDMULTI); + sv_setiv(pointer, PTR2IV(module)); +} + +#ifdef __cplusplus +} +#endif + +/* Workaround perl5 global namespace pollution. Note that undefining library + * functions like fopen will not solve the problem on all platforms as fopen + * might be a macro on Windows but not necessarily on other operating systems. */ +#ifdef do_open + #undef do_open +#endif +#ifdef do_close + #undef do_close +#endif +#ifdef scalar + #undef scalar +#endif +#ifdef list + #undef list +#endif +#ifdef apply + #undef apply +#endif +#ifdef convert + #undef convert +#endif +#ifdef Error + #undef Error +#endif +#ifdef form + #undef form +#endif +#ifdef vform + #undef vform +#endif +#ifdef LABEL + #undef LABEL +#endif +#ifdef METHOD + #undef METHOD +#endif +#ifdef Move + #undef Move +#endif +#ifdef yylex + #undef yylex +#endif +#ifdef yyparse + #undef yyparse +#endif +#ifdef yyerror + #undef yyerror +#endif +#ifdef invert + #undef invert +#endif +#ifdef ref + #undef ref +#endif +#ifdef read + #undef read +#endif +#ifdef write + #undef write +#endif +#ifdef eof + #undef eof +#endif +#ifdef bool + #undef bool +#endif +#ifdef close + #undef close +#endif +#ifdef rewind + #undef rewind +#endif +#ifdef free + #undef free +#endif +#ifdef malloc + #undef malloc +#endif +#ifdef calloc + #undef calloc +#endif +#ifdef Stat + #undef Stat +#endif +#ifdef check + #undef check +#endif +#ifdef seekdir + #undef seekdir +#endif +#ifdef open + #undef open +#endif + + + +#define SWIG_exception_fail(code, msg) do { SWIG_Error(code, msg); SWIG_fail; } while(0) + +#define SWIG_contract_assert(expr, msg) if (!(expr)) { SWIG_Error(SWIG_RuntimeError, msg); SWIG_fail; } else + + + +/* -------- TYPES TABLE (BEGIN) -------- */ + +#define SWIGTYPE_p_McastHandle swig_types[0] +#define SWIGTYPE_p_char swig_types[1] +static swig_type_info *swig_types[3]; +static swig_module_info swig_module = {swig_types, 2, 0, 0, 0, 0}; +#define SWIG_TypeQuery(name) SWIG_TypeQueryModule(&swig_module, &swig_module, name) +#define SWIG_MangledTypeQuery(name) SWIG_MangledTypeQueryModule(&swig_module, &swig_module, name) + +/* -------- TYPES TABLE (END) -------- */ + +#define SWIG_init boot_MCAST + +#define SWIG_name "MCASTc::boot_MCAST" +#define SWIG_prefix "MCASTc::" + +#define SWIGVERSION 0x010335 +#define SWIG_VERSION SWIGVERSION + + +#define SWIG_as_voidptr(a) const_cast< void * >(static_cast< const void * >(a)) +#define SWIG_as_voidptrptr(a) ((void)SWIG_as_voidptr(*a),reinterpret_cast< void** >(a)) + + +#include + + +#ifdef __cplusplus +extern "C" +#endif +#ifndef PERL_OBJECT +#ifndef MULTIPLICITY +SWIGEXPORT void SWIG_init (CV* cv); +#else +SWIGEXPORT void SWIG_init (pTHXo_ CV* cv); +#endif +#else +SWIGEXPORT void SWIG_init (CV *cv, CPerlObj *); +#endif + + +#include "mcast.h" +#include "mcast_cpp.h" + + +SWIGINTERN swig_type_info* +SWIG_pchar_descriptor(void) +{ + static int init = 0; + static swig_type_info* info = 0; + if (!init) { + info = SWIG_TypeQuery("_p_char"); + init = 1; + } + return info; +} + + +SWIGINTERN int +SWIG_AsCharPtrAndSize(SV *obj, char** cptr, size_t* psize, int *alloc) +{ + if (SvPOK(obj)) { + STRLEN len = 0; + char *cstr = SvPV(obj, len); + size_t size = len + 1; + if (cptr) { + if (alloc) { + if (*alloc == SWIG_NEWOBJ) { + *cptr = reinterpret_cast< char* >(memcpy((new char[size]), cstr, sizeof(char)*(size))); + } else { + *cptr = cstr; + *alloc = SWIG_OLDOBJ; + } + } + } + if (psize) *psize = size; + return SWIG_OK; + } else { + swig_type_info* pchar_descriptor = SWIG_pchar_descriptor(); + if (pchar_descriptor) { + char* vptr = 0; + if (SWIG_ConvertPtr(obj, (void**)&vptr, pchar_descriptor, 0) == SWIG_OK) { + if (cptr) *cptr = vptr; + if (psize) *psize = vptr ? (strlen(vptr) + 1) : 0; + if (alloc) *alloc = SWIG_OLDOBJ; + return SWIG_OK; + } + } + } + return SWIG_TypeError; +} + + + + + +#include +#if !defined(SWIG_NO_LLONG_MAX) +# if !defined(LLONG_MAX) && defined(__GNUC__) && defined (__LONG_LONG_MAX__) +# define LLONG_MAX __LONG_LONG_MAX__ +# define LLONG_MIN (-LLONG_MAX - 1LL) +# define ULLONG_MAX (LLONG_MAX * 2ULL + 1ULL) +# endif +#endif + + +SWIGINTERN int +SWIG_AsVal_double SWIG_PERL_DECL_ARGS_2(SV *obj, double *val) +{ + if (SvNIOK(obj)) { + if (val) *val = SvNV(obj); + return SWIG_OK; + } else if (SvIOK(obj)) { + if (val) *val = (double) SvIV(obj); + return SWIG_AddCast(SWIG_OK); + } else { + const char *nptr = SvPV_nolen(obj); + if (nptr) { + char *endptr; + double v = strtod(nptr, &endptr); + if (errno == ERANGE) { + errno = 0; + return SWIG_OverflowError; + } else { + if (*endptr == '\0') { + if (val) *val = v; + return SWIG_Str2NumCast(SWIG_OK); + } + } + } + } + return SWIG_TypeError; +} + + +#include + + +#include + + +SWIGINTERNINLINE int +SWIG_CanCastAsInteger(double *d, double min, double max) { + double x = *d; + if ((min <= x && x <= max)) { + double fx = floor(x); + double cx = ceil(x); + double rd = ((x - fx) < 0.5) ? fx : cx; /* simple rint */ + if ((errno == EDOM) || (errno == ERANGE)) { + errno = 0; + } else { + double summ, reps, diff; + if (rd < x) { + diff = x - rd; + } else if (rd > x) { + diff = rd - x; + } else { + return 1; + } + summ = rd + x; + reps = diff/summ; + if (reps < 8*DBL_EPSILON) { + *d = rd; + return 1; + } + } + } + return 0; +} + + +SWIGINTERN int +SWIG_AsVal_long SWIG_PERL_DECL_ARGS_2(SV *obj, long* val) +{ + if (SvIOK(obj)) { + if (val) *val = SvIV(obj); + return SWIG_OK; + } else { + int dispatch = 0; + const char *nptr = SvPV_nolen(obj); + if (nptr) { + char *endptr; + long v; + errno = 0; + v = strtol(nptr, &endptr,0); + if (errno == ERANGE) { + errno = 0; + return SWIG_OverflowError; + } else { + if (*endptr == '\0') { + if (val) *val = v; + return SWIG_Str2NumCast(SWIG_OK); + } + } + } + if (!dispatch) { + double d; + int res = SWIG_AddCast(SWIG_AsVal_double SWIG_PERL_CALL_ARGS_2(obj,&d)); + if (SWIG_IsOK(res) && SWIG_CanCastAsInteger(&d, LONG_MIN, LONG_MAX)) { + if (val) *val = (long)(d); + return res; + } + } + } + return SWIG_TypeError; +} + + +SWIGINTERN int +SWIG_AsVal_int SWIG_PERL_DECL_ARGS_2(SV * obj, int *val) +{ + long v; + int res = SWIG_AsVal_long SWIG_PERL_CALL_ARGS_2(obj, &v); + if (SWIG_IsOK(res)) { + if ((v < INT_MIN || v > INT_MAX)) { + return SWIG_OverflowError; + } else { + if (val) *val = static_cast< int >(v); + } + } + return res; +} + + +SWIGINTERNINLINE SV * +SWIG_From_long SWIG_PERL_DECL_ARGS_1(long value) +{ + SV *obj = sv_newmortal(); + sv_setiv(obj, (IV) value); + return obj; +} + + +SWIGINTERNINLINE SV * +SWIG_From_int SWIG_PERL_DECL_ARGS_1(int value) +{ + return SWIG_From_long SWIG_PERL_CALL_ARGS_1(value); +} + + +SWIGINTERNINLINE SV * +SWIG_FromCharPtrAndSize(const char* carray, size_t size) +{ + SV *obj = sv_newmortal(); + if (carray) { + sv_setpvn(obj, carray, size); + } else { + sv_setsv(obj, &PL_sv_undef); + } + return obj; +} + + +SWIGINTERNINLINE SV * +SWIG_FromCharPtr(const char *cptr) +{ + return SWIG_FromCharPtrAndSize(cptr, (cptr ? strlen(cptr) : 0)); +} + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef PERL_OBJECT +#define MAGIC_CLASS _wrap_MCAST_var:: +class _wrap_MCAST_var : public CPerlObj { +public: +#else +#define MAGIC_CLASS +#endif +SWIGCLASS_STATIC int swig_magic_readonly(pTHX_ SV *SWIGUNUSEDPARM(sv), MAGIC *SWIGUNUSEDPARM(mg)) { + MAGIC_PPERL + croak("Value is read-only."); + return 0; +} + + +#ifdef PERL_OBJECT +}; +#endif + +#ifdef __cplusplus +} +#endif + +#ifdef __cplusplus +extern "C" { +#endif +XS(_wrap_new_McastHandle) { + { + char *arg1 = (char *) 0 ; + int arg2 ; + int arg3 ; + McastHandle *result = 0 ; + int res1 ; + char *buf1 = 0 ; + int alloc1 = 0 ; + int val2 ; + int ecode2 = 0 ; + int val3 ; + int ecode3 = 0 ; + int argvi = 0; + dXSARGS; + + if ((items < 3) || (items > 3)) { + SWIG_croak("Usage: new_McastHandle(host,port,flags);"); + } + res1 = SWIG_AsCharPtrAndSize(ST(0), &buf1, NULL, &alloc1); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "new_McastHandle" "', argument " "1"" of type '" "char const *""'"); + } + arg1 = reinterpret_cast< char * >(buf1); + ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "new_McastHandle" "', argument " "2"" of type '" "int""'"); + } + arg2 = static_cast< int >(val2); + ecode3 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(2), &val3); + if (!SWIG_IsOK(ecode3)) { + SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "new_McastHandle" "', argument " "3"" of type '" "int""'"); + } + arg3 = static_cast< int >(val3); + result = (McastHandle *)new McastHandle((char const *)arg1,arg2,arg3); + ST(argvi) = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_McastHandle, SWIG_OWNER | SWIG_SHADOW); argvi++ ; + if (alloc1 == SWIG_NEWOBJ) delete[] buf1; + + + XSRETURN(argvi); + fail: + if (alloc1 == SWIG_NEWOBJ) delete[] buf1; + + + SWIG_croak_null(); + } +} + + +XS(_wrap_delete_McastHandle) { + { + McastHandle *arg1 = (McastHandle *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int argvi = 0; + dXSARGS; + + if ((items < 1) || (items > 1)) { + SWIG_croak("Usage: delete_McastHandle(self);"); + } + res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_McastHandle, SWIG_POINTER_DISOWN | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_McastHandle" "', argument " "1"" of type '" "McastHandle *""'"); + } + arg1 = reinterpret_cast< McastHandle * >(argp1); + delete arg1; + + + + XSRETURN(argvi); + fail: + + SWIG_croak_null(); + } +} + + +XS(_wrap_McastHandle_send) { + { + McastHandle *arg1 = (McastHandle *) 0 ; + char *arg2 = (char *) 0 ; + int result; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + int argvi = 0; + dXSARGS; + + if ((items < 2) || (items > 2)) { + SWIG_croak("Usage: McastHandle_send(self,data);"); + } + res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_McastHandle, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "McastHandle_send" "', argument " "1"" of type '" "McastHandle *""'"); + } + arg1 = reinterpret_cast< McastHandle * >(argp1); + res2 = SWIG_AsCharPtrAndSize(ST(1), &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "McastHandle_send" "', argument " "2"" of type '" "char const *""'"); + } + arg2 = reinterpret_cast< char * >(buf2); + result = (int)(arg1)->send((char const *)arg2); + ST(argvi) = SWIG_From_int SWIG_PERL_CALL_ARGS_1(static_cast< int >(result)); argvi++ ; + + if (alloc2 == SWIG_NEWOBJ) delete[] buf2; + XSRETURN(argvi); + fail: + + if (alloc2 == SWIG_NEWOBJ) delete[] buf2; + SWIG_croak_null(); + } +} + + +XS(_wrap_McastHandle_recv) { + { + McastHandle *arg1 = (McastHandle *) 0 ; + int arg2 = (int) 0 ; + char *result = 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + int val2 ; + int ecode2 = 0 ; + int argvi = 0; + dXSARGS; + + if ((items < 1) || (items > 2)) { + SWIG_croak("Usage: McastHandle_recv(self,ms);"); + } + res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_McastHandle, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "McastHandle_recv" "', argument " "1"" of type '" "McastHandle *""'"); + } + arg1 = reinterpret_cast< McastHandle * >(argp1); + if (items > 1) { + ecode2 = SWIG_AsVal_int SWIG_PERL_CALL_ARGS_2(ST(1), &val2); + if (!SWIG_IsOK(ecode2)) { + SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "McastHandle_recv" "', argument " "2"" of type '" "int""'"); + } + arg2 = static_cast< int >(val2); + } + result = (char *)(arg1)->recv(arg2); + ST(argvi) = SWIG_FromCharPtr((const char *)result); argvi++ ; + + + XSRETURN(argvi); + fail: + + + SWIG_croak_null(); + } +} + + +XS(_wrap_McastHandle_fileno) { + { + McastHandle *arg1 = (McastHandle *) 0 ; + int result; + void *argp1 = 0 ; + int res1 = 0 ; + int argvi = 0; + dXSARGS; + + if ((items < 1) || (items > 1)) { + SWIG_croak("Usage: McastHandle_fileno(self);"); + } + res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_McastHandle, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "McastHandle_fileno" "', argument " "1"" of type '" "McastHandle *""'"); + } + arg1 = reinterpret_cast< McastHandle * >(argp1); + result = (int)(arg1)->fileno(); + ST(argvi) = SWIG_From_int SWIG_PERL_CALL_ARGS_1(static_cast< int >(result)); argvi++ ; + + XSRETURN(argvi); + fail: + + SWIG_croak_null(); + } +} + + + +/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (BEGIN) -------- */ + +static swig_type_info _swigt__p_McastHandle = {"_p_McastHandle", "McastHandle *", 0, 0, (void*)"MCAST::McastHandle", 0}; +static swig_type_info _swigt__p_char = {"_p_char", "char *", 0, 0, (void*)0, 0}; + +static swig_type_info *swig_type_initial[] = { + &_swigt__p_McastHandle, + &_swigt__p_char, +}; + +static swig_cast_info _swigc__p_McastHandle[] = { {&_swigt__p_McastHandle, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_char[] = { {&_swigt__p_char, 0, 0, 0},{0, 0, 0, 0}}; + +static swig_cast_info *swig_cast_initial[] = { + _swigc__p_McastHandle, + _swigc__p_char, +}; + + +/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (END) -------- */ + +static swig_constant_info swig_constants[] = { +{0,0,0,0,0,0} +}; +#ifdef __cplusplus +} +#endif +static swig_variable_info swig_variables[] = { +{0,0,0,0} +}; +static swig_command_info swig_commands[] = { +{"MCASTc::new_McastHandle", _wrap_new_McastHandle}, +{"MCASTc::delete_McastHandle", _wrap_delete_McastHandle}, +{"MCASTc::McastHandle_send", _wrap_McastHandle_send}, +{"MCASTc::McastHandle_recv", _wrap_McastHandle_recv}, +{"MCASTc::McastHandle_fileno", _wrap_McastHandle_fileno}, +{0,0} +}; +/* ----------------------------------------------------------------------------- + * Type initialization: + * This problem is tough by the requirement that no dynamic + * memory is used. Also, since swig_type_info structures store pointers to + * swig_cast_info structures and swig_cast_info structures store pointers back + * to swig_type_info structures, we need some lookup code at initialization. + * The idea is that swig generates all the structures that are needed. + * The runtime then collects these partially filled structures. + * The SWIG_InitializeModule function takes these initial arrays out of + * swig_module, and does all the lookup, filling in the swig_module.types + * array with the correct data and linking the correct swig_cast_info + * structures together. + * + * The generated swig_type_info structures are assigned staticly to an initial + * array. We just loop through that array, and handle each type individually. + * First we lookup if this type has been already loaded, and if so, use the + * loaded structure instead of the generated one. Then we have to fill in the + * cast linked list. The cast data is initially stored in something like a + * two-dimensional array. Each row corresponds to a type (there are the same + * number of rows as there are in the swig_type_initial array). Each entry in + * a column is one of the swig_cast_info structures for that type. + * The cast_initial array is actually an array of arrays, because each row has + * a variable number of columns. So to actually build the cast linked list, + * we find the array of casts associated with the type, and loop through it + * adding the casts to the list. The one last trick we need to do is making + * sure the type pointer in the swig_cast_info struct is correct. + * + * First off, we lookup the cast->type name to see if it is already loaded. + * There are three cases to handle: + * 1) If the cast->type has already been loaded AND the type we are adding + * casting info to has not been loaded (it is in this module), THEN we + * replace the cast->type pointer with the type pointer that has already + * been loaded. + * 2) If BOTH types (the one we are adding casting info to, and the + * cast->type) are loaded, THEN the cast info has already been loaded by + * the previous module so we just ignore it. + * 3) Finally, if cast->type has not already been loaded, then we add that + * swig_cast_info to the linked list (because the cast->type) pointer will + * be correct. + * ----------------------------------------------------------------------------- */ + +#ifdef __cplusplus +extern "C" { +#if 0 +} /* c-mode */ +#endif +#endif + +#if 0 +#define SWIGRUNTIME_DEBUG +#endif + + +SWIGRUNTIME void +SWIG_InitializeModule(void *clientdata) { + size_t i; + swig_module_info *module_head, *iter; + int found, init; + + clientdata = clientdata; + + /* check to see if the circular list has been setup, if not, set it up */ + if (swig_module.next==0) { + /* Initialize the swig_module */ + swig_module.type_initial = swig_type_initial; + swig_module.cast_initial = swig_cast_initial; + swig_module.next = &swig_module; + init = 1; + } else { + init = 0; + } + + /* Try and load any already created modules */ + module_head = SWIG_GetModule(clientdata); + if (!module_head) { + /* This is the first module loaded for this interpreter */ + /* so set the swig module into the interpreter */ + SWIG_SetModule(clientdata, &swig_module); + module_head = &swig_module; + } else { + /* the interpreter has loaded a SWIG module, but has it loaded this one? */ + found=0; + iter=module_head; + do { + if (iter==&swig_module) { + found=1; + break; + } + iter=iter->next; + } while (iter!= module_head); + + /* if the is found in the list, then all is done and we may leave */ + if (found) return; + /* otherwise we must add out module into the list */ + swig_module.next = module_head->next; + module_head->next = &swig_module; + } + + /* When multiple interpeters are used, a module could have already been initialized in + a different interpreter, but not yet have a pointer in this interpreter. + In this case, we do not want to continue adding types... everything should be + set up already */ + if (init == 0) return; + + /* Now work on filling in swig_module.types */ +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: size %d\n", swig_module.size); +#endif + for (i = 0; i < swig_module.size; ++i) { + swig_type_info *type = 0; + swig_type_info *ret; + swig_cast_info *cast; + +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: type %d %s\n", i, swig_module.type_initial[i]->name); +#endif + + /* if there is another module already loaded */ + if (swig_module.next != &swig_module) { + type = SWIG_MangledTypeQueryModule(swig_module.next, &swig_module, swig_module.type_initial[i]->name); + } + if (type) { + /* Overwrite clientdata field */ +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: found type %s\n", type->name); +#endif + if (swig_module.type_initial[i]->clientdata) { + type->clientdata = swig_module.type_initial[i]->clientdata; +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: found and overwrite type %s \n", type->name); +#endif + } + } else { + type = swig_module.type_initial[i]; + } + + /* Insert casting types */ + cast = swig_module.cast_initial[i]; + while (cast->type) { + /* Don't need to add information already in the list */ + ret = 0; +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: look cast %s\n", cast->type->name); +#endif + if (swig_module.next != &swig_module) { + ret = SWIG_MangledTypeQueryModule(swig_module.next, &swig_module, cast->type->name); +#ifdef SWIGRUNTIME_DEBUG + if (ret) printf("SWIG_InitializeModule: found cast %s\n", ret->name); +#endif + } + if (ret) { + if (type == swig_module.type_initial[i]) { +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: skip old type %s\n", ret->name); +#endif + cast->type = ret; + ret = 0; + } else { + /* Check for casting already in the list */ + swig_cast_info *ocast = SWIG_TypeCheck(ret->name, type); +#ifdef SWIGRUNTIME_DEBUG + if (ocast) printf("SWIG_InitializeModule: skip old cast %s\n", ret->name); +#endif + if (!ocast) ret = 0; + } + } + + if (!ret) { +#ifdef SWIGRUNTIME_DEBUG + printf("SWIG_InitializeModule: adding cast %s\n", cast->type->name); +#endif + if (type->cast) { + type->cast->prev = cast; + cast->next = type->cast; + } + type->cast = cast; + } + cast++; + } + /* Set entry in modules->types array equal to the type */ + swig_module.types[i] = type; + } + swig_module.types[i] = 0; + +#ifdef SWIGRUNTIME_DEBUG + printf("**** SWIG_InitializeModule: Cast List ******\n"); + for (i = 0; i < swig_module.size; ++i) { + int j = 0; + swig_cast_info *cast = swig_module.cast_initial[i]; + printf("SWIG_InitializeModule: type %d %s\n", i, swig_module.type_initial[i]->name); + while (cast->type) { + printf("SWIG_InitializeModule: cast type %s\n", cast->type->name); + cast++; + ++j; + } + printf("---- Total casts: %d\n",j); + } + printf("**** SWIG_InitializeModule: Cast List ******\n"); +#endif +} + +/* This function will propagate the clientdata field of type to +* any new swig_type_info structures that have been added into the list +* of equivalent types. It is like calling +* SWIG_TypeClientData(type, clientdata) a second time. +*/ +SWIGRUNTIME void +SWIG_PropagateClientData(void) { + size_t i; + swig_cast_info *equiv; + static int init_run = 0; + + if (init_run) return; + init_run = 1; + + for (i = 0; i < swig_module.size; i++) { + if (swig_module.types[i]->clientdata) { + equiv = swig_module.types[i]->cast; + while (equiv) { + if (!equiv->converter) { + if (equiv->type && !equiv->type->clientdata) + SWIG_TypeClientData(equiv->type, swig_module.types[i]->clientdata); + } + equiv = equiv->next; + } + } + } +} + +#ifdef __cplusplus +#if 0 +{ + /* c-mode */ +#endif +} +#endif + + + +#ifdef __cplusplus +extern "C" +#endif + +XS(SWIG_init) { + dXSARGS; + int i; + + SWIG_InitializeModule(0); + + /* Install commands */ + for (i = 0; swig_commands[i].name; i++) { + newXS((char*) swig_commands[i].name,swig_commands[i].wrapper, (char*)__FILE__); + } + + /* Install variables */ + for (i = 0; swig_variables[i].name; i++) { + SV *sv; + sv = get_sv((char*) swig_variables[i].name, TRUE | 0x2 | GV_ADDMULTI); + if (swig_variables[i].type) { + SWIG_MakePtr(sv,(void *)1, *swig_variables[i].type,0); + } else { + sv_setiv(sv,(IV) 0); + } + swig_create_magic(sv, (char *) swig_variables[i].name, swig_variables[i].set, swig_variables[i].get); + } + + /* Install constant */ + for (i = 0; swig_constants[i].type; i++) { + SV *sv; + sv = get_sv((char*)swig_constants[i].name, TRUE | 0x2 | GV_ADDMULTI); + switch(swig_constants[i].type) { + case SWIG_INT: + sv_setiv(sv, (IV) swig_constants[i].lvalue); + break; + case SWIG_FLOAT: + sv_setnv(sv, (double) swig_constants[i].dvalue); + break; + case SWIG_STRING: + sv_setpv(sv, (char *) swig_constants[i].pvalue); + break; + case SWIG_POINTER: + SWIG_MakePtr(sv, swig_constants[i].pvalue, *(swig_constants[i].ptype),0); + break; + case SWIG_BINARY: + SWIG_MakePackedObj(sv, swig_constants[i].pvalue, swig_constants[i].lvalue, *(swig_constants[i].ptype)); + break; + default: + break; + } + SvREADONLY_on(sv); + } + + SWIG_TypeClientData(SWIGTYPE_p_McastHandle, (void*) "MCAST::McastHandle"); + ST(0) = &PL_sv_yes; + XSRETURN(1); +} + diff --git a/src/mod/endpoints/mod_verto/mcast/perlxsi.c b/src/mod/endpoints/mod_verto/mcast/perlxsi.c new file mode 100644 index 0000000000..9ca8fc1fb1 --- /dev/null +++ b/src/mod/endpoints/mod_verto/mcast/perlxsi.c @@ -0,0 +1,16 @@ +#include +#include + +EXTERN_C void xs_init (pTHX); + +EXTERN_C void boot_DynaLoader (pTHX_ CV* cv); + +EXTERN_C void +xs_init(pTHX) +{ + char *file = __FILE__; + dXSUB_SYS; + + /* DynaLoader is a special case */ + newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file); +} diff --git a/src/mod/endpoints/mod_verto/mcast/test.c b/src/mod/endpoints/mod_verto/mcast/test.c new file mode 100644 index 0000000000..2e07518285 --- /dev/null +++ b/src/mod/endpoints/mod_verto/mcast/test.c @@ -0,0 +1,29 @@ +#include +#include +#include +#include +#include "mcast.h" + +int main(int argc, char *argv[]) +{ + mcast_handle_t handle; + + if (argc < 2) { + printf("WTF\n"); + exit(-1); + } + + mcast_socket_create("231.3.3.7", 1337, &handle, MCAST_SEND | MCAST_RECV | MCAST_TTL_HOST); + perror("create"); + + if (!strcmp(argv[1], "send")) { + mcast_socket_send(&handle, argv[2], strlen(argv[2])); + exit(0); + } + + for(;;) { + int r = mcast_socket_recv(&handle, NULL, 0); + printf("RECV %d [%s]\n", r, (char *)handle.buffer); + } + +} diff --git a/src/mod/endpoints/mod_verto/mcast/test.pl b/src/mod/endpoints/mod_verto/mcast/test.pl new file mode 100644 index 0000000000..ca8b58aa30 --- /dev/null +++ b/src/mod/endpoints/mod_verto/mcast/test.pl @@ -0,0 +1,19 @@ +use MCAST; + +my $s = new MCAST::McastHandle("231.3.3.7", 1337, MCAST_SEND | MCAST_RECV | MCAST_TTL_HOST); + +my $action = shift; + +if ($action eq "send") { + $s->send("W00t from Perl " . shift); + exit; +} + +for(;;) { + my $foo = $s->recv(100); + if ($foo) { + print "RECV [$foo]\n"; + } else { + print "PING\n"; + } +} diff --git a/src/mod/endpoints/mod_verto/mcast/test2.pl b/src/mod/endpoints/mod_verto/mcast/test2.pl new file mode 100644 index 0000000000..341e87ba99 --- /dev/null +++ b/src/mod/endpoints/mod_verto/mcast/test2.pl @@ -0,0 +1,23 @@ +use MCAST; + + + +my $action = shift; + +if ($action eq "send") { + my $s = new MCAST::McastHandle("224.1.1.1", 1337, MCAST::MCAST_SEND | MCAST::MCAST_TTL_HOST); + $s->send(shift); + print "Sending message"; + exit; +} + +my $s = new MCAST::McastHandle("224.1.1.1", 1338, MCAST::MCAST_RECV | MCAST::MCAST_TTL_HOST); + +for(;;) { + my $foo = $s->recv(); + if ($foo) { + print "RECV [$foo]\n"; + } else { + print "PING\n"; + } +} diff --git a/src/mod/endpoints/mod_verto/mod_verto.2008.vcproj b/src/mod/endpoints/mod_verto/mod_verto.2008.vcproj new file mode 100644 index 0000000000..548b114237 --- /dev/null +++ b/src/mod/endpoints/mod_verto/mod_verto.2008.vcproj @@ -0,0 +1,287 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mod/endpoints/mod_verto/mod_verto.2010.vcxproj b/src/mod/endpoints/mod_verto/mod_verto.2010.vcxproj new file mode 100644 index 0000000000..1dc1aac6dc --- /dev/null +++ b/src/mod/endpoints/mod_verto/mod_verto.2010.vcxproj @@ -0,0 +1,131 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + mod_verto + {11C9BC3D-45E9-46E3-BE84-B8CEE4685E39} + mod_verto + Win32Proj + + + + DynamicLibrary + MultiByte + + + DynamicLibrary + MultiByte + + + DynamicLibrary + MultiByte + + + DynamicLibrary + MultiByte + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + + + + + + + + false + + + + + + + X64 + + + + + + + false + + + MachineX64 + + + + + + + + + false + + + + + + + X64 + + + + + + + false + + + MachineX64 + + + + + + + + {202d7a4e-760d-4d0e-afa1-d7459ced30ff} + false + + + + + + diff --git a/src/mod/endpoints/mod_verto/mod_verto.2012.vcxproj b/src/mod/endpoints/mod_verto/mod_verto.2012.vcxproj new file mode 100644 index 0000000000..8930918614 --- /dev/null +++ b/src/mod/endpoints/mod_verto/mod_verto.2012.vcxproj @@ -0,0 +1,135 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + mod_verto + {11C9BC3D-45E9-46E3-BE84-B8CEE4685E39} + mod_verto + Win32Proj + + + + DynamicLibrary + MultiByte + v110 + + + DynamicLibrary + MultiByte + v110 + + + DynamicLibrary + MultiByte + v110 + + + DynamicLibrary + MultiByte + v110 + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + + + + + + + + false + + + + + + + X64 + + + + + + + false + + + MachineX64 + + + + + + + + + false + + + + + + + X64 + + + + + + + false + + + MachineX64 + + + + + + + + {202d7a4e-760d-4d0e-afa1-d7459ced30ff} + false + + + + + + diff --git a/src/mod/endpoints/mod_verto/mod_verto.c b/src/mod/endpoints/mod_verto/mod_verto.c new file mode 100644 index 0000000000..8e5c94ef51 --- /dev/null +++ b/src/mod/endpoints/mod_verto/mod_verto.c @@ -0,0 +1,4485 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2005-2014, Anthony Minessale II + * + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * + * The Initial Developer of the Original Code is + * Anthony Minessale II + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Anthony Minessale II + * + * mod_verto.c -- HTML5 Verto interface + * + */ +#include +#include + + +/* Prototypes */ +SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_verto_shutdown); +SWITCH_MODULE_LOAD_FUNCTION(mod_verto_load); +SWITCH_MODULE_RUNTIME_FUNCTION(mod_verto_runtime); + +SWITCH_MODULE_DEFINITION(mod_verto, mod_verto_load, mod_verto_shutdown, mod_verto_runtime); + +#define EP_NAME "verto.rtc" +#define WSS_STANDALONE 1 +#include "ws.h" + +////////////////////////// +#include +#include +#include +#include +#include +#include +#include + + + +#define die(...) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, __VA_ARGS__); goto error + +struct globals_s globals; + + +static struct { + switch_mutex_t *store_mutex; + switch_hash_t *store_hash; +} json_GLOBALS; + + +const char json_sql[] = + "create table json_store (\n" + " name varchar(255) not null,\n" + " data text\n" + ");\n"; + + +typedef enum { + CMD_ADD, + CMD_DEL, + CMD_DUMP, + CMD_COMMIT, + CMD_RETRIEVE +} store_cmd_t; + +typedef struct { + switch_mutex_t *mutex; + cJSON *JSON_STORE; +} json_store_t; + +static void json_cleanup(void) +{ + switch_hash_index_t *hi = NULL; + void *val; + const void *var; + cJSON *json; + + switch_mutex_lock(json_GLOBALS.store_mutex); + top: + + for (hi = switch_core_hash_first_iter(json_GLOBALS.store_hash, hi); hi; hi = switch_core_hash_next(&hi)) { + switch_core_hash_this(hi, &var, NULL, &val); + json = (cJSON *) val; + cJSON_Delete(json); + switch_core_hash_delete(json_GLOBALS.store_hash, var); + goto top; + } + switch_safe_free(hi); + + switch_mutex_unlock(json_GLOBALS.store_mutex); + +} + +static switch_bool_t check_name(const char *name) +{ + const char *p; + + for(p = name; p && *p; p++) { + if ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z') || (*p >= '0' && *p <= '9') || *p == '-' || *p == '_') continue; + return SWITCH_FALSE; + } + + return SWITCH_TRUE; +} + + +static verto_profile_t *find_profile(const char *name); +static jsock_t *get_jsock(const char *uuid); + +static void verto_deinit_ssl(verto_profile_t *profile) +{ + if (profile->ssl_ctx) { + SSL_CTX_free(profile->ssl_ctx); + profile->ssl_ctx = NULL; + } +} + +static int ssl_init = 0; + +static void verto_init_ssl(verto_profile_t *profile) +{ + if (!ssl_init) { + SSL_library_init(); + ssl_init = 1; + } + + profile->ssl_method = SSLv23_server_method(); /* create server instance */ + profile->ssl_ctx = SSL_CTX_new(profile->ssl_method); /* create context */ + profile->ssl_ready = 1; + assert(profile->ssl_ctx); + + /* set the local certificate from CertFile */ + if (!zstr(profile->chain)) { + SSL_CTX_use_certificate_chain_file(profile->ssl_ctx, profile->chain); + } + + SSL_CTX_use_certificate_file(profile->ssl_ctx, profile->cert, SSL_FILETYPE_PEM); + + /* set the private key from KeyFile */ + SSL_CTX_use_PrivateKey_file(profile->ssl_ctx, profile->key, SSL_FILETYPE_PEM); + /* verify private key */ + if ( !SSL_CTX_check_private_key(profile->ssl_ctx) ) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "SSL NOT AVAILABLE\n"); + profile->ssl_ready = 0; + verto_deinit_ssl(profile); + } else { + SSL_CTX_set_cipher_list(profile->ssl_ctx, "HIGH:!DSS:!aNULL@STRENGTH"); + } +} + + +struct jsock_sub_node_head_s; + +typedef struct jsock_sub_node_s { + jsock_t *jsock; + struct jsock_sub_node_head_s *head; + struct jsock_sub_node_s *next; +} jsock_sub_node_t; + +typedef struct jsock_sub_node_head_s { + jsock_sub_node_t *node; + jsock_sub_node_t *tail; + char *event_channel; +} jsock_sub_node_head_t; + +static uint32_t jsock_unsub_head(jsock_t *jsock, jsock_sub_node_head_t *head) +{ + uint32_t x = 0; + + jsock_sub_node_t *thisnp = NULL, *np, *last = NULL; + + np = head->tail = head->node; + + while (np) { + + thisnp = np; + np = np->next; + + if (!jsock || thisnp->jsock == jsock) { + x++; + + if (last) { + last->next = np; + } else { + head->node = np; + } + + if (thisnp->jsock->profile->debug || globals.debug) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ALERT, "UNSUBBING %s [%s]\n", thisnp->jsock->name, thisnp->head->event_channel); + } + + thisnp->jsock = NULL; + free(thisnp); + } else { + last = thisnp; + head->tail = last; + } + } + + return x; +} + +static void unsub_all_jsock(void) +{ + switch_hash_index_t *hi; + void *val; + jsock_sub_node_head_t *head; + + switch_thread_rwlock_wrlock(globals.event_channel_rwlock); + top: + head = NULL; + + for (hi = switch_core_hash_first(globals.event_channel_hash); hi; hi = switch_core_hash_next(&hi)) { + switch_core_hash_this(hi, NULL, NULL, &val); + head = (jsock_sub_node_head_t *) val; + jsock_unsub_head(NULL, head); + switch_core_hash_delete(globals.event_channel_hash, head->event_channel); + free(head->event_channel); + free(head); + switch_safe_free(hi); + goto top; + } + + switch_thread_rwlock_unlock(globals.event_channel_rwlock); +} + +static uint32_t jsock_unsub_channel(jsock_t *jsock, const char *event_channel) +{ + jsock_sub_node_head_t *head; + uint32_t x = 0; + + switch_thread_rwlock_wrlock(globals.event_channel_rwlock); + + if (!event_channel) { + switch_hash_index_t *hi; + void *val; + + for (hi = switch_core_hash_first(globals.event_channel_hash); hi; hi = switch_core_hash_next(&hi)) { + switch_core_hash_this(hi, NULL, NULL, &val); + + if (val) { + head = (jsock_sub_node_head_t *) val; + x += jsock_unsub_head(jsock, head); + } + } + + } else { + if ((head = switch_core_hash_find(globals.event_channel_hash, event_channel))) { + x += jsock_unsub_head(jsock, head); + } + } + + switch_thread_rwlock_unlock(globals.event_channel_rwlock); + + return x; +} + +static void presence_ping(const char *event_channel) +{ + switch_console_callback_match_t *matches; + const char *val = event_channel; + + if (val) { + if (!strcasecmp(val, "presence")) { + val = NULL; + } else { + char *p; + if ((p = strchr(val, '.'))) { + val = (p+1); + } + } + } + + if ((matches = switch_core_session_findall_matching_var("presence_id", val))) { + switch_console_callback_match_node_t *m; + switch_core_session_t *session; + + for (m = matches->head; m; m = m->next) { + if ((session = switch_core_session_locate(m->val))) { + switch_channel_t *channel = switch_core_session_get_channel(session); + switch_event_t *event; + + if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_CALLSTATE) == SWITCH_STATUS_SUCCESS) { + switch_channel_callstate_t callstate = switch_channel_get_callstate(channel); + + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Original-Channel-Call-State", switch_channel_callstate2str(callstate)); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Channel-Call-State-Number", "%d", callstate); + switch_channel_event_set_data(channel, event); + switch_event_fire(&event); + } + + switch_core_session_rwunlock(session); + } + } + + switch_console_free_matches(&matches); + } +} + +static switch_status_t jsock_sub_channel(jsock_t *jsock, const char *event_channel) +{ + jsock_sub_node_t *node, *np; + jsock_sub_node_head_t *head; + switch_status_t status = SWITCH_STATUS_FALSE; + + switch_thread_rwlock_wrlock(globals.event_channel_rwlock); + + if (!(head = switch_core_hash_find(globals.event_channel_hash, event_channel))) { + switch_zmalloc(head, sizeof(*head)); + head->event_channel = strdup(event_channel); + switch_core_hash_insert(globals.event_channel_hash, event_channel, head); + + switch_zmalloc(node, sizeof(*node)); + node->jsock = jsock; + node->head = head; + head->node = node; + head->tail = node; + status = SWITCH_STATUS_SUCCESS; + } else { + int exist = 0; + + for (np = head->node; np; np = np->next) { + if (np->jsock == jsock) { + exist = 1; + break; + } + } + + if (!exist) { + switch_zmalloc(node, sizeof(*node)); + node->jsock = jsock; + node->head = head; + + if (!head->node) { + head->node = node; + head->tail = node; + } else { + head->tail->next = node; + head->tail = head->tail->next; + } + status = SWITCH_STATUS_SUCCESS; + } + } + + switch_thread_rwlock_unlock(globals.event_channel_rwlock); + + if (status == SWITCH_STATUS_SUCCESS && !strncasecmp(event_channel, "presence", 8)) { + presence_ping(event_channel); + } + + return status; +} + +static uint32_t ID = 1; + +static void close_file(int *sock) +{ + if (*sock > -1) { + close(*sock); + *sock = -1; + } +} + +static void close_socket(int *sock) +{ + if (*sock > -1) { + shutdown(*sock, 2); + close_file(sock); + } +} + +static void del_jsock(jsock_t *jsock) +{ + jsock_t *p, *last = NULL; + + jsock_unsub_channel(jsock, NULL); + switch_event_channel_permission_clear(jsock->uuid_str); + + switch_mutex_lock(jsock->profile->mutex); + for(p = jsock->profile->jsock_head; p; p = p->next) { + if (p == jsock) { + if (last) { + last->next = p->next; + } else { + jsock->profile->jsock_head = p->next; + } + jsock->profile->jsock_count--; + break; + } + + last = p; + } + switch_mutex_unlock(jsock->profile->mutex); + +} + +static void add_jsock(jsock_t *jsock) +{ + + switch_mutex_lock(jsock->profile->mutex); + jsock->next = jsock->profile->jsock_head; + jsock->profile->jsock_head = jsock; + jsock->profile->jsock_count++; + switch_mutex_unlock(jsock->profile->mutex); + +} + +static uint32_t next_id(void) +{ + uint32_t id; + + switch_mutex_lock(globals.mutex); + id = ID++; + switch_mutex_unlock(globals.mutex); + + return id; +} + +static cJSON *jrpc_new(uint32_t id) +{ + cJSON *obj = cJSON_CreateObject(); + cJSON_AddItemToObject(obj, "jsonrpc", cJSON_CreateString("2.0")); + + if (id) { + cJSON_AddItemToObject(obj, "id", cJSON_CreateNumber(id)); + } + + return obj; +} + +static cJSON *jrpc_new_req(const char *method, const char *call_id, cJSON **paramsP) +{ + cJSON *msg, *params = NULL; + uint32_t id = next_id(); + + msg = jrpc_new(id); + + if (paramsP && *paramsP) { + params = *paramsP; + } + + if (!params) { + params = cJSON_CreateObject(); + } + + cJSON_AddItemToObject(msg, "method", cJSON_CreateString(method)); + cJSON_AddItemToObject(msg, "params", params); + + if (call_id) { + cJSON_AddItemToObject(params, "callID", cJSON_CreateString(call_id)); + } + + if (paramsP) { + *paramsP = params; + } + + return msg; +} + +static void jrpc_add_id(cJSON *obj, cJSON *jid, const char *idstr, int id) +{ + if (jid) { + cJSON_AddItemToObject(obj, "id", cJSON_Duplicate(jid, 1)); + } else if (idstr) { + cJSON_AddItemToObject(obj, "id", zstr(idstr) ? cJSON_CreateNull() : cJSON_CreateString(idstr)); + } else { + cJSON_AddItemToObject(obj, "id", cJSON_CreateNumber(id)); + } +} + +static void jrpc_add_error(cJSON *obj, int code, const char *message, cJSON *jid) +{ + cJSON *error = cJSON_CreateObject(); + + cJSON_AddItemToObject(obj, "error", error); + cJSON_AddItemToObject(error, "code", cJSON_CreateNumber(code)); + cJSON_AddItemToObject(error, "message", cJSON_CreateString(message)); + if (!cJSON_GetObjectItem(obj, "id")) { + jrpc_add_id(obj, jid, "", 0); + } +} + +static void jrpc_add_result(cJSON *obj, cJSON *result) +{ + if (result) { + cJSON_AddItemToObject(obj, "result", result); + } +} + +static switch_ssize_t ws_write_json(jsock_t *jsock, cJSON **json, switch_bool_t destroy) +{ + char *json_text; + switch_ssize_t r = -1; + + switch_assert(json); + + if (!*json) { + return r; + } + + if (jsock->uuid_str) { + cJSON *result = cJSON_GetObjectItem(*json, "result"); + + if (result) { + cJSON_AddItemToObject(result, "sessid", cJSON_CreateString(jsock->uuid_str)); + } + } + + if ((json_text = cJSON_PrintUnformatted(*json))) { + if (jsock->profile->debug || globals.debug) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ALERT, "WRITE %s [%s]\n", jsock->name, json_text); + } + switch_mutex_lock(jsock->write_mutex); + ws_write_frame(&jsock->ws, WSOC_TEXT, json_text, strlen(json_text)); + switch_mutex_unlock(jsock->write_mutex); + switch_safe_free(json_text); + } + + if (destroy) { + cJSON_Delete(*json); + *json = NULL; + } + + return r; +} + + +static void write_event(const char *event_channel, jsock_t *use_jsock, cJSON *event) +{ + jsock_sub_node_head_t *head; + + if ((head = switch_core_hash_find(globals.event_channel_hash, event_channel))) { + jsock_sub_node_t *np; + + for(np = head->node; np; np = np->next) { + cJSON *msg = NULL, *params; + + if (!use_jsock || use_jsock == np->jsock) { + params = cJSON_Duplicate(event, 1); + msg = jrpc_new_req("verto.event", NULL, ¶ms); + ws_write_json(np->jsock, &msg, SWITCH_TRUE); + } + } + } +} + +static void jsock_send_event(cJSON *event) +{ + + const char *event_channel, *session_uuid = NULL; + jsock_t *use_jsock = NULL; + switch_core_session_t *session = NULL; + + if (!(event_channel = cJSON_GetObjectCstr(event, "eventChannel"))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "NO EVENT CHANNEL SPECIFIED\n"); + return; + } + + + if ((session = switch_core_session_locate(event_channel))) { + switch_channel_t *channel = switch_core_session_get_channel(session); + const char *jsock_uuid_str = switch_channel_get_variable(channel, "jsock_uuid_str"); + if (jsock_uuid_str) { + use_jsock = get_jsock(jsock_uuid_str); + } + switch_core_session_rwunlock(session); + } + + if (use_jsock || (use_jsock = get_jsock(event_channel))) { /* implicit subscription to channel identical to the connection uuid or session uuid */ + cJSON *msg = NULL, *params; + params = cJSON_Duplicate(event, 1); + msg = jrpc_new_req("verto.event", NULL, ¶ms); + ws_write_json(use_jsock, &msg, SWITCH_TRUE); + switch_thread_rwlock_unlock(use_jsock->rwlock); + use_jsock = NULL; + return; + } + + + if ((session_uuid = cJSON_GetObjectCstr(event, "sessid"))) { + if (!(use_jsock = get_jsock(session_uuid))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Socket %s not connected\n", session_uuid); + return; + } + } + + switch_thread_rwlock_rdlock(globals.event_channel_rwlock); + write_event(event_channel, use_jsock, event); + if (strchr(event_channel, '.')) { + char *main_channel = strdup(event_channel); + char *p = strchr(main_channel, '.'); + if (p) *p = '\0'; + write_event(main_channel, use_jsock, event); + free(main_channel); + } + switch_thread_rwlock_unlock(globals.event_channel_rwlock); + + if (use_jsock) { + switch_thread_rwlock_unlock(use_jsock->rwlock); + use_jsock = NULL; + } +} + +static jrpc_func_t jrpc_get_func(jsock_t *jsock, const char *method) +{ + jrpc_func_t func = NULL; + char *main_method = NULL; + + switch_assert(method); + + if (jsock->allowed_methods) { + if (strchr(method, '.')) { + char *p; + main_method = strdup(method); + if ((p = strchr(main_method, '.'))) { + *p = '\0'; + } + } + + if (!(switch_event_get_header(jsock->allowed_methods, method) || (main_method && switch_event_get_header(jsock->allowed_methods, main_method)))) { + goto end; + } + } + + switch_mutex_lock(globals.method_mutex); + func = (jrpc_func_t) (intptr_t) switch_core_hash_find(globals.method_hash, method); + switch_mutex_unlock(globals.method_mutex); + + end: + + switch_safe_free(main_method); + + return func; +} + + +static void jrpc_add_func(const char *method, jrpc_func_t func) +{ + switch_assert(method); + switch_assert(func); + + switch_mutex_lock(globals.method_mutex); + switch_core_hash_insert(globals.method_hash, method, (void *) (intptr_t) func); + switch_mutex_unlock(globals.method_mutex); +} + +static char *MARKER = "X"; + +static void set_perm(const char *str, switch_event_t **event) +{ + char delim = ','; + char *cur, *next; + int count = 0; + char *edup; + + if (!zstr(str)) { + if (!strcasecmp(str, "__ANY__")) { + return; + } + } + + switch_event_create(event, SWITCH_EVENT_REQUEST_PARAMS); + + if (!zstr(str)) { + edup = strdup(str); + cur = edup; + + if (strchr(edup, ' ')) { + delim = ' '; + } + + for (cur = edup; cur; count++) { + if ((next = strchr(cur, delim))) { + *next++ = '\0'; + } + + switch_event_add_header_string(*event, SWITCH_STACK_BOTTOM, cur, MARKER); + + cur = next; + } + + switch_safe_free(edup); + + } +} + +static void check_permissions(jsock_t *jsock, switch_xml_t x_user, cJSON *params) +{ + switch_xml_t x_param, x_params; + const char *allowed_methods = NULL, *allowed_jsapi = NULL, *allowed_fsapi = NULL, *allowed_event_channels = NULL; + + if ((x_params = switch_xml_child(x_user, "params"))) { + for (x_param = switch_xml_child(x_params, "param"); x_param; x_param = x_param->next) { + const char *var = switch_xml_attr(x_param, "name"); + const char *val = switch_xml_attr(x_param, "value"); + + if (zstr(val) || zstr(var)) { + continue; + } + + if (!strcasecmp(var, "jsonrpc-allowed-methods")) { + allowed_methods = val; + } + + if (!strcasecmp(var, "jsonrpc-allowed-jsapi")) { + allowed_jsapi = val; + } + + if (!strcasecmp(var, "jsonrpc-allowed-fsapi")) { + allowed_fsapi = val; + } + + if (!strcasecmp(var, "jsonrpc-allowed-event-channels")) { + allowed_event_channels = val; + } + } + } + + set_perm(allowed_methods, &jsock->allowed_methods); + set_perm(allowed_jsapi, &jsock->allowed_jsapi); + set_perm(allowed_fsapi, &jsock->allowed_fsapi); + set_perm(allowed_event_channels, &jsock->allowed_event_channels); + + switch_event_add_header_string(jsock->allowed_methods, SWITCH_STACK_BOTTOM, "login", MARKER); + +} + +static switch_bool_t check_auth(jsock_t *jsock, cJSON *params, int *code, char *message, switch_size_t mlen) +{ + switch_bool_t r = SWITCH_FALSE; + const char *passwd = NULL; + const char *login = NULL; + + if (!params) { + *code = CODE_AUTH_FAILED; + switch_snprintf(message, mlen, "Missing params"); + goto end; + } + + login = cJSON_GetObjectCstr(params, "login"); + passwd = cJSON_GetObjectCstr(params, "passwd"); + + if (zstr(login)) { + goto end; + } + + if (zstr(passwd)) { + *code = CODE_AUTH_FAILED; + switch_snprintf(message, mlen, "Missing passwd"); + goto end; + } + + + if (!strcmp(login, "root")) { + if (!(r = !strcmp(passwd, jsock->profile->root_passwd))) { + *code = CODE_AUTH_FAILED; + switch_snprintf(message, mlen, "Authentication Failure"); + } + + } else if (!zstr(jsock->profile->userauth)) { + switch_xml_t x_user = NULL; + char *id = NULL, *domain = NULL; + switch_event_t *req_params; + + if (*jsock->profile->userauth == '@') { + domain = jsock->profile->userauth + 1; + id = (char *) login; + } else if (switch_true(jsock->profile->userauth)) { + id = switch_core_strdup(jsock->pool, login); + + if ((domain = strchr(id, '@'))) { + *domain++ = '\0'; + } + + } + + if (!(id && domain)) { + *code = CODE_AUTH_FAILED; + switch_snprintf(message, mlen, "Missing or improper credentials"); + goto end; + } + + switch_event_create(&req_params, SWITCH_EVENT_REQUEST_PARAMS); + switch_assert(req_params); + + switch_event_add_header_string(req_params, SWITCH_STACK_BOTTOM, "action", "jsonrpc-authenticate"); + + if (switch_xml_locate_user_merged("id", id, domain, NULL, &x_user, req_params) != SWITCH_STATUS_SUCCESS) { + *code = CODE_AUTH_FAILED; + switch_snprintf(message, mlen, "Login Incorrect"); + } else { + switch_xml_t x_param, x_params; + const char *use_passwd = NULL, *verto_context = NULL, *verto_dialplan = NULL; + + jsock->id = switch_core_strdup(jsock->pool, id); + jsock->domain = switch_core_strdup(jsock->pool, domain); + jsock->uid = switch_core_sprintf(jsock->pool, "%s@%s", id, domain); + + + if ((x_params = switch_xml_child(x_user, "params"))) { + for (x_param = switch_xml_child(x_params, "param"); x_param; x_param = x_param->next) { + const char *var = switch_xml_attr_soft(x_param, "name"); + const char *val = switch_xml_attr_soft(x_param, "value"); + + if (!use_passwd && !strcasecmp(var, "password")) { + use_passwd = val; + } else if (!strcasecmp(var, "jsonrpc-password")) { + use_passwd = val; + } else if (!strcasecmp(var, "verto-context")) { + verto_context = val; + } else if (!strcasecmp(var, "verto-dialplan")) { + verto_dialplan = val; + } + + switch_event_add_header(jsock->params, SWITCH_STACK_BOTTOM, var, val); + } + } + + if ((x_params = switch_xml_child(x_user, "variables"))) { + for (x_param = switch_xml_child(x_params, "variable"); x_param; x_param = x_param->next) { + const char *var = switch_xml_attr_soft(x_param, "name"); + const char *val = switch_xml_attr_soft(x_param, "value"); + + switch_event_add_header(jsock->vars, SWITCH_STACK_BOTTOM, var, val); + } + } + + if (!zstr(verto_dialplan)) { + jsock->dialplan = switch_core_strdup(jsock->pool, verto_dialplan); + } + + if (!zstr(verto_context)) { + jsock->context = switch_core_strdup(jsock->pool, verto_context); + } + + if (zstr(use_passwd) || strcmp(passwd, use_passwd)) { + r = SWITCH_FALSE; + *code = CODE_AUTH_FAILED; + switch_snprintf(message, mlen, "Authentication Failure"); + } else { + r = SWITCH_TRUE; + check_permissions(jsock, x_user, params); + } + + switch_xml_free(x_user); + } + + switch_event_destroy(&req_params); + } + + + end: + + return r; + +} + +static void set_call_params(cJSON *params, verto_pvt_t *tech_pvt) { + const char *caller_id_name = NULL; + const char *caller_id_number = NULL; + + if (switch_channel_outbound_display(tech_pvt->channel)) { + caller_id_name = switch_channel_get_variable(tech_pvt->channel, "caller_id_name"); + caller_id_number = switch_channel_get_variable(tech_pvt->channel, "caller_id_number"); + } else { + caller_id_name = switch_channel_get_variable(tech_pvt->channel, "callee_id_name"); + caller_id_number = switch_channel_get_variable(tech_pvt->channel, "callee_id_number"); + } + + if (zstr(caller_id_name)) { + caller_id_name = "Outbound Call"; + } + + if (zstr(caller_id_number)) { + caller_id_number = switch_channel_get_variable(tech_pvt->channel, "destination_number"); + } + + cJSON_AddItemToObject(params, "caller_id_name", cJSON_CreateString(caller_id_name)); + cJSON_AddItemToObject(params, "caller_id_number", cJSON_CreateString(caller_id_number)); +} + +static jsock_t *get_jsock(const char *uuid) +{ + jsock_t *jsock = NULL; + + switch_mutex_lock(globals.jsock_mutex); + if ((jsock = switch_core_hash_find(globals.jsock_hash, uuid))) { + if (switch_thread_rwlock_tryrdlock(jsock->rwlock) != SWITCH_STATUS_SUCCESS) { + jsock = NULL; + } + } + switch_mutex_unlock(globals.jsock_mutex); + + return jsock; +} + +static void attach_jsock(jsock_t *jsock) +{ + switch_mutex_lock(globals.jsock_mutex); + switch_core_hash_insert(globals.jsock_hash, jsock->uuid_str, jsock); + switch_mutex_unlock(globals.jsock_mutex); +} + +static void detach_jsock(jsock_t *jsock) +{ + switch_mutex_lock(globals.jsock_mutex); + switch_core_hash_delete(globals.jsock_hash, jsock->uuid_str); + switch_mutex_unlock(globals.jsock_mutex); +} + +static int attach_wake(void) +{ + switch_status_t status; + int tries = 0; + + top: + + status = switch_mutex_trylock(globals.detach_mutex); + + if (status == SWITCH_STATUS_SUCCESS) { + switch_thread_cond_signal(globals.detach_cond); + switch_mutex_unlock(globals.detach_mutex); + return 1; + } else { + if (switch_mutex_trylock(globals.detach2_mutex) == SWITCH_STATUS_SUCCESS) { + switch_mutex_unlock(globals.detach2_mutex); + } else { + if (++tries < 10) { + switch_cond_next(); + goto top; + } + } + } + + return 0; +} + +static void tech_reattach(verto_pvt_t *tech_pvt, jsock_t *jsock) +{ + cJSON *params = NULL; + cJSON *msg = NULL; + + tech_pvt->detach_time = 0; + globals.detached--; + attach_wake(); + switch_set_flag(tech_pvt, TFLAG_ATTACH_REQ); + msg = jrpc_new_req("verto.attach", tech_pvt->call_id, ¶ms); + cJSON_AddItemToObject(params, "sdp", cJSON_CreateString(tech_pvt->mparams->local_sdp_str)); + set_call_params(params, tech_pvt); + ws_write_json(jsock, &msg, SWITCH_TRUE); +} + +static void drop_detached(void) +{ + verto_pvt_t *tech_pvt; + switch_time_t now = switch_epoch_time_now(NULL); + + switch_thread_rwlock_rdlock(globals.tech_rwlock); + for(tech_pvt = globals.tech_head; tech_pvt; tech_pvt = tech_pvt->next) { + if (!switch_channel_up_nosig(tech_pvt->channel)) { + continue; + } + + if (tech_pvt->detach_time && (now - tech_pvt->detach_time) > globals.detach_timeout) { + switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_RECOVERY_ON_TIMER_EXPIRE); + } + } + switch_thread_rwlock_unlock(globals.tech_rwlock); +} + +static void attach_calls(jsock_t *jsock) +{ + verto_pvt_t *tech_pvt; + + switch_thread_rwlock_rdlock(globals.tech_rwlock); + for(tech_pvt = globals.tech_head; tech_pvt; tech_pvt = tech_pvt->next) { + if (tech_pvt->detach_time && !strcmp(tech_pvt->jsock_uuid, jsock->uuid_str)) { + if (!switch_channel_up_nosig(tech_pvt->channel)) { + continue; + } + + tech_reattach(tech_pvt, jsock); + } + } + switch_thread_rwlock_unlock(globals.tech_rwlock); +} + +static void detach_calls(jsock_t *jsock) +{ + verto_pvt_t *tech_pvt; + + switch_thread_rwlock_rdlock(globals.tech_rwlock); + for(tech_pvt = globals.tech_head; tech_pvt; tech_pvt = tech_pvt->next) { + if (!strcmp(tech_pvt->jsock_uuid, jsock->uuid_str)) { + if (!switch_channel_up_nosig(tech_pvt->channel)) { + continue; + } + + tech_pvt->detach_time = switch_epoch_time_now(NULL); + globals.detached++; + attach_wake(); + } + } + switch_thread_rwlock_unlock(globals.tech_rwlock); +} + +static void process_jrpc_response(jsock_t *jsock, cJSON *json) +{ +} + +static void set_session_id(jsock_t *jsock, const char *uuid) +{ + //cJSON *params, *msg = jrpc_new(0); + + if (!zstr(uuid)) { + switch_set_string(jsock->uuid_str, uuid); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s re-connecting session %s\n", jsock->name, jsock->uuid_str); + } else { + switch_uuid_str(jsock->uuid_str, sizeof(jsock->uuid_str)); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s new RPC session %s\n", jsock->name, jsock->uuid_str); + } + + attach_jsock(jsock); + +} + +static cJSON *process_jrpc(jsock_t *jsock, cJSON *json) +{ + cJSON *reply = NULL, *echo = NULL, *id = NULL, *params = NULL, *response = NULL, *result; + const char *method = NULL, *version = NULL, *sessid = NULL; + jrpc_func_t func = NULL; + + switch_assert(json); + + method = cJSON_GetObjectCstr(json, "method"); + result = cJSON_GetObjectItem(json, "result"); + version = cJSON_GetObjectCstr(json, "jsonrpc"); + id = cJSON_GetObjectItem(json, "id"); + + if ((params = cJSON_GetObjectItem(json, "params"))) { + sessid = cJSON_GetObjectCstr(params, "sessid"); + } + + if (!switch_test_flag(jsock, JPFLAG_INIT)) { + set_session_id(jsock, sessid); + switch_set_flag(jsock, JPFLAG_INIT); + } + + if (zstr(version) || strcmp(version, "2.0")) { + reply = jrpc_new(0); + jrpc_add_error(reply, CODE_INVALID, "Invalid message", id); + goto end; + } + + if (result) { + process_jrpc_response(jsock, json); + return NULL; + } + + reply = jrpc_new(0); + + jrpc_add_id(reply, id, "", 0); + + if (!switch_test_flag(jsock, JPFLAG_AUTHED) && (jsock->profile->userauth || jsock->profile->root_passwd)) { + int code = CODE_AUTH_REQUIRED; + char message[128] = "Authentication Required"; + + if (!check_auth(jsock, params, &code, message, sizeof(message))) { + jrpc_add_error(reply, code, message, id); + goto end; + } + switch_set_flag(jsock, JPFLAG_AUTHED); + } + + if (!method || !(func = jrpc_get_func(jsock, method))) { + jrpc_add_error(reply, -32601, "Invalid Method, Missing Method or Permission Denied", id); + } else { + if (func(method, params, jsock, &response) == SWITCH_TRUE) { + + if (params) { + echo = cJSON_GetObjectItem(params, "echoParams"); + } + if (echo) { + if ((echo->type == cJSON_True || (echo->type == cJSON_String && switch_true(echo->valuestring)))) { + cJSON_AddItemToObject(response, "requestParams", cJSON_Duplicate(params, 1)); + } else { + cJSON_AddItemToObject(response, "requestParams", cJSON_Duplicate(echo, 1)); + } + } + + jrpc_add_result(reply, response); + } else { + if (response) { + cJSON_AddItemToObject(reply, "error", response); + } else { + jrpc_add_error(reply, -32602, "Permission Denied", id); + } + } + } + + end: + + return reply; +} + +static switch_status_t process_input(jsock_t *jsock, uint8_t *data, switch_ssize_t bytes) +{ + cJSON *json = NULL, *reply = NULL; + char *ascii = (char *) data; + switch_status_t status = SWITCH_STATUS_SUCCESS; + + if (ascii) { + if (jsock->profile->debug || globals.debug) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ALERT, "READ %s [%s]\n", jsock->name, ascii); + } + json = cJSON_Parse(ascii); + } + + if (json) { + if (json->type == cJSON_Array) { /* batch mode */ + int i, len = cJSON_GetArraySize(json); + + reply = cJSON_CreateArray(); + + for(i = 0; i < len; i++) { + cJSON *obj, *item = cJSON_GetArrayItem(json, i); + + if ((obj = process_jrpc(jsock, item))) { + cJSON_AddItemToArray(reply, obj); + } + } + } else { + reply = process_jrpc(jsock, json); + } + } else { + reply = jrpc_new(0); + jrpc_add_error(reply, -32600, "Invalid Request", NULL); + } + + if (reply) { + ws_write_json(jsock, &reply, SWITCH_TRUE); + } + + if (json) { + cJSON_Delete(json); + } + + return status; +} + +static void client_run(jsock_t *jsock) +{ + + jsock->local_addr.sin_family = AF_INET; + jsock->local_addr.sin_addr.s_addr = htonl(INADDR_ANY); + jsock->local_addr.sin_port = 0; + + + if (ws_init(&jsock->ws, jsock->client_socket, (jsock->ptype & PTYPE_CLIENT_SSL) ? jsock->profile->ssl_ctx : NULL, 0, 1) < 0) { + die("%s WS SETUP FAILED", jsock->name); + } + + while(jsock->profile->running) { + struct pollfd pfds[1]; + int res; + + memset(&pfds[0], 0, sizeof(pfds[0])); + + pfds[0].fd = jsock->client_socket; + pfds[0].events = POLLIN|POLLERR|POLLHUP|POLLRDNORM|POLLRDBAND|POLLPRI; + + + if ((res = poll(pfds, 1, -1)) < 0) { + if (errno != EINTR) { + die("%s POLL FAILED\n", jsock->name); + } + } + + if (res < 0) { + die("%s POLL ERROR\n", jsock->name); + } + + if (jsock->drop) { + die("%s Dropping Connection\n", jsock->name); + } + + + if (pfds[0].revents & POLLERR) { + die("%s POLL ERROR\n", jsock->name); + } + + if (pfds[0].revents & POLLHUP) { + die("%s POLL HANGUP DETECTED\n", jsock->name); + } + + if (pfds[0].revents & POLLNVAL) { + die("%s POLL INVALID SOCKET\n", jsock->name); + } + + if (pfds[0].revents & POLLIN) { + switch_ssize_t bytes; + ws_opcode_t oc; + uint8_t *data; + + bytes = ws_read_frame(&jsock->ws, &oc, &data); + + if (bytes < 0) { + die("BAD READ %ld\n", bytes); + break; + } + + if (bytes) { + if (process_input(jsock, data, bytes) != SWITCH_STATUS_SUCCESS) { + die("Input Error\n"); + } + + if (!switch_test_flag(jsock, JPFLAG_CHECK_ATTACH) && switch_test_flag(jsock, JPFLAG_AUTHED)) { + attach_calls(jsock); + switch_set_flag(jsock, JPFLAG_CHECK_ATTACH); + } + } + } + } + + error: + + detach_jsock(jsock); + ws_destroy(&jsock->ws); + + return; +} + +static void *SWITCH_THREAD_FUNC client_thread(switch_thread_t *thread, void *obj) +{ + jsock_t *jsock = (jsock_t *) obj; + + switch_event_create(&jsock->params, SWITCH_EVENT_CHANNEL_DATA); + switch_event_create(&jsock->vars, SWITCH_EVENT_CHANNEL_DATA); + + + add_jsock(jsock); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s Starting client thread.\n", jsock->name); + + if ((jsock->ptype & PTYPE_CLIENT) || (jsock->ptype & PTYPE_CLIENT_SSL)) { + client_run(jsock); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s Ending client thread.\n", jsock->name); + } + + detach_calls(jsock); + + del_jsock(jsock); + + switch_event_destroy(&jsock->params); + switch_event_destroy(&jsock->vars); + + if (jsock->client_socket > -1) { + close_socket(&jsock->client_socket); + } + + switch_event_destroy(&jsock->allowed_methods); + switch_event_destroy(&jsock->allowed_fsapi); + switch_event_destroy(&jsock->allowed_jsapi); + switch_event_destroy(&jsock->allowed_event_channels); + + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s Ending client thread.\n", jsock->name); + switch_thread_rwlock_wrlock(jsock->rwlock); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s Thread ended\n", jsock->name); + switch_thread_rwlock_unlock(jsock->rwlock); + + return NULL; +} + + +static switch_bool_t auth_api_command(jsock_t *jsock, const char *api_cmd, const char *arg) +{ + const char *check_cmd = api_cmd; + char *sneaky_commands[] = { "bgapi", "sched_api", "eval", "expand", "xml_wrap", NULL }; + int x = 0; + char *dup_arg = NULL; + char *next = NULL; + switch_bool_t ok = SWITCH_TRUE; + + top: + + if (!jsock->allowed_fsapi) { + ok = SWITCH_FALSE; + goto end; + } + + if (!switch_event_get_header(jsock->allowed_fsapi, check_cmd)) { + ok = SWITCH_FALSE; + goto end; + } + + while (check_cmd) { + for (x = 0; sneaky_commands[x]; x++) { + if (!strcasecmp(sneaky_commands[x], check_cmd)) { + if (check_cmd == api_cmd) { + if (arg) { + switch_safe_free(dup_arg); + dup_arg = strdup(arg); + check_cmd = dup_arg; + if ((next = strchr(check_cmd, ' '))) { + *next++ = '\0'; + } + } else { + break; + } + } else { + if (next) { + check_cmd = next; + } else { + check_cmd = dup_arg; + } + + if ((next = strchr(check_cmd, ' '))) { + *next++ = '\0'; + } + } + goto top; + } + } + break; + } + + end: + + switch_safe_free(dup_arg); + return ok; + +} + +//// VERTO + +static void track_pvt(verto_pvt_t *tech_pvt) +{ + switch_thread_rwlock_wrlock(globals.tech_rwlock); + tech_pvt->next = globals.tech_head; + globals.tech_head = tech_pvt; + switch_thread_rwlock_unlock(globals.tech_rwlock); +} + +static void untrack_pvt(verto_pvt_t *tech_pvt) +{ + verto_pvt_t *p, *last = NULL; + + switch_thread_rwlock_wrlock(globals.tech_rwlock); + if (tech_pvt->detach_time) { + globals.detached--; + tech_pvt->detach_time = 0; + attach_wake(); + } + + for(p = globals.tech_head; p; p = p->next) { + if (p == tech_pvt) { + if (last) { + last->next = p->next; + } else { + globals.tech_head = p->next; + } + break; + } + + last = p; + } + switch_thread_rwlock_unlock(globals.tech_rwlock); +} + + +static switch_status_t verto_on_hangup(switch_core_session_t *session) +{ + jsock_t *jsock = NULL; + verto_pvt_t *tech_pvt = switch_core_session_get_private_class(session, SWITCH_PVT_SECONDARY); + + untrack_pvt(tech_pvt); + + // get the jsock and send hangup notice + if (!tech_pvt->remote_hangup_cause && (jsock = get_jsock(tech_pvt->jsock_uuid))) { + cJSON *msg = jrpc_new_req("verto.bye", tech_pvt->call_id, NULL); + ws_write_json(jsock, &msg, SWITCH_TRUE); + + switch_thread_rwlock_unlock(jsock->rwlock); + } + + return SWITCH_STATUS_SUCCESS; +} + +static void verto_set_media_options(verto_pvt_t *tech_pvt, verto_profile_t *profile); + +static switch_status_t verto_connect(switch_core_session_t *session, const char *method) +{ + switch_status_t status = SWITCH_STATUS_SUCCESS; + jsock_t *jsock = NULL; + verto_pvt_t *tech_pvt = switch_core_session_get_private_class(session, SWITCH_PVT_SECONDARY); + + if (!(jsock = get_jsock(tech_pvt->jsock_uuid))) { + status = SWITCH_STATUS_BREAK; + } else { + cJSON *params = NULL; + cJSON *msg = NULL; + const char *var = NULL; + switch_caller_profile_t *caller_profile = switch_channel_get_caller_profile(tech_pvt->channel); + + + switch_channel_set_variable(tech_pvt->channel, "verto_user", jsock->uid); + switch_channel_set_variable(tech_pvt->channel, "verto_host", jsock->domain); + + if ((var = switch_event_get_header(jsock->params, "caller-id-name"))) { + caller_profile->callee_id_name = switch_core_strdup(caller_profile->pool, var); + } + + if ((var = switch_event_get_header(jsock->params, "caller-id-number"))) { + caller_profile->callee_id_number = switch_core_strdup(caller_profile->pool, var); + } + + if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE)) { + switch_core_media_absorb_sdp(session); + } else { + switch_channel_set_variable(tech_pvt->channel, "media_webrtc", "true"); + switch_core_session_set_ice(tech_pvt->session); + + verto_set_media_options(tech_pvt, jsock->profile); + + switch_core_media_prepare_codecs(tech_pvt->session, SWITCH_TRUE); + switch_channel_set_variable(tech_pvt->channel, "verto_profile_name", jsock->profile->name); + + if (!switch_channel_test_flag(tech_pvt->channel, CF_RECOVERING)) { + if ((status = switch_core_media_choose_ports(tech_pvt->session, SWITCH_TRUE, SWITCH_TRUE)) != SWITCH_STATUS_SUCCESS) { + //if ((status = switch_core_media_choose_port(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO, 0)) != SWITCH_STATUS_SUCCESS) { + switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + switch_thread_rwlock_unlock(jsock->rwlock); + return status; + } + } + + switch_core_media_gen_local_sdp(session, SDP_TYPE_REQUEST, NULL, 0, NULL, 0); + } + + msg = jrpc_new_req(method, tech_pvt->call_id, ¶ms); + + if (tech_pvt->mparams->local_sdp_str) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Local %s SDP %s:\n%s\n", + method, + switch_channel_get_name(tech_pvt->channel), + tech_pvt->mparams->local_sdp_str); + + cJSON_AddItemToObject(params, "sdp", cJSON_CreateString(tech_pvt->mparams->local_sdp_str)); + set_call_params(params, tech_pvt); + + ws_write_json(jsock, &msg, SWITCH_TRUE); + } else { + status = SWITCH_STATUS_FALSE; + } + + switch_thread_rwlock_unlock(jsock->rwlock); + } + + return status; +} + +switch_status_t verto_tech_media(verto_pvt_t *tech_pvt, const char *r_sdp, switch_sdp_type_t sdp_type) +{ + uint8_t match = 0, p = 0; + + switch_assert(tech_pvt != NULL); + switch_assert(r_sdp != NULL); + + if (zstr(r_sdp)) { + return SWITCH_STATUS_FALSE; + } + + if ((match = switch_core_media_negotiate_sdp(tech_pvt->session, r_sdp, &p, sdp_type))) { + if (switch_core_media_choose_ports(tech_pvt->session, SWITCH_TRUE, SWITCH_FALSE) != SWITCH_STATUS_SUCCESS) { + //if (switch_core_media_choose_port(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO, 0) != SWITCH_STATUS_SUCCESS) { + return SWITCH_STATUS_FALSE; + } + + if (switch_core_media_activate_rtp(tech_pvt->session) != SWITCH_STATUS_SUCCESS) { + return SWITCH_STATUS_FALSE; + } + //if (!switch_channel_test_flag(tech_pvt->channel, CF_ANSWERED)) { + // switch_channel_set_variable(tech_pvt->channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "EARLY MEDIA"); + // switch_channel_mark_pre_answered(tech_pvt->channel); + //} + return SWITCH_STATUS_SUCCESS; + } + + + return SWITCH_STATUS_FALSE; +} + +static switch_status_t verto_on_init(switch_core_session_t *session) +{ + switch_status_t status = SWITCH_STATUS_SUCCESS; + verto_pvt_t *tech_pvt = switch_core_session_get_private_class(session, SWITCH_PVT_SECONDARY); + + if (switch_channel_test_flag(tech_pvt->channel, CF_RECOVERING_BRIDGE) || switch_channel_test_flag(tech_pvt->channel, CF_RECOVERING)) { + int tries = 120; + + switch_core_session_clear_crypto(session); + + while(--tries > 0) { + + status = verto_connect(session, "verto.attach"); + + if (status == SWITCH_STATUS_SUCCESS) { + switch_set_flag(tech_pvt, TFLAG_ATTACH_REQ); + break; + } else if (status == SWITCH_STATUS_BREAK) { + switch_yield(1000000); + continue; + } else { + tries = 0; + break; + } + } + + if (!tries) { + switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + status = SWITCH_STATUS_FALSE; + } + + switch_channel_set_flag(tech_pvt->channel, CF_VIDEO_BREAK); + switch_core_session_kill_channel(tech_pvt->session, SWITCH_SIG_BREAK); + + tries = 500; + while(--tries > 0 && switch_test_flag(tech_pvt, TFLAG_ATTACH_REQ)) { + switch_yield(10000); + } + + switch_core_session_refresh_video(session); + switch_channel_set_flag(tech_pvt->channel, CF_VIDEO_BREAK); + switch_core_session_kill_channel(tech_pvt->session, SWITCH_SIG_BREAK); + + return status; + } + + if (switch_channel_direction(tech_pvt->channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { + if ((status = verto_connect(tech_pvt->session, "verto.invite")) != SWITCH_STATUS_SUCCESS) { + switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + } + } + + return status; +} + + +static switch_state_handler_table_t verto_state_handlers = { + /*.on_init */ verto_on_init, + /*.on_routing */ NULL, + /*.on_execute */ NULL, + /*.on_hangup */ verto_on_hangup, + /*.on_exchange_media */ NULL, + /*.on_soft_execute */ NULL, + /*.on_consume_media */ NULL, + /*.on_hibernate */ NULL, + /*.on_reset */ NULL, + /*.on_park */ NULL, + /*.on_reporting */ NULL, + /*.on_destroy */ NULL, + SSH_FLAG_STICKY +}; + + + + +static void verto_set_media_options(verto_pvt_t *tech_pvt, verto_profile_t *profile) +{ + int i; + + tech_pvt->mparams->rtpip = switch_core_session_strdup(tech_pvt->session, profile->rtpip[profile->rtpip_cur++]); + + if (profile->rtpip_cur == profile->rtpip_index) { + profile->rtpip_cur = 0; + } + + tech_pvt->mparams->extrtpip = profile->extrtpip; + + //tech_pvt->mparams->dtmf_type = tech_pvt->profile->dtmf_type; + switch_channel_set_flag(tech_pvt->channel, CF_TRACKABLE); + switch_channel_set_variable(tech_pvt->channel, "secondary_recovery_module", modname); + + switch_core_media_check_dtmf_type(tech_pvt->session); + + //switch_channel_set_cap(tech_pvt->channel, CC_MEDIA_ACK); + switch_channel_set_cap(tech_pvt->channel, CC_BYPASS_MEDIA); + //switch_channel_set_cap(tech_pvt->channel, CC_PROXY_MEDIA); + switch_channel_set_cap(tech_pvt->channel, CC_JITTERBUFFER); + switch_channel_set_cap(tech_pvt->channel, CC_FS_RTP); + + //switch_channel_set_cap(tech_pvt->channel, CC_QUEUEABLE_DTMF_DELAY); + //tech_pvt->mparams->ndlb = tech_pvt->profile->mndlb; + + tech_pvt->mparams->inbound_codec_string = switch_core_session_strdup(tech_pvt->session, profile->inbound_codec_string); + tech_pvt->mparams->outbound_codec_string = switch_core_session_strdup(tech_pvt->session, profile->outbound_codec_string); + + tech_pvt->mparams->jb_msec = "-3"; + switch_media_handle_set_media_flag(tech_pvt->smh, SCMF_SUPPRESS_CNG); + + switch_media_handle_set_media_flag(tech_pvt->smh, SCMF_RENEG_ON_REINVITE); + + //tech_pvt->mparams->auto_rtp_bugs = profile->auto_rtp_bugs; + tech_pvt->mparams->timer_name = profile->timer_name; + //tech_pvt->mparams->vflags = profile->vflags; + //tech_pvt->mparams->manual_rtp_bugs = profile->manual_rtp_bugs; + //tech_pvt->mparams->manual_video_rtp_bugs = profile->manual_video_rtp_bugs; + + + tech_pvt->mparams->local_network = switch_core_session_strdup(tech_pvt->session, profile->local_network); + + + //tech_pvt->mparams->rtcp_audio_interval_msec = profile->rtpp_audio_interval_msec; + //tech_pvt->mparams->rtcp_video_interval_msec = profile->rtpp_video_interval_msec; + //tech_pvt->mparams->sdp_username = profile->sdp_username; + //tech_pvt->mparams->cng_pt = tech_pvt->cng_pt; + //tech_pvt->mparams->rtc_timeout_sec = profile->rtp_timeout_sec; + //tech_pvt->mparams->rtc_hold_timeout_sec = profile->rtp_hold_timeout_sec; + //switch_media_handle_set_media_flags(tech_pvt->media_handle, tech_pvt->profile->media_flags); + + + for(i = 0; i < profile->cand_acl_count; i++) { + switch_core_media_add_ice_acl(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO, profile->cand_acl[i]); + switch_core_media_add_ice_acl(tech_pvt->session, SWITCH_MEDIA_TYPE_VIDEO, profile->cand_acl[i]); + } +} + +static switch_status_t verto_media(switch_core_session_t *session) +{ + verto_pvt_t *tech_pvt = switch_core_session_get_private_class(session, SWITCH_PVT_SECONDARY); + switch_status_t status = SWITCH_STATUS_SUCCESS; + + switch_core_media_prepare_codecs(tech_pvt->session, SWITCH_TRUE); + + if (tech_pvt->r_sdp) { + if (verto_tech_media(tech_pvt, tech_pvt->r_sdp, SDP_TYPE_REQUEST) != SWITCH_STATUS_SUCCESS) { + switch_channel_set_variable(tech_pvt->channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "CODEC NEGOTIATION ERROR"); + return SWITCH_STATUS_FALSE; + } + } + + if ((status = switch_core_media_choose_ports(tech_pvt->session, SWITCH_TRUE, SWITCH_FALSE)) != SWITCH_STATUS_SUCCESS) { + //if ((status = switch_core_media_choose_port(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO, 0)) != SWITCH_STATUS_SUCCESS) { + switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + return status; + } + + switch_core_media_gen_local_sdp(session, SDP_TYPE_RESPONSE, NULL, 0, NULL, 0); + + if (switch_core_media_activate_rtp(tech_pvt->session) != SWITCH_STATUS_SUCCESS) { + switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + } + + if (tech_pvt->mparams->local_sdp_str) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Local SDP %s:\n%s\n", switch_channel_get_name(tech_pvt->channel), + tech_pvt->mparams->local_sdp_str); + } else { + status = SWITCH_STATUS_FALSE; + } + + return status; +} + + +static switch_status_t verto_send_media_indication(switch_core_session_t *session, const char *method) +{ + switch_status_t status = SWITCH_STATUS_FALSE; + verto_pvt_t *tech_pvt = switch_core_session_get_private_class(session, SWITCH_PVT_SECONDARY); + const char *proxy_sdp = NULL; + + if (switch_test_flag(tech_pvt, TFLAG_SENT_MEDIA)) { + status = SWITCH_STATUS_SUCCESS; + } + + if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE)) { + if ((proxy_sdp = switch_channel_get_variable(tech_pvt->channel, SWITCH_B_SDP_VARIABLE))) { + status = SWITCH_STATUS_SUCCESS; + switch_core_media_set_local_sdp(session, proxy_sdp, SWITCH_TRUE); + } + } + + + if (status == SWITCH_STATUS_SUCCESS || (status = verto_media(session)) == SWITCH_STATUS_SUCCESS) { + jsock_t *jsock = NULL; + + if (!(jsock = get_jsock(tech_pvt->jsock_uuid))) { + status = SWITCH_STATUS_FALSE; + } else { + cJSON *params = NULL; + cJSON *msg = jrpc_new_req(method, tech_pvt->call_id, ¶ms); + + if (!switch_test_flag(tech_pvt, TFLAG_SENT_MEDIA)) { + cJSON_AddItemToObject(params, "sdp", cJSON_CreateString(tech_pvt->mparams->local_sdp_str)); + } + + switch_set_flag(tech_pvt, TFLAG_SENT_MEDIA); + + ws_write_json(jsock, &msg, SWITCH_TRUE); + switch_thread_rwlock_unlock(jsock->rwlock); + } + } + + return status; +} + +static switch_status_t messagehook (switch_core_session_t *session, switch_core_session_message_t *msg) +{ + switch_status_t r = SWITCH_STATUS_SUCCESS; + verto_pvt_t *tech_pvt = switch_core_session_get_private_class(session, SWITCH_PVT_SECONDARY); + + switch(msg->message_id) { + case SWITCH_MESSAGE_INDICATE_DISPLAY: + { + const char *name, *number; + cJSON *jmsg = NULL, *params = NULL; + jsock_t *jsock = NULL; + + if ((jsock = get_jsock(tech_pvt->jsock_uuid))) { + name = msg->string_array_arg[0]; + number = msg->string_array_arg[1]; + + if (name || number) { + jmsg = jrpc_new_req("verto.display", tech_pvt->call_id, ¶ms); + cJSON_AddItemToObject(params, "display_name", cJSON_CreateString(name)); + cJSON_AddItemToObject(params, "display_number", cJSON_CreateString(number)); + ws_write_json(jsock, &jmsg, SWITCH_TRUE); + } + + switch_thread_rwlock_unlock(jsock->rwlock); + } + + } + break; + case SWITCH_MESSAGE_INDICATE_ANSWER: + r = verto_send_media_indication(session, "verto.answer"); + break; + case SWITCH_MESSAGE_INDICATE_PROGRESS: + r = verto_send_media_indication(session, "verto.media"); + break; + default: + break; + } + + return r; +} + + + +static int verto_recover_callback(switch_core_session_t *session) +{ + int r = 0; + char name[512]; + verto_pvt_t *tech_pvt = NULL; + verto_profile_t *profile = NULL; + const char *profile_name = NULL, *jsock_uuid_str = NULL; + switch_channel_t *channel = switch_core_session_get_channel(session); + + + profile_name = switch_channel_get_variable(channel, "verto_profile_name"); + jsock_uuid_str = switch_channel_get_variable(channel, "jsock_uuid_str"); + + if (!(profile_name && jsock_uuid_str && (profile = find_profile(profile_name)))) { + return 0; + } + + tech_pvt = switch_core_session_alloc(session, sizeof(*tech_pvt)); + tech_pvt->session = session; + tech_pvt->channel = channel; + tech_pvt->jsock_uuid = (char *) jsock_uuid_str; + switch_core_session_set_private_class(session, tech_pvt, SWITCH_PVT_SECONDARY); + + + tech_pvt->call_id = switch_core_session_strdup(session, switch_core_session_get_uuid(session)); + if ((tech_pvt->smh = switch_core_session_get_media_handle(session))) { + tech_pvt->mparams = switch_core_media_get_mparams(tech_pvt->smh); + verto_set_media_options(tech_pvt, profile); + } + + switch_snprintf(name, sizeof(name), "verto.rtc/%s", tech_pvt->jsock_uuid); + switch_channel_set_name(channel, name); + + switch_channel_add_state_handler(channel, &verto_state_handlers); + switch_core_event_hook_add_receive_message(session, messagehook); + + track_pvt(tech_pvt); + + //switch_channel_clear_flag(tech_pvt->channel, CF_ANSWERED); + //switch_channel_clear_flag(tech_pvt->channel, CF_EARLY_MEDIA); + + switch_thread_rwlock_unlock(profile->rwlock); + + r++; + + return r; +} + + +static void pass_sdp(verto_pvt_t *tech_pvt) +{ + switch_core_session_t *other_session = NULL; + switch_channel_t *other_channel = NULL; + + if (switch_core_session_get_partner(tech_pvt->session, &other_session) == SWITCH_STATUS_SUCCESS) { + other_channel = switch_core_session_get_channel(other_session); + switch_channel_set_variable(other_channel, SWITCH_B_SDP_VARIABLE, tech_pvt->r_sdp); + switch_channel_set_flag(other_channel, CF_PROXY_MODE); + switch_core_session_queue_indication(other_session, SWITCH_MESSAGE_INDICATE_ANSWER); + switch_core_session_rwunlock(other_session); + } +} + + +//// METHODS + +#define switch_either(_A, _B) zstr(_A) ? _B : _A + +static switch_bool_t verto__answer_func(const char *method, cJSON *params, jsock_t *jsock, cJSON **response) +{ + cJSON *obj = cJSON_CreateObject(); + switch_core_session_t *session; + cJSON *dialog = NULL; + const char *call_id = NULL, *sdp = NULL; + int err = 0; + + *response = obj; + + if (!(dialog = cJSON_GetObjectItem(params, "dialogParams"))) { + cJSON_AddItemToObject(obj, "message", cJSON_CreateString("Dialog data missing")); + err = 1; goto cleanup; + } + + if (!(call_id = cJSON_GetObjectCstr(dialog, "callID"))) { + cJSON_AddItemToObject(obj, "message", cJSON_CreateString("CallID missing")); + err = 1; goto cleanup; + } + + if (!(sdp = cJSON_GetObjectCstr(params, "sdp"))) { + cJSON_AddItemToObject(obj, "message", cJSON_CreateString("SDP missing")); + err = 1; goto cleanup; + } + + + if ((session = switch_core_session_locate(call_id))) { + verto_pvt_t *tech_pvt = switch_core_session_get_private_class(session, SWITCH_PVT_SECONDARY); + + tech_pvt->r_sdp = switch_core_session_strdup(session, sdp); + switch_channel_set_variable(tech_pvt->channel, SWITCH_R_SDP_VARIABLE, sdp); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Remote SDP %s:\n%s\n", switch_channel_get_name(tech_pvt->channel), sdp); + switch_core_media_set_sdp_codec_string(session, sdp, SDP_TYPE_RESPONSE); + + if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE)) { + pass_sdp(tech_pvt); + } else { + if (verto_tech_media(tech_pvt, tech_pvt->r_sdp, SDP_TYPE_RESPONSE) != SWITCH_STATUS_SUCCESS) { + switch_channel_set_variable(tech_pvt->channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "CODEC NEGOTIATION ERROR"); + cJSON_AddItemToObject(obj, "message", cJSON_CreateString("CODEC ERROR")); + err = 1; + } + + if (!err && switch_core_media_activate_rtp(tech_pvt->session) != SWITCH_STATUS_SUCCESS) { + switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + cJSON_AddItemToObject(obj, "message", cJSON_CreateString("MEDIA ERROR")); + err = 1; + } + } + + if (!err) { + switch_channel_mark_answered(tech_pvt->channel); + } + + switch_core_session_rwunlock(session); + } + + cleanup: + + + if (!err) return SWITCH_TRUE; + + cJSON_AddItemToObject(obj, "message", cJSON_CreateString("CALL DOES NOT EXIST")); + cJSON_AddItemToObject(obj, "code", cJSON_CreateNumber(CODE_SESSION_ERROR)); + + + return SWITCH_FALSE; + +} + +static switch_bool_t verto__bye_func(const char *method, cJSON *params, jsock_t *jsock, cJSON **response) +{ + cJSON *obj = cJSON_CreateObject(); + switch_core_session_t *session; + cJSON *dialog = NULL; + const char *call_id = NULL, *cause_str = NULL; + int err = 0; + switch_call_cause_t cause = SWITCH_CAUSE_NORMAL_CLEARING; + + *response = obj; + + if (!(dialog = cJSON_GetObjectItem(params, "dialogParams"))) { + cJSON_AddItemToObject(obj, "message", cJSON_CreateString("Dialog data missing")); + err = 1; goto cleanup; + } + + if (!(call_id = cJSON_GetObjectCstr(dialog, "callID"))) { + cJSON_AddItemToObject(obj, "message", cJSON_CreateString("CallID missing")); + err = 1; goto cleanup; + } + + if ((cause_str = cJSON_GetObjectCstr(params, "cause"))) { + switch_call_cause_t check = switch_channel_str2cause(cause_str); + + if (check != SWITCH_CAUSE_NONE) { + cause = check; + } + } + + cJSON_AddItemToObject(obj, "callID", cJSON_CreateString(call_id)); + + if ((session = switch_core_session_locate(call_id))) { + verto_pvt_t *tech_pvt = switch_core_session_get_private_class(session, SWITCH_PVT_SECONDARY); + tech_pvt->remote_hangup_cause = cause; + switch_channel_hangup(tech_pvt->channel, cause); + + cJSON_AddItemToObject(obj, "message", cJSON_CreateString("CALL ENDED")); + cJSON_AddItemToObject(obj, "causeCode", cJSON_CreateNumber(cause)); + cJSON_AddItemToObject(obj, "cause", cJSON_CreateString(switch_channel_cause2str(cause))); + switch_core_session_rwunlock(session); + } else { + err = 1; + } + + cleanup: + + + if (!err) return SWITCH_TRUE; + + cJSON_AddItemToObject(obj, "message", cJSON_CreateString("CALL DOES NOT EXIST")); + cJSON_AddItemToObject(obj, "code", cJSON_CreateNumber(CODE_SESSION_ERROR)); + + + return SWITCH_FALSE; +} + +static switch_status_t xfer_hanguphook(switch_core_session_t *session) +{ + switch_channel_t *channel = switch_core_session_get_channel(session); + switch_channel_state_t state = switch_channel_get_state(channel); + + if (state == CS_HANGUP) { + switch_core_session_t *ksession; + const char *uuid = switch_channel_get_variable(channel, "att_xfer_kill_uuid"); + + if (uuid && (ksession = switch_core_session_force_locate(uuid))) { + switch_channel_t *kchannel = switch_core_session_get_channel(ksession); + + switch_channel_clear_flag(kchannel, CF_XFER_ZOMBIE); + switch_channel_clear_flag(kchannel, CF_TRANSFER); + if (switch_channel_up(kchannel)) { + switch_channel_hangup(kchannel, SWITCH_CAUSE_NORMAL_CLEARING); + } + + switch_core_session_rwunlock(ksession); + } + + switch_core_event_hook_remove_state_change(session, xfer_hanguphook); + + } + + return SWITCH_STATUS_SUCCESS; +} + +static void mark_transfer_record(switch_core_session_t *session, const char *br_a, const char *br_b) +{ + switch_core_session_t *br_b_session, *br_a_session; + switch_channel_t *channel; + const char *uvar1, *dvar1, *uvar2, *dvar2; + + channel = switch_core_session_get_channel(session); + + uvar1 = "verto_user"; + dvar1 = "verto_host"; + + if ((br_b_session = switch_core_session_locate(br_b)) ) { + switch_channel_t *br_b_channel = switch_core_session_get_channel(br_b_session); + switch_caller_profile_t *cp = switch_channel_get_caller_profile(br_b_channel); + + if (switch_channel_direction(br_b_channel) == SWITCH_CALL_DIRECTION_INBOUND) { + uvar2 = "sip_from_user"; + dvar2 = "sip_from_host"; + } else { + uvar2 = "sip_to_user"; + dvar2 = "sip_to_host"; + } + + cp->transfer_source = switch_core_sprintf(cp->pool, + "%ld:%s:att_xfer:%s@%s/%s@%s", + (long) switch_epoch_time_now(NULL), + cp->uuid_str, + switch_channel_get_variable(channel, uvar1), + switch_channel_get_variable(channel, dvar1), + switch_channel_get_variable(br_b_channel, uvar2), + switch_channel_get_variable(br_b_channel, dvar2)); + + switch_channel_add_variable_var_check(br_b_channel, SWITCH_TRANSFER_HISTORY_VARIABLE, cp->transfer_source, SWITCH_FALSE, SWITCH_STACK_PUSH); + switch_channel_set_variable(br_b_channel, SWITCH_TRANSFER_SOURCE_VARIABLE, cp->transfer_source); + + switch_core_session_rwunlock(br_b_session); + } + + + + if ((br_a_session = switch_core_session_locate(br_a)) ) { + switch_channel_t *br_a_channel = switch_core_session_get_channel(br_a_session); + switch_caller_profile_t *cp = switch_channel_get_caller_profile(br_a_channel); + + if (switch_channel_direction(br_a_channel) == SWITCH_CALL_DIRECTION_INBOUND) { + uvar2 = "sip_from_user"; + dvar2 = "sip_from_host"; + } else { + uvar2 = "sip_to_user"; + dvar2 = "sip_to_host"; + } + + cp->transfer_source = switch_core_sprintf(cp->pool, + "%ld:%s:att_xfer:%s@%s/%s@%s", + (long) switch_epoch_time_now(NULL), + cp->uuid_str, + switch_channel_get_variable(channel, uvar1), + switch_channel_get_variable(channel, dvar1), + switch_channel_get_variable(br_a_channel, uvar2), + switch_channel_get_variable(br_a_channel, dvar2)); + + switch_channel_add_variable_var_check(br_a_channel, SWITCH_TRANSFER_HISTORY_VARIABLE, cp->transfer_source, SWITCH_FALSE, SWITCH_STACK_PUSH); + switch_channel_set_variable(br_a_channel, SWITCH_TRANSFER_SOURCE_VARIABLE, cp->transfer_source); + + switch_core_session_rwunlock(br_a_session); + } + + +} + +static switch_bool_t attended_transfer(switch_core_session_t *session, switch_core_session_t *b_session) { + verto_pvt_t *tech_pvt = NULL, *b_tech_pvt = NULL; + switch_bool_t result = SWITCH_FALSE; + const char *br_a = NULL, *br_b = NULL; + + tech_pvt = switch_core_session_get_private_class(session, SWITCH_PVT_SECONDARY); + b_tech_pvt = switch_core_session_get_private_class(b_session, SWITCH_PVT_SECONDARY); + + switch_channel_set_variable(tech_pvt->channel, "refer_uuid", switch_core_session_get_uuid(b_tech_pvt->session)); + switch_channel_set_variable(b_tech_pvt->channel, "transfer_disposition", "replaced"); + + br_a = switch_channel_get_partner_uuid(tech_pvt->channel); + br_b = switch_channel_get_partner_uuid(b_tech_pvt->channel); + + if (!switch_ivr_uuid_exists(br_a)) { + br_a = NULL; + } + + if (!switch_ivr_uuid_exists(br_b)) { + br_b = NULL; + } + + if (switch_channel_test_flag(b_tech_pvt->channel, CF_ORIGINATOR)) { + switch_core_session_t *a_session; + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, + "Attended Transfer on originating session %s\n", switch_core_session_get_uuid(b_session)); + + + + switch_channel_set_variable_printf(b_tech_pvt->channel, "transfer_to", "satt:%s", br_a); + + switch_channel_set_variable(b_tech_pvt->channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER"); + + + switch_channel_clear_flag(b_tech_pvt->channel, CF_LEG_HOLDING); + switch_channel_set_variable(b_tech_pvt->channel, SWITCH_HOLDING_UUID_VARIABLE, br_a); + switch_channel_set_flag(b_tech_pvt->channel, CF_XFER_ZOMBIE); + switch_channel_set_flag(b_tech_pvt->channel, CF_TRANSFER); + + + if ((a_session = switch_core_session_locate(br_a))) { + const char *moh = "local_stream://moh"; + switch_channel_t *a_channel = switch_core_session_get_channel(a_session); + switch_caller_profile_t *prof = switch_channel_get_caller_profile(b_tech_pvt->channel); + const char *tmp; + + switch_core_event_hook_add_state_change(a_session, xfer_hanguphook); + switch_channel_set_variable(a_channel, "att_xfer_kill_uuid", switch_core_session_get_uuid(b_session)); + switch_channel_set_variable(a_channel, "att_xfer_destination_number", prof->destination_number); + switch_channel_set_variable(a_channel, "att_xfer_callee_id_name", prof->callee_id_name); + switch_channel_set_variable(a_channel, "att_xfer_callee_id_number", prof->callee_id_number); + + if ((tmp = switch_channel_get_hold_music(a_channel))) { + moh = tmp; + } + + if (!zstr(moh) && !strcasecmp(moh, "silence")) { + moh = NULL; + } + + if (moh) { + char *xdest; + xdest = switch_core_session_sprintf(a_session, "endless_playback:%s,park", moh); + switch_ivr_session_transfer(a_session, xdest, "inline", NULL); + } else { + switch_ivr_session_transfer(a_session, "park", "inline", NULL); + } + + switch_core_session_rwunlock(a_session); + + result = SWITCH_TRUE; + + if (b_tech_pvt) { + switch_channel_hangup(b_tech_pvt->channel, SWITCH_CAUSE_NORMAL_CLEARING); + } + } else { + result = SWITCH_FALSE; + } + + } else if (br_a && br_b) { + switch_core_session_t *tmp = NULL; + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Attended Transfer [%s][%s]\n", + switch_str_nil(br_a), switch_str_nil(br_b)); + + if ((tmp = switch_core_session_locate(br_b))) { + switch_channel_t *tchannel = switch_core_session_get_channel(tmp); + + switch_channel_set_variable(tchannel, "transfer_disposition", "bridge"); + + switch_channel_set_flag(tchannel, CF_ATTENDED_TRANSFER); + switch_core_session_rwunlock(tmp); + } + + if (switch_true(switch_channel_get_variable(tech_pvt->channel, "recording_follow_transfer")) && + (tmp = switch_core_session_locate(br_a))) { + switch_channel_set_variable(switch_core_session_get_channel(tmp), "transfer_disposition", "bridge"); + switch_core_media_bug_transfer_recordings(session, tmp); + switch_core_session_rwunlock(tmp); + } + + + if (switch_true(switch_channel_get_variable(b_tech_pvt->channel, "recording_follow_transfer")) && + (tmp = switch_core_session_locate(br_b))) { + switch_core_media_bug_transfer_recordings(b_session, tmp); + switch_core_session_rwunlock(tmp); + } + + switch_channel_set_variable_printf(tech_pvt->channel, "transfer_to", "att:%s", br_b); + + mark_transfer_record(session, br_a, br_b); + + switch_ivr_uuid_bridge(br_a, br_b); + switch_channel_set_variable(b_tech_pvt->channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER"); + + result = SWITCH_TRUE; + + switch_channel_clear_flag(b_tech_pvt->channel, CF_LEG_HOLDING); + switch_channel_set_variable(b_tech_pvt->channel, "park_timeout", "2:attended_transfer"); + switch_channel_set_state(b_tech_pvt->channel, CS_PARK); + + } else { + if (!br_a && !br_b) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, + "Cannot transfer channels that are not in a bridge.\n"); + result = SWITCH_FALSE; + } else { + switch_core_session_t *t_session, *hup_session; + switch_channel_t *hup_channel; + const char *ext; + + if (br_a && !br_b) { + t_session = switch_core_session_locate(br_a); + hup_channel = b_tech_pvt->channel; + hup_session = b_session; + } else { + verto_pvt_t *h_tech_pvt = (verto_pvt_t *) switch_core_session_get_private_class(b_session, SWITCH_PVT_SECONDARY); + t_session = switch_core_session_locate(br_b); + hup_channel = tech_pvt->channel; + hup_session = session; + switch_channel_clear_flag(h_tech_pvt->channel, CF_LEG_HOLDING); + switch_channel_hangup(b_tech_pvt->channel, SWITCH_CAUSE_ATTENDED_TRANSFER); + } + + if (t_session) { + //switch_channel_t *t_channel = switch_core_session_get_channel(t_session); + const char *idest = switch_channel_get_variable(hup_channel, "inline_destination"); + ext = switch_channel_get_variable(hup_channel, "destination_number"); + + if (switch_true(switch_channel_get_variable(hup_channel, "recording_follow_transfer"))) { + switch_core_media_bug_transfer_recordings(hup_session, t_session); + } + + if (idest) { + switch_ivr_session_transfer(t_session, idest, "inline", NULL); + } else { + switch_ivr_session_transfer(t_session, ext, NULL, NULL); + } + + result = SWITCH_TRUE; + switch_channel_hangup(hup_channel, SWITCH_CAUSE_ATTENDED_TRANSFER); + } else { + result = SWITCH_FALSE; + } + } + } + if (b_session) { + switch_core_session_rwunlock(b_session); + } + + return result; +} + + +static switch_bool_t verto__modify_func(const char *method, cJSON *params, jsock_t *jsock, cJSON **response) +{ + cJSON *obj = cJSON_CreateObject(); + switch_core_session_t *session; + cJSON *dialog = NULL; + const char *call_id = NULL, *destination = NULL, *action = NULL; + int err = 0; + + *response = obj; + + if (!(dialog = cJSON_GetObjectItem(params, "dialogParams"))) { + cJSON_AddItemToObject(obj, "message", cJSON_CreateString("Dialog data missing")); + err = 1; goto cleanup; + } + + if (!(call_id = cJSON_GetObjectCstr(dialog, "callID"))) { + cJSON_AddItemToObject(obj, "message", cJSON_CreateString("CallID missing")); + err = 1; goto cleanup; + } + + if (!(action = cJSON_GetObjectCstr(params, "action"))) { + cJSON_AddItemToObject(obj, "message", cJSON_CreateString("action missing")); + err = 1; goto cleanup; + } + + cJSON_AddItemToObject(obj, "callID", cJSON_CreateString(call_id)); + cJSON_AddItemToObject(obj, "action", cJSON_CreateString(action)); + + + if ((session = switch_core_session_locate(call_id))) { + verto_pvt_t *tech_pvt = switch_core_session_get_private_class(session, SWITCH_PVT_SECONDARY); + + if (!strcasecmp(action, "transfer")) { + switch_core_session_t *other_session = NULL; + + if (!(destination = cJSON_GetObjectCstr(params, "destination"))) { + cJSON_AddItemToObject(obj, "message", cJSON_CreateString("destination missing")); + err = 1; goto rwunlock; + } + + if (switch_core_session_get_partner(tech_pvt->session, &other_session) == SWITCH_STATUS_SUCCESS) { + switch_ivr_session_transfer(other_session, destination, NULL, NULL); + cJSON_AddItemToObject(obj, "message", cJSON_CreateString("CALL TRANSFERRED")); + switch_core_session_rwunlock(other_session); + } else { + cJSON_AddItemToObject(obj, "message", cJSON_CreateString("call is not bridged")); + err = 1; goto rwunlock; + } + + } else if (!strcasecmp(action, "replace")) { + const char *replace_call_id; + switch_core_session_t *b_session = NULL; + + if (!(replace_call_id = cJSON_GetObjectCstr(params, "replaceCallID"))) { + cJSON_AddItemToObject(obj, "message", cJSON_CreateString("replaceCallID missing")); + err = 1; goto rwunlock; + } + + if ((b_session = switch_core_session_locate(replace_call_id))) { + err = (int) attended_transfer(session, b_session); + if (err) { + cJSON_AddItemToObject(obj, "message", cJSON_CreateString("transfer failed")); + } + switch_core_session_rwunlock(b_session); + } else { + cJSON_AddItemToObject(obj, "message", cJSON_CreateString("invalid transfer leg")); + err = 1; goto rwunlock; + } + } else if (!strcasecmp(action, "hold")) { + switch_core_media_toggle_hold(session, 1); + } else if (!strcasecmp(action, "unhold")) { + switch_core_media_toggle_hold(session, 0); + } else if (!strcasecmp(action, "toggleHold")) { + switch_core_media_toggle_hold(session, !!!switch_channel_test_flag(tech_pvt->channel, CF_PROTO_HOLD)); + } + + cJSON_AddItemToObject(obj, "holdState", cJSON_CreateString(switch_channel_test_flag(tech_pvt->channel, CF_PROTO_HOLD) ? "held" : "active")); + + + rwunlock: + + switch_core_session_rwunlock(session); + } else { + err = 1; + } + + cleanup: + + + if (!err) return SWITCH_TRUE; + + cJSON_AddItemToObject(obj, "message", cJSON_CreateString("CALL DOES NOT EXIST")); + cJSON_AddItemToObject(obj, "code", cJSON_CreateNumber(CODE_SESSION_ERROR)); + + + return SWITCH_FALSE; +} + +static switch_bool_t verto__attach_func(const char *method, cJSON *params, jsock_t *jsock, cJSON **response) +{ + cJSON *obj = cJSON_CreateObject(); + switch_core_session_t *session = NULL; + int err = 0; + cJSON *dialog; + verto_pvt_t *tech_pvt = NULL; + const char *call_id = NULL, *sdp = NULL; + uint8_t match = 0, p = 0; + + *response = obj; + + if (!(dialog = cJSON_GetObjectItem(params, "dialogParams"))) { + cJSON_AddItemToObject(obj, "message", cJSON_CreateString("Dialog data missing")); + err = 1; goto cleanup; + } + + if (!(call_id = cJSON_GetObjectCstr(dialog, "callID"))) { + cJSON_AddItemToObject(obj, "message", cJSON_CreateString("CallID missing")); + err = 1; goto cleanup; + } + + if (!(sdp = cJSON_GetObjectCstr(params, "sdp"))) { + cJSON_AddItemToObject(obj, "message", cJSON_CreateString("SDP missing")); + err = 1; goto cleanup; + } + + if (!(call_id = cJSON_GetObjectCstr(dialog, "callID"))) { + cJSON_AddItemToObject(obj, "message", cJSON_CreateString("CallID missing")); + err = 1; goto cleanup; + } + + if (!(session = switch_core_session_locate(call_id))) { + cJSON_AddItemToObject(obj, "message", cJSON_CreateString("Call does not exist")); + err = 1; goto cleanup; + } + + tech_pvt = switch_core_session_get_private_class(session, SWITCH_PVT_SECONDARY); + tech_pvt->r_sdp = switch_core_session_strdup(session, sdp); + + switch_channel_set_variable(tech_pvt->channel, SWITCH_R_SDP_VARIABLE, tech_pvt->r_sdp); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Remote SDP %s:\n%s\n", + switch_channel_get_name(tech_pvt->channel), tech_pvt->r_sdp); + + switch_channel_set_flag(tech_pvt->channel, CF_REINVITE); + + if ((match = switch_core_media_negotiate_sdp(tech_pvt->session, tech_pvt->r_sdp, &p, SDP_TYPE_RESPONSE))) { + if (switch_core_media_activate_rtp(tech_pvt->session) != SWITCH_STATUS_SUCCESS) { + switch_channel_set_variable(tech_pvt->channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "MEDIA ERROR"); + cJSON_AddItemToObject(obj, "message", cJSON_CreateString("MEDIA ERROR")); + err = 1; goto cleanup; + } + } else { + switch_channel_set_variable(tech_pvt->channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "CODEC NEGOTIATION ERROR"); + cJSON_AddItemToObject(obj, "message", cJSON_CreateString("CODEC NEGOTIATION ERROR")); + err = 1; goto cleanup; + } + + cleanup: + + if (tech_pvt) { + switch_channel_clear_flag(tech_pvt->channel, CF_REINVITE); + switch_clear_flag(tech_pvt, TFLAG_ATTACH_REQ); + if (switch_channel_test_flag(tech_pvt->channel, CF_CONFERENCE)) { + switch_channel_set_flag(tech_pvt->channel, CF_CONFERENCE_ADV); + } + } + + if (session) { + switch_core_session_rwunlock(session); + } + + if (!err) { + return SWITCH_TRUE; + } + + if (tech_pvt && tech_pvt->channel) { + switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_BEARERCAPABILITY_NOTAVAIL); + } + + + cJSON_AddItemToObject(obj, "code", cJSON_CreateNumber(CODE_SESSION_ERROR)); + + return SWITCH_FALSE; +} + +static switch_bool_t verto__info_func(const char *method, cJSON *params, jsock_t *jsock, cJSON **response) +{ + cJSON *msg = NULL, *dialog = NULL; + const char *call_id = NULL, *dtmf = NULL; + switch_bool_t r = SWITCH_TRUE; + char *proto = VERTO_CHAT_PROTO; + char *pproto = NULL; + + *response = cJSON_CreateObject(); + + if ((dialog = cJSON_GetObjectItem(params, "dialogParams")) && (call_id = cJSON_GetObjectCstr(dialog, "callID"))) { + switch_core_session_t *session = NULL; + + if ((session = switch_core_session_locate(call_id))) { + + if ((dtmf = cJSON_GetObjectCstr(params, "dtmf"))) { + verto_pvt_t *tech_pvt = switch_core_session_get_private_class(session, SWITCH_PVT_SECONDARY); + char *send = switch_mprintf("~%s", dtmf); + switch_channel_queue_dtmf_string(tech_pvt->channel, send); + free(send); + cJSON_AddItemToObject(*response, "message", cJSON_CreateString("SENT")); + } + + switch_core_session_rwunlock(session); + } + } + + if ((msg = cJSON_GetObjectItem(params, "msg"))) { + switch_event_t *event; + char *to = (char *) cJSON_GetObjectCstr(msg, "to"); + cJSON *indialog = cJSON_GetObjectItem(msg, "inDialog"); + const char *body = cJSON_GetObjectCstr(msg, "body"); + + + if (!zstr(to)) { + if (strchr(to, '+')) { + pproto = strdup(to); + if ((to = strchr(pproto, '+'))) { + *to++ = '\0'; + } + proto = pproto; + } + } + + if (!zstr(to) && !zstr(body) && switch_event_create(&event, SWITCH_EVENT_MESSAGE) == SWITCH_STATUS_SUCCESS) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", VERTO_CHAT_PROTO); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "from", jsock->uid); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "from_user", jsock->id); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "from_host", jsock->domain); + + + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "to", to); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "type", "text/plain"); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "from_full", jsock->id); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "verto_profile", jsock->profile->name); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "verto_jsock_uuid", jsock->uuid_str); + + if (indialog && (indialog->type == cJSON_True || (indialog->type == cJSON_String && switch_true(indialog->valuestring))) && call_id) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "call_id", call_id); + } + + switch_event_add_body(event, "%s", body); + + if (strcasecmp(proto, VERTO_CHAT_PROTO)) { + switch_core_chat_send(proto, event); + } + + switch_core_chat_send("GLOBAL", event); + + switch_event_destroy(&event); + + } else { + r = SWITCH_FALSE; + cJSON_AddItemToObject(*response, "message", cJSON_CreateString("INVALID MESSAGE to and body params required")); + } + + + switch_safe_free(pproto); + } + + + return r; +} + +static switch_bool_t verto__invite_func(const char *method, cJSON *params, jsock_t *jsock, cJSON **response) +{ + cJSON *obj = cJSON_CreateObject(); + switch_core_session_t *session = NULL; + switch_channel_t *channel; + switch_event_t *var_event; + switch_call_cause_t reason = SWITCH_CAUSE_INVALID_MSG_UNSPECIFIED, cancel_cause = 0; + switch_caller_profile_t *caller_profile; + int err = 0; + cJSON *dialog; + verto_pvt_t *tech_pvt; + char name[512]; + const char *var, *destination_number, *call_id = NULL, *sdp = NULL, *caller_id_name = NULL, *caller_id_number = NULL, *context = NULL; + + *response = obj; + + switch_event_create_plain(&var_event, SWITCH_EVENT_CHANNEL_DATA); + + if (!(dialog = cJSON_GetObjectItem(params, "dialogParams"))) { + cJSON_AddItemToObject(obj, "message", cJSON_CreateString("Dialog data missing")); + err = 1; goto cleanup; + } + + if (!(call_id = cJSON_GetObjectCstr(dialog, "callID"))) { + cJSON_AddItemToObject(obj, "message", cJSON_CreateString("CallID missing")); + err = 1; goto cleanup; + } + + if (!(sdp = cJSON_GetObjectCstr(params, "sdp"))) { + cJSON_AddItemToObject(obj, "message", cJSON_CreateString("SDP missing")); + err = 1; goto cleanup; + } + + switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, "origination_uuid", call_id); + if ((reason = switch_core_session_outgoing_channel(NULL, var_event, "rtc", + NULL, &session, NULL, SOF_NONE, &cancel_cause)) != SWITCH_CAUSE_SUCCESS) { + cJSON_AddItemToObject(obj, "message", cJSON_CreateString("Cannot create channel")); + err = 1; goto cleanup; + } + + channel = switch_core_session_get_channel(session); + switch_channel_set_direction(channel, SWITCH_CALL_DIRECTION_INBOUND); + + tech_pvt = switch_core_session_alloc(session, sizeof(*tech_pvt)); + tech_pvt->session = session; + tech_pvt->channel = channel; + tech_pvt->jsock_uuid = switch_core_session_strdup(session, jsock->uuid_str); + tech_pvt->r_sdp = switch_core_session_strdup(session, sdp); + switch_core_media_set_sdp_codec_string(session, sdp, SDP_TYPE_REQUEST); + switch_core_session_set_private_class(session, tech_pvt, SWITCH_PVT_SECONDARY); + + + tech_pvt->call_id = switch_core_session_strdup(session, call_id); + if ((tech_pvt->smh = switch_core_session_get_media_handle(session))) { + tech_pvt->mparams = switch_core_media_get_mparams(tech_pvt->smh); + verto_set_media_options(tech_pvt, jsock->profile); + } else { + cJSON_AddItemToObject(obj, "message", cJSON_CreateString("Cannot create media handle")); + err = 1; goto cleanup; + } + + if (!(destination_number = cJSON_GetObjectCstr(dialog, "destination_number"))) { + destination_number = "service"; + } + + switch_snprintf(name, sizeof(name), "verto.rtc/%s", destination_number); + switch_channel_set_name(channel, name); + switch_channel_set_variable(channel, "jsock_uuid_str", jsock->uuid_str); + switch_channel_set_variable(channel, "verto_user", jsock->uid); + switch_channel_set_variable(channel, "verto_host", jsock->domain); + switch_channel_set_variable(channel, "event_channel_cookie", tech_pvt->jsock_uuid); + switch_channel_set_variable(channel, "verto_profile_name", jsock->profile->name); + + caller_id_name = cJSON_GetObjectCstr(dialog, "caller_id_name"); + caller_id_number = cJSON_GetObjectCstr(dialog, "caller_id_number"); + + if (zstr(caller_id_name)) { + if ((var = switch_event_get_header(jsock->params, "caller-id-name"))) { + caller_id_name = var; + } + } + + if (zstr(caller_id_number)) { + if ((var = switch_event_get_header(jsock->params, "caller-id-number"))) { + caller_id_number = var; + } + } + + if (!(context = switch_event_get_header(jsock->vars, "user_context"))) { + context = switch_either(jsock->context, jsock->profile->context); + } + + if ((caller_profile = switch_caller_profile_new(switch_core_session_get_pool(session), + jsock->uid, + switch_either(jsock->dialplan, jsock->profile->dialplan), + caller_id_name, + caller_id_number, + inet_ntoa(jsock->remote_addr.sin_addr), + cJSON_GetObjectCstr(dialog, "ani"), + cJSON_GetObjectCstr(dialog, "aniii"), + cJSON_GetObjectCstr(dialog, "rdnis"), + modname, + context, + destination_number))) { + + switch_channel_set_caller_profile(channel, caller_profile); + + } + + + switch_channel_set_variable(channel, SWITCH_R_SDP_VARIABLE, sdp); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Remote SDP %s:\n%s\n", switch_channel_get_name(tech_pvt->channel), sdp); + + cJSON_AddItemToObject(obj, "message", cJSON_CreateString("CALL CREATED")); + cJSON_AddItemToObject(obj, "callID", cJSON_CreateString(tech_pvt->call_id)); + + switch_channel_add_state_handler(channel, &verto_state_handlers); + switch_core_event_hook_add_receive_message(session, messagehook); + switch_channel_set_state(channel, CS_INIT); + track_pvt(tech_pvt); + switch_core_session_thread_launch(session); + + cleanup: + + switch_event_destroy(&var_event); + + if (!err) { + return SWITCH_TRUE; + } + + if (session) { + switch_core_session_destroy(&session); + } + + cJSON_AddItemToObject(obj, "causeCode", cJSON_CreateNumber(reason)); + cJSON_AddItemToObject(obj, "cause", cJSON_CreateString(switch_channel_cause2str(reason))); + cJSON_AddItemToObject(obj, "message", cJSON_CreateString("CALL ERROR")); + cJSON_AddItemToObject(obj, "code", cJSON_CreateNumber(CODE_SESSION_ERROR)); + + return SWITCH_FALSE; + +} + +static switch_bool_t event_channel_check_auth(jsock_t *jsock, const char *event_channel) +{ + + char *main_event_channel = NULL; + switch_bool_t ok = SWITCH_TRUE, pre_ok = SWITCH_FALSE; + switch_core_session_t *session = NULL; + + switch_assert(event_channel); + + pre_ok = switch_event_channel_permission_verify(jsock->uuid_str, event_channel); + + if (!pre_ok && (session = switch_core_session_locate(event_channel))) { + switch_channel_t *channel = switch_core_session_get_channel(session); + const char *jsock_uuid_str = switch_channel_get_variable(channel, "jsock_uuid_str"); + + if (jsock_uuid_str && !strcmp(jsock_uuid_str, jsock->uuid_str)) { + pre_ok = SWITCH_TRUE; + } + + switch_core_session_rwunlock(session); + } + + if (pre_ok) { + return pre_ok; + } + + if (jsock->allowed_event_channels) { + if (strchr(event_channel, '.')) { + char *p; + main_event_channel = strdup(event_channel); + if ((p = strchr(main_event_channel, '.'))) { + *p = '\0'; + } + } + + if (!(switch_event_get_header(jsock->allowed_event_channels, event_channel) || + (main_event_channel && switch_event_get_header(jsock->allowed_event_channels, main_event_channel)))) { + ok = SWITCH_FALSE; + } + } + + switch_safe_free(main_event_channel); + return ok; + +} + +static switch_bool_t parse_subs(jsock_t *jsock, const char *event_channel, cJSON **sub_list, cJSON **err_list, cJSON **exist_list) +{ + switch_bool_t r = SWITCH_FALSE; + + if (event_channel_check_auth(jsock, event_channel)) { + if (!*sub_list) { + *sub_list = cJSON_CreateArray(); + } + + if (jsock_sub_channel(jsock, event_channel) == SWITCH_STATUS_SUCCESS) { + cJSON_AddItemToArray(*sub_list, cJSON_CreateString(event_channel)); + } else { + if (!*exist_list) { + *exist_list = cJSON_CreateArray(); + } + cJSON_AddItemToArray(*exist_list, cJSON_CreateString(event_channel)); + } + + r = SWITCH_TRUE; + } else { + if (!*err_list) { + *err_list = cJSON_CreateArray(); + } + cJSON_AddItemToArray(*err_list, cJSON_CreateString(event_channel)); + } + + return r; +} + +static switch_bool_t verto__subscribe_func(const char *method, cJSON *params, jsock_t *jsock, cJSON **response) +{ + switch_bool_t r = SWITCH_TRUE; + cJSON *subs = NULL, *errs = NULL, *exist = NULL; + + *response = cJSON_CreateObject(); + + if (params) { + cJSON *jchannel = cJSON_GetObjectItem(params, "eventChannel"); + + if (jchannel) { + if (jchannel->type == cJSON_String) { + parse_subs(jsock, jchannel->valuestring, &subs, &errs, &exist); + } else if (jchannel->type == cJSON_Array) { + int i, len = cJSON_GetArraySize(jchannel); + + for(i = 0; i < len; i++) { + cJSON *str = cJSON_GetArrayItem(jchannel, i); + if (str->type == cJSON_String) { + parse_subs(jsock, str->valuestring, &subs, &errs, &exist); + } + } + } + } + } + + if (subs) { + cJSON_AddItemToObject(*response, "subscribedChannels", subs); + } + + if (errs) { + cJSON_AddItemToObject(*response, "unauthorizedChannels", errs); + } + + if (exist) { + cJSON_AddItemToObject(*response, "alreadySubscribedChannels", exist); + } + + if (!subs) { + r = SWITCH_FALSE; + } + + return r; +} + +static void do_unsub(jsock_t *jsock, const char *event_channel, cJSON **subs, cJSON **errs) +{ + if (jsock_unsub_channel(jsock, event_channel)) { + if (!*subs) { + *subs = cJSON_CreateArray(); + } + cJSON_AddItemToArray(*subs, cJSON_CreateString(event_channel)); + } else { + if (!*errs) { + *errs = cJSON_CreateArray(); + } + cJSON_AddItemToArray(*errs, cJSON_CreateString(event_channel)); + } +} + +static switch_bool_t verto__unsubscribe_func(const char *method, cJSON *params, jsock_t *jsock, cJSON **response) +{ + switch_bool_t r = SWITCH_TRUE; + cJSON *subs = NULL, *errs = NULL; + + *response = cJSON_CreateObject(); + + if (params) { + cJSON *jchannel = cJSON_GetObjectItem(params, "eventChannel"); + + if (jchannel) { + if (jchannel->type == cJSON_String) { + do_unsub(jsock, jchannel->valuestring, &subs, &errs); + } else if (jchannel->type == cJSON_Array) { + int i, len = cJSON_GetArraySize(jchannel); + + for(i = 0; i < len; i++) { + cJSON *str = cJSON_GetArrayItem(jchannel, i); + if (str->type == cJSON_String) { + do_unsub(jsock, str->valuestring, &subs, &errs); + } + } + } + } + } + + if (subs) { + cJSON_AddItemToObject(*response, "unsubscribedChannels", subs); + } + + if (errs) { + cJSON_AddItemToObject(*response, "notSubscribedChannels", errs); + } + + if (errs && !subs) { + r = SWITCH_FALSE; + } + + return r; +} + +static switch_bool_t verto__broadcast_func(const char *method, cJSON *params, jsock_t *jsock, cJSON **response) +{ + char *json_text = NULL; + switch_bool_t r = SWITCH_FALSE; + const char *event_channel = cJSON_GetObjectCstr(params, "eventChannel"); + cJSON *jevent; + + *response = cJSON_CreateObject(); + + + if (!event_channel) { + cJSON_AddItemToObject(*response, "message", cJSON_CreateString("eventChannel not specified.")); + cJSON_AddItemToObject(*response, "code", cJSON_CreateNumber(CODE_SESSION_ERROR)); + goto end; + } + + if (!event_channel_check_auth(jsock, event_channel)) { + cJSON_AddItemToObject(*response, "message", cJSON_CreateString("Permission Denied.")); + cJSON_AddItemToObject(*response, "code", cJSON_CreateNumber(CODE_SESSION_ERROR)); + goto end; + } + + + cJSON_AddItemToObject(params, "userid", cJSON_CreateString(jsock->uid)); + + jevent = cJSON_Duplicate(params, 1); + switch_event_channel_broadcast(event_channel, &jevent, modname, globals.event_channel_id); + + if (jsock->profile->mcast_pub.sock > -1) { + if ((json_text = cJSON_PrintUnformatted(params))) { + + mcast_socket_send(&jsock->profile->mcast_pub, json_text, strlen(json_text) + 1); + + + free(json_text); + json_text = NULL; + r = SWITCH_TRUE; + cJSON_AddItemToObject(*response, "message", cJSON_CreateString("MCAST Data Sent")); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "JSON ERROR!\n"); + } + } + + end: + + return r; +} + +static switch_bool_t login_func(const char *method, cJSON *params, jsock_t *jsock, cJSON **response) +{ + *response = cJSON_CreateObject(); + cJSON_AddItemToObject(*response, "message", cJSON_CreateString("logged in")); + + return SWITCH_TRUE; +} + +static switch_bool_t echo_func(const char *method, cJSON *params, jsock_t *jsock, cJSON **response) +{ + *response = cJSON_Duplicate(params, 1); + return SWITCH_TRUE; +} + +static switch_bool_t jsapi_func(const char *method, cJSON *params, jsock_t *jsock, cJSON **response) +{ + if (jsock->allowed_jsapi) { + const char *function; + + if (params) { + if ((function = cJSON_GetObjectCstr(params, "command"))) { + if (!switch_event_get_header(jsock->allowed_jsapi, function)) { + return SWITCH_FALSE; + } + + if (jsock->allowed_fsapi && !strcmp(function, "fsapi")) { + cJSON *cmd = cJSON_GetObjectItem(params, "cmd"); + cJSON *arg = cJSON_GetObjectItem(params, "arg"); + + if (cmd->type == cJSON_String && cmd->valuestring && !auth_api_command(jsock, cmd->valuestring, arg ? arg->valuestring : NULL)) { + return SWITCH_FALSE; + } + } + } + } + } + + switch_json_api_execute(params, NULL, response); + + return *response ? SWITCH_TRUE : SWITCH_FALSE; +} + +static switch_bool_t fsapi_func(const char *method, cJSON *params, jsock_t *jsock, cJSON **response) +{ + cJSON *cmd, *arg, *reply; + switch_stream_handle_t stream = { 0 }; + switch_status_t status = SWITCH_STATUS_SUCCESS; + + cmd = cJSON_GetObjectItem(params, "cmd"); + arg = cJSON_GetObjectItem(params, "arg"); + + + if (jsock->allowed_fsapi) { + if (cmd->type == cJSON_String && cmd->valuestring && !auth_api_command(jsock, cmd->valuestring, arg ? arg->valuestring : NULL)) { + return SWITCH_FALSE; + } + } + + if (cmd && !cmd->valuestring) { + cmd = NULL; + } + + if (arg && !arg->valuestring) { + arg = NULL; + } + + reply = cJSON_CreateObject(); + + SWITCH_STANDARD_STREAM(stream); + + if (cmd && (status = switch_api_execute(cmd->valuestring, arg ? arg->valuestring : NULL, NULL, &stream)) == SWITCH_STATUS_SUCCESS) { + cJSON_AddItemToObject(reply, "message", cJSON_CreateString((char *) stream.data)); + } else { + cJSON_AddItemToObject(reply, "message", cJSON_CreateString("INVALID CALL")); + } + + switch_safe_free(stream.data); + + if (reply) { + *response = reply; + return SWITCH_TRUE; + } + + return SWITCH_FALSE; +} + +//// + +static void jrpc_init(void) +{ + jrpc_add_func("echo", echo_func); + jrpc_add_func("jsapi", jsapi_func); + jrpc_add_func("fsapi", fsapi_func); + jrpc_add_func("login", login_func); + + jrpc_add_func("verto.invite", verto__invite_func); + jrpc_add_func("verto.info", verto__info_func); + jrpc_add_func("verto.attach", verto__attach_func); + jrpc_add_func("verto.bye", verto__bye_func); + jrpc_add_func("verto.answer", verto__answer_func); + jrpc_add_func("verto.subscribe", verto__subscribe_func); + jrpc_add_func("verto.unsubscribe", verto__unsubscribe_func); + jrpc_add_func("verto.broadcast", verto__broadcast_func); + jrpc_add_func("verto.modify", verto__modify_func); + +} + + + + +static int start_jsock(verto_profile_t *profile, int sock) +{ + jsock_t *jsock = NULL; + int flag = 1; + int i; + unsigned int len; + jsock_type_t ptype = PTYPE_CLIENT; + switch_thread_data_t *td; + switch_memory_pool_t *pool; + + switch_core_new_memory_pool(&pool); + + + jsock = (jsock_t *) switch_core_alloc(pool, sizeof(*jsock)); + jsock->pool = pool; + + len = sizeof(jsock->remote_addr); + + if ((jsock->client_socket = accept(sock, (struct sockaddr *) &jsock->remote_addr, &len)) < 0) { + die("ACCEPT FAILED\n"); + } + + for (i = 0; i < profile->i; i++) { + if ( profile->server_socket[i] == sock ) { + if (profile->ip[i].secure) { + ptype = PTYPE_CLIENT_SSL; + } + break; + } + } + + jsock->local_sock = sock; + jsock->profile = profile; + + if (zstr(jsock->name)) { + jsock->name = switch_core_sprintf(pool, "%s:%d", inet_ntoa(jsock->remote_addr.sin_addr), ntohs(jsock->remote_addr.sin_port)); + } + + jsock->ptype = ptype; + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s Client Connect.\n", jsock->name); + + /* no nagle please */ + setsockopt(jsock->client_socket, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag)); + + td = switch_core_alloc(jsock->pool, sizeof(*td)); + + td->alloc = 0; + td->func = client_thread; + td->obj = jsock; + td->pool = pool; + + switch_mutex_init(&jsock->write_mutex, SWITCH_MUTEX_NESTED, jsock->pool); + switch_thread_rwlock_create(&jsock->rwlock, jsock->pool); + switch_thread_pool_launch_thread(&td); + + return 0; + + error: + + if (jsock) { + if (jsock->client_socket > -1) { + close_socket(&jsock->client_socket); + } + + switch_core_destroy_memory_pool(&pool); + } + + return -1; +} + +static int prepare_socket(int ip, int port) +{ + int sock = -1; + int reuse_addr = 1; + struct sockaddr_in addr; + + if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { + die("Socket Error!\n"); + } + + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, sizeof(reuse_addr)); + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = ip; + addr.sin_port = htons(port); + + if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + die("Bind Error!\n"); + return -1; + } + + if (listen(sock, MAXPENDING) < 0) { + die("Listen error\n"); + return -1; + } + + return sock; + + error: + + close_file(&sock); + + return -1; +} + +static void handle_mcast_sub(verto_profile_t *profile) +{ + int bytes = mcast_socket_recv(&profile->mcast_sub, NULL, 0, 0); + + if (bytes > 0) { + cJSON *json; + + profile->mcast_sub.buffer[bytes] = '\0'; + + if ((json = cJSON_Parse((char *)profile->mcast_sub.buffer))) { + jsock_send_event(json); + cJSON_Delete(json); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "MCAST JSON PARSE ERR: %s\n", (char *)profile->mcast_sub.buffer); + } + + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "MCAST INVALID READ %d\n", bytes); + } + +} + +static int runtime(verto_profile_t *profile) +{ + int max = 2; + int i; + + for (i = 0; i < profile->i; i++) { + if ((profile->server_socket[i] = prepare_socket(profile->ip[i].local_ip_addr, profile->ip[i].local_port)) < 0) { + die("Client Socket Error!\n"); + } + } + + if (profile->mcast_ip) { + if (mcast_socket_create(profile->mcast_ip, profile->mcast_port, &profile->mcast_sub, MCAST_RECV | MCAST_TTL_HOST) < 0) { + die("mcast recv socket create"); + } + + if (mcast_socket_create(profile->mcast_ip, profile->mcast_port + 1, &profile->mcast_pub, MCAST_SEND | MCAST_TTL_HOST) > 0) { + mcast_socket_close(&profile->mcast_sub); + die("mcast send socket create"); + } + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "MCAST Bound to %s:%d/%d\n", profile->mcast_ip, profile->mcast_port, profile->mcast_port + 1); + } + + + while(profile->running) { + struct pollfd pfds[MAX_BIND+4]; + int res, x = 0; + int i = 0; + + memset(&pfds[0], 0, sizeof(pfds[0]) * MAX_BIND+2); + + for (i = 0; i < profile->i; i++) { + pfds[i].fd = profile->server_socket[i]; + pfds[i].events = POLLIN|POLLERR; + } + + if (profile->mcast_ip) { + pfds[i].fd = profile->mcast_sub.sock; + pfds[i++].events = POLLIN|POLLERR; + } + + max = i; + + if ((res = poll(pfds, max, 1000)) < 0) { + if (errno != EINTR) { + die("POLL FAILED\n"); + } + } + + if (res == 0) { + continue; + } + + for (x = 0; x < max; x++) { + if (pfds[x].revents & POLLERR) { + die("POLL ERROR\n"); + } + + if (pfds[x].revents & POLLHUP) { + die("POLL HUP\n"); + } + + if (pfds[x].revents & POLLIN) { + if (pfds[x].fd == profile->mcast_sub.sock) { + handle_mcast_sub(profile); + } else { + start_jsock(profile, pfds[x].fd); + } + } + } + } + + if (profile->mcast_sub.sock > -1) { + mcast_socket_close(&profile->mcast_sub); + } + + if (profile->mcast_pub.sock > -1) { + mcast_socket_close(&profile->mcast_pub); + } + + return 0; + + error: + + return -1; + +} + +static void kill_profile(verto_profile_t *profile) +{ + jsock_t *p; + int i; + + profile->running = 0; + + //if (switch_thread_rwlock_tryrdlock(profile->rwlock) != SWITCH_STATUS_SUCCESS) { + // return; + //} + + switch_mutex_lock(profile->mutex); + for (i = 0; i < profile->i; i++) { + close_socket(&profile->server_socket[i]); + } + + for(p = profile->jsock_head; p; p = p->next) { + close_socket(&p->client_socket); + } + switch_mutex_unlock(profile->mutex); + + + + //switch_thread_rwlock_unlock(profile->rwlock); +} + +static void kill_profiles(void) +{ + verto_profile_t *pp; + int sanity = 50; + + switch_mutex_lock(globals.mutex); + for(pp = globals.profile_head; pp; pp = pp->next) { + kill_profile(pp); + } + switch_mutex_unlock(globals.mutex); + + + while(--sanity > 0 && globals.profile_threads > 0) { + usleep(100000); + } +} + + +static void do_shutdown(void) +{ + globals.running = 0; + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Shutting down (SIG %d)\n", globals.sig); + + kill_profiles(); + + unsub_all_jsock(); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Done\n"); +} + +static void parse_ip(char *host, int *port, in_addr_t *addr, char *input) +{ + char *p; + struct hostent *hent; + + strncpy(host, input, 255); + + if ((p = strchr(host, ':')) != NULL) { + *p++ = '\0'; + *port = atoi(p); + } + + if ( host[0] < '0' || host[0] > '9' ) { + // Non-numeric host (at least it doesn't start with one). Convert it to ip addr first + if ((hent = gethostbyname(host)) != NULL) { + if (hent->h_addrtype == AF_INET) { + memcpy(addr, hent->h_addr_list[0], 4); + } + } + + } else { + *addr = inet_addr(host); + } +} + +static verto_profile_t *find_profile(const char *name) +{ + verto_profile_t *p, *r = NULL; + switch_mutex_lock(globals.mutex); + for(p = globals.profile_head; p; p = p->next) { + if (!strcmp(name, p->name)) { + r = p; + break; + } + } + + if (!r->in_thread || !r->running) { + r = NULL; + } + + if (switch_thread_rwlock_tryrdlock(r->rwlock) != SWITCH_STATUS_SUCCESS) { + r = NULL; + } + switch_mutex_unlock(globals.mutex); + + return r; +} + +static switch_bool_t profile_exists(const char *name) +{ + switch_bool_t r = SWITCH_FALSE; + verto_profile_t *p; + + switch_mutex_lock(globals.mutex); + for(p = globals.profile_head; p; p = p->next) { + if (!strcmp(p->name, name)) { + r = SWITCH_TRUE; + break; + } + } + switch_mutex_unlock(globals.mutex); + + return r; +} + +static void del_profile(verto_profile_t *profile) +{ + verto_profile_t *p, *last = NULL; + + switch_mutex_lock(globals.mutex); + for(p = globals.profile_head; p; p = p->next) { + if (p == profile) { + if (last) { + last->next = p->next; + } else { + globals.profile_head = p->next; + } + globals.profile_count--; + break; + } + + last = p; + } + switch_mutex_unlock(globals.mutex); +} + +static switch_status_t add_profile(verto_profile_t *profile) +{ + switch_status_t status = SWITCH_STATUS_FALSE; + + switch_mutex_lock(globals.mutex); + + if (!profile_exists(profile->name)) { + status = SWITCH_STATUS_SUCCESS; + } + + if (status == SWITCH_STATUS_SUCCESS) { + profile->next = globals.profile_head; + globals.profile_head = profile; + globals.profile_count++; + } + + switch_mutex_unlock(globals.mutex); + + return status; +} + +static switch_status_t parse_config(const char *cf) +{ + + switch_xml_t cfg, xml, settings, param, xprofile, xprofiles; + switch_status_t status = SWITCH_STATUS_SUCCESS; + + if (!(xml = switch_xml_open_cfg(cf, &cfg, NULL))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", cf); + return SWITCH_STATUS_TERM; + } + + if ((xprofiles = switch_xml_child(cfg, "profiles"))) { + for (xprofile = switch_xml_child(xprofiles, "profile"); xprofile; xprofile = xprofile->next) { + verto_profile_t *profile; + switch_memory_pool_t *pool; + const char *name = switch_xml_attr(xprofile, "name"); + + if (zstr(name)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Required field name missing\n"); + continue; + } + + if (profile_exists(name)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Profile %s already exists\n", name); + continue; + } + + + switch_core_new_memory_pool(&pool); + profile = switch_core_alloc(pool, sizeof(*profile)); + profile->pool = pool; + profile->name = switch_core_strdup(profile->pool, name); + switch_mutex_init(&profile->mutex, SWITCH_MUTEX_NESTED, profile->pool); + switch_thread_rwlock_create(&profile->rwlock, profile->pool); + add_profile(profile); + + profile->local_network = "localnet.auto"; + + for (param = switch_xml_child(xprofile, "param"); param; param = param->next) { + char *var = NULL; + char *val = NULL; + int i = 0; + + var = (char *) switch_xml_attr_soft(param, "name"); + val = (char *) switch_xml_attr_soft(param, "value"); + + if (!strcasecmp(var, "bind-local")) { + const char *secure = switch_xml_attr_soft(param, "secure"); + if (i < MAX_BIND) { + parse_ip(profile->ip[profile->i].local_ip, &profile->ip[profile->i].local_port, &profile->ip[profile->i].local_ip_addr, val); + if (switch_true(secure)) { + profile->ip[profile->i].secure = 1; + } + profile->i++; + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Max Bindings Reached!\n"); + } + } else if (!strcasecmp(var, "secure-combined")) { + set_string(profile->cert, val); + set_string(profile->key, val); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Secure key and cert specified\n"); + } else if (!strcasecmp(var, "secure-cert")) { + set_string(profile->cert, val); + } else if (!strcasecmp(var, "secure-key")) { + set_string(profile->key, val); + } else if (!strcasecmp(var, "secure-chain")) { + set_string(profile->chain, val); + } else if (!strcasecmp(var, "userauth") && !zstr(val)) { + profile->userauth = switch_core_strdup(profile->pool, val); + } else if (!strcasecmp(var, "root-password") && !zstr(val)) { + profile->root_passwd = switch_core_strdup(profile->pool, val); + } else if (!strcasecmp(var, "context") && !zstr(val)) { + profile->context = switch_core_strdup(profile->pool, val); + } else if (!strcasecmp(var, "dialplan") && !zstr(val)) { + profile->dialplan = switch_core_strdup(profile->pool, val); + } else if (!strcasecmp(var, "mcast-ip") && val) { + profile->mcast_ip = switch_core_strdup(profile->pool, val); + } else if (!strcasecmp(var, "mcast-port") && val) { + profile->mcast_port = (switch_port_t) atoi(val); + } else if (!strcasecmp(var, "timer-name") && !zstr(var)) { + profile->timer_name = switch_core_strdup(profile->pool, val); + } else if (!strcasecmp(var, "local-network") && !zstr(val)) { + profile->local_network = switch_core_strdup(profile->pool, val); + } else if (!strcasecmp(var, "apply-candidate-acl")) { + if (profile->cand_acl_count < SWITCH_MAX_CAND_ACL) { + profile->cand_acl[profile->cand_acl_count++] = switch_core_strdup(profile->pool, val); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Max acl records of %d reached\n", SWITCH_MAX_CAND_ACL); + } + } else if (!strcasecmp(var, "rtp-ip")) { + if (zstr(val)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid RTP IP.\n"); + } else { + if (profile->rtpip_index < MAX_RTPIP -1) { + profile->rtpip[profile->rtpip_index++] = switch_core_strdup(profile->pool, val); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Too many RTP IP.\n"); + } + } + } else if (!strcasecmp(var, "ext-rtp-ip")) { + if (zstr(val)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid External RTP IP.\n"); + } else { + profile->extrtpip = switch_core_strdup(profile->pool, val); + } + } else if (!strcasecmp(var, "debug")) { + if (val) { + profile->debug = atoi(val); + } + } + } + + if (zstr(profile->outbound_codec_string)) { + profile->outbound_codec_string = "opus,vp8"; + } + + if (zstr(profile->inbound_codec_string)) { + profile->outbound_codec_string = profile->outbound_codec_string; + } + + if (zstr(profile->timer_name)) { + profile->timer_name = "soft"; + } + + if (zstr(profile->dialplan)) { + profile->dialplan = "XML"; + } + + if (zstr(profile->context)) { + profile->context = "default"; + } + + if (zstr(profile->ip[0].local_ip) ) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s: local_ip bad\n", profile->name); + if (profile->ip[0].local_port <= 0 ) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s: local_port bad\n", profile->name); + + if (zstr(profile->ip[0].local_ip) || profile->ip[0].local_port <= 0) { + del_profile(profile); + switch_core_destroy_memory_pool(&pool); + } else { + int i; + + for (i = 0; i < profile->i; i++) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s Bound to %s:%d\n", + profile->name, profile->ip[i].local_ip, profile->ip[i].local_port); + } + } + } + } + + if ((settings = switch_xml_child(cfg, "settings"))) { + for (param = switch_xml_child(settings, "param"); param; param = param->next) { + char *var = NULL; + char *val = NULL; + + var = (char *) switch_xml_attr_soft(param, "name"); + val = (char *) switch_xml_attr_soft(param, "value"); + + + if (!strcasecmp(var, "debug")) { + if (val) { + globals.debug = atoi(val); + } + } else if (!strcasecmp(var, "enable-presence") && val) { + globals.enable_presence = switch_true(val); + } else if (!strcasecmp(var, "detach-timeout-sec") && val) { + int tmp = atoi(val); + if (tmp > 0) { + globals.detach_timeout = tmp; + } + } + } + } + + switch_xml_free(xml); + + return status; +} + +static int init(void) +{ + verto_profile_t *p; + + parse_config("verto.conf"); + + switch_mutex_lock(globals.mutex); + for(p = globals.profile_head; p; p = p->next) { + verto_init_ssl(p); + } + switch_mutex_unlock(globals.mutex); + + globals.running = 1; + + return 0; +} + + +#if 0 +static void print_status(verto_profile_t *profile, switch_stream_handle_t *stream) +{ + jsock_t *p; + + stream->write_function(stream, "REMOTE\t\t\tLOCAL\n"); + + for(p = profile->jsock_head; p; p = p->next) { + if (p->ptype & PTYPE_CLIENT) { + int i; + + for (i = 0; i < profile->i; i++) { + if (profile->server_socket[i] == p->local_sock) { + stream->write_function(stream, "%s\t%s:%d\n", p->name, profile->ip[i].local_ip, profile->ip[i].local_port); + } + } + } + } +} +#endif + +SWITCH_STANDARD_API(verto_function) +{ + + int argc = 0; + char *argv[5] = { 0 }; + char *mydata = NULL; + + if (cmd) { + mydata = strdup(cmd); + argc = switch_split(mydata, ' ', argv); + } + + if (argc > 0) { + if (!strcasecmp(argv[0], "connections")) { + //print_status(profile, stream); + } + } + + switch_safe_free(mydata); + + return SWITCH_STATUS_SUCCESS; +} + +static void *SWITCH_THREAD_FUNC profile_thread(switch_thread_t *thread, void *obj) +{ + verto_profile_t *profile = (verto_profile_t *) obj; + int sanity = 50; + + switch_mutex_lock(globals.mutex); + globals.profile_threads++; + switch_mutex_unlock(globals.mutex); + + profile->in_thread = 1; + profile->running = 1; + + + runtime(profile); + profile->running = 0; + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "profile %s shutdown, Waiting for %d threads\n", profile->name, profile->jsock_count); + + while(--sanity > 0 && profile->jsock_count > 0) { + usleep(100000); + } + + verto_deinit_ssl(profile); + + del_profile(profile); + + switch_thread_rwlock_wrlock(profile->rwlock); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s Thread ending\n", profile->name); + switch_thread_rwlock_unlock(profile->rwlock); + profile->in_thread = 0; + + switch_mutex_lock(globals.mutex); + globals.profile_threads--; + switch_mutex_unlock(globals.mutex); + + return NULL; + +} + +static void run_profile_thread(verto_profile_t *profile) { + switch_thread_data_t *td; + + td = switch_core_alloc(profile->pool, sizeof(*td)); + + td->alloc = 0; + td->func = profile_thread; + td->obj = profile; + td->pool = profile->pool; + + switch_thread_pool_launch_thread(&td); +} + +static void run_profiles(void) +{ + verto_profile_t *p; + + switch_mutex_lock(globals.mutex); + for(p = globals.profile_head; p; p = p->next) { + if (!p->in_thread) { + run_profile_thread(p); + } + } + switch_mutex_unlock(globals.mutex); + +} + + +//// ENDPOINT + +switch_endpoint_interface_t *verto_endpoint_interface; +static switch_call_cause_t verto_outgoing_channel(switch_core_session_t *session, + switch_event_t *var_event, + switch_caller_profile_t *outbound_profile, + switch_core_session_t **new_session, + switch_memory_pool_t **pool, + switch_originate_flag_t flags, + switch_call_cause_t *cancel_cause); +switch_io_routines_t verto_io_routines = { + /*.outgoing_channel */ verto_outgoing_channel +}; + +static char *verto_get_dial_string(const char *uid, switch_stream_handle_t *rstream) +{ + jsock_t *jsock; + verto_profile_t *profile; + switch_stream_handle_t *use_stream = NULL, stream = { 0 }; + char *gen_uid = NULL; + int hits = 0; + + if (!strchr(uid, '@')) { + gen_uid = switch_mprintf("%s@%s", uid, switch_core_get_domain(SWITCH_FALSE)); + uid = gen_uid; + } + + if (rstream) { + use_stream = rstream; + } else { + SWITCH_STANDARD_STREAM(stream); + use_stream = &stream; + } + + switch_mutex_lock(globals.mutex); + for(profile = globals.profile_head; profile; profile = profile->next) { + + switch_mutex_lock(profile->mutex); + + for(jsock = profile->jsock_head; jsock; jsock = jsock->next) { + if (!strcmp(uid, jsock->uid)) { + use_stream->write_function(use_stream, "%s/u:%s,", EP_NAME, jsock->uuid_str); + hits++; + } + } + + switch_mutex_unlock(profile->mutex); + } + switch_mutex_unlock(globals.mutex); + + switch_safe_free(gen_uid); + + if (!hits) { + use_stream->write_function(use_stream, "error/user_not_registered"); + } + + if (use_stream->data) { + char *p = use_stream->data; + if (end_of(p) == ',') { + end_of(p) = '\0'; + } + } + + return use_stream->data; +} + +SWITCH_STANDARD_API(verto_contact_function) +{ + char *uid = (char *) cmd; + + if (!zstr(uid)) { + verto_get_dial_string(uid, stream); + } + + return SWITCH_STATUS_SUCCESS; +} + + +static switch_call_cause_t verto_outgoing_channel(switch_core_session_t *session, + switch_event_t *var_event, + switch_caller_profile_t *outbound_profile, + switch_core_session_t **new_session, + switch_memory_pool_t **pool, + switch_originate_flag_t flags, + switch_call_cause_t *cancel_cause) +{ + switch_call_cause_t cause = SWITCH_CAUSE_CHANNEL_UNACCEPTABLE; + char *dest = NULL; + + if (!zstr(outbound_profile->destination_number)) { + dest = strdup(outbound_profile->destination_number); + } + + if (zstr(dest)) { + goto end; + } + + if (!switch_stristr("u:", dest)) { + char *dial_str = verto_get_dial_string(dest, NULL); + + cause = SWITCH_CAUSE_USER_NOT_REGISTERED; + + if (dial_str) { + switch_originate_flag_t myflags = SOF_NONE; + + if ((flags & SOF_NO_LIMITS)) { + myflags |= SOF_NO_LIMITS; + } + + if ((flags & SOF_FORKED_DIAL)) { + myflags |= SOF_NOBLOCK; + } + + if (switch_ivr_originate(session, new_session, &cause, dial_str, 0, NULL, + NULL, NULL, outbound_profile, var_event, myflags, cancel_cause) == SWITCH_STATUS_SUCCESS) { + switch_core_session_rwunlock(*new_session); + } + + free(dial_str); + } + + return cause; + } + + if ((cause = switch_core_session_outgoing_channel(session, var_event, "rtc", + outbound_profile, new_session, NULL, SOF_NONE, cancel_cause)) == SWITCH_CAUSE_SUCCESS) { + switch_channel_t *channel = switch_core_session_get_channel(*new_session); + char *jsock_uuid_str = outbound_profile->destination_number + 2; + switch_caller_profile_t *caller_profile; + verto_pvt_t *tech_pvt = NULL; + char name[512]; + + tech_pvt = switch_core_session_alloc(*new_session, sizeof(*tech_pvt)); + tech_pvt->session = *new_session; + tech_pvt->channel = channel; + tech_pvt->jsock_uuid = switch_core_session_strdup(*new_session, jsock_uuid_str); + switch_core_session_set_private_class(*new_session, tech_pvt, SWITCH_PVT_SECONDARY); + + if (session) { + switch_channel_t *ochannel = switch_core_session_get_channel(session); + if (switch_true(switch_channel_get_variable(ochannel, SWITCH_BYPASS_MEDIA_VARIABLE))) { + switch_channel_set_flag(channel, CF_PROXY_MODE); + switch_channel_set_flag(ochannel, CF_PROXY_MODE); + switch_channel_set_cap(channel, CC_BYPASS_MEDIA); + } + } + + tech_pvt->call_id = switch_core_session_strdup(*new_session, switch_core_session_get_uuid(*new_session)); + if ((tech_pvt->smh = switch_core_session_get_media_handle(*new_session))) { + tech_pvt->mparams = switch_core_media_get_mparams(tech_pvt->smh); + } + + switch_snprintf(name, sizeof(name), "verto.rtc/%s", tech_pvt->jsock_uuid); + switch_channel_set_name(channel, name); + switch_channel_set_variable(channel, "jsock_uuid_str", tech_pvt->jsock_uuid); + switch_channel_set_variable(channel, "event_channel_cookie", tech_pvt->jsock_uuid); + + if ((caller_profile = switch_caller_profile_dup(switch_core_session_get_pool(*new_session), outbound_profile))) { + switch_channel_set_caller_profile(channel, caller_profile); + } + + switch_channel_add_state_handler(channel, &verto_state_handlers); + switch_core_event_hook_add_receive_message(*new_session, messagehook); + switch_channel_set_state(channel, CS_INIT); + track_pvt(tech_pvt); + } + + end: + + switch_safe_free(dest); + + return cause; +} + +void verto_broadcast(const char *event_channel, cJSON *json, const char *key, switch_event_channel_id_t id) +{ + + { + char *json_text; + if ((json_text = cJSON_Print(json))) { + if (globals.debug) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ALERT, "EVENT BROADCAST %s %s\n", event_channel, json_text); + } + free(json_text); + } + } + + + + + jsock_send_event(json); +} + + +static int verto_send_chat(const char *uid, const char *call_id, cJSON *msg) +{ + jsock_t *jsock; + verto_profile_t *profile; + int hits = 0; + int done = 0; + + if (!strchr(uid, '@')) { + return 0; + } + + if (call_id) { + switch_core_session_t *session; + if ((session = switch_core_session_locate(call_id))) { + verto_pvt_t *tech_pvt = switch_core_session_get_private_class(session, SWITCH_PVT_SECONDARY); + jsock_t *jsock; + + if ((jsock = get_jsock(tech_pvt->jsock_uuid))) { + ws_write_json(jsock, &msg, SWITCH_FALSE); + switch_thread_rwlock_unlock(jsock->rwlock); + done = 1; + } + + switch_core_session_rwunlock(session); + } + } + + if (done) { + return 1; + } + + switch_mutex_lock(globals.mutex); + for(profile = globals.profile_head; profile; profile = profile->next) { + + switch_mutex_lock(profile->mutex); + + for(jsock = profile->jsock_head; jsock; jsock = jsock->next) { + if (!strcmp(uid, jsock->uid)) { + ws_write_json(jsock, &msg, SWITCH_FALSE); + hits++; + } + } + + switch_mutex_unlock(profile->mutex); + } + switch_mutex_unlock(globals.mutex); + + return hits; +} + +static switch_status_t chat_send(switch_event_t *message_event) +{ + switch_status_t status = SWITCH_STATUS_SUCCESS; + const char *to = switch_event_get_header(message_event, "to"); + const char *from = switch_event_get_header(message_event, "from"); + const char *body = switch_event_get_body(message_event); + const char *call_id = switch_event_get_header(message_event, "call_id"); + + DUMP_EVENT(message_event); + + + if (!zstr(to) && !zstr(body) && !zstr(from)) { + cJSON *obj = NULL, *msg = NULL, *params = NULL; + + obj = jrpc_new_req("verto.info", call_id, ¶ms); + msg = json_add_child_obj(params, "msg", NULL); + + cJSON_AddItemToObject(msg, "from", cJSON_CreateString(from)); + cJSON_AddItemToObject(msg, "to", cJSON_CreateString(to)); + cJSON_AddItemToObject(msg, "body", cJSON_CreateString(body)); + verto_send_chat(to, call_id, obj); + cJSON_Delete(obj); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "INVALID EVENT\n"); + status = SWITCH_STATUS_FALSE; + } + + + return status; +} + + + +static switch_cache_db_handle_t *json_get_db_handle(void) +{ + + switch_cache_db_handle_t *dbh = NULL; + const char *dsn; + + + if (!(dsn = switch_core_get_variable("json_db_handle"))) { + dsn = "json"; + } + + + if (switch_cache_db_get_db_handle_dsn(&dbh, dsn) != SWITCH_STATUS_SUCCESS) { + dbh = NULL; + } + + return dbh; +} + + +static int jcallback(void *pArg, int argc, char **argv, char **columnNames) +{ + char **data = (char **) pArg; + + if (argv[0] && !*data) { + *data = strdup(argv[0]); + } + + return 0; +} + +static cJSON *json_retrieve(const char *name, switch_mutex_t *mutex) +{ + char *sql, *errmsg; + switch_cache_db_handle_t *dbh; + char *ascii = NULL; + cJSON *json = NULL; + + if (!check_name(name)) { + return NULL; + } + + sql = switch_mprintf("select data from json_store where name='%q'", name); + + dbh = json_get_db_handle(); + + if (mutex) switch_mutex_lock(mutex); + switch_cache_db_execute_sql_callback(dbh, sql, jcallback, &ascii, &errmsg); + + switch_cache_db_release_db_handle(&dbh); + + if (errmsg) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SQL ERR: [%s] %s\n", sql, errmsg); + free(errmsg); + } else { + if (ascii) { + json = cJSON_Parse(ascii); + } + } + + if (mutex) switch_mutex_unlock(mutex); + + + switch_safe_free(ascii); + + return json; + +} + +static switch_bool_t json_commit(cJSON *json, const char *name, switch_mutex_t *mutex) +{ + char *ascii = cJSON_PrintUnformatted(json); + char *sql; + char del_sql[128] = ""; + switch_cache_db_handle_t *dbh; + char *err; + + if (!check_name(name)) { + return SWITCH_FALSE; + } + + if (!(ascii = cJSON_PrintUnformatted(json))) { + return SWITCH_FALSE; + } + + + sql = switch_mprintf("insert into json_store (name,data) values('%q','%q')", name, ascii); + switch_snprintf(del_sql, sizeof(del_sql), "delete from json_store where name='%q'", name); + + dbh = json_get_db_handle(); + + + if (mutex) switch_mutex_lock(mutex); + switch_cache_db_execute_sql(dbh, del_sql, &err); + + if (err) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "sql err [%s]\n", err); + free(err); + } else { + switch_cache_db_execute_sql(dbh, sql, &err); + + if (err) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "sql err [%s]\n", err); + free(err); + } + } + + if (mutex) switch_mutex_unlock(mutex); + + switch_safe_free(sql); + switch_safe_free(ascii); + + switch_cache_db_release_db_handle(&dbh); + + return SWITCH_TRUE; +} + +static switch_status_t json_hanguphook(switch_core_session_t *session) +{ + switch_channel_t *channel = switch_core_session_get_channel(session); + switch_channel_state_t state = switch_channel_get_state(channel); + json_store_t *session_store = NULL; + char *ascii = NULL; + + if (state == CS_HANGUP) { + if ((session_store = (json_store_t *) switch_channel_get_private(channel, "_json_store_"))) { + if ((ascii = cJSON_PrintUnformatted(session_store->JSON_STORE))) { + switch_channel_set_variable(channel, "json_store_data", ascii); + free(ascii); + } + cJSON_Delete(session_store->JSON_STORE); + session_store->JSON_STORE = NULL; + switch_channel_set_private(channel, "_json_store_", NULL); + } + switch_core_event_hook_remove_state_change(session, json_hanguphook); + } + + return SWITCH_STATUS_SUCCESS; +} + +SWITCH_STANDARD_JSON_API(json_store_function) +{ + cJSON *JSON_STORE, *reply = NULL, *data = cJSON_GetObjectItem(json, "data"); + switch_status_t status = SWITCH_STATUS_FALSE; + const char *cmd_attr = cJSON_GetObjectCstr(data, "cmd"); + const char *uuid = cJSON_GetObjectCstr(data, "uuid"); + const char *error = NULL, *message = NULL; + store_cmd_t cmd; + const char *key = cJSON_GetObjectCstr(data, "key"); + const char *verbose = cJSON_GetObjectCstr(data, "verbose"); + const char *commit = cJSON_GetObjectCstr(data, "commit"); + const char *file = cJSON_GetObjectCstr(data, "file"); + const char *storename = cJSON_GetObjectCstr(data, "storeName"); + cJSON *obj, **use_store = NULL; + switch_core_session_t *tsession = NULL; + switch_channel_t *tchannel = NULL; + json_store_t *session_store = NULL; + + reply = cJSON_CreateObject(); + + if (uuid) { + if ((tsession = switch_core_session_locate(uuid))) { + tchannel = switch_core_session_get_channel(tsession); + } else { + error = "Invalid INPUT, Missing UUID"; + goto end; + } + } else { + if (zstr(storename)) { + storename = "global"; + } + } + + + if (zstr(cmd_attr)) { + error = "INVALID INPUT, Command not supplied"; + goto end; + } + + + if (!strcasecmp(cmd_attr, "add")) { + cmd = CMD_ADD; + } else if (!strcasecmp(cmd_attr, "del")) { + cmd = CMD_DEL; + } else if (!strcasecmp(cmd_attr, "dump")) { + cmd = CMD_DUMP; + } else if (!strcasecmp(cmd_attr, "commit")) { + cmd = CMD_COMMIT; + } else if (!strcasecmp(cmd_attr, "retrieve")) { + cmd = CMD_RETRIEVE; + } else { + error = "INVALID INPUT, Unknown Command"; + goto end; + } + + + if (cmd == CMD_ADD) { + if (zstr(key)) { + error = "INVALID INPUT, No key supplied"; + goto end; + } + } + + + if (cmd == CMD_RETRIEVE || cmd == CMD_COMMIT) { + if (zstr(file)) { + error = "INVALID INPUT, No file specified"; + goto end; + } + } + + switch_mutex_lock(json_GLOBALS.store_mutex); + if (tsession) { + if (!(session_store = (json_store_t *) switch_channel_get_private(tchannel, "_json_store_"))) { + session_store = switch_core_session_alloc(tsession, sizeof(*session_store)); + switch_mutex_init(&session_store->mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(tsession)); + session_store->JSON_STORE = cJSON_CreateObject(); + switch_channel_set_private(tchannel, "_json_store_", session_store); + switch_core_event_hook_add_state_change(tsession, json_hanguphook); + } + + use_store = &session_store->JSON_STORE; + switch_mutex_lock(session_store->mutex); + switch_mutex_unlock(json_GLOBALS.store_mutex); + } else { + JSON_STORE = switch_core_hash_find(json_GLOBALS.store_hash, storename); + + if (!JSON_STORE) { + JSON_STORE = cJSON_CreateObject(); + switch_core_hash_insert(json_GLOBALS.store_hash, storename, JSON_STORE); + } + use_store = &JSON_STORE; + } + + switch(cmd) { + case CMD_RETRIEVE: + obj = json_retrieve(file, NULL); + + if (!obj) { + error = "CANNOT LOAD DATA"; + + if (session_store) { + switch_mutex_unlock(session_store->mutex); + } else { + switch_mutex_unlock(json_GLOBALS.store_mutex); + } + + goto end; + } + + cJSON_Delete(*use_store); + *use_store = obj; + message = "Store Loaded"; + + break; + case CMD_ADD: + + if (!(obj = cJSON_GetObjectItem(data, key))) { + error = "INVALID INPUT"; + + if (session_store) { + switch_mutex_unlock(session_store->mutex); + } else { + switch_mutex_unlock(json_GLOBALS.store_mutex); + } + + goto end; + } + + cJSON_DeleteItemFromObject(*use_store, key); + obj = cJSON_Duplicate(obj, 1); + cJSON_AddItemToObject(*use_store, key, obj); + message = "Item Added"; + break; + + case CMD_DEL: + + if (!key) { + cJSON_Delete(*use_store); + *use_store = cJSON_CreateObject(); + message = "Store Deleted"; + } else { + cJSON_DeleteItemFromObject(*use_store, key); + message = "Item Deleted"; + } + break; + + default: + break; + } + + + if (switch_true(verbose) || cmd == CMD_DUMP) { + cJSON *dump; + + if (key) { + dump = cJSON_GetObjectItem(*use_store, key); + } else { + dump = *use_store; + } + + if (dump) { + dump = cJSON_Duplicate(dump, 1); + cJSON_AddItemToObject(reply, "data", dump); + message = "Data Dumped"; + } else { + error = "Key not found"; + } + } + + if (session_store) { + switch_mutex_unlock(session_store->mutex); + } else { + switch_mutex_unlock(json_GLOBALS.store_mutex); + } + + if (cmd == CMD_COMMIT || commit) { + switch_bool_t ok; + + if (commit && zstr(file)) { + file = commit; + } + + if (session_store) { + ok = json_commit(session_store->JSON_STORE, file, session_store->mutex); + } else { + ok = json_commit(JSON_STORE, file, json_GLOBALS.store_mutex); + } + + cJSON_AddItemToObject(reply, "commitStatus", cJSON_CreateString(ok ? "success" : "fail")); + if (!message) { + message = "Message Comitted"; + } + status = SWITCH_STATUS_SUCCESS; + } + + + end: + + if (!zstr(error)) { + cJSON_AddItemToObject(reply, "errorMessage", cJSON_CreateString(error)); + } + + if (!zstr(message)) { + cJSON_AddItemToObject(reply, "message", cJSON_CreateString(message)); + status = SWITCH_STATUS_SUCCESS; + } + + *json_reply = reply; + + if (tsession) { + switch_core_session_rwunlock(tsession); + } + + return status; +} + +#define add_it(_name, _ename) if ((tmp = switch_event_get_header(event, _ename))) { cJSON_AddItemToObject(data, _name, cJSON_CreateString(tmp));} + +static void presence_event_handler(switch_event_t *event) +{ + cJSON *msg = NULL, *data = NULL; + const char *tmp; + switch_event_header_t *hp; + char *event_channel; + const char *presence_id = switch_event_get_header(event, "channel-presence-id"); + + if (!globals.enable_presence || zstr(presence_id)) { + return; + } + + msg = cJSON_CreateObject(); + data = json_add_child_obj(msg, "data", NULL); + + event_channel = switch_mprintf("presence.%s", presence_id); + + cJSON_AddItemToObject(msg, "eventChannel", cJSON_CreateString(event_channel)); + add_it("channelCallState", "channel-call-state"); + add_it("originalChannelCallState", "original-channel-call-state"); + add_it("channelState", "channel-state"); + + add_it("callerUserName", "caller-username"); + add_it("callerIDName", "caller-caller-id-name"); + add_it("callerIDNumber", "caller-caller-id-number"); + add_it("calleeIDName", "caller-callee-id-name"); + add_it("calleeIDNumber", "caller-callee-id-number"); + add_it("channelUUID", "unique-id"); + + add_it("presenceCallDirection", "presence-call-direction"); + add_it("channelPresenceID", "channel-presence-id"); + add_it("channelPresenceData", "channel-presence-data"); + + for(hp = event->headers; hp; hp = hp->next) { + if (!strncasecmp(hp->name, "PD-", 3)) { + add_it(hp->name, hp->name); + } + } + + switch_event_channel_broadcast(event_channel, &msg, __FILE__, NO_EVENT_CHANNEL_ID); + + free(event_channel); + +} + + +/* Macro expands to: switch_status_t mod_verto_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool) */ +SWITCH_MODULE_LOAD_FUNCTION(mod_verto_load) +{ + switch_api_interface_t *api_interface = NULL; + switch_chat_interface_t *chat_interface = NULL; + switch_json_api_interface_t *json_api_interface = NULL; + int r; + switch_cache_db_handle_t *dbh; + //switch_application_interface_t *app_interface = NULL; + + memset(&globals, 0, sizeof(globals)); + globals.pool = pool; + globals.ready = SIGUSR1; + globals.enable_presence = SWITCH_TRUE; + + switch_mutex_init(&globals.mutex, SWITCH_MUTEX_NESTED, globals.pool); + + switch_mutex_init(&globals.method_mutex, SWITCH_MUTEX_NESTED, globals.pool); + switch_core_hash_init(&globals.method_hash); + + switch_thread_rwlock_create(&globals.event_channel_rwlock, globals.pool); + switch_core_hash_init(&globals.event_channel_hash); + + switch_mutex_init(&globals.jsock_mutex, SWITCH_MUTEX_NESTED, globals.pool); + switch_core_hash_init(&globals.jsock_hash); + + switch_thread_rwlock_create(&globals.tech_rwlock, globals.pool); + + switch_mutex_init(&globals.detach_mutex, SWITCH_MUTEX_NESTED, globals.pool); + switch_mutex_init(&globals.detach2_mutex, SWITCH_MUTEX_NESTED, globals.pool); + switch_thread_cond_create(&globals.detach_cond, globals.pool); + globals.detach_timeout = 120; + + + switch_event_bind(modname, SWITCH_EVENT_CHANNEL_CALLSTATE, SWITCH_EVENT_SUBCLASS_ANY, presence_event_handler, NULL); + + + + memset(&json_GLOBALS, 0, sizeof(json_GLOBALS)); + switch_mutex_init(&json_GLOBALS.store_mutex, SWITCH_MUTEX_NESTED, pool); + switch_core_hash_init(&json_GLOBALS.store_hash); + + + dbh = json_get_db_handle(); + switch_cache_db_test_reactive(dbh, "select name from json_store where name=''", "drop table json_store", json_sql); + switch_cache_db_release_db_handle(&dbh); + + + + switch_event_channel_bind(SWITCH_EVENT_CHANNEL_GLOBAL, verto_broadcast, &globals.event_channel_id); + + + r = init(); + + if (r) return SWITCH_STATUS_TERM; + + jrpc_init(); + + /* connect my internal structure to the blank pointer passed to me */ + *module_interface = switch_loadable_module_create_module_interface(pool, modname); + + SWITCH_ADD_API(api_interface, "verto", "Verto API", verto_function, "syntax"); + SWITCH_ADD_API(api_interface, "verto_contact", "Generate a verto endpoint dialstring", verto_contact_function, "user@domain"); + SWITCH_ADD_JSON_API(json_api_interface, "store", "JSON store", json_store_function, ""); + + verto_endpoint_interface = (switch_endpoint_interface_t *) switch_loadable_module_create_interface(*module_interface, SWITCH_ENDPOINT_INTERFACE); + verto_endpoint_interface->interface_name = EP_NAME; + verto_endpoint_interface->io_routines = &verto_io_routines; + + SWITCH_ADD_CHAT(chat_interface, VERTO_CHAT_PROTO, chat_send); + + switch_core_register_secondary_recover_callback(modname, verto_recover_callback); + + run_profiles(); + + /* indicate that the module should continue to be loaded */ + return SWITCH_STATUS_SUCCESS; +} + +/* + Called when the system shuts down + Macro expands to: switch_status_t mod_verto_shutdown() */ +SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_verto_shutdown) +{ + json_cleanup(); + switch_core_hash_destroy(&json_GLOBALS.store_hash); + + switch_event_channel_unbind(NULL, verto_broadcast); + switch_event_unbind_callback(presence_event_handler); + + switch_core_unregister_secondary_recover_callback(modname); + do_shutdown(); + attach_wake(); + attach_wake(); + + switch_core_hash_destroy(&globals.method_hash); + switch_core_hash_destroy(&globals.event_channel_hash); + switch_core_hash_destroy(&globals.jsock_hash); + + return SWITCH_STATUS_SUCCESS; +} + +SWITCH_MODULE_RUNTIME_FUNCTION(mod_verto_runtime) +{ + switch_mutex_lock(globals.detach_mutex); + + while(globals.running) { + if (globals.detached) { + drop_detached(); + switch_yield(1000000); + } else { + switch_mutex_lock(globals.detach2_mutex); + if (globals.running) { + switch_thread_cond_wait(globals.detach_cond, globals.detach_mutex); + } + switch_mutex_unlock(globals.detach2_mutex); + } + } + + switch_mutex_unlock(globals.detach_mutex); + + return SWITCH_STATUS_TERM; +} + + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet + */ diff --git a/src/mod/endpoints/mod_verto/mod_verto.h b/src/mod/endpoints/mod_verto/mod_verto.h new file mode 100644 index 0000000000..1b4591d898 --- /dev/null +++ b/src/mod/endpoints/mod_verto/mod_verto.h @@ -0,0 +1,272 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2005-2012, Anthony Minessale II + * + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * + * The Initial Developer of the Original Code is + * Anthony Minessale II + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Anthony Minessale II + * + * mod_html.h -- HTML 5 interface + * + */ + +#ifndef MOD_VERTO_H +#define MOD_VERTO_H +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mcast.h" + +#define MAXPENDING 10000 +#define STACK_SIZE 80 * 1024 + +#define VERTO_CHAT_PROTO "verto" + +#define copy_string(x,y,z) strncpy(x, y, z - 1) +#define set_string(x,y) strncpy(x, y, sizeof(x)-1) + +#define CODE_INVALID -32600 +#define CODE_AUTH_REQUIRED -32000 +#define CODE_AUTH_FAILED -32001 +#define CODE_SESSION_ERROR -32002 + + +typedef enum { + PTYPE_CLIENT = (1 << 0), + PTYPE_CLIENT_SSL = (1 << 1) +} jsock_type_t; + +typedef enum { + JPFLAG_INIT = (1 << 0), + JPFLAG_AUTHED = (1 << 1), + JPFLAG_CHECK_ATTACH = (1 << 2) +} jpflag_t; + +struct verto_profile_s; + +struct jsock_s { + int client_socket; + switch_memory_pool_t *pool; + switch_thread_t *thread; + wsh_t ws; + unsigned char buf[65535]; + char *name; + jsock_type_t ptype; + struct sockaddr_in local_addr; + struct sockaddr_in remote_addr; + struct sockaddr_in send_addr; + struct ucred credentials; + struct passwd pw; + + int drop; + int local_sock; + SSL *ssl; + + jpflag_t flags; + + char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1]; + switch_event_t *allowed_methods; + switch_event_t *allowed_jsapi; + switch_event_t *allowed_fsapi; + switch_event_t *allowed_event_channels; + + + char *id; + char *domain; + char *uid; + char *dialplan; + char *context; + + struct verto_profile_s *profile; + switch_thread_rwlock_t *rwlock; + + switch_mutex_t *write_mutex; + + switch_event_t *params; + switch_event_t *vars; + + struct jsock_s *next; +}; + +typedef struct jsock_s jsock_t; + +#define MAX_BIND 25 +#define MAX_RTPIP 25 + +struct ips { + char local_ip[256]; + in_addr_t local_ip_addr; + int local_port; + int secure; +}; + +typedef enum { + TFLAG_SENT_MEDIA = (1 << 0), + TFLAG_ATTACH_REQ = (1 << 1) +} tflag_t; + +typedef struct verto_pvt_s { + char *jsock_uuid; + char *call_id; + char *r_sdp; + tflag_t flags; + switch_core_session_t *session; + switch_channel_t *channel; + switch_media_handle_t *smh; + switch_core_media_params_t *mparams; + switch_call_cause_t remote_hangup_cause; + time_t detach_time; + struct verto_pvt_s *next; +} verto_pvt_t; + +struct verto_profile_s { + char *name; + switch_mutex_t *mutex; + switch_memory_pool_t *pool; + switch_thread_rwlock_t *rwlock; + + struct ips ip[MAX_BIND]; + int i; + + const SSL_METHOD *ssl_method; + SSL_CTX *ssl_ctx; + char cert[512]; + char key[512]; + char chain[512]; + + jsock_t *jsock_head; + int jsock_count; + int server_socket[MAX_BIND]; + int running; + + int ssl_ready; + int ready; + int debug; + + int in_thread; + + char *userauth; + char *root_passwd; + + char *context; + char *dialplan; + + char *mcast_ip; + switch_port_t mcast_port; + + mcast_handle_t mcast_sub; + mcast_handle_t mcast_pub; + + char *extrtpip; + + char *rtpip[MAX_RTPIP]; + int rtpip_index; + int rtpip_cur; + + char *cand_acl[SWITCH_MAX_CAND_ACL]; + uint32_t cand_acl_count; + + char *inbound_codec_string; + char *outbound_codec_string; + + char *timer_name; + char *local_network; + + + + struct verto_profile_s *next; +}; + +typedef struct verto_profile_s verto_profile_t; + +struct globals_s { + switch_mutex_t *mutex; + switch_memory_pool_t *pool; + + int profile_count; + verto_profile_t *profile_head; + int sig; + int running; + + switch_hash_t *method_hash; + switch_mutex_t *method_mutex; + + switch_hash_t *event_channel_hash; + switch_thread_rwlock_t *event_channel_rwlock; + + int debug; + int ready; + int profile_threads; + int enable_presence; + + switch_hash_t *jsock_hash; + switch_mutex_t *jsock_mutex; + + verto_pvt_t *tech_head; + switch_thread_rwlock_t *tech_rwlock; + + switch_thread_cond_t *detach_cond; + switch_mutex_t *detach_mutex; + switch_mutex_t *detach2_mutex; + + uint32_t detached; + uint32_t detach_timeout; + + switch_event_channel_id_t event_channel_id; +}; + + +extern struct globals_s globals; + +typedef switch_bool_t (*jrpc_func_t)(const char *method, cJSON *params, jsock_t *jsock, cJSON **response); + + +void set_log_path(const char *path); + + +/** @} */ +#endif +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4: + */ diff --git a/src/mod/endpoints/mod_verto/ws.c b/src/mod/endpoints/mod_verto/ws.c new file mode 100644 index 0000000000..11b92945c8 --- /dev/null +++ b/src/mod/endpoints/mod_verto/ws.c @@ -0,0 +1,879 @@ +#include "ws.h" +#include + +#ifndef _MSC_VER +#include +#endif + +#ifndef _MSC_VER +#define ms_sleep(x) usleep( x * 1000); +#else +#define ms_sleep(x) Sleep( x ); +#endif + +#define WS_BLOCK 1 +#define WS_NOBLOCK 0 + +#define SHA1_HASH_SIZE 20 +struct ws_globals_s ws_globals; + +#ifndef WSS_STANDALONE + +void init_ssl(void) +{ + SSL_library_init(); +} +void deinit_ssl(void) +{ + return; +} + +#else +static unsigned long pthreads_thread_id(void); +static void pthreads_locking_callback(int mode, int type, const char *file, int line); + +static pthread_mutex_t *lock_cs; +static long *lock_count; + + + +static void thread_setup(void) +{ + int i; + + lock_cs = OPENSSL_malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t)); + lock_count = OPENSSL_malloc(CRYPTO_num_locks() * sizeof(long)); + + for (i = 0; i < CRYPTO_num_locks(); i++) { + lock_count[i] = 0; + pthread_mutex_init(&(lock_cs[i]), NULL); + } + + CRYPTO_set_id_callback(pthreads_thread_id); + CRYPTO_set_locking_callback(pthreads_locking_callback); +} + +static void thread_cleanup(void) +{ + int i; + + CRYPTO_set_locking_callback(NULL); + + for (i=0; i buflen - 1) { + cplen = buflen -1; + } else { + cplen = len; + } + + strncpy(buf, v, cplen); + *(buf+cplen) = '\0'; + return 1; + } + + } + } + return 0; +} + +static int b64encode(unsigned char *in, size_t ilen, unsigned char *out, size_t olen) +{ + int y=0,bytes=0; + size_t x=0; + unsigned int b=0,l=0; + + if(olen) { + } + + for(x=0;x= 6) { + out[bytes++] = c64[(b>>(l-=6))%64]; + if(++y!=72) { + continue; + } + //out[bytes++] = '\n'; + y=0; + } + } + + if (l > 0) { + out[bytes++] = c64[((b%16)<<(6-l))%64]; + } + if (l != 0) while (l < 6) { + out[bytes++] = '=', l += 2; + } + + return 0; +} + +#ifdef NO_OPENSSL +static void sha1_digest(char *digest, unsigned char *in) +{ + SHA1Context sha; + char *p; + int x; + + + SHA1Init(&sha); + SHA1Update(&sha, in, strlen(in)); + SHA1Final(&sha, digest); +} +#else + +static void sha1_digest(unsigned char *digest, char *in) +{ + SHA_CTX sha; + + SHA1_Init(&sha); + SHA1_Update(&sha, in, strlen(in)); + SHA1_Final(digest, &sha); + +} + +#endif + +int ws_handshake(wsh_t *wsh) +{ + char key[256] = ""; + char version[5] = ""; + char proto[256] = ""; + char proto_buf[384] = ""; + char uri[256] = ""; + char input[256] = ""; + unsigned char output[SHA1_HASH_SIZE] = ""; + char b64[256] = ""; + char respond[512] = ""; + ssize_t bytes; + char *p, *e = 0; + + if (wsh->sock == ws_sock_invalid) { + return -3; + } + + while((bytes = ws_raw_read(wsh, wsh->buffer + wsh->datalen, wsh->buflen - wsh->datalen, WS_BLOCK)) > 0) { + wsh->datalen += bytes; + if (strstr(wsh->buffer, "\r\n\r\n") || strstr(wsh->buffer, "\n\n")) { + break; + } + } + + if (bytes > sizeof(wsh->buffer) -1) { + goto err; + } + + *(wsh->buffer+bytes) = '\0'; + + if (strncasecmp(wsh->buffer, "GET ", 4)) { + goto err; + } + + p = wsh->buffer + 4; + + e = strchr(p, ' '); + if (!e) { + goto err; + } + + strncpy(uri, p, e-p); + + cheezy_get_var(wsh->buffer, "Sec-WebSocket-Key", key, sizeof(key)); + cheezy_get_var(wsh->buffer, "Sec-WebSocket-Version", version, sizeof(version)); + cheezy_get_var(wsh->buffer, "Sec-WebSocket-Protocol", proto, sizeof(proto)); + + if (!*key) { + goto err; + } + + snprintf(input, sizeof(input), "%s%s", key, WEBSOCKET_GUID); + sha1_digest(output, input); + b64encode((unsigned char *)output, SHA1_HASH_SIZE, (unsigned char *)b64, sizeof(b64)); + + if (*proto) { + snprintf(proto_buf, sizeof(proto_buf), "Sec-WebSocket-Protocol: %s\r\n", proto); + } + + snprintf(respond, sizeof(respond), + "HTTP/1.1 101 Switching Protocols\r\n" + "Upgrade: websocket\r\n" + "Connection: Upgrade\r\n" + "Sec-WebSocket-Accept: %s\r\n" + "%s\r\n", + b64, + proto_buf); + + + ws_raw_write(wsh, respond, strlen(respond)); + wsh->handshake = 1; + + return 0; + + err: + + snprintf(respond, sizeof(respond), "HTTP/1.1 400 Bad Request\r\n" + "Sec-WebSocket-Version: 13\r\n\r\n"); + + //printf("ERR:\n%s\n", respond); + + + ws_raw_write(wsh, respond, strlen(respond)); + + ws_close(wsh, WS_NONE); + + return -1; + +} + +ssize_t ws_raw_read(wsh_t *wsh, void *data, size_t bytes, int block) +{ + ssize_t r; + int err = 0; + + if (wsh->ssl) { + do { + r = SSL_read(wsh->ssl, data, bytes); + + ms_sleep(10); + + if (r == -1) { + err = SSL_get_error(wsh->ssl, r); + + if (!block && err == SSL_ERROR_WANT_READ) { + r = -2; + goto end; + } + } + + } while (r == -1 && err == SSL_ERROR_WANT_READ && wsh->x < 100); + + goto end; + } + + do { + r = recv(wsh->sock, data, bytes, 0); + ms_sleep(10); + } while (r == -1 && xp_is_blocking(xp_errno()) && wsh->x < 100); + + if (wsh->x >= 100) { + r = -1; + } + + end: + + if (r > 0) { + *((char *)data + r) = '\0'; + } + + if (r >= 0) { + wsh->x = 0; + } + + return r; +} + +ssize_t ws_raw_write(wsh_t *wsh, void *data, size_t bytes) +{ + size_t r; + + if (wsh->ssl) { + do { + r = SSL_write(wsh->ssl, data, bytes); + } while (r == -1 && SSL_get_error(wsh->ssl, r) == SSL_ERROR_WANT_WRITE); + + return r; + } + + do { + r = send(wsh->sock, data, bytes, 0); + } while (r == -1 && xp_is_blocking(xp_errno())); + + //if (r<0) { + //printf("wRITE FAIL: %s\n", strerror(errno)); + //} + + return r; +} + +#ifdef _MSC_VER +static int setup_socket(ws_socket_t sock) +{ + unsigned long v = 1; + + if (ioctlsocket(sock, FIONBIO, &v) == SOCKET_ERROR) { + return -1; + } + + return 0; + +} + +static int restore_socket(ws_socket_t sock) +{ + unsigned long v = 0; + + if (ioctlsocket(sock, FIONBIO, &v) == SOCKET_ERROR) { + return -1; + } + + return 0; + +} + +#else + +static int setup_socket(ws_socket_t sock) +{ + int flags = fcntl(sock, F_GETFL, 0); + return fcntl(sock, F_SETFL, flags | O_NONBLOCK); +} + +static int restore_socket(ws_socket_t sock) +{ + int flags = fcntl(sock, F_GETFL, 0); + + flags &= ~O_NONBLOCK; + + return fcntl(sock, F_SETFL, flags); + +} + +#endif + + +static int establish_logical_layer(wsh_t *wsh) +{ + + if (!wsh->sanity) { + return -1; + } + + if (wsh->logical_established) { + return 0; + } + + if (wsh->secure && !wsh->secure_established) { + int code; + + if (!wsh->ssl) { + wsh->ssl = SSL_new(wsh->ssl_ctx); + assert(wsh->ssl); + + SSL_set_fd(wsh->ssl, wsh->sock); + } + + do { + code = SSL_accept(wsh->ssl); + + if (code == 1) { + wsh->secure_established = 1; + break; + } + + if (code == 0) { + return -1; + } + + if (code < 0) { + if (code == -1 && SSL_get_error(wsh->ssl, code) != SSL_ERROR_WANT_READ) { + return -1; + } + } + + if (wsh->block) { + ms_sleep(10); + } else { + ms_sleep(1); + } + + wsh->sanity--; + + if (!wsh->block) { + return -2; + } + + } while (wsh->sanity > 0); + + if (!wsh->sanity) { + return -1; + } + + } + + while (!wsh->down && !wsh->handshake) { + int r = ws_handshake(wsh); + + if (r < 0) { + wsh->down = 1; + return -1; + } + + if (!wsh->handshake && !wsh->block) { + return -2; + } + + } + + wsh->logical_established = 1; + + return 0; +} + + +int ws_init(wsh_t *wsh, ws_socket_t sock, SSL_CTX *ssl_ctx, int close_sock, int block) +{ + memset(wsh, 0, sizeof(*wsh)); + + wsh->sock = sock; + wsh->block = block; + wsh->sanity = 5000; + wsh->ssl_ctx = ssl_ctx; + + if (!ssl_ctx) { + ssl_ctx = ws_globals.ssl_ctx; + } + + if (close_sock) { + wsh->close_sock = 1; + } + + wsh->buflen = sizeof(wsh->buffer); + wsh->secure = ssl_ctx ? 1 : 0; + + setup_socket(sock); + + if (establish_logical_layer(wsh) == -1) { + return -1; + } + + if (wsh->down) { + return -1; + } + + return 0; +} + +void ws_destroy(wsh_t *wsh) +{ + + if (!wsh) { + return; + } + + if (!wsh->down) { + ws_close(wsh, WS_NONE); + } + + if (wsh->down > 1) { + return; + } + + wsh->down = 2; + + if (wsh->ssl) { + int code; + do { + code = SSL_shutdown(wsh->ssl); + } while (code == -1 && SSL_get_error(wsh->ssl, code) == SSL_ERROR_WANT_READ); + + SSL_free(wsh->ssl); + wsh->ssl = NULL; + } +} + +ssize_t ws_close(wsh_t *wsh, int16_t reason) +{ + + if (wsh->down) { + return -1; + } + + wsh->down = 1; + + if (reason && wsh->sock != ws_sock_invalid) { + uint16_t *u16; + uint8_t fr[4] = {WSOC_CLOSE | 0x80, 2, 0}; + + u16 = (uint16_t *) &fr[2]; + *u16 = htons((int16_t)reason); + ws_raw_write(wsh, fr, 4); + } + + restore_socket(wsh->sock); + + if (wsh->close_sock && wsh->sock != ws_sock_invalid) { + close(wsh->sock); + } + + wsh->sock = ws_sock_invalid; + + return reason * -1; + +} + +ssize_t ws_read_frame(wsh_t *wsh, ws_opcode_t *oc, uint8_t **data) +{ + + ssize_t need = 2; + char *maskp; + int ll = 0; + + again: + need = 2; + maskp = NULL; + *data = NULL; + + ll = establish_logical_layer(wsh); + + if (ll < 0) { + return ll; + } + + if (wsh->down) { + return -1; + } + + if (!wsh->handshake) { + return ws_close(wsh, WS_PROTO_ERR); + } + + if ((wsh->datalen = ws_raw_read(wsh, wsh->buffer, 9, wsh->block)) < 0) { + if (wsh->datalen == -2) { + return -2; + } + return ws_close(wsh, WS_PROTO_ERR); + } + + if (wsh->datalen < need) { + if ((wsh->datalen += ws_raw_read(wsh, wsh->buffer + wsh->datalen, 9 - wsh->datalen, WS_BLOCK)) < need) { + /* too small - protocol err */ + return ws_close(wsh, WS_PROTO_ERR); + } + } + + *oc = *wsh->buffer & 0xf; + + switch(*oc) { + case WSOC_CLOSE: + { + wsh->plen = wsh->buffer[1] & 0x7f; + *data = (uint8_t *) &wsh->buffer[2]; + return ws_close(wsh, 1000); + } + break; + case WSOC_CONTINUATION: + case WSOC_TEXT: + case WSOC_BINARY: + case WSOC_PING: + case WSOC_PONG: + { + //int fin = (wsh->buffer[0] >> 7) & 1; + int mask = (wsh->buffer[1] >> 7) & 1; + + if (mask) { + need += 4; + + if (need > wsh->datalen) { + /* too small - protocol err */ + *oc = WSOC_CLOSE; + return ws_close(wsh, WS_PROTO_ERR); + } + } + + wsh->plen = wsh->buffer[1] & 0x7f; + wsh->payload = &wsh->buffer[2]; + + if (wsh->plen == 127) { + uint64_t *u64; + + need += 8; + + if (need > wsh->datalen) { + /* too small - protocol err */ + *oc = WSOC_CLOSE; + return ws_close(wsh, WS_PROTO_ERR); + } + + u64 = (uint64_t *) wsh->payload; + wsh->payload += 8; + + wsh->plen = ntohl((u_long)*u64); + + } else if (wsh->plen == 126) { + uint16_t *u16; + + need += 2; + + if (need > wsh->datalen) { + /* too small - protocol err */ + *oc = WSOC_CLOSE; + return ws_close(wsh, WS_PROTO_ERR); + } + + u16 = (uint16_t *) wsh->payload; + wsh->payload += 2; + wsh->plen = ntohs(*u16); + } + + if (mask) { + maskp = (char *)wsh->payload; + wsh->payload += 4; + } + + need = (wsh->plen - (wsh->datalen - need)); + + if (need < 0) { + /* invalid read - protocol err .. */ + *oc = WSOC_CLOSE; + return ws_close(wsh, WS_PROTO_ERR); + } + + if ((need + wsh->datalen) > (ssize_t)wsh->buflen) { + /* too big - Ain't nobody got time fo' dat */ + *oc = WSOC_CLOSE; + return ws_close(wsh, WS_DATA_TOO_BIG); + } + + wsh->rplen = wsh->plen - need; + + while(need) { + ssize_t r = ws_raw_read(wsh, wsh->payload + wsh->rplen, need, WS_BLOCK); + + if (r < 1) { + /* invalid read - protocol err .. */ + *oc = WSOC_CLOSE; + return ws_close(wsh, WS_PROTO_ERR); + } + + wsh->datalen += r; + wsh->rplen += r; + need -= r; + } + + if (mask && maskp) { + ssize_t i; + + for (i = 0; i < wsh->datalen; i++) { + wsh->payload[i] ^= maskp[i % 4]; + } + } + + + if (*oc == WSOC_PING) { + ws_write_frame(wsh, WSOC_PONG, wsh->payload, wsh->rplen); + goto again; + } + + + *(wsh->payload+wsh->rplen) = '\0'; + *data = (uint8_t *)wsh->payload; + + //printf("READ[%ld][%d]-----------------------------:\n[%s]\n-------------------------------\n", wsh->rplen, *oc, (char *)*data); + + + return wsh->rplen; + } + break; + default: + { + /* invalid op code - protocol err .. */ + *oc = WSOC_CLOSE; + return ws_close(wsh, WS_PROTO_ERR); + } + break; + } +} + +ssize_t ws_feed_buf(wsh_t *wsh, void *data, size_t bytes) +{ + + if (bytes + wsh->wdatalen > wsh->buflen) { + return -1; + } + + memcpy(wsh->wbuffer + wsh->wdatalen, data, bytes); + + wsh->wdatalen += bytes; + + return bytes; +} + +ssize_t ws_send_buf(wsh_t *wsh, ws_opcode_t oc) +{ + ssize_t r = 0; + + if (!wsh->wdatalen) { + return -1; + } + + r = ws_write_frame(wsh, oc, wsh->wbuffer, wsh->wdatalen); + + wsh->wdatalen = 0; + + return r; +} + + +ssize_t ws_write_frame(wsh_t *wsh, ws_opcode_t oc, void *data, size_t bytes) +{ + uint8_t hdr[14] = { 0 }; + size_t hlen = 2; + + if (wsh->down) { + return -1; + } + + //printf("WRITE[%ld]-----------------------------:\n[%s]\n-----------------------------------\n", bytes, (char *) data); + + hdr[0] = (uint8_t)(oc | 0x80); + + if (bytes < 126) { + hdr[1] = (uint8_t)bytes; + } else if (bytes < 0x10000) { + uint16_t *u16; + + hdr[1] = 126; + hlen += 2; + + u16 = (uint16_t *) &hdr[2]; + *u16 = htons((uint16_t) bytes); + + } else { + uint64_t *u64; + + hdr[1] = 127; + hlen += 8; + + u64 = (uint64_t *) &hdr[2]; + *u64 = htonl(bytes); + } + + if (ws_raw_write(wsh, (void *) &hdr[0], hlen) != (ssize_t)hlen) { + return -1; + } + + if (ws_raw_write(wsh, data, bytes) != (ssize_t)bytes) { + return -2; + } + + return bytes; +} + +#ifdef _MSC_VER + +int xp_errno(void) +{ + return WSAGetLastError(); +} + +int xp_is_blocking(int errcode) +{ + return errcode == WSAEWOULDBLOCK || errcode == WSAEINPROGRESS; +} + +#else + +int xp_errno(void) +{ + return errno; +} + +int xp_is_blocking(int errcode) +{ + return errcode == EAGAIN || errcode == EWOULDBLOCK || errcode == EINPROGRESS || errcode == EINTR || errcode == ETIMEDOUT; +} + +#endif diff --git a/src/mod/endpoints/mod_verto/ws.h b/src/mod/endpoints/mod_verto/ws.h new file mode 100644 index 0000000000..699779b515 --- /dev/null +++ b/src/mod/endpoints/mod_verto/ws.h @@ -0,0 +1,120 @@ +#ifndef _WS_H +#define _WS_H + +//#define WSS_STANDALONE 1 + +#define WEBSOCKET_GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" +#define B64BUFFLEN 1024 + +#include +#ifndef _MSC_VER +#include +#include +#include +#else +#pragma warning(disable:4996) +#endif +#include +#include +#include +#include +#include +#include +#include +#include +//#include "sha1.h" +#include + +#ifdef _MSC_VER +#define strncasecmp _strnicmp +#define snprintf _snprintf +#ifdef _WIN64 +#define WS_SSIZE_T __int64 +#elif _MSC_VER >= 1400 +#define WS_SSIZE_T __int32 __w64 +#else +#define WS_SSIZE_T __int32 +#endif +typedef WS_SSIZE_T ssize_t; +#endif + + +struct ws_globals_s { + const SSL_METHOD *ssl_method; + SSL_CTX *ssl_ctx; + char cert[512]; + char key[512]; +}; + +extern struct ws_globals_s ws_globals; + +typedef int ws_socket_t; +#define ws_sock_invalid -1 + + +typedef enum { + WS_NONE = 0, + WS_NORMAL = 1000, + WS_PROTO_ERR = 1002, + WS_DATA_TOO_BIG = 1009 +} ws_cause_t; + +typedef enum { + WSOC_CONTINUATION = 0x0, + WSOC_TEXT = 0x1, + WSOC_BINARY = 0x2, + WSOC_CLOSE = 0x8, + WSOC_PING = 0x9, + WSOC_PONG = 0xA +} ws_opcode_t; + +typedef struct wsh_s { + ws_socket_t sock; + char buffer[65536]; + char wbuffer[65536]; + size_t buflen; + ssize_t datalen; + ssize_t wdatalen; + char *payload; + ssize_t plen; + ssize_t rplen; + SSL *ssl; + int handshake; + uint8_t down; + int secure; + uint8_t close_sock; + SSL_CTX *ssl_ctx; + int block; + int sanity; + int secure_established; + int logical_established; + int x; +} wsh_t; + +ssize_t ws_send_buf(wsh_t *wsh, ws_opcode_t oc); +ssize_t ws_feed_buf(wsh_t *wsh, void *data, size_t bytes); + + +ssize_t ws_raw_read(wsh_t *wsh, void *data, size_t bytes, int block); +ssize_t ws_raw_write(wsh_t *wsh, void *data, size_t bytes); +ssize_t ws_read_frame(wsh_t *wsh, ws_opcode_t *oc, uint8_t **data); +ssize_t ws_write_frame(wsh_t *wsh, ws_opcode_t oc, void *data, size_t bytes); +int ws_init(wsh_t *wsh, ws_socket_t sock, SSL_CTX *ssl_ctx, int close_sock, int block); +ssize_t ws_close(wsh_t *wsh, int16_t reason); +void ws_destroy(wsh_t *wsh); +void init_ssl(void); +void deinit_ssl(void); +int xp_errno(void); +int xp_is_blocking(int errcode); + + + +#ifndef _MSC_VER +static inline uint64_t get_unaligned_uint64(const void *p) +{ + const struct { uint64_t d; } __attribute__((packed)) *pp = p; + return pp->d; +} +#endif + +#endif From bfaf20c2f327fdf06f722eda29f56cb81e70740b Mon Sep 17 00:00:00 2001 From: Michael Jerris Date: Wed, 11 Jun 2014 15:20:38 -0500 Subject: [PATCH 024/231] fix install --- src/mod/endpoints/mod_verto/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mod/endpoints/mod_verto/Makefile.am b/src/mod/endpoints/mod_verto/Makefile.am index 08b82bd32c..00744270bc 100644 --- a/src/mod/endpoints/mod_verto/Makefile.am +++ b/src/mod/endpoints/mod_verto/Makefile.am @@ -20,7 +20,7 @@ MCAST_la_LDFLAGS = -avoid-version -module -no-undefined -shared $(PERL_LDFLAGS install-data-local: perlmod-install perlmod-install: install-perlLTLIBRARIES - install -m 755 MCAST.pm $(PERL_SITEDIR) + install -m 755 mcast/MCAST.pm $(PERL_SITEDIR) endif mcast/esl_wrap.cpp: From b333714906cdf959a3294d65260fa9a6e828a3d6 Mon Sep 17 00:00:00 2001 From: Michael Jerris Date: Wed, 11 Jun 2014 17:11:47 -0500 Subject: [PATCH 025/231] fix coverity warnings --- src/mod/endpoints/mod_verto/mcast/mcast.c | 11 +++++--- src/mod/endpoints/mod_verto/mod_verto.c | 31 +++++++++++------------ 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/src/mod/endpoints/mod_verto/mcast/mcast.c b/src/mod/endpoints/mod_verto/mcast/mcast.c index a3234d743f..71080b0677 100644 --- a/src/mod/endpoints/mod_verto/mcast/mcast.c +++ b/src/mod/endpoints/mod_verto/mcast/mcast.c @@ -51,7 +51,7 @@ int mcast_socket_create(const char *host, int16_t port, mcast_handle_t *handle, memset(handle, 0, sizeof(*handle)); - if ((!(flags & MCAST_SEND) && !(flags & MCAST_RECV)) || !(handle->sock = socket(AF_INET, SOCK_DGRAM, 0))) { + if ((!(flags & MCAST_SEND) && !(flags & MCAST_RECV)) || (handle->sock = socket(AF_INET, SOCK_DGRAM, 0)) <= 0 ) { return -1; } @@ -59,7 +59,10 @@ int mcast_socket_create(const char *host, int16_t port, mcast_handle_t *handle, handle->send_addr.sin_addr.s_addr = inet_addr(host); handle->send_addr.sin_port = htons(port); - setsockopt(handle->sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); + if ( setsockopt(handle->sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) != 0 ) { + close(handle->sock); + return -1; + } if ((flags & MCAST_RECV)) { @@ -113,7 +116,9 @@ int mcast_socket_create(const char *host, int16_t port, mcast_handle_t *handle, handle->ttl = 255; } - setsockopt(handle->sock, IPPROTO_IP, IP_MULTICAST_TTL, &handle->ttl, sizeof(handle->ttl)); + if ( setsockopt(handle->sock, IPPROTO_IP, IP_MULTICAST_TTL, &handle->ttl, sizeof(handle->ttl)) != 0 ) { + return -1; + } handle->ready = 1; diff --git a/src/mod/endpoints/mod_verto/mod_verto.c b/src/mod/endpoints/mod_verto/mod_verto.c index 8e5c94ef51..7d30e7dc84 100644 --- a/src/mod/endpoints/mod_verto/mod_verto.c +++ b/src/mod/endpoints/mod_verto/mod_verto.c @@ -515,7 +515,7 @@ static switch_ssize_t ws_write_json(jsock_t *jsock, cJSON **json, switch_bool_t return r; } - if (jsock->uuid_str) { + if (!zstr(jsock->uuid_str)) { cJSON *result = cJSON_GetObjectItem(*json, "result"); if (result) { @@ -2065,6 +2065,9 @@ static switch_bool_t attended_transfer(switch_core_session_t *session, switch_co tech_pvt = switch_core_session_get_private_class(session, SWITCH_PVT_SECONDARY); b_tech_pvt = switch_core_session_get_private_class(b_session, SWITCH_PVT_SECONDARY); + switch_assert(b_tech_pvt); + switch_assert(tech_pvt); + switch_channel_set_variable(tech_pvt->channel, "refer_uuid", switch_core_session_get_uuid(b_tech_pvt->session)); switch_channel_set_variable(b_tech_pvt->channel, "transfer_disposition", "replaced"); @@ -2130,9 +2133,7 @@ static switch_bool_t attended_transfer(switch_core_session_t *session, switch_co result = SWITCH_TRUE; - if (b_tech_pvt) { - switch_channel_hangup(b_tech_pvt->channel, SWITCH_CAUSE_NORMAL_CLEARING); - } + switch_channel_hangup(b_tech_pvt->channel, SWITCH_CAUSE_NORMAL_CLEARING); } else { result = SWITCH_FALSE; } @@ -2347,11 +2348,6 @@ static switch_bool_t verto__attach_func(const char *method, cJSON *params, jsock err = 1; goto cleanup; } - if (!(call_id = cJSON_GetObjectCstr(dialog, "callID"))) { - cJSON_AddItemToObject(obj, "message", cJSON_CreateString("CallID missing")); - err = 1; goto cleanup; - } - if (!(sdp = cJSON_GetObjectCstr(params, "sdp"))) { cJSON_AddItemToObject(obj, "message", cJSON_CreateString("SDP missing")); err = 1; goto cleanup; @@ -2850,8 +2846,9 @@ static switch_bool_t verto__broadcast_func(const char *method, cJSON *params, js if (jsock->profile->mcast_pub.sock > -1) { if ((json_text = cJSON_PrintUnformatted(params))) { - mcast_socket_send(&jsock->profile->mcast_pub, json_text, strlen(json_text) + 1); - + if ( mcast_socket_send(&jsock->profile->mcast_pub, json_text, strlen(json_text) + 1) < 0 ) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "multicast socket send error!\n"); + } free(json_text); json_text = NULL; @@ -3058,7 +3055,9 @@ static int prepare_socket(int ip, int port) die("Socket Error!\n"); } - setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, sizeof(reuse_addr)); + if ( setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, sizeof(reuse_addr)) < 0 ) { + die("Socket setsockopt Error!\n"); + } memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; @@ -3288,11 +3287,11 @@ static verto_profile_t *find_profile(const char *name) } } - if (!r->in_thread || !r->running) { + if (r && (!r->in_thread || !r->running)) { r = NULL; } - if (switch_thread_rwlock_tryrdlock(r->rwlock) != SWITCH_STATUS_SUCCESS) { + if (r && switch_thread_rwlock_tryrdlock(r->rwlock) != SWITCH_STATUS_SUCCESS) { r = NULL; } switch_mutex_unlock(globals.mutex); @@ -3476,7 +3475,7 @@ static switch_status_t parse_config(const char *cf) } if (zstr(profile->inbound_codec_string)) { - profile->outbound_codec_string = profile->outbound_codec_string; + profile->inbound_codec_string = profile->outbound_codec_string; } if (zstr(profile->timer_name)) { @@ -4014,7 +4013,7 @@ static cJSON *json_retrieve(const char *name, switch_mutex_t *mutex) static switch_bool_t json_commit(cJSON *json, const char *name, switch_mutex_t *mutex) { - char *ascii = cJSON_PrintUnformatted(json); + char *ascii; char *sql; char del_sql[128] = ""; switch_cache_db_handle_t *dbh; From 7f36607ea513f89d3bdf2a63ba1141c57a1adfed Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Wed, 11 Jun 2014 17:53:39 -0500 Subject: [PATCH 026/231] verto default config --- conf/vanilla/autoload_configs/verto.conf.xml | 27 ++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 conf/vanilla/autoload_configs/verto.conf.xml diff --git a/conf/vanilla/autoload_configs/verto.conf.xml b/conf/vanilla/autoload_configs/verto.conf.xml new file mode 100644 index 0000000000..6d84929baf --- /dev/null +++ b/conf/vanilla/autoload_configs/verto.conf.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + From 928a989de1d24e977d0fd92cff9862c3db65c09e Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Thu, 12 Jun 2014 22:06:33 +0500 Subject: [PATCH 027/231] first pass of stereo support --- src/include/switch_core.h | 4 +- src/include/switch_module_interfaces.h | 7 +- src/include/switch_resample.h | 4 +- .../mod_conference/mod_conference.c | 157 ++++++++++---- src/mod/asr_tts/mod_cepstral/mod_cepstral.c | 3 +- src/mod/codecs/mod_opus/mod_opus.c | 80 +++++-- .../mod_local_stream/mod_local_stream.c | 12 +- .../mod_shell_stream/mod_shell_stream.c | 2 + src/mod/formats/mod_shout/mod_shout.c | 22 +- .../formats/mod_tone_stream/mod_tone_stream.c | 3 + src/mod/formats/mod_vlc/mod_vlc.c | 27 ++- src/mod/languages/mod_v8/src/fssession.cpp | 2 +- src/switch_core_codec.c | 7 +- src/switch_core_file.c | 58 ++--- src/switch_core_io.c | 43 +++- src/switch_core_speech.c | 24 +- src/switch_ivr_async.c | 12 +- src/switch_ivr_play_say.c | 71 +++--- src/switch_pcm.c | 205 +++++++++++++++++- src/switch_resample.c | 54 ++++- 20 files changed, 592 insertions(+), 205 deletions(-) diff --git a/src/include/switch_core.h b/src/include/switch_core.h index e38a8ae003..1414d518a2 100644 --- a/src/include/switch_core.h +++ b/src/include/switch_core.h @@ -1870,7 +1870,9 @@ SWITCH_DECLARE(switch_status_t) switch_core_speech_open(_In_ switch_speech_handl const char *module_name, const char *voice_name, _In_ unsigned int rate, - _In_ unsigned int interval, switch_speech_flag_t *flags, _In_opt_ switch_memory_pool_t *pool); + _In_ unsigned int interval, + _In_ unsigned int channels, + switch_speech_flag_t *flags, _In_opt_ switch_memory_pool_t *pool); /*! \brief Feed text to the TTS module \param sh the speech handle to feed diff --git a/src/include/switch_module_interfaces.h b/src/include/switch_module_interfaces.h index 62fea0b3f7..aff702962b 100644 --- a/src/include/switch_module_interfaces.h +++ b/src/include/switch_module_interfaces.h @@ -311,6 +311,7 @@ struct switch_file_handle { uint32_t native_rate; /*! the number of channels */ uint32_t channels; + uint32_t real_channels; /*! integer representation of the format */ unsigned int format; /*! integer representation of the sections */ @@ -435,7 +436,7 @@ struct switch_speech_interface { /*! the name of the interface */ const char *interface_name; /*! function to open the speech interface */ - switch_status_t (*speech_open) (switch_speech_handle_t *sh, const char *voice_name, int rate, switch_speech_flag_t *flags); + switch_status_t (*speech_open) (switch_speech_handle_t *sh, const char *voice_name, int rate, int channels, switch_speech_flag_t *flags); /*! function to close the speech interface */ switch_status_t (*speech_close) (switch_speech_handle_t *, switch_speech_flag_t *flags); /*! function to feed audio to the ASR */ @@ -466,6 +467,8 @@ struct switch_speech_handle { uint32_t rate; uint32_t speed; uint32_t samples; + uint32_t channels; + uint32_t real_channels; char voice[80]; char *engine; /*! module specific param */ @@ -599,6 +602,8 @@ struct switch_codec_fmtp { int bits_per_second; /*! number of microseconds of media in one packet (ptime * 1000) */ int microseconds_per_packet; + /*! stereo */ + int stereo; /*! private data for the codec module to store handle specific info */ void *private_info; diff --git a/src/include/switch_resample.h b/src/include/switch_resample.h index bc1677079f..355510f575 100644 --- a/src/include/switch_resample.h +++ b/src/include/switch_resample.h @@ -67,6 +67,8 @@ SWITCH_BEGIN_EXTERN_C uint32_t to_len; /*! the total size of the to buffer */ uint32_t to_size; + /*! the number of channels */ + int channels; } switch_audio_resampler_t; @@ -171,7 +173,7 @@ SWITCH_DECLARE(void) switch_change_sln_volume_granular(int16_t *data, uint32_t s SWITCH_DECLARE(uint32_t) switch_merge_sln(int16_t *data, uint32_t samples, int16_t *other_data, uint32_t other_samples); SWITCH_DECLARE(uint32_t) switch_unmerge_sln(int16_t *data, uint32_t samples, int16_t *other_data, uint32_t other_samples); -SWITCH_DECLARE(void) switch_mux_channels(int16_t *data, switch_size_t samples, uint32_t channels); +SWITCH_DECLARE(void) switch_mux_channels(int16_t *data, switch_size_t samples, uint32_t orig_channels, uint32_t channels); SWITCH_END_EXTERN_C #endif diff --git a/src/mod/applications/mod_conference/mod_conference.c b/src/mod/applications/mod_conference/mod_conference.c index 36ecbf7d43..f04581736d 100644 --- a/src/mod/applications/mod_conference/mod_conference.c +++ b/src/mod/applications/mod_conference/mod_conference.c @@ -359,6 +359,7 @@ typedef struct conference_obj { switch_mutex_t *flag_mutex; uint32_t rate; uint32_t interval; + uint32_t channels; switch_mutex_t *mutex; conference_member_t *members; conference_member_t *floor_holder; @@ -2532,7 +2533,7 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v conference_obj_t *conference = (conference_obj_t *) obj; conference_member_t *imember, *omember; uint32_t samples = switch_samples_per_packet(conference->rate, conference->interval); - uint32_t bytes = samples * 2; + uint32_t bytes = samples * 2 * conference->channels; uint8_t ready = 0, total = 0; switch_timer_t timer = { 0 }; switch_event_t *event; @@ -2595,12 +2596,12 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v while (globals.running && !switch_test_flag(conference, CFLAG_DESTRUCT)) { switch_size_t file_sample_len = samples; - switch_size_t file_data_len = samples * 2; + switch_size_t file_data_len = samples * 2 * conference->channels; int has_file_data = 0, members_with_video = 0; uint32_t conf_energy = 0; int nomoh = 0; - conference_member_t *floor_holder, *video_bridge_members[2] = { 0 }; - + conference_member_t *floor_holder, *video_bridge_members[2] = { 0 }; + /* Sync the conference to a single timing source */ if (switch_core_timer_next(&timer) != SWITCH_STATUS_SUCCESS) { switch_set_flag(conference, CFLAG_DESTRUCT); @@ -2744,11 +2745,13 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v conference->fnode->leadin--; } else if (!conference->fnode->done) { file_sample_len = samples; + if (conference->fnode->type == NODE_TYPE_SPEECH) { switch_speech_flag_t flags = SWITCH_SPEECH_FLAG_BLOCKING; - + if (switch_core_speech_read_tts(conference->fnode->sh, file_frame, &file_data_len, &flags) == SWITCH_STATUS_SUCCESS) { - file_sample_len = file_data_len / 2; + file_sample_len = file_data_len / 2 / conference->fnode->sh->channels; + } else { file_sample_len = file_data_len = 0; } @@ -2780,8 +2783,7 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v } else { if (has_file_data) { switch_size_t x; - - for (x = 0; x < file_sample_len; x++) { + for (x = 0; x < file_sample_len * conference->channels; x++) { int32_t z; int16_t *muxed; @@ -2792,27 +2794,29 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v muxed[x] = (int16_t) z; } } else { - memcpy(file_frame, async_file_frame, file_sample_len * 2); + memcpy(file_frame, async_file_frame, file_sample_len * 2 * conference->channels); has_file_data = 1; } } } } - + if (ready || has_file_data) { /* Use more bits in the main_frame to preserve the exact sum of the audio samples. */ - int main_frame[SWITCH_RECOMMENDED_BUFFER_SIZE / 2] = { 0 }; - int16_t write_frame[SWITCH_RECOMMENDED_BUFFER_SIZE / 2] = { 0 }; + int main_frame[SWITCH_RECOMMENDED_BUFFER_SIZE] = { 0 }; + int16_t write_frame[SWITCH_RECOMMENDED_BUFFER_SIZE] = { 0 }; /* Init the main frame with file data if there is any. */ bptr = (int16_t *) file_frame; if (has_file_data && file_sample_len) { + for (x = 0; x < bytes / 2; x++) { - if (x <= file_sample_len) { + if (x <= file_sample_len * conference->channels) { main_frame[x] = (int32_t) bptr[x]; } else { memset(&main_frame[x], 255, sizeof(main_frame[x])); + //printf("FUCCCK %d <= %ld (%ld/%d)\n", x, file_sample_len * conference->channels, file_sample_len, conference->channels); } } } @@ -2876,8 +2880,10 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v } bptr = (int16_t *) omember->frame; - for (x = 0; x < bytes / 2; x++) { + + for (x = 0; x < bytes / 2 ; x++) { z = main_frame[x]; + /* bptr[x] represents my own contribution to this audio sample */ if (switch_test_flag(omember, MFLAG_HAS_AUDIO) && x <= omember->read / 2) { z -= (int32_t) bptr[x]; @@ -3678,6 +3684,27 @@ static void check_agc_levels(conference_member_t *member) } +static void member_check_channels(switch_frame_t *frame, conference_member_t *member, switch_bool_t in) +{ + if (member->conference->channels != member->read_impl.number_of_channels) { + uint32_t rlen; + int from, to; + + if (in) { + to = member->conference->channels; + from = member->read_impl.number_of_channels; + } else { + from = member->conference->channels; + to = member->read_impl.number_of_channels; + } + + rlen = frame->datalen / 2 / from; + + switch_mux_channels((int16_t *) frame->data, rlen, from, to); + + frame->datalen = rlen * 2 * to; + } +} /* marshall frames from the call leg to the conference thread for muxing to other call legs */ @@ -3729,6 +3756,8 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v break; } + member_check_channels(read_frame, member, SWITCH_TRUE); + if (switch_channel_test_flag(channel, CF_VIDEO) && !switch_test_flag(member, MFLAG_ACK_VIDEO)) { switch_set_flag_locked(member, MFLAG_ACK_VIDEO); switch_channel_clear_flag(channel, CF_VIDEO_ECHO); @@ -3827,7 +3856,7 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v switch_change_sln_volume_granular(read_frame->data, read_frame->datalen / 2, member->agc_volume_in_level); } - if ((samples = read_frame->datalen / sizeof(*data))) { + if ((samples = read_frame->datalen / sizeof(*data) / member->read_impl.number_of_channels)) { for (i = 0; i < samples; i++) { energy += abs(data[j]); j += member->read_impl.number_of_channels; @@ -3980,9 +4009,9 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v int16_t *bptr = (int16_t *) read_frame->data; int len = (int) read_frame->datalen; - switch_resample_process(read_resampler, bptr, len / 2); - memcpy(member->resample_out, read_resampler->to, read_resampler->to_len * 2); - len = read_resampler->to_len * 2; + switch_resample_process(read_resampler, bptr, len / 2 / member->conference->channels); + memcpy(member->resample_out, read_resampler->to, read_resampler->to_len * 2 * member->conference->channels); + len = read_resampler->to_len * 2 * member->conference->channels; datalen = len; data = member->resample_out; } else { @@ -4039,8 +4068,8 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v static void member_add_file_data(conference_member_t *member, int16_t *data, switch_size_t file_data_len) { - switch_size_t file_sample_len = file_data_len / 2; - int16_t file_frame[SWITCH_RECOMMENDED_BUFFER_SIZE / 2] = { 0 }; + switch_size_t file_sample_len; + int16_t file_frame[SWITCH_RECOMMENDED_BUFFER_SIZE] = { 0 }; switch_mutex_lock(member->fnode_mutex); @@ -4049,6 +4078,8 @@ static void member_add_file_data(conference_member_t *member, int16_t *data, swi goto done; } + file_sample_len = file_data_len / 2 / member->conference->channels; + /* if we are done, clean it up */ if (member->fnode->done) { conference_file_node_t *fnode; @@ -4071,15 +4102,15 @@ static void member_add_file_data(conference_member_t *member, int16_t *data, swi } else { if (member->fnode->type == NODE_TYPE_SPEECH) { switch_speech_flag_t flags = SWITCH_SPEECH_FLAG_BLOCKING; - + if (switch_core_speech_read_tts(member->fnode->sh, file_frame, &file_data_len, &flags) == SWITCH_STATUS_SUCCESS) { - file_sample_len = file_data_len / 2; + file_sample_len = file_data_len / 2 / member->conference->channels; } else { file_sample_len = file_data_len = 0; } } else if (member->fnode->type == NODE_TYPE_FILE) { switch_core_file_read(&member->fnode->fh, file_frame, &file_sample_len); - file_data_len = file_sample_len * 2; + file_data_len = file_sample_len * 2 * member->fnode->fh.channels; } if (file_sample_len <= 0) { @@ -4092,7 +4123,7 @@ static void member_add_file_data(conference_member_t *member, int16_t *data, swi switch_change_sln_volume(file_frame, (uint32_t)file_sample_len, member->volume_out_level); } - for (i = 0; i < (int)file_sample_len; i++) { + for (i = 0; i < (int)file_sample_len * member->conference->channels; i++) { if (member->fnode->mux) { sample = data[i] + file_frame[i]; switch_normalize_to_16bit(sample); @@ -4157,7 +4188,7 @@ static void conference_loop_output(conference_member_t *member) //csamples = samples; tsamples = member->orig_read_impl.samples_per_packet; low_count = 0; - bytes = samples * 2; + bytes = samples * 2 * member->conference->channels; call_list = NULL; cp = NULL; @@ -4165,7 +4196,7 @@ static void conference_loop_output(conference_member_t *member) switch_assert(member->conference != NULL); - flush_len = switch_samples_per_packet(member->conference->rate, member->conference->interval) * 10; + flush_len = switch_samples_per_packet(member->conference->rate, member->conference->interval) * 10 * member->conference->channels; if (switch_core_timer_init(&timer, member->conference->timer_name, interval, tsamples, NULL) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_ERROR, "Timer Setup Failed. Conference Cannot Start\n"); @@ -4331,7 +4362,7 @@ static void conference_loop_output(conference_member_t *member) mux_used = (uint32_t) switch_buffer_inuse(member->mux_buffer); use_timer = 1; - + if (mux_used) { if (mux_used < bytes) { if (++low_count >= 5) { @@ -4354,7 +4385,7 @@ static void conference_loop_output(conference_member_t *member) low_count = 0; if ((write_frame.datalen = (uint32_t) switch_buffer_read(use_buffer, write_frame.data, bytes))) { if (write_frame.datalen) { - write_frame.samples = write_frame.datalen / 2; + write_frame.samples = write_frame.datalen / 2 / member->conference->channels; if( !switch_test_flag(member, MFLAG_CAN_HEAR)) { memset(write_frame.data, 255, write_frame.datalen); @@ -4369,6 +4400,9 @@ static void conference_loop_output(conference_member_t *member) if (member->fnode) { member_add_file_data(member, write_frame.data, write_frame.datalen); } + + member_check_channels(&write_frame, member, SWITCH_FALSE); + if (switch_core_session_write_frame(member->session, &write_frame, SWITCH_IO_FLAG_NONE, 0) != SWITCH_STATUS_SUCCESS) { switch_mutex_unlock(member->audio_out_mutex); break; @@ -4383,6 +4417,7 @@ static void conference_loop_output(conference_member_t *member) memset(write_frame.data, 255, write_frame.datalen); write_frame.timestamp = timer.samplecount; member_add_file_data(member, write_frame.data, write_frame.datalen); + member_check_channels(&write_frame, member, SWITCH_FALSE); if (switch_core_session_write_frame(member->session, &write_frame, SWITCH_IO_FLAG_NONE, 0) != SWITCH_STATUS_SUCCESS) { switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); break; @@ -4399,6 +4434,8 @@ static void conference_loop_output(conference_member_t *member) write_frame.samples = samples; write_frame.timestamp = timer.samplecount; + member_check_channels(&write_frame, member, SWITCH_FALSE); + if (switch_core_session_write_frame(member->session, &write_frame, SWITCH_IO_FLAG_NONE, 0) != SWITCH_STATUS_SUCCESS) { switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); break; @@ -4521,7 +4558,7 @@ static void *SWITCH_THREAD_FUNC conference_record_thread_run(switch_thread_t *th return NULL; } - data_buf_len = samples * sizeof(int16_t); + data_buf_len = samples * sizeof(int16_t) * conference->channels; switch_zmalloc(data_buf, data_buf_len); switch_mutex_lock(globals.hash_mutex); @@ -4574,7 +4611,7 @@ static void *SWITCH_THREAD_FUNC conference_record_thread_run(switch_thread_t *th fh.pre_buffer_datalen = SWITCH_DEFAULT_FILE_BUFFER_LEN; if (switch_core_file_open(&fh, - rec->path, (uint8_t) 1, conference->rate, SWITCH_FILE_FLAG_WRITE | SWITCH_FILE_DATA_SHORT, + rec->path, (uint8_t) conference->channels, conference->rate, SWITCH_FILE_FLAG_WRITE | SWITCH_FILE_DATA_SHORT, rec->pool) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening File [%s]\n", rec->path); @@ -4917,7 +4954,7 @@ static switch_status_t conference_play_file(conference_obj_t *conference, char * /* Open the file */ fnode->fh.pre_buffer_datalen = SWITCH_DEFAULT_FILE_BUFFER_LEN; - if (switch_core_file_open(&fnode->fh, file, (uint8_t) 1, conference->rate, SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, pool) != + if (switch_core_file_open(&fnode->fh, file, (uint8_t) conference->channels, conference->rate, SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, pool) != SWITCH_STATUS_SUCCESS) { switch_event_t *event; @@ -5043,7 +5080,7 @@ static switch_status_t conference_member_play_file(conference_member_t *member, /* Open the file */ fnode->fh.pre_buffer_datalen = SWITCH_DEFAULT_FILE_BUFFER_LEN; if (switch_core_file_open(&fnode->fh, - file, (uint8_t) 1, member->conference->rate, SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, + file, (uint8_t) member->conference->channels, member->conference->rate, SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, pool) != SWITCH_STATUS_SUCCESS) { switch_core_destroy_memory_pool(&pool); status = SWITCH_STATUS_NOTFOUND; @@ -5109,7 +5146,7 @@ static switch_status_t conference_member_say(conference_member_t *member, char * if (!member->sh) { memset(&member->lsh, 0, sizeof(member->lsh)); if (switch_core_speech_open(&member->lsh, conference->tts_engine, conference->tts_voice, - conference->rate, conference->interval, &flags, switch_core_session_get_pool(member->session)) != + conference->rate, conference->interval, conference->channels, &flags, switch_core_session_get_pool(member->session)) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_ERROR, "Invalid TTS module [%s]!\n", conference->tts_engine); return SWITCH_STATUS_FALSE; @@ -5198,7 +5235,7 @@ static switch_status_t conference_say(conference_obj_t *conference, const char * if (!conference->sh) { memset(&conference->lsh, 0, sizeof(conference->lsh)); if (switch_core_speech_open(&conference->lsh, conference->tts_engine, conference->tts_voice, - conference->rate, conference->interval, &flags, NULL) != SWITCH_STATUS_SUCCESS) { + conference->rate, conference->interval, conference->channels, &flags, NULL) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid TTS module [%s]!\n", conference->tts_engine); return SWITCH_STATUS_FALSE; } @@ -8075,14 +8112,15 @@ static int setup_media(conference_member_t *member, conference_obj_t *conference if (switch_core_codec_init(&member->read_codec, "L16", NULL, read_impl.actual_samples_per_second, read_impl.microseconds_per_packet / 1000, - 1, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, member->pool) == SWITCH_STATUS_SUCCESS) { + read_impl.number_of_channels, + SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, member->pool) == SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_DEBUG, - "Raw Codec Activation Success L16@%uhz 1 channel %dms\n", - read_impl.actual_samples_per_second, read_impl.microseconds_per_packet / 1000); + "Raw Codec Activation Success L16@%uhz %d channel %dms\n", + read_impl.actual_samples_per_second, read_impl.number_of_channels, read_impl.microseconds_per_packet / 1000); } else { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_DEBUG, "Raw Codec Activation Failed L16@%uhz 1 channel %dms\n", - read_impl.actual_samples_per_second, read_impl.microseconds_per_packet / 1000); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_DEBUG, "Raw Codec Activation Failed L16@%uhz %d channel %dms\n", + read_impl.actual_samples_per_second, read_impl.number_of_channels, read_impl.microseconds_per_packet / 1000); goto done; } @@ -8096,7 +8134,7 @@ static int setup_media(conference_member_t *member, conference_obj_t *conference if (read_impl.actual_samples_per_second != conference->rate) { if (switch_resample_create(&member->read_resampler, read_impl.actual_samples_per_second, - conference->rate, member->frame_size, SWITCH_RESAMPLE_QUALITY, 1) != SWITCH_STATUS_SUCCESS) { + conference->rate, member->frame_size, SWITCH_RESAMPLE_QUALITY, conference->channels) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_CRIT, "Unable to create resampler!\n"); goto done; } @@ -8120,12 +8158,14 @@ static int setup_media(conference_member_t *member, conference_obj_t *conference NULL, conference->rate, read_impl.microseconds_per_packet / 1000, - 1, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, member->pool) == SWITCH_STATUS_SUCCESS) { + read_impl.number_of_channels, + SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, member->pool) == SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_DEBUG, - "Raw Codec Activation Success L16@%uhz 1 channel %dms\n", conference->rate, read_impl.microseconds_per_packet / 1000); + "Raw Codec Activation Success L16@%uhz %d channel %dms\n", + conference->rate, conference->channels, read_impl.microseconds_per_packet / 1000); } else { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_DEBUG, "Raw Codec Activation Failed L16@%uhz 1 channel %dms\n", - conference->rate, read_impl.microseconds_per_packet / 1000); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_DEBUG, "Raw Codec Activation Failed L16@%uhz %d channel %dms\n", + conference->rate, conference->channels, read_impl.microseconds_per_packet / 1000); goto codec_done2; } @@ -9027,6 +9067,7 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_c uint32_t announce_count = 0; char *maxmember_sound = NULL; uint32_t rate = 8000, interval = 20; + uint32_t channels = 1; int broadcast_chat_messages = 0; int comfort_noise_level = 0; int pin_retries = 3; @@ -9044,8 +9085,8 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_c switch_uuid_t uuid; switch_codec_implementation_t read_impl = { 0 }; switch_channel_t *channel = NULL; - const char *force_rate = NULL, *force_interval = NULL, *presence_id = NULL; - uint32_t force_rate_i = 0, force_interval_i = 0; + const char *force_rate = NULL, *force_interval = NULL, *force_channels = NULL, *presence_id = NULL; + uint32_t force_rate_i = 0, force_interval_i = 0, force_channels_i = NULL; /* Validate the conference name */ if (zstr(name)) { @@ -9073,6 +9114,18 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_c } } + if ((force_channels = switch_channel_get_variable(channel, "conference_force_channels"))) { + if (!strcasecmp(force_channels, "auto")) { + force_rate_i = read_impl.number_of_channels; + } else { + tmp = atoi(force_channels); + + if (tmp == 1 || tmp == 2) { + force_channels_i = channels = tmp; + } + } + } + if ((force_interval = switch_channel_get_variable(channel, "conference_force_interval"))) { if (!strcasecmp(force_interval, "auto")) { force_interval_i = read_impl.microseconds_per_packet / 1000; @@ -9117,6 +9170,17 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_c rate = tmp; } } + } else if (!force_channels_i && !strcasecmp(var, "channels") && !zstr(val)) { + uint32_t tmp = atoi(val); + if (session && tmp == 0) { + if (!strcasecmp(val, "auto")) { + channels = read_impl.number_of_channels; + } + } else { + if (tmp == 1 || tmp == 2) { + channels = tmp; + } + } } else if (!strcasecmp(var, "domain") && !zstr(val)) { domain = val; } else if (!strcasecmp(var, "description") && !zstr(val)) { @@ -9507,6 +9571,7 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_c conference->domain = "cluecon.com"; } + conference->channels = channels; conference->rate = rate; conference->interval = interval; conference->ivr_dtmf_timeout = ivr_dtmf_timeout; diff --git a/src/mod/asr_tts/mod_cepstral/mod_cepstral.c b/src/mod/asr_tts/mod_cepstral/mod_cepstral.c index b00b709354..c368c28b24 100644 --- a/src/mod/asr_tts/mod_cepstral/mod_cepstral.c +++ b/src/mod/asr_tts/mod_cepstral/mod_cepstral.c @@ -118,7 +118,7 @@ static swift_result_t write_audio(swift_event * event, swift_event_t type, void return rv; } -static switch_status_t cepstral_speech_open(switch_speech_handle_t *sh, const char *voice_name, int rate, switch_speech_flag_t *flags) +static switch_status_t cepstral_speech_open(switch_speech_handle_t *sh, const char *voice_name, int rate, int channels, switch_speech_flag_t *flags) { cepstral_t *cepstral = switch_core_alloc(sh->memory_pool, sizeof(*cepstral)); char srate[25]; @@ -290,7 +290,6 @@ static switch_status_t cepstral_speech_read_tts(switch_speech_handle_t *sh, void if (!used && cepstral->done_gen) { - status = SWITCH_STATUS_BREAK; break; } diff --git a/src/mod/codecs/mod_opus/mod_opus.c b/src/mod/codecs/mod_opus/mod_opus.c index cb9b558a48..af10ca3371 100644 --- a/src/mod/codecs/mod_opus/mod_opus.c +++ b/src/mod/codecs/mod_opus/mod_opus.c @@ -143,6 +143,11 @@ static switch_status_t switch_opus_fmtp_parse(const char *fmtp, switch_codec_fmt codec_settings->samplerate = atoi(arg); codec_fmtp->actual_samples_per_second = codec_settings->samplerate; } + + if (!strcasecmp(data, "stereo")) { + codec_settings->stereo = atoi(arg); + codec_fmtp->stereo = codec_settings->stereo; + } if (!strcasecmp(data, "maxaveragebitrate")) { codec_settings->maxaveragebitrate = atoi(arg); @@ -202,36 +207,40 @@ static char *gen_fmtp(opus_codec_settings_t *settings, switch_memory_pool_t *poo char buf[256] = ""; if (settings->useinbandfec) { - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "useinbandfec=1;"); + snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "useinbandfec=1; "); } if (settings->usedtx) { - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "usedtx=1;"); + snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "usedtx=1; "); } if (settings->maxaveragebitrate) { - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "maxaveragebitrate=%d;", settings->maxaveragebitrate); + snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "maxaveragebitrate=%d; ", settings->maxaveragebitrate); } if (settings->ptime) { - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "ptime=%d;", settings->ptime); + snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "ptime=%d; ", settings->ptime); } if (settings->minptime) { - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "minptime=%d;", settings->minptime); + snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "minptime=%d; ", settings->minptime); } - + if (settings->maxptime) { - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "maxptime=%d;", settings->maxptime); + snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "maxptime=%d; ", settings->maxptime); } if (settings->samplerate) { - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "samplerate=%d;", settings->samplerate); + snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "samplerate=%d; ", settings->samplerate); } - - if (end_of(buf) == ';') { - end_of(buf) = '\0'; + + if (settings->stereo) { + snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "stereo=%d; ", settings->stereo); + } + + if (end_of(buf) == ' ') { + *(end_of_p(buf) - 1) = '\0'; } return switch_core_strdup(pool, buf); @@ -255,9 +264,8 @@ static switch_status_t switch_opus_init(switch_codec_t *codec, switch_codec_flag memset(&codec_fmtp, '\0', sizeof(struct switch_codec_fmtp)); codec_fmtp.private_info = &opus_codec_settings; switch_opus_fmtp_parse(codec->fmtp_in, &codec_fmtp); - codec->fmtp_out = gen_fmtp(&opus_codec_settings, codec->memory_pool); - + if (encoding) { /* come up with a way to specify these */ int bitrate_bps = OPUS_AUTO; @@ -268,7 +276,7 @@ static switch_status_t switch_opus_init(switch_codec_t *codec, switch_codec_flag context->encoder_object = opus_encoder_create(samplerate, codec->implementation->number_of_channels, - OPUS_APPLICATION_VOIP, &err); + codec->implementation->number_of_channels == 1 ? OPUS_APPLICATION_VOIP : OPUS_APPLICATION_AUDIO, &err); if (err != OPUS_OK) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot create encoder: %s\n", opus_strerror(err)); @@ -358,17 +366,19 @@ static switch_status_t switch_opus_encode(switch_codec_t *codec, if (!context) { return SWITCH_STATUS_FALSE; } - - if (len > 1275) len = 1275; - - bytes = opus_encode(context->encoder_object, (void *) decoded_data, decoded_data_len / 2, (unsigned char *) encoded_data, len); - + + if (len > 2880) len = 2880; + + bytes = opus_encode(context->encoder_object, (void *) decoded_data, + decoded_data_len / 2 / codec->implementation->number_of_channels, (unsigned char *) encoded_data, len); + if (bytes > 0) { *encoded_data_len = (uint32_t) bytes; return SWITCH_STATUS_SUCCESS; } - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Encoder Error!\n"); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Encoder Error: %s Decoded Datalen %u Codec NumberChans %u Len %u DecodedDate %p EncodedData %p ContextEncoderObject %p!\n", opus_strerror(bytes),decoded_data_len,codec->implementation->number_of_channels,len,(void *) decoded_data,(void *) encoded_data,(void *) context->encoder_object); + return SWITCH_STATUS_GENERR; } @@ -387,12 +397,13 @@ static switch_status_t switch_opus_decode(switch_codec_t *codec, } samples = opus_decode(context->decoder_object, (*flag & SFF_PLC) ? NULL : encoded_data, encoded_data_len, decoded_data, *decoded_data_len, 0); - + if (samples < 0) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Decoder Error: %s!\n", opus_strerror(samples)); return SWITCH_STATUS_GENERR; } - - *decoded_data_len = samples * 2; + + *decoded_data_len = samples * 2 * codec->implementation->number_of_channels; return SWITCH_STATUS_SUCCESS; } @@ -481,6 +492,27 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_opus_load) switch_opus_decode, /* function to decode encoded data into raw data */ switch_opus_destroy); /* deinitalize a codec handle using this implementation */ + settings.stereo = 1; + dft_fmtp = gen_fmtp(&settings, pool); + + switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */ + 116, /* the IANA code number */ + "opus",/* the IANA code name */ + dft_fmtp, /* default fmtp to send (can be overridden by the init function) */ + rate, /* samples transferred per second */ + rate, /* actual samples transferred per second */ + bits, /* bits transferred per second */ + mss, /* number of microseconds per frame */ + samples, /* number of samples per frame */ + bytes * 2, /* number of bytes per frame decompressed */ + 0, /* number of bytes per frame compressed */ + 2,/* number of channels represented */ + 1, /* number of frames per network packet */ + switch_opus_init, /* function to initialize a codec handle using this implementation */ + switch_opus_encode, /* function to encode raw data into encoded data */ + switch_opus_decode, /* function to decode encoded data into raw data */ + switch_opus_destroy); /* deinitalize a codec handle using this implementation */ + bytes *= 2; samples *= 2; mss *= 2; diff --git a/src/mod/formats/mod_local_stream/mod_local_stream.c b/src/mod/formats/mod_local_stream/mod_local_stream.c index 35ea59d841..5f4a1e0645 100644 --- a/src/mod/formats/mod_local_stream/mod_local_stream.c +++ b/src/mod/formats/mod_local_stream/mod_local_stream.c @@ -298,7 +298,7 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void } } - switch_buffer_write(audio_buffer, abuf, olen * 2); + switch_buffer_write(audio_buffer, abuf, olen * 2 * source->channels); } } @@ -308,8 +308,8 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void break; } - if (!is_open || used >= source->prebuf || (source->total && used > source->samples * 2)) { - used = switch_buffer_read(audio_buffer, dist_buf, source->samples * 2); + if (!is_open || used >= source->prebuf || (source->total && used > source->samples * 2 * source->channels)) { + used = switch_buffer_read(audio_buffer, dist_buf, source->samples * 2 * source->channels); if (source->total) { uint32_t bused = 0; switch_mutex_lock(source->mutex); @@ -548,7 +548,7 @@ static switch_status_t local_stream_file_read(switch_file_handle_t *handle, void { local_stream_context_t *context = handle->private_info; switch_size_t bytes = 0; - size_t need = *len * 2; + size_t need = *len * 2 * handle->real_channels; if (!context->source->ready) { *len = 0; @@ -557,13 +557,13 @@ static switch_status_t local_stream_file_read(switch_file_handle_t *handle, void switch_mutex_lock(context->audio_mutex); if ((bytes = switch_buffer_read(context->audio_buffer, data, need))) { - *len = bytes / 2; + *len = bytes / 2 / handle->real_channels; } else { if (need > 2560) { need = 2560; } memset(data, 255, need); - *len = need / 2; + *len = need / 2 / handle->real_channels; } switch_mutex_unlock(context->audio_mutex); handle->sample_count += *len; diff --git a/src/mod/formats/mod_shell_stream/mod_shell_stream.c b/src/mod/formats/mod_shell_stream/mod_shell_stream.c index 4c41e2e63a..07e0e41ce7 100644 --- a/src/mod/formats/mod_shell_stream/mod_shell_stream.c +++ b/src/mod/formats/mod_shell_stream/mod_shell_stream.c @@ -99,6 +99,8 @@ static switch_status_t shell_stream_file_open(switch_file_handle_t *handle, cons return SWITCH_STATUS_FALSE; } + handle->channels = 1; + context = switch_core_alloc(handle->memory_pool, sizeof(*context)); context->fds[0] = -1; diff --git a/src/mod/formats/mod_shout/mod_shout.c b/src/mod/formats/mod_shout/mod_shout.c index 662de882c3..68ea6b77b0 100644 --- a/src/mod/formats/mod_shout/mod_shout.c +++ b/src/mod/formats/mod_shout/mod_shout.c @@ -625,6 +625,9 @@ static switch_status_t shout_file_open(switch_file_handle_t *handle, const char char *err = NULL; const char *mpg123err = NULL; int portno = 0; + long rate = 0; + int channels = 0; + int encoding = 0; if ((context = switch_core_alloc(handle->memory_pool, sizeof(*context))) == 0) { return SWITCH_STATUS_MEMERR; @@ -659,9 +662,6 @@ static switch_status_t shout_file_open(switch_file_handle_t *handle, const char } if (handle->handler) { - if (mpg123_param(context->mh, MPG123_FLAGS, MPG123_SEEKBUFFER | MPG123_MONO_MIX, 0) != MPG123_OK) { - MPGERROR(); - } if (mpg123_open_feed(context->mh) != MPG123_OK) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error opening mpg feed\n"); mpg123err = mpg123_strerror(context->mh); @@ -672,9 +672,7 @@ static switch_status_t shout_file_open(switch_file_handle_t *handle, const char launch_read_stream_thread(context); } else { handle->seekable = 1; - if (mpg123_param(context->mh, MPG123_FLAGS, MPG123_MONO_MIX, 0) != MPG123_OK) { - MPGERROR(); - } + if (mpg123_open(context->mh, path) != MPG123_OK) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error opening %s\n", path); mpg123err = mpg123_strerror(context->mh); @@ -682,6 +680,12 @@ static switch_status_t shout_file_open(switch_file_handle_t *handle, const char } } + + + mpg123_getformat(context->mh, &rate, &channels, &encoding); + handle->channels = channels; + handle->samplerate = rate; + } else if (switch_test_flag(handle, SWITCH_FILE_FLAG_WRITE)) { if (!(context->gfp = lame_init())) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not allocate lame\n"); @@ -897,7 +901,7 @@ static switch_status_t shout_file_seek(switch_file_handle_t *handle, unsigned in static switch_status_t shout_file_read(switch_file_handle_t *handle, void *data, size_t *len) { shout_context_t *context = handle->private_info; - size_t rb = 0, bytes = *len * sizeof(int16_t), newbytes = 0; + size_t rb = 0, bytes = *len * sizeof(int16_t) * handle->channels, newbytes = 0; *len = 0; @@ -919,7 +923,7 @@ static switch_status_t shout_file_read(switch_file_handle_t *handle, void *data, /* switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "rb: %d, bytes: %d\n", (int) rb, (int) bytes); */ if (rb) { - *len = rb / sizeof(int16_t); + *len = rb / sizeof(int16_t) / handle->channels; } else { /* no data, so insert 1 second of silence */ newbytes = 2 * handle->samplerate; @@ -929,7 +933,7 @@ static switch_status_t shout_file_read(switch_file_handle_t *handle, void *data, switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Padding mp3 stream with 1s of empty audio. (%s)\n", context->stream_url); memset(data, 255, bytes); - *len = bytes / sizeof(int16_t); + *len = bytes / sizeof(int16_t) / handle->channels; } handle->sample_count += *len; diff --git a/src/mod/formats/mod_tone_stream/mod_tone_stream.c b/src/mod/formats/mod_tone_stream/mod_tone_stream.c index 3c6e69ac8e..06a5de98c2 100644 --- a/src/mod/formats/mod_tone_stream/mod_tone_stream.c +++ b/src/mod/formats/mod_tone_stream/mod_tone_stream.c @@ -67,6 +67,7 @@ static switch_status_t silence_stream_file_open(switch_file_handle_t *handle, co } } + handle->channels = 1; handle->private_info = sh; return SWITCH_STATUS_SUCCESS; @@ -153,6 +154,8 @@ static switch_status_t tone_stream_file_open(switch_file_handle_t *handle, const handle->samplerate = 8000; } + handle->channels = 1; + teletone_init_session(&ts, 0, teletone_handler, audio_buffer); ts.rate = handle->samplerate; ts.channels = 1; diff --git a/src/mod/formats/mod_vlc/mod_vlc.c b/src/mod/formats/mod_vlc/mod_vlc.c index 24488f8899..51996686dc 100644 --- a/src/mod/formats/mod_vlc/mod_vlc.c +++ b/src/mod/formats/mod_vlc/mod_vlc.c @@ -73,6 +73,7 @@ struct vlc_file_context { int samples; int playing; int samplerate; + int channels; int err; int pts; libvlc_instance_t *inst_out; @@ -113,7 +114,7 @@ void vlc_auto_play_callback(void *data, const void *samples, unsigned count, int switch_mutex_lock(context->audio_mutex); if (context->audio_buffer) { - if (!switch_buffer_write(context->audio_buffer, samples, count * 2)) { + if (!switch_buffer_write(context->audio_buffer, samples, count * 2 * context->channels)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Buffer error\n"); } } @@ -145,7 +146,7 @@ int vlc_imem_get_callback(void *data, const char *cookie, int64_t *dts, int64_t context->samples = 0; if ( samples ) { - bytes = samples * 2; + bytes = samples * 2 * context->channels; *output = malloc(bytes); bytes = switch_buffer_read(context->audio_buffer, *output, bytes); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "VLC imem samples: %d\n", samples); @@ -210,12 +211,14 @@ static switch_status_t vlc_file_open(switch_file_handle_t *handle, const char *p context->mp = libvlc_media_player_new_from_media(context->m); - if ( !handle->samplerate) + if (!handle->samplerate) { handle->samplerate = 16000; + } context->samplerate = handle->samplerate; - - libvlc_audio_set_format(context->mp, "S16N", context->samplerate, 1); + context->channels = handle->channels; + + libvlc_audio_set_format(context->mp, "S16N", context->samplerate, handle->channels); m_event_manager = libvlc_media_event_manager(context->m); libvlc_event_attach(m_event_manager, libvlc_MediaStateChanged, vlc_media_state_callback, (void *) context); @@ -246,7 +249,7 @@ static switch_status_t vlc_file_open(switch_file_handle_t *handle, const char *p opts[6] = "--rawaud-fourcc=s16l"; opts[7] = switch_mprintf("--rawaud-samplerate=%d", context->samplerate); opts[8] = switch_mprintf("--imem-data=%ld", context); - opts[9] = "--rawaud-channels=1"; + //opts[9] = "--rawaud-channels=1"; /* Prepare to write to an output stream. */ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "VLC open %s for writing\n", path); @@ -274,7 +277,7 @@ static switch_status_t vlc_file_open(switch_file_handle_t *handle, const char *p static switch_status_t vlc_file_read(switch_file_handle_t *handle, void *data, size_t *len) { vlc_file_context_t *context = handle->private_info; - size_t bytes = *len * sizeof(int16_t), read; + size_t bytes = *len * sizeof(int16_t) * handle->channels, read; libvlc_state_t status; if (!context) { @@ -310,7 +313,8 @@ static switch_status_t vlc_file_read(switch_file_handle_t *handle, void *data, s read = switch_buffer_read(context->audio_buffer, data, bytes); switch_mutex_unlock(context->audio_mutex); - status = libvlc_media_get_state(context->m); + status = libvlc_media_get_state(context->m); + if (!read && (status == libvlc_Stopped || status == libvlc_Ended || status == libvlc_Error)) { return SWITCH_STATUS_FALSE; } else if (!read) { @@ -318,8 +322,9 @@ static switch_status_t vlc_file_read(switch_file_handle_t *handle, void *data, s memset(data, 0, read); } - if (read) - *len = read/2; + if (read) { + *len = read / 2 / handle->channels; + } return SWITCH_STATUS_SUCCESS; } @@ -327,7 +332,7 @@ static switch_status_t vlc_file_read(switch_file_handle_t *handle, void *data, s static switch_status_t vlc_file_write(switch_file_handle_t *handle, void *data, size_t *len) { vlc_file_context_t *context = handle->private_info; - size_t bytes = *len * sizeof(int16_t); + size_t bytes = *len * sizeof(int16_t) * handle->channels; switch_mutex_lock(context->audio_mutex); context->samples += *len; diff --git a/src/mod/languages/mod_v8/src/fssession.cpp b/src/mod/languages/mod_v8/src/fssession.cpp index eeaef7894c..dce66a053d 100644 --- a/src/mod/languages/mod_v8/src/fssession.cpp +++ b/src/mod/languages/mod_v8/src/fssession.cpp @@ -982,7 +982,7 @@ switch_status_t FSSession::InitSpeechEngine(const char *engine, const char *voic return SWITCH_STATUS_FALSE; } - if (switch_core_speech_open(&this->_speech->sh, engine, voice, rate, interval, + if (switch_core_speech_open(&this->_speech->sh, engine, voice, rate, interval, read_codec->implementation->number_of_channels, &flags, switch_core_session_get_pool(this->_session)) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid TTS module!\n"); switch_core_codec_destroy(&this->_speech->codec); diff --git a/src/switch_core_codec.c b/src/switch_core_codec.c index 4b47e27c0f..63e33ec2b6 100644 --- a/src/switch_core_codec.c +++ b/src/switch_core_codec.c @@ -700,8 +700,9 @@ SWITCH_DECLARE(switch_status_t) switch_core_codec_init_with_bitrate(switch_codec switch_set_flag(codec, SWITCH_CODEC_FLAG_READY); return SWITCH_STATUS_SUCCESS; } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Codec %s Exists but not at the desired implementation. %dhz %dms\n", codec_name, rate, - ms); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Codec %s Exists but not at the desired implementation. %dhz %dms %dch\n", + codec_name, rate, ms, channels); + } UNPROTECT_INTERFACE(codec_interface); @@ -765,7 +766,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_codec_decode(switch_codec_t *codec, } if (codec->implementation->encoded_bytes_per_packet) { - uint32_t frames = encoded_data_len / codec->implementation->encoded_bytes_per_packet; + uint32_t frames = encoded_data_len / codec->implementation->encoded_bytes_per_packet / codec->implementation->number_of_channels; if (frames && codec->implementation->decoded_bytes_per_packet * frames > *decoded_data_len) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Buffer size sanity check failed! edl:%u ebpp:%u fr:%u ddl:%u\n", diff --git a/src/switch_core_file.c b/src/switch_core_file.c index 3c6a2f8494..66e5df1d6e 100644 --- a/src/switch_core_file.c +++ b/src/switch_core_file.c @@ -188,6 +188,11 @@ SWITCH_DECLARE(switch_status_t) switch_core_perform_file_open(const char *file, switch_goto_status(status, fail); } + fh->real_channels = fh->channels; + + if (channels) { + fh->channels = channels; + } if ((flags & SWITCH_FILE_FLAG_WRITE) && !is_stream && (status = switch_file_exists(file_path, fh->memory_pool)) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "File [%s] not created!\n", file_path); @@ -216,12 +221,13 @@ SWITCH_DECLARE(switch_status_t) switch_core_perform_file_open(const char *file, if (fh->pre_buffer_datalen) { //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Prebuffering %d bytes\n", (int)fh->pre_buffer_datalen); - switch_buffer_create_dynamic(&fh->pre_buffer, fh->pre_buffer_datalen * fh->channels, fh->pre_buffer_datalen * fh->channels / 2, 0); + switch_buffer_create_dynamic(&fh->pre_buffer, fh->pre_buffer_datalen * fh->channels, fh->pre_buffer_datalen * fh->channels, 0); fh->pre_buffer_data = switch_core_alloc(fh->memory_pool, fh->pre_buffer_datalen * fh->channels); } - if (fh->channels > 1 && (flags & SWITCH_FILE_FLAG_READ) && !(fh->flags & SWITCH_FILE_NOMUX)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "File has %d channels, muxing to mono will occur.\n", fh->channels); + + if (fh->real_channels != fh->channels && (flags & SWITCH_FILE_FLAG_READ) && !(fh->flags & SWITCH_FILE_NOMUX)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "File has %d channels, muxing to %d channel%s will occur.\n", fh->real_channels, fh->channels, fh->channels == 1 ? "" : "s"); } switch_set_flag(fh, SWITCH_FILE_OPEN); @@ -264,8 +270,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_file_read(switch_file_handle_t *fh, return SWITCH_STATUS_FALSE; } - if (fh->buffer && switch_buffer_inuse(fh->buffer) >= *len * 2) { - *len = switch_buffer_read(fh->buffer, data, orig_len * 2) / 2; + if (fh->buffer && switch_buffer_inuse(fh->buffer) >= *len * 2 * fh->channels) { + *len = switch_buffer_read(fh->buffer, data, orig_len * 2 * fh->channels) / 2 / fh->channels; return *len == 0 ? SWITCH_STATUS_FALSE : SWITCH_STATUS_SUCCESS; } @@ -284,9 +290,9 @@ SWITCH_DECLARE(switch_status_t) switch_core_file_read(switch_file_handle_t *fh, int asis = switch_test_flag(fh, SWITCH_FILE_NATIVE); if (!switch_test_flag(fh, SWITCH_FILE_BUFFER_DONE)) { - rlen = asis ? fh->pre_buffer_datalen : fh->pre_buffer_datalen / 2; + rlen = asis ? fh->pre_buffer_datalen : fh->pre_buffer_datalen / 2 / fh->real_channels; - if (switch_buffer_inuse(fh->pre_buffer) < rlen * 2) { + if (switch_buffer_inuse(fh->pre_buffer) < rlen * 2 * fh->channels) { if ((status = fh->file_interface->file_read(fh, fh->pre_buffer_data, &rlen)) == SWITCH_STATUS_BREAK) { return SWITCH_STATUS_BREAK; } @@ -296,16 +302,16 @@ SWITCH_DECLARE(switch_status_t) switch_core_file_read(switch_file_handle_t *fh, switch_set_flag(fh, SWITCH_FILE_BUFFER_DONE); } else { fh->samples_in += rlen; - if (fh->channels > 1 && !switch_test_flag(fh, SWITCH_FILE_NOMUX)) { - switch_mux_channels((int16_t *) fh->pre_buffer_data, rlen, fh->channels); + if (fh->real_channels != fh->channels && !switch_test_flag(fh, SWITCH_FILE_NOMUX)) { + switch_mux_channels((int16_t *) fh->pre_buffer_data, rlen, fh->real_channels, fh->channels); } - switch_buffer_write(fh->pre_buffer, fh->pre_buffer_data, asis ? rlen : rlen * 2); + switch_buffer_write(fh->pre_buffer, fh->pre_buffer_data, asis ? rlen : rlen * 2 * fh->channels); } } } - rlen = switch_buffer_read(fh->pre_buffer, data, asis ? *len : *len * 2); - *len = asis ? rlen : rlen / 2; + rlen = switch_buffer_read(fh->pre_buffer, data, asis ? *len : *len * 2 * fh->channels); + *len = asis ? rlen : rlen / 2 / fh->channels; if (*len == 0) { switch_set_flag(fh, SWITCH_FILE_DONE); @@ -327,23 +333,21 @@ SWITCH_DECLARE(switch_status_t) switch_core_file_read(switch_file_handle_t *fh, fh->samples_in += *len; - if (fh->channels > 1 && !switch_test_flag(fh, SWITCH_FILE_NOMUX)) { - switch_mux_channels((int16_t *) data, *len, fh->channels); + if (fh->real_channels != fh->channels && !switch_test_flag(fh, SWITCH_FILE_NOMUX)) { + switch_mux_channels((int16_t *) data, *len, fh->real_channels, fh->channels); } - } - if (!switch_test_flag(fh, SWITCH_FILE_NATIVE) && fh->native_rate != fh->samplerate) { if (!fh->resampler) { if (switch_resample_create(&fh->resampler, - fh->native_rate, fh->samplerate, (uint32_t) orig_len, SWITCH_RESAMPLE_QUALITY, 1) != SWITCH_STATUS_SUCCESS) { + fh->native_rate, fh->samplerate, (uint32_t) orig_len, SWITCH_RESAMPLE_QUALITY, fh->channels) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Unable to create resampler!\n"); return SWITCH_STATUS_GENERR; } } - switch_resample_process(fh->resampler, data, (uint32_t) * len); + switch_resample_process(fh->resampler, data, (uint32_t) *len); if (fh->resampler->to_len < want || fh->resampler->to_len > orig_len) { if (!fh->buffer) { @@ -351,24 +355,24 @@ SWITCH_DECLARE(switch_status_t) switch_core_file_read(switch_file_handle_t *fh, switch_buffer_create_dynamic(&fh->buffer, factor, factor, 0); switch_assert(fh->buffer); } - if (!fh->dbuf || fh->dbuflen < fh->resampler->to_len * 2) { + if (!fh->dbuf || fh->dbuflen < fh->resampler->to_len * 2 * fh->channels) { void *mem; - fh->dbuflen = fh->resampler->to_len * 2; + fh->dbuflen = fh->resampler->to_len * 2 * fh->channels; mem = realloc(fh->dbuf, fh->dbuflen); switch_assert(mem); fh->dbuf = mem; } - switch_assert(fh->resampler->to_len * 2 <= fh->dbuflen); - memcpy((int16_t *) fh->dbuf, fh->resampler->to, fh->resampler->to_len * 2); - switch_buffer_write(fh->buffer, fh->dbuf, fh->resampler->to_len * 2); + switch_assert(fh->resampler->to_len * 2 * fh->channels <= fh->dbuflen); + memcpy((int16_t *) fh->dbuf, fh->resampler->to, fh->resampler->to_len * 2 * fh->channels); + switch_buffer_write(fh->buffer, fh->dbuf, fh->resampler->to_len * 2 * fh->channels); - if (switch_buffer_inuse(fh->buffer) < want * 2) { + if (switch_buffer_inuse(fh->buffer) < want * 2 * fh->channels) { *len = want; goto more; } - *len = switch_buffer_read(fh->buffer, data, orig_len * 2) / 2; + *len = switch_buffer_read(fh->buffer, data, orig_len * 2 * fh->channels) / 2 / fh->channels; } else { - memcpy(data, fh->resampler->to, fh->resampler->to_len * 2); + memcpy(data, fh->resampler->to, fh->resampler->to_len * 2 * fh->channels); *len = fh->resampler->to_len; } @@ -415,7 +419,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_file_write(switch_file_handle_t *fh, switch_assert(mem); fh->dbuf = mem; } - switch_assert(fh->resampler->to_len * 2 <= fh->dbuflen); + switch_assert(fh->resampler->to_len * 2 *fh->channels <= fh->dbuflen); memcpy(fh->dbuf, fh->resampler->to, fh->resampler->to_len * 2 * fh->channels); data = fh->dbuf; } else { diff --git a/src/switch_core_io.c b/src/switch_core_io.c index eb294a6773..430993df1f 100644 --- a/src/switch_core_io.c +++ b/src/switch_core_io.c @@ -596,6 +596,15 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi status = SWITCH_STATUS_RESAMPLE; } + /* mux or demux to match */ + if (session->read_impl.number_of_channels != read_frame->codec->implementation->number_of_channels) { + uint32_t rlen = session->raw_read_frame.datalen / 2 / read_frame->codec->implementation->number_of_channels; + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "%s MUX READ\n", switch_channel_get_name(session->channel)); + switch_mux_channels((int16_t *) session->raw_read_frame.data, rlen, + read_frame->codec->implementation->number_of_channels, session->read_impl.number_of_channels); + session->raw_write_frame.datalen = rlen * 2 * session->read_impl.number_of_channels; + } + switch (status) { case SWITCH_STATUS_RESAMPLE: if (!session->read_resampler) { @@ -604,7 +613,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi status = switch_resample_create(&session->read_resampler, read_frame->codec->implementation->actual_samples_per_second, session->read_impl.actual_samples_per_second, - session->read_impl.decoded_bytes_per_packet, SWITCH_RESAMPLE_QUALITY, 1); + session->read_impl.decoded_bytes_per_packet, SWITCH_RESAMPLE_QUALITY, + session->read_impl.number_of_channels); switch_mutex_unlock(session->resample_mutex); @@ -807,10 +817,10 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi if (session->read_resampler) { short *data = read_frame->data; switch_mutex_lock(session->resample_mutex); - switch_resample_process(session->read_resampler, data, (int) read_frame->datalen / 2); - memcpy(data, session->read_resampler->to, session->read_resampler->to_len * 2); + switch_resample_process(session->read_resampler, data, (int) read_frame->datalen / 2 / session->read_resampler->channels); + memcpy(data, session->read_resampler->to, session->read_resampler->to_len * 2 * session->read_resampler->channels); read_frame->samples = session->read_resampler->to_len; - read_frame->datalen = session->read_resampler->to_len * 2; + read_frame->datalen = session->read_resampler->to_len * 2 * session->read_resampler->channels; read_frame->rate = session->read_resampler->to_rate; switch_mutex_unlock(session->resample_mutex); } @@ -1206,6 +1216,14 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_frame(switch_core_sess status = SWITCH_STATUS_RESAMPLE; } + /* mux or demux to match */ + if (session->write_impl.number_of_channels != frame->codec->implementation->number_of_channels) { + uint32_t rlen = session->raw_write_frame.datalen / 2 / frame->codec->implementation->number_of_channels; + switch_mux_channels((int16_t *) session->raw_write_frame.data, rlen, + frame->codec->implementation->number_of_channels, session->write_impl.number_of_channels); + session->raw_write_frame.datalen = rlen * 2 * session->write_impl.number_of_channels; + } + switch (status) { case SWITCH_STATUS_RESAMPLE: resample++; @@ -1216,7 +1234,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_frame(switch_core_sess status = switch_resample_create(&session->write_resampler, frame->codec->implementation->actual_samples_per_second, session->write_impl.actual_samples_per_second, - session->write_impl.decoded_bytes_per_packet, SWITCH_RESAMPLE_QUALITY, 1); + session->write_impl.decoded_bytes_per_packet, SWITCH_RESAMPLE_QUALITY, session->write_impl.number_of_channels); switch_mutex_unlock(session->resample_mutex); @@ -1294,13 +1312,13 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_frame(switch_core_sess switch_mutex_lock(session->resample_mutex); if (session->write_resampler) { - switch_resample_process(session->write_resampler, data, write_frame->datalen / 2); + switch_resample_process(session->write_resampler, data, write_frame->datalen / 2 / session->write_resampler->channels); - memcpy(data, session->write_resampler->to, session->write_resampler->to_len * 2); + memcpy(data, session->write_resampler->to, session->write_resampler->to_len * 2 * session->write_resampler->channels); write_frame->samples = session->write_resampler->to_len; - write_frame->datalen = write_frame->samples * 2; + write_frame->datalen = write_frame->samples * 2 * session->write_resampler->channels; write_frame->rate = session->write_resampler->to_rate; @@ -1527,7 +1545,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_frame(switch_core_sess status = switch_resample_create(&session->write_resampler, frame->codec->implementation->actual_samples_per_second, session->write_impl.actual_samples_per_second, - session->write_impl.decoded_bytes_per_packet, SWITCH_RESAMPLE_QUALITY, 1); + session->write_impl.decoded_bytes_per_packet, SWITCH_RESAMPLE_QUALITY, + session->write_impl.number_of_channels); } switch_mutex_unlock(session->resample_mutex); @@ -1598,10 +1617,10 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_frame(switch_core_sess short *data = write_frame->data; switch_mutex_lock(session->resample_mutex); if (session->read_resampler) { - switch_resample_process(session->read_resampler, data, write_frame->datalen / 2); - memcpy(data, session->read_resampler->to, session->read_resampler->to_len * 2); + switch_resample_process(session->read_resampler, data, write_frame->datalen / 2 / session->read_resampler->channels); + memcpy(data, session->read_resampler->to, session->read_resampler->to_len * 2 * session->read_resampler->channels); write_frame->samples = session->read_resampler->to_len; - write_frame->datalen = session->read_resampler->to_len * 2; + write_frame->datalen = session->read_resampler->to_len * 2 * session->read_resampler->channels; write_frame->rate = session->read_resampler->to_rate; } switch_mutex_unlock(session->resample_mutex); diff --git a/src/switch_core_speech.c b/src/switch_core_speech.c index 82cc3c75c2..95403dbf42 100644 --- a/src/switch_core_speech.c +++ b/src/switch_core_speech.c @@ -39,7 +39,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_speech_open(switch_speech_handle_t *sh, const char *module_name, const char *voice_name, - unsigned int rate, unsigned int interval, switch_speech_flag_t *flags, switch_memory_pool_t *pool) + unsigned int rate, unsigned int interval, unsigned int channels, + switch_speech_flag_t *flags, switch_memory_pool_t *pool) { switch_status_t status; char buf[256] = ""; @@ -83,8 +84,10 @@ SWITCH_DECLARE(switch_status_t) switch_core_speech_open(switch_speech_handle_t * sh->samples = switch_samples_per_packet(rate, interval); sh->samplerate = rate; sh->native_rate = rate; + sh->channels = channels; + sh->real_channels = 1; - if ((status = sh->speech_interface->speech_open(sh, voice_name, rate, flags)) == SWITCH_STATUS_SUCCESS) { + if ((status = sh->speech_interface->speech_open(sh, voice_name, rate, channels, flags)) == SWITCH_STATUS_SUCCESS) { switch_set_flag(sh, SWITCH_SPEECH_FLAG_OPEN); } else { UNPROTECT_INTERFACE(sh->speech_interface); @@ -205,7 +208,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_speech_read_tts(switch_speech_handle if (sh->buffer && (switch_buffer_inuse(sh->buffer) >= orig_len || switch_test_flag(sh, SWITCH_SPEECH_FLAG_DONE))) { if ((*datalen = switch_buffer_read(sh->buffer, data, orig_len))) { - return SWITCH_STATUS_SUCCESS; + status = SWITCH_STATUS_SUCCESS; + goto done; } } @@ -217,16 +221,17 @@ SWITCH_DECLARE(switch_status_t) switch_core_speech_read_tts(switch_speech_handle more: + *datalen = orig_len / sh->channels; + if ((status = sh->speech_interface->speech_read_tts(sh, data, datalen, flags)) != SWITCH_STATUS_SUCCESS) { switch_set_flag(sh, SWITCH_SPEECH_FLAG_DONE); goto top; } - if (sh->native_rate && sh->samplerate && sh->native_rate != sh->samplerate) { if (!sh->resampler) { if (switch_resample_create(&sh->resampler, - sh->native_rate, sh->samplerate, (uint32_t) orig_len, SWITCH_RESAMPLE_QUALITY, 1) != SWITCH_STATUS_SUCCESS) { + sh->native_rate, sh->samplerate, (uint32_t) orig_len / sh->channels, SWITCH_RESAMPLE_QUALITY, 1) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Unable to create resampler!\n"); return SWITCH_STATUS_GENERR; } @@ -261,6 +266,15 @@ SWITCH_DECLARE(switch_status_t) switch_core_speech_read_tts(switch_speech_handle } } + + done: + + if (sh->channels != sh->real_channels) { + uint32_t rlen = *datalen / 2; + switch_mux_channels((int16_t *) data, rlen, 1, sh->channels); + *datalen = rlen * 2 * sh->channels; + } + return status; } diff --git a/src/switch_ivr_async.c b/src/switch_ivr_async.c index 9a69776380..00a933efcd 100644 --- a/src/switch_ivr_async.c +++ b/src/switch_ivr_async.c @@ -767,7 +767,7 @@ static switch_bool_t write_displace_callback(switch_media_bug_t *bug, void *user st = switch_core_file_read(&dh->fh, buf, &len); - for (x = 0; x < (uint32_t) len; x++) { + for (x = 0; x < (uint32_t) len * dh->fh.channels; x++) { int32_t mixed = fp[x] + buf[x]; switch_normalize_to_16bit(mixed); fp[x] = (int16_t) mixed; @@ -779,6 +779,9 @@ static switch_bool_t write_displace_callback(switch_media_bug_t *bug, void *user } } + rframe->datalen = rframe->samples * 2 * dh->fh.channels; + + if (st != SWITCH_STATUS_SUCCESS || len == 0) { if (dh->loop) { uint32_t pos = 0; @@ -848,17 +851,20 @@ static switch_bool_t read_displace_callback(switch_media_bug_t *bug, void *user_ st = switch_core_file_read(&dh->fh, buf, &len); - for (x = 0; x < (uint32_t) len; x++) { + for (x = 0; x < (uint32_t) len * dh->fh.channels; x++) { int32_t mixed = fp[x] + buf[x]; switch_normalize_to_16bit(mixed); fp[x] = (int16_t) mixed; } + } else { st = switch_core_file_read(&dh->fh, rframe->data, &len); rframe->samples = (uint32_t) len; - rframe->datalen = rframe->samples * 2; } + rframe->datalen = rframe->samples * 2 * dh->fh.channels; + + if (st != SWITCH_STATUS_SUCCESS || len == 0) { if (dh->loop) { uint32_t pos = 0; diff --git a/src/switch_ivr_play_say.c b/src/switch_ivr_play_say.c index b07aee0ef0..9ac573d5dd 100644 --- a/src/switch_ivr_play_say.c +++ b/src/switch_ivr_play_say.c @@ -737,13 +737,13 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_file(switch_core_session_t *se if (!switch_test_flag(fh, SWITCH_FILE_PAUSE) && !switch_test_flag(read_frame, SFF_CNG)) { int16_t *data = read_frame->data; - len = (switch_size_t) asis ? read_frame->datalen : read_frame->datalen / 2; + len = (switch_size_t) asis ? read_frame->datalen : read_frame->datalen / 2 / fh->channels; if (switch_core_file_write(fh, data, &len) != SWITCH_STATUS_SUCCESS) { break; } } else if (switch_test_flag(read_frame, SFF_CNG) && fill_cng) { - len = write_frame.datalen / 2; + len = write_frame.datalen / 2 / fh->channels; if (switch_core_file_write(fh, write_frame.data, &len) != SWITCH_STATUS_SUCCESS) { break; } @@ -1301,14 +1301,17 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess codec_name, NULL, fh->samplerate, - interval, 1, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, pool) == SWITCH_STATUS_SUCCESS) { + interval, read_impl.number_of_channels, + SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, pool) == SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), - SWITCH_LOG_DEBUG, "Codec Activated %s@%uhz %u channels %dms\n", codec_name, fh->samplerate, fh->channels, interval); + SWITCH_LOG_DEBUG, "Codec Activated %s@%uhz %u channels %dms\n", + codec_name, fh->samplerate, read_impl.number_of_channels, interval); } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, - "Raw Codec Activation Failed %s@%uhz %u channels %dms\n", codec_name, fh->samplerate, fh->channels, interval); + "Raw Codec Activation Failed %s@%uhz %u channels %dms\n", codec_name, + fh->samplerate, read_impl.number_of_channels, interval); switch_core_session_io_write_lock(session); switch_channel_set_private(channel, "__fh", NULL); switch_core_session_io_rwunlock(session); @@ -1339,7 +1342,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess uint32_t len; len = samples * 2; - if (switch_core_timer_init(&timer, timer_name, interval, samples, pool) != SWITCH_STATUS_SUCCESS) { + if (switch_core_timer_init(&timer, timer_name, interval, samples / codec.implementation->number_of_channels, pool) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Setup timer failed!\n"); switch_core_codec_destroy(&codec); switch_core_session_io_write_lock(session); @@ -1351,7 +1354,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess continue; } switch_core_timer_sync(&timer); // Sync timer - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Setup timer success %u bytes per %d ms!\n", len, interval); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, + "Setup timer success %u bytes per %d ms! %d ch\n", len, interval, codec.implementation->number_of_channels); } write_frame.rate = fh->samplerate; @@ -1445,7 +1449,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess } } - buflen = FILE_STARTSAMPLES * sizeof(*abuf) * fh->cur_channels; + buflen = FILE_STARTSAMPLES * sizeof(*abuf) * fh->cur_channels ? fh->cur_channels : fh->channels; if (buflen > write_frame.buflen) { abuf = realloc(abuf, buflen); @@ -1502,10 +1506,11 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess olen /= 2; } switch_set_flag(fh, SWITCH_FILE_BREAK_ON_CHANGE); + if ((rstatus = switch_core_file_read(fh, abuf, &olen)) == SWITCH_STATUS_BREAK) { continue; } - + if (rstatus != SWITCH_STATUS_SUCCESS) { eof++; continue; @@ -1528,7 +1533,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess last_native = test_native; - switch_buffer_write(fh->audio_buffer, abuf, switch_test_flag(fh, SWITCH_FILE_NATIVE) ? olen : olen * 2); + switch_buffer_write(fh->audio_buffer, abuf, switch_test_flag(fh, SWITCH_FILE_NATIVE) ? olen : olen * 2 * fh->channels); olen = switch_buffer_read(fh->audio_buffer, abuf, framelen); fh->offset_pos += (uint32_t)(olen / 2); @@ -2142,14 +2147,12 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_speak_text_handle(switch_core_session switch_codec_t *codec, switch_timer_t *timer, char *text, switch_input_args_t *args) { switch_channel_t *channel = switch_core_session_get_channel(session); - short abuf[960]; + short abuf[SWITCH_RECOMMENDED_BUFFER_SIZE]; switch_dtmf_t dtmf = { 0 }; uint32_t len = 0; switch_size_t ilen = 0; switch_frame_t write_frame = { 0 }; - int x; int done = 0; - int lead_in_out = 10; switch_status_t status = SWITCH_STATUS_SUCCESS; switch_speech_flag_t flags = SWITCH_SPEECH_FLAG_NONE; switch_size_t extra = 0; @@ -2174,7 +2177,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_speak_text_handle(switch_core_session write_frame.data = abuf; write_frame.buflen = sizeof(abuf); - len = sh->samples * 2; + len = sh->samples * 2 * sh->channels; flags = 0; @@ -2227,7 +2230,6 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_speak_text_handle(switch_core_session text = NULL; write_frame.rate = sh->rate; - memset(write_frame.data, 0, len); write_frame.datalen = len; write_frame.samples = len / 2; @@ -2235,23 +2237,14 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_speak_text_handle(switch_core_session switch_assert(codec->implementation != NULL); - for (x = 0; !done && x < lead_in_out; x++) { - switch_yield(codec->implementation->microseconds_per_packet); - if (timer) { - write_frame.timestamp = timer->samplecount; - } - if (switch_core_session_write_frame(session, &write_frame, SWITCH_IO_FLAG_NONE, 0) != SWITCH_STATUS_SUCCESS) { - done = 1; - break; - } - } - switch_channel_audio_sync(channel); - ilen = len; + for (;;) { switch_event_t *event; + ilen = len; + if (!switch_channel_ready(channel)) { status = SWITCH_STATUS_FALSE; break; @@ -2348,23 +2341,11 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_speak_text_handle(switch_core_session continue; } + flags = SWITCH_SPEECH_FLAG_BLOCKING; status = switch_core_speech_read_tts(sh, abuf, &ilen, &flags); if (status != SWITCH_STATUS_SUCCESS) { - write_frame.datalen = (uint32_t) codec->implementation->decoded_bytes_per_packet; - write_frame.samples = (uint32_t) (write_frame.datalen / 2); - memset(write_frame.data, 0, write_frame.datalen); - for (x = 0; !done && x < lead_in_out; x++) { - switch_yield(codec->implementation->microseconds_per_packet); - if (timer) { - write_frame.timestamp = timer->samplecount; - } - if (switch_core_session_write_frame(session, &write_frame, SWITCH_IO_FLAG_NONE, 0) != SWITCH_STATUS_SUCCESS) { - done = 1; - break; - } - } if (status == SWITCH_STATUS_BREAK) { status = SWITCH_STATUS_SUCCESS; } @@ -2376,7 +2357,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_speak_text_handle(switch_core_session } write_frame.datalen = (uint32_t) ilen; - write_frame.samples = (uint32_t) (ilen / 2); + write_frame.samples = (uint32_t) (ilen / 2 / sh->channels); if (timer) { write_frame.timestamp = timer->samplecount; } @@ -2466,6 +2447,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_speak_text(switch_core_session_t *ses switch_channel_t *channel = switch_core_session_get_channel(session); uint32_t rate = 0; int interval = 0; + uint32_t channels; switch_frame_t write_frame = { 0 }; switch_timer_t ltimer, *timer; switch_codec_t lcodec, *codec; @@ -2519,10 +2501,11 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_speak_text(switch_core_session_t *ses rate = read_impl.actual_samples_per_second; interval = read_impl.microseconds_per_packet / 1000; + channels = read_impl.number_of_channels; if (need_create) { memset(sh, 0, sizeof(*sh)); - if ((status = switch_core_speech_open(sh, tts_name, voice_name, (uint32_t) rate, interval, &flags, NULL)) != SWITCH_STATUS_SUCCESS) { + if ((status = switch_core_speech_open(sh, tts_name, voice_name, (uint32_t) rate, interval, read_impl.number_of_channels, &flags, NULL)) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Invalid TTS module!\n"); switch_core_session_reset(session, SWITCH_TRUE, SWITCH_TRUE); switch_ivr_clear_speech_cache(session); @@ -2543,11 +2526,11 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_speak_text(switch_core_session_t *ses switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "OPEN TTS %s\n", tts_name); codec_name = "L16"; - + if (need_create) { if (switch_core_codec_init(codec, codec_name, - NULL, (int) rate, interval, 1, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, + NULL, (int) rate, interval, channels, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, pool) == SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Raw Codec Activated\n"); } else { diff --git a/src/switch_pcm.c b/src/switch_pcm.c index 36ee0e7796..d62e5f7337 100644 --- a/src/switch_pcm.c +++ b/src/switch_pcm.c @@ -364,6 +364,25 @@ SWITCH_MODULE_LOAD_FUNCTION(core_pcm_load) switch_proxy_decode, /* function to decode encoded data into raw data */ switch_proxy_destroy); /* deinitalize a codec handle using this implementation */ + SWITCH_ADD_CODEC(codec_interface, "PROXY PASS-THROUGH"); + switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */ + 0, /* the IANA code number */ + "PROXY", /* the IANA code name */ + NULL, /* default fmtp to send (can be overridden by the init function) */ + 8000, /* samples transferred per second */ + 8000, /* actual samples transferred per second */ + 0, /* bits transferred per second */ + 20000, /* number of microseconds per frame */ + 160, /* number of samples per frame */ + 320 * 2, /* number of bytes per frame decompressed */ + 320 * 2, /* number of bytes per frame compressed */ + 2, /* number of channels represented */ + 1, /* number of frames per network packet */ + switch_proxy_init, /* function to initialize a codec handle using this implementation */ + switch_proxy_encode, /* function to encode raw data into encoded data */ + switch_proxy_decode, /* function to decode encoded data into raw data */ + switch_proxy_destroy); /* deinitalize a codec handle using this implementation */ + SWITCH_ADD_CODEC(codec_interface, "RAW Signed Linear (16 bit)"); for (counta = 1; counta <= 3; counta++) { @@ -377,6 +396,11 @@ SWITCH_MODULE_LOAD_FUNCTION(core_pcm_load) SWITCH_CODEC_TYPE_AUDIO, 70, "L16", NULL, rate, rate, bps, mpf * countb, spf * countb, bpf * countb, ebpf * countb, 1, spf * countb, switch_raw_init, switch_raw_encode, switch_raw_decode, switch_raw_destroy); + + switch_core_codec_add_implementation(pool, codec_interface, + SWITCH_CODEC_TYPE_AUDIO, 70, "L16", NULL, rate, rate, bps, + mpf * countb, spf * countb, bpf * countb * 2, ebpf * countb, 2, spf * countb, + switch_raw_init, switch_raw_encode, switch_raw_decode, switch_raw_destroy); } rate = rate * 2; bps = bps * 2; @@ -408,6 +432,24 @@ SWITCH_MODULE_LOAD_FUNCTION(core_pcm_load) switch_raw_decode, /* function to decode encoded data into raw data */ switch_raw_destroy); /* deinitalize a codec handle using this implementation */ + switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */ + 70, /* the IANA code number */ + "L16", /* the IANA code name */ + NULL, /* default fmtp to send (can be overridden by the init function) */ + 12000, /* samples transferred per second */ + 12000, /* actual samples transferred per second */ + 192000 * 2, /* bits transferred per second */ + ms_per_frame, /* number of microseconds per frame */ + samples_per_frame, /* number of samples per frame */ + bytes_per_frame * 2, /* number of bytes per frame decompressed */ + bytes_per_frame * 2, /* number of bytes per frame compressed */ + 2, /* number of channels represented */ + 1, /* number of frames per network packet */ + switch_raw_init, /* function to initialize a codec handle using this implementation */ + switch_raw_encode, /* function to encode raw data into encoded data */ + switch_raw_decode, /* function to decode encoded data into raw data */ + switch_raw_destroy); /* deinitalize a codec handle using this implementation */ + samples_per_frame += 240; bytes_per_frame += 480; ms_per_frame += 20000; @@ -437,6 +479,24 @@ SWITCH_MODULE_LOAD_FUNCTION(core_pcm_load) switch_raw_decode, /* function to decode encoded data into raw data */ switch_raw_destroy); /* deinitalize a codec handle using this implementation */ + switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */ + 70, /* the IANA code number */ + "L16", /* the IANA code name */ + NULL, /* default fmtp to send (can be overridden by the init function) */ + 24000, /* samples transferred per second */ + 24000, /* actual samples transferred per second */ + 384000 * 2, /* bits transferred per second */ + ms_per_frame, /* number of microseconds per frame */ + samples_per_frame, /* number of samples per frame */ + bytes_per_frame * 2, /* number of bytes per frame decompressed */ + bytes_per_frame * 2, /* number of bytes per frame compressed */ + 2, /* number of channels represented */ + 1, /* number of frames per network packet */ + switch_raw_init, /* function to initialize a codec handle using this implementation */ + switch_raw_encode, /* function to encode raw data into encoded data */ + switch_raw_decode, /* function to decode encoded data into raw data */ + switch_raw_destroy); /* deinitalize a codec handle using this implementation */ + samples_per_frame += 480; bytes_per_frame += 960; ms_per_frame += 20000; @@ -468,6 +528,24 @@ SWITCH_MODULE_LOAD_FUNCTION(core_pcm_load) switch_raw_decode, /* function to decode encoded data into raw data */ switch_raw_destroy); /* deinitalize a codec handle using this implementation */ + switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */ + 70, /* the IANA code number */ + "L16", /* the IANA code name */ + NULL, /* default fmtp to send (can be overridden by the init function) */ + 48000, /* samples transferred per second */ + 48000, /* actual samples transferred per second */ + 768000 * 2, /* bits transferred per second */ + ms_per_frame, /* number of microseconds per frame */ + samples_per_frame * 2, /* number of samples per frame */ + bytes_per_frame * 2, /* number of bytes per frame decompressed */ + bytes_per_frame * 2, /* number of bytes per frame compressed */ + 2, /* number of channels represented */ + 1, /* number of frames per network packet */ + switch_raw_init, /* function to initialize a codec handle using this implementation */ + switch_raw_encode, /* function to encode raw data into encoded data */ + switch_raw_decode, /* function to decode encoded data into raw data */ + switch_raw_destroy); /* deinitalize a codec handle using this implementation */ + samples_per_frame += 96; bytes_per_frame += 192; ms_per_frame += 2000; @@ -498,6 +576,24 @@ SWITCH_MODULE_LOAD_FUNCTION(core_pcm_load) switch_raw_decode, /* function to decode encoded data into raw data */ switch_raw_destroy); /* deinitalize a codec handle using this implementation */ + switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */ + 70, /* the IANA code number */ + "L16", /* the IANA code name */ + NULL, /* default fmtp to send (can be overridden by the init function) */ + 8000, /* samples transferred per second */ + 8000, /* actual samples transferred per second */ + 128000 * 2, /* bits transferred per second */ + ms_per_frame, /* number of microseconds per frame */ + samples_per_frame, /* number of samples per frame */ + bytes_per_frame * 2, /* number of bytes per frame decompressed */ + bytes_per_frame * 2, /* number of bytes per frame compressed */ + 2, /* number of channels represented */ + 1, /* number of frames per network packet */ + switch_raw_init, /* function to initialize a codec handle using this implementation */ + switch_raw_encode, /* function to encode raw data into encoded data */ + switch_raw_decode, /* function to decode encoded data into raw data */ + switch_raw_destroy); /* deinitalize a codec handle using this implementation */ + samples_per_frame += 16; bytes_per_frame += 32; ms_per_frame += 2000; @@ -527,6 +623,24 @@ SWITCH_MODULE_LOAD_FUNCTION(core_pcm_load) switch_raw_decode, /* function to decode encoded data into raw data */ switch_raw_destroy); /* deinitalize a codec handle using this implementation */ + switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */ + 70, /* the IANA code number */ + "L16", /* the IANA code name */ + NULL, /* default fmtp to send (can be overridden by the init function) */ + 16000, /* samples transferred per second */ + 16000, /* actual samples transferred per second */ + 256000 * 2, /* bits transferred per second */ + ms_per_frame, /* number of microseconds per frame */ + samples_per_frame, /* number of samples per frame */ + bytes_per_frame * 2, /* number of bytes per frame decompressed */ + bytes_per_frame * 2, /* number of bytes per frame compressed */ + 2, /* number of channels represented */ + 1, /* number of frames per network packet */ + switch_raw_init, /* function to initialize a codec handle using this implementation */ + switch_raw_encode, /* function to encode raw data into encoded data */ + switch_raw_decode, /* function to decode encoded data into raw data */ + switch_raw_destroy); /* deinitalize a codec handle using this implementation */ + samples_per_frame += 32; bytes_per_frame += 64; ms_per_frame += 2000; @@ -557,6 +671,24 @@ SWITCH_MODULE_LOAD_FUNCTION(core_pcm_load) switch_raw_decode, /* function to decode encoded data into raw data */ switch_raw_destroy); /* deinitalize a codec handle using this implementation */ + switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */ + 70, /* the IANA code number */ + "L16", /* the IANA code name */ + NULL, /* default fmtp to send (can be overridden by the init function) */ + 32000, /* samples transferred per second */ + 32000, /* actual samples transferred per second */ + 512000 * 2, /* bits transferred per second */ + ms_per_frame, /* number of microseconds per frame */ + samples_per_frame, /* number of samples per frame */ + bytes_per_frame * 2, /* number of bytes per frame decompressed */ + bytes_per_frame * 2, /* number of bytes per frame compressed */ + 2, /* number of channels represented */ + 1, /* number of frames per network packet */ + switch_raw_init, /* function to initialize a codec handle using this implementation */ + switch_raw_encode, /* function to encode raw data into encoded data */ + switch_raw_decode, /* function to decode encoded data into raw data */ + switch_raw_destroy); /* deinitalize a codec handle using this implementation */ + samples_per_frame += 64; bytes_per_frame += 128; ms_per_frame += 2000; @@ -585,6 +717,25 @@ SWITCH_MODULE_LOAD_FUNCTION(core_pcm_load) switch_raw_encode, /* function to encode raw data into encoded data */ switch_raw_decode, /* function to decode encoded data into raw data */ switch_raw_destroy); /* deinitalize a codec handle using this implementation */ + + switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */ + 70, /* the IANA code number */ + "L16", /* the IANA code name */ + NULL, /* default fmtp to send (can be overridden by the init function) */ + 48000, /* samples transferred per second */ + 48000, /* actual samples transferred per second */ + 768000 * 2, /* bits transferred per second */ + ms_per_frame, /* number of microseconds per frame */ + samples_per_frame * 2, /* number of samples per frame */ + bytes_per_frame * 2, /* number of bytes per frame decompressed */ + bytes_per_frame * 2, /* number of bytes per frame compressed */ + 2, /* number of channels represented */ + 1, /* number of frames per network packet */ + switch_raw_init, /* function to initialize a codec handle using this implementation */ + switch_raw_encode, /* function to encode raw data into encoded data */ + switch_raw_decode, /* function to decode encoded data into raw data */ + switch_raw_destroy); /* deinitalize a codec handle using this implementation */ + samples_per_frame += 480; bytes_per_frame += 960; ms_per_frame += 10000; @@ -608,6 +759,24 @@ SWITCH_MODULE_LOAD_FUNCTION(core_pcm_load) switch_raw_decode, /* function to decode encoded data into raw data */ switch_raw_destroy); /* deinitalize a codec handle using this implementation */ + switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */ + 70, /* the IANA code number */ + "L16", /* the IANA code name */ + NULL, /* default fmtp to send (can be overridden by the init function) */ + 22050, /* samples transferred per second */ + 22050, /* actual samples transferred per second */ + 352800 * 2, /* bits transferred per second */ + 20000, /* number of microseconds per frame */ + 441, /* number of samples per frame */ + 882 * 2, /* number of bytes per frame decompressed */ + 882 * 2, /* number of bytes per frame compressed */ + 2, /* number of channels represented */ + 1, /* number of frames per network packet */ + switch_raw_init, /* function to initialize a codec handle using this implementation */ + switch_raw_encode, /* function to encode raw data into encoded data */ + switch_raw_decode, /* function to decode encoded data into raw data */ + switch_raw_destroy); /* deinitalize a codec handle using this implementation */ + switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */ 70, /* the IANA code number */ "L16", /* the IANA code name */ @@ -626,6 +795,24 @@ SWITCH_MODULE_LOAD_FUNCTION(core_pcm_load) switch_raw_decode, /* function to decode encoded data into raw data */ switch_raw_destroy); /* deinitalize a codec handle using this implementation */ + switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */ + 70, /* the IANA code number */ + "L16", /* the IANA code name */ + NULL, /* default fmtp to send (can be overridden by the init function) */ + 11025, /* samples transferred per second */ + 11025, /* actual samples transferred per second */ + 176400 * 2, /* bits transferred per second */ + 40000, /* number of microseconds per frame */ + 441, /* number of samples per frame */ + 882 * 2, /* number of bytes per frame decompressed */ + 882 * 2, /* number of bytes per frame compressed */ + 2, /* number of channels represented */ + 1, /* number of frames per network packet */ + switch_raw_init, /* function to initialize a codec handle using this implementation */ + switch_raw_encode, /* function to encode raw data into encoded data */ + switch_raw_decode, /* function to decode encoded data into raw data */ + switch_raw_destroy); /* deinitalize a codec handle using this implementation */ + switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */ 70, /* the IANA code number */ @@ -645,7 +832,23 @@ SWITCH_MODULE_LOAD_FUNCTION(core_pcm_load) switch_raw_decode, /* function to decode encoded data into raw data */ switch_raw_destroy); /* deinitalize a codec handle using this implementation */ - + switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */ + 70, /* the IANA code number */ + "L16", /* the IANA code name */ + NULL, /* default fmtp to send (can be overridden by the init function) */ + 11025, /* samples transferred per second */ + 11025, /* actual samples transferred per second */ + 176400 * 2, /* bits transferred per second */ + 32000, /* number of microseconds per frame */ + 256, /* number of samples per frame */ + 512 * 2, /* number of bytes per frame decompressed */ + 512 * 2, /* number of bytes per frame compressed */ + 2, /* number of channels represented */ + 1, /* number of frames per network packet */ + switch_raw_init, /* function to initialize a codec handle using this implementation */ + switch_raw_encode, /* function to encode raw data into encoded data */ + switch_raw_decode, /* function to decode encoded data into raw data */ + switch_raw_destroy); /* deinitalize a codec handle using this implementation */ /* indicate that the module should continue to be loaded */ diff --git a/src/switch_resample.c b/src/switch_resample.c index 2363ace9c8..a0b7249763 100644 --- a/src/switch_resample.c +++ b/src/switch_resample.c @@ -78,7 +78,8 @@ SWITCH_DECLARE(switch_status_t) switch_resample_perform_create(switch_audio_resa resampler->factor = (lto_rate / lfrom_rate); resampler->rfactor = (lfrom_rate / lto_rate); resampler->to_size = resample_buffer(to_rate, from_rate, (uint32_t) to_size); - resampler->to = malloc(resampler->to_size * sizeof(int16_t)); + resampler->to = malloc(resampler->to_size * sizeof(int16_t) * channels); + resampler->channels = channels; return SWITCH_STATUS_SUCCESS; } @@ -271,18 +272,55 @@ SWITCH_DECLARE(uint32_t) switch_unmerge_sln(int16_t *data, uint32_t samples, int return x; } -SWITCH_DECLARE(void) switch_mux_channels(int16_t *data, switch_size_t samples, uint32_t channels) +SWITCH_DECLARE(void) switch_mux_channels(int16_t *data, switch_size_t samples, uint32_t orig_channels, uint32_t channels) { switch_size_t i = 0; uint32_t j = 0; - for (i = 0; i < samples; i++) { - int32_t z = 0; - for (j = 0; j < channels; j++) { - z += data[i * channels + j]; - switch_normalize_to_16bit(z); - data[i] = (int16_t) z; + switch_assert(channels < 11); + + if (orig_channels > channels) { + for (i = 0; i < samples; i++) { + int32_t z = 0; + for (j = 0; j < orig_channels; j++) { + z += data[i * orig_channels + j]; + switch_normalize_to_16bit(z); + data[i] = (int16_t) z; + } } + } else if (orig_channels < channels) { + + /* interesting problem... take a give buffer and double up every sample in the buffer without using any other buffer..... + This way beats the other i think bacause there is no malloc but I do have to copy the data twice */ +#if 1 + uint32_t k = 0, len = samples * orig_channels; + + for (i = 0; i < len; i++) { + data[i+len] = data[i]; + } + + for (i = 0; i < samples; i++) { + for (j = 0; j < channels; j++) { + data[k++] = data[i + samples]; + } + } + +#else + uint32_t k = 0, len = samples * 2 * orig_channels; + int16_t *orig = NULL; + + switch_zmalloc(orig, len); + memcpy(orig, data, len); + + for (i = 0; i < samples; i++) { + for (j = 0; j < channels; j++) { + data[k++] = orig[i]; + } + } + + free(orig); +#endif + } } From 97cc0898269f801c68e2c83870119428626f9284 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Thu, 12 Jun 2014 13:12:39 -0400 Subject: [PATCH 028/231] fix compile errs --- src/mod/applications/mod_conference/mod_conference.c | 2 +- src/mod/asr_tts/mod_tts_commandline/mod_tts_commandline.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mod/applications/mod_conference/mod_conference.c b/src/mod/applications/mod_conference/mod_conference.c index f04581736d..1ab7d2fa62 100644 --- a/src/mod/applications/mod_conference/mod_conference.c +++ b/src/mod/applications/mod_conference/mod_conference.c @@ -9086,7 +9086,7 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_c switch_codec_implementation_t read_impl = { 0 }; switch_channel_t *channel = NULL; const char *force_rate = NULL, *force_interval = NULL, *force_channels = NULL, *presence_id = NULL; - uint32_t force_rate_i = 0, force_interval_i = 0, force_channels_i = NULL; + uint32_t force_rate_i = 0, force_interval_i = 0, force_channels_i = 0; /* Validate the conference name */ if (zstr(name)) { diff --git a/src/mod/asr_tts/mod_tts_commandline/mod_tts_commandline.c b/src/mod/asr_tts/mod_tts_commandline/mod_tts_commandline.c index 6ff5bada84..9264f0ec22 100644 --- a/src/mod/asr_tts/mod_tts_commandline/mod_tts_commandline.c +++ b/src/mod/asr_tts/mod_tts_commandline/mod_tts_commandline.c @@ -91,7 +91,7 @@ static void event_handler(switch_event_t *event) } } -static switch_status_t tts_commandline_speech_open(switch_speech_handle_t *sh, const char *voice_name, int rate, switch_speech_flag_t *flags) +static switch_status_t tts_commandline_speech_open(switch_speech_handle_t *sh, const char *voice_name, int rate, int channels, switch_speech_flag_t *flags) { switch_uuid_t uuid; char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1]; From ab5278c02fdc8519f2cd5c297a0d2ea78f9041dc Mon Sep 17 00:00:00 2001 From: Chris Rienzo Date: Thu, 12 Jun 2014 17:41:52 -0400 Subject: [PATCH 029/231] stereo: fix mod_flite, mod_ssml, mod_unimrcp compile errors --- src/mod/asr_tts/mod_flite/mod_flite.c | 2 +- src/mod/asr_tts/mod_unimrcp/mod_unimrcp.c | 5 +++-- src/mod/formats/mod_ssml/mod_ssml.c | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/mod/asr_tts/mod_flite/mod_flite.c b/src/mod/asr_tts/mod_flite/mod_flite.c index c9cb69f6f6..b21b86b841 100644 --- a/src/mod/asr_tts/mod_flite/mod_flite.c +++ b/src/mod/asr_tts/mod_flite/mod_flite.c @@ -72,7 +72,7 @@ typedef struct flite_data flite_t; #define free_wave(w) if (w) {delete_wave(w) ; w = NULL; } #define FLITE_BLOCK_SIZE 1024 * 32 -static switch_status_t flite_speech_open(switch_speech_handle_t *sh, const char *voice_name, int rate, switch_speech_flag_t *flags) +static switch_status_t flite_speech_open(switch_speech_handle_t *sh, const char *voice_name, int rate, int channels, switch_speech_flag_t *flags) { flite_t *flite = switch_core_alloc(sh->memory_pool, sizeof(*flite)); diff --git a/src/mod/asr_tts/mod_unimrcp/mod_unimrcp.c b/src/mod/asr_tts/mod_unimrcp/mod_unimrcp.c index b0c4d98150..db50ef3056 100644 --- a/src/mod/asr_tts/mod_unimrcp/mod_unimrcp.c +++ b/src/mod/asr_tts/mod_unimrcp/mod_unimrcp.c @@ -378,7 +378,7 @@ static switch_status_t synth_load(switch_loadable_module_interface_t *module_int static switch_status_t synth_shutdown(); /* synthesizer's interface for FreeSWITCH */ -static switch_status_t synth_speech_open(switch_speech_handle_t *sh, const char *voice_name, int rate, switch_speech_flag_t *flags); +static switch_status_t synth_speech_open(switch_speech_handle_t *sh, const char *voice_name, int rate, int channels, switch_speech_flag_t *flags); static switch_status_t synth_speech_close(switch_speech_handle_t *sh, switch_speech_flag_t *flags); static switch_status_t synth_speech_feed_tts(switch_speech_handle_t *sh, char *text, switch_speech_flag_t *flags); static switch_status_t synth_speech_read_tts(switch_speech_handle_t *sh, void *data, switch_size_t *datalen, switch_speech_flag_t *flags); @@ -1571,10 +1571,11 @@ static switch_status_t speech_channel_set_state_unlocked(speech_channel_t *schan * @param sh the FreeSWITCH speech handle * @param voice_name the voice to use * @param rate the sampling rate requested + * @param channels the number of channels requested * @param flags other options * @return SWITCH_STATUS_SUCCESS if successful, otherwise SWITCH_STATUS_FALSE */ -static switch_status_t synth_speech_open(switch_speech_handle_t *sh, const char *voice_name, int rate, switch_speech_flag_t *flags) +static switch_status_t synth_speech_open(switch_speech_handle_t *sh, const char *voice_name, int rate, int channels, switch_speech_flag_t *flags) { switch_status_t status = SWITCH_STATUS_SUCCESS; speech_channel_t *schannel = NULL; diff --git a/src/mod/formats/mod_ssml/mod_ssml.c b/src/mod/formats/mod_ssml/mod_ssml.c index be0857c482..f99b50c1a3 100644 --- a/src/mod/formats/mod_ssml/mod_ssml.c +++ b/src/mod/formats/mod_ssml/mod_ssml.c @@ -938,7 +938,7 @@ static switch_status_t tts_file_open(switch_file_handle_t *handle, const char *p memset(context, 0, sizeof(*context)); context->flags = SWITCH_SPEECH_FLAG_NONE; - if ((status = switch_core_speech_open(&context->sh, module, voice, handle->samplerate, handle->interval, &context->flags, NULL)) == SWITCH_STATUS_SUCCESS) { + if ((status = switch_core_speech_open(&context->sh, module, voice, handle->samplerate, handle->interval, handle->channels, &context->flags, NULL)) == SWITCH_STATUS_SUCCESS) { if ((status = switch_core_speech_feed_tts(&context->sh, document, &context->flags)) == SWITCH_STATUS_SUCCESS) { handle->channels = 1; handle->samples = 0; From 09ae3a9841f1832b46f932a51cce4e3316e4ad2b Mon Sep 17 00:00:00 2001 From: Michael Jerris Date: Thu, 12 Jun 2014 17:34:02 -0500 Subject: [PATCH 030/231] don't require more libs than we really need when linking embedded perl modules --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 294f6b469d..c6ff69b3ae 100644 --- a/configure.ac +++ b/configure.ac @@ -1238,7 +1238,7 @@ if test "x$ac_cv_have_perl" != "xno" ; then PERL_LIBDIR="-L`$PERL -MConfig -e 'print $Config{archlib}'`/CORE" PERL_LIBS="`$PERL -MConfig -e 'print $Config{libs}'`" PERL_CFLAGS="-w -DMULTIPLICITY `$PERL -MExtUtils::Embed -e ccopts` -DEMBED_PERL" - PERL_LDFLAGS="`$PERL -MExtUtils::Embed -e ldopts` `$PERL -MConfig -e 'print $Config{libs}'`" + PERL_LDFLAGS="`$PERL -MExtUtils::Embed -e ldopts`" PERL_INC="`$PERL -MExtUtils::Embed -e perl_inc`" AC_SUBST(PERL_SITEDIR) AC_SUBST(PERL_LIBDIR) From 579a05186731136cec591669ca0a881e87f3b12b Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Fri, 13 Jun 2014 04:49:37 +0500 Subject: [PATCH 031/231] add channels param the the silence generator function --- src/include/switch_resample.h | 2 +- .../mod_conference/mod_conference.c | 2 +- src/mod/applications/mod_random/mod_random.c | 2 +- .../formats/mod_tone_stream/mod_tone_stream.c | 2 +- src/switch_ivr.c | 9 +++-- src/switch_ivr_async.c | 6 ++- src/switch_ivr_bridge.c | 3 +- src/switch_ivr_originate.c | 5 ++- src/switch_ivr_play_say.c | 9 ++--- src/switch_resample.c | 40 +++++-------------- 10 files changed, 34 insertions(+), 46 deletions(-) diff --git a/src/include/switch_resample.h b/src/include/switch_resample.h index 355510f575..1d2f6c694b 100644 --- a/src/include/switch_resample.h +++ b/src/include/switch_resample.h @@ -152,7 +152,7 @@ SWITCH_DECLARE(void) switch_swap_linear(int16_t *buf, int len); \param samples the number of 2 byte samples \param divisor the volume factor */ -SWITCH_DECLARE(void) switch_generate_sln_silence(int16_t *data, uint32_t samples, uint32_t divisor); +SWITCH_DECLARE(void) switch_generate_sln_silence(int16_t *data, uint32_t samples, uint32_t channels, uint32_t divisor); /*! \brief Change the volume of a signed linear audio frame diff --git a/src/mod/applications/mod_conference/mod_conference.c b/src/mod/applications/mod_conference/mod_conference.c index 1ab7d2fa62..728ea17462 100644 --- a/src/mod/applications/mod_conference/mod_conference.c +++ b/src/mod/applications/mod_conference/mod_conference.c @@ -4425,7 +4425,7 @@ static void conference_loop_output(conference_member_t *member) } else { if (member->conference->comfort_noise_level) { - switch_generate_sln_silence(write_frame.data, samples, member->conference->comfort_noise_level); + switch_generate_sln_silence(write_frame.data, samples, member->conference->channels, member->conference->comfort_noise_level); } else { memset(write_frame.data, 255, bytes); } diff --git a/src/mod/applications/mod_random/mod_random.c b/src/mod/applications/mod_random/mod_random.c index c4ffa25af0..e14aaac875 100644 --- a/src/mod/applications/mod_random/mod_random.c +++ b/src/mod/applications/mod_random/mod_random.c @@ -199,7 +199,7 @@ SWITCH_MODULE_RUNTIME_FUNCTION(mod_random_runtime) int i = 0; int len = sizeof(data) / 2; - switch_generate_sln_silence(data, len, 1); + switch_generate_sln_silence(data, len, 1, 1); random_add_entropy(rfd, data, len); while(i < len && !data[i]) i++; diff --git a/src/mod/formats/mod_tone_stream/mod_tone_stream.c b/src/mod/formats/mod_tone_stream/mod_tone_stream.c index 06a5de98c2..ffc970adee 100644 --- a/src/mod/formats/mod_tone_stream/mod_tone_stream.c +++ b/src/mod/formats/mod_tone_stream/mod_tone_stream.c @@ -94,7 +94,7 @@ static switch_status_t silence_stream_file_read(switch_file_handle_t *handle, vo sh->samples -= (int32_t)*len; } - switch_generate_sln_silence((int16_t *) data, (uint32_t)*len, + switch_generate_sln_silence((int16_t *) data, (uint32_t)*len, handle->channels, sh->silence ? sh->silence : (uint32_t)-1); return SWITCH_STATUS_SUCCESS; diff --git a/src/switch_ivr.c b/src/switch_ivr.c index ef4707b561..d53d3e6a72 100644 --- a/src/switch_ivr.c +++ b/src/switch_ivr.c @@ -142,6 +142,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_sleep(switch_core_session_t *session, arg_recursion_check_start(args); + switch_core_session_get_read_impl(session, &imp); + /* if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND && !switch_channel_test_flag(channel, CF_PROXY_MODE) && !switch_channel_media_ready(channel) && !switch_channel_test_flag(channel, CF_SERVICE)) { @@ -171,7 +173,6 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_sleep(switch_core_session_t *session, } if (ms > 10 && sval) { - switch_core_session_get_read_impl(session, &imp); if (switch_core_codec_init(&codec, "L16", @@ -299,7 +300,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_sleep(switch_core_session_t *session, } if (sval && write_frame.datalen) { - switch_generate_sln_silence((int16_t *) write_frame.data, write_frame.samples, sval); + switch_generate_sln_silence((int16_t *) write_frame.data, write_frame.samples, imp.number_of_channels, sval); switch_core_session_write_frame(session, &write_frame, SWITCH_IO_FLAG_NONE, 0); } else { switch_core_session_write_frame(session, &cng_frame, SWITCH_IO_FLAG_NONE, 0); @@ -992,7 +993,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_park(switch_core_session_t *session, } if (rate && write_frame.data && sval) { - switch_generate_sln_silence((int16_t *) write_frame.data, write_frame.samples, sval); + switch_generate_sln_silence((int16_t *) write_frame.data, write_frame.samples, read_impl.number_of_channels, sval); switch_core_session_write_frame(session, &write_frame, SWITCH_IO_FLAG_NONE, 0); } @@ -1409,7 +1410,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_collect_digits_count(switch_core_sess } if (write_frame.data) { - switch_generate_sln_silence((int16_t *) write_frame.data, write_frame.samples, sval); + switch_generate_sln_silence((int16_t *) write_frame.data, write_frame.samples, imp.number_of_channels, sval); switch_core_session_write_frame(session, &write_frame, SWITCH_IO_FLAG_NONE, 0); } diff --git a/src/switch_ivr_async.c b/src/switch_ivr_async.c index 00a933efcd..95b167af27 100644 --- a/src/switch_ivr_async.c +++ b/src/switch_ivr_async.c @@ -2531,6 +2531,10 @@ static switch_bool_t session_audio_callback(switch_media_bug_t *bug, void *user_ switch_session_audio_t *pvt = (switch_session_audio_t *) user_data; switch_frame_t *frame = NULL; int level = 0, mute = 0; + switch_core_session_t *session = switch_core_media_bug_get_session(bug); + switch_codec_implementation_t read_impl = { 0 }; + + switch_core_session_get_read_impl(session, &read_impl); if (type == SWITCH_ABC_TYPE_READ_REPLACE || type == SWITCH_ABC_TYPE_WRITE_REPLACE) { @@ -2553,7 +2557,7 @@ static switch_bool_t session_audio_callback(switch_media_bug_t *bug, void *user_ if (frame) { if (mute) { if (mute > 1) { - switch_generate_sln_silence(frame->data, frame->datalen / 2, mute); + switch_generate_sln_silence(frame->data, frame->datalen / 2, read_impl.number_of_channels, mute); } else { memset(frame->data, 0, frame->datalen); } diff --git a/src/switch_ivr_bridge.c b/src/switch_ivr_bridge.c index ff9db1e2b6..b2f1d56375 100644 --- a/src/switch_ivr_bridge.c +++ b/src/switch_ivr_bridge.c @@ -562,7 +562,8 @@ static void *audio_bridge_thread(switch_thread_t *thread, void *obj) read_frame_count++; if (switch_test_flag(read_frame, SFF_CNG)) { if (silence_val) { - switch_generate_sln_silence((int16_t *) silence_frame.data, silence_frame.samples, silence_val); + switch_generate_sln_silence((int16_t *) silence_frame.data, silence_frame.samples, + read_frame->codec->implementation->number_of_channels, silence_val); read_frame = &silence_frame; } else if (!switch_channel_test_flag(chan_b, CF_ACCEPT_CNG)) { continue; diff --git a/src/switch_ivr_originate.c b/src/switch_ivr_originate.c index 317647efff..7a16363069 100644 --- a/src/switch_ivr_originate.c +++ b/src/switch_ivr_originate.c @@ -1084,7 +1084,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_wait_for_answer(switch_core_session_t } } else if (ringback.silence) { write_frame.datalen = write_frame.codec->implementation->decoded_bytes_per_packet; - switch_generate_sln_silence((int16_t *) write_frame.data, write_frame.datalen / 2, ringback.silence); + switch_generate_sln_silence((int16_t *) write_frame.data, write_frame.datalen / 2, + write_frame.codec->implementation->number_of_channels, ringback.silence); } if ((ringback.fh || ringback.silence || ringback.audio_buffer) && write_frame.codec && write_frame.datalen) { @@ -3213,7 +3214,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess if ((ringback.fh || silence || ringback.audio_buffer || oglobals.bridge_early_media > -1) && write_frame.codec && write_frame.datalen) { if (silence) { write_frame.datalen = read_impl.decoded_bytes_per_packet; - switch_generate_sln_silence((int16_t *) write_frame.data, write_frame.datalen / 2, silence); + switch_generate_sln_silence((int16_t *) write_frame.data, write_frame.datalen / 2, write_frame.codec->implementation->number_of_channels, silence); } if (switch_core_session_write_frame(oglobals.session, &write_frame, SWITCH_IO_FLAG_NONE, 0) != SWITCH_STATUS_SUCCESS) { diff --git a/src/switch_ivr_play_say.c b/src/switch_ivr_play_say.c index 9ac573d5dd..ec1f66f125 100644 --- a/src/switch_ivr_play_say.c +++ b/src/switch_ivr_play_say.c @@ -713,9 +713,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_file(switch_core_session_t *se double energy = 0; - for (count = 0; count < samples; count++) { - energy += abs(fdata[j]); - j += read_impl.number_of_channels; + for (count = 0; count < samples * read_impl.number_of_channels; count++) { + energy += abs(fdata[j++]); } score = (uint32_t) (energy / (samples / divisor)); @@ -730,9 +729,9 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_file(switch_core_session_t *se } if (fill_cng) { - switch_generate_sln_silence((int16_t *) write_frame.data, write_frame.samples, fill_cng); + switch_generate_sln_silence((int16_t *) write_frame.data, write_frame.samples, read_impl.number_of_channels, fill_cng); } else if (waste_resources) { - switch_generate_sln_silence((int16_t *) write_frame.data, write_frame.samples, waste_resources); + switch_generate_sln_silence((int16_t *) write_frame.data, write_frame.samples, read_impl.number_of_channels, waste_resources); } if (!switch_test_flag(fh, SWITCH_FILE_PAUSE) && !switch_test_flag(read_frame, SFF_CNG)) { diff --git a/src/switch_resample.c b/src/switch_resample.c index a0b7249763..fa229a68cf 100644 --- a/src/switch_resample.c +++ b/src/switch_resample.c @@ -181,14 +181,16 @@ SWITCH_DECLARE(void) switch_swap_linear(int16_t *buf, int len) } } -#if 1 -SWITCH_DECLARE(void) switch_generate_sln_silence(int16_t *data, uint32_t samples, uint32_t divisor) + +SWITCH_DECLARE(void) switch_generate_sln_silence(int16_t *data, uint32_t samples, uint32_t channels, uint32_t divisor) { - int16_t x; - uint32_t i; + int16_t s; + uint32_t x, i, j; int sum_rnd = 0; int16_t rnd2 = (int16_t) switch_micro_time_now() + (int16_t) (intptr_t) data; + if (channels == 0) channels = 1; + assert(divisor); if (divisor == (uint32_t)-1) { @@ -201,38 +203,18 @@ SWITCH_DECLARE(void) switch_generate_sln_silence(int16_t *data, uint32_t samples rnd2 = rnd2 * 31821U + 13849U; sum_rnd += rnd2; } - //switch_normalize_to_16bit(sum_rnd); - *data = (int16_t) ((int16_t) sum_rnd / (int) divisor); - data++; - } -} -#else + s = (int16_t) ((int16_t) sum_rnd / (int) divisor); -SWITCH_DECLARE(void) switch_generate_sln_silence(int16_t *data, uint32_t samples, uint32_t divisor) -{ - int16_t rnd = 0, rnd2, x; - uint32_t i; - int sum_rnd = 0; - - assert(divisor); - - rnd2 = (int16_t) (intptr_t) (&data + switch_epoch_time_now(NULL)); - - for (i = 0; i < samples; i++, sum_rnd = 0) { - for (x = 0; x < 10; x++) { - rnd = rnd + (int16_t) ((x + i) * rnd2); - sum_rnd += rnd; + for (j = 0; j < channels; j++) { + *data = s; + data++; } - switch_normalize_to_16bit(sum_rnd); - *data = (int16_t) ((int16_t) sum_rnd / (int) divisor); - data++; + } } -#endif - SWITCH_DECLARE(uint32_t) switch_merge_sln(int16_t *data, uint32_t samples, int16_t *other_data, uint32_t other_samples) { int i; From 7642d846a9be0d5090232056d225735466631cd3 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Fri, 13 Jun 2014 05:13:43 +0500 Subject: [PATCH 032/231] some more channels updates --- src/switch_ivr_originate.c | 4 ++-- src/switch_ivr_play_say.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/switch_ivr_originate.c b/src/switch_ivr_originate.c index 7a16363069..dd38b94af7 100644 --- a/src/switch_ivr_originate.c +++ b/src/switch_ivr_originate.c @@ -1075,7 +1075,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_wait_for_answer(switch_core_session_t break; } } - write_frame.datalen = (uint32_t) (ringback.asis ? olen : olen * 2); + write_frame.datalen = (uint32_t) (ringback.asis ? olen : olen * 2 * ringback.fh.channels); } else if (ringback.audio_buffer) { if ((write_frame.datalen = (uint32_t) switch_buffer_read_loop(ringback.audio_buffer, write_frame.data, @@ -3188,7 +3188,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess break; } } - write_frame.datalen = (uint32_t) (ringback.asis ? olen : olen * 2); + write_frame.datalen = (uint32_t) (ringback.asis ? olen : olen * 2 ( ringback.fh.channels); write_frame.samples = (uint32_t) olen; } else if (ringback.audio_buffer) { diff --git a/src/switch_ivr_play_say.c b/src/switch_ivr_play_say.c index ec1f66f125..148b6ed3eb 100644 --- a/src/switch_ivr_play_say.c +++ b/src/switch_ivr_play_say.c @@ -1861,7 +1861,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_wait_for_silence(switch_core_session_ } write_frame.samples = (uint32_t) olen; - write_frame.datalen = (uint32_t) (olen * sizeof(int16_t)); + write_frame.datalen = (uint32_t) (olen * sizeof(int16_t) * fh.channels); if ((status = switch_core_session_write_frame(session, &write_frame, SWITCH_IO_FLAG_NONE, 0)) != SWITCH_STATUS_SUCCESS) { break; } From ed7264b6d364424b27ca06f534f1aeff0b3e5fc3 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Fri, 13 Jun 2014 05:28:14 +0500 Subject: [PATCH 033/231] doh --- src/switch_ivr_originate.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/switch_ivr_originate.c b/src/switch_ivr_originate.c index dd38b94af7..10130dc224 100644 --- a/src/switch_ivr_originate.c +++ b/src/switch_ivr_originate.c @@ -1075,7 +1075,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_wait_for_answer(switch_core_session_t break; } } - write_frame.datalen = (uint32_t) (ringback.asis ? olen : olen * 2 * ringback.fh.channels); + write_frame.datalen = (uint32_t) (ringback.asis ? olen : olen * 2 * ringback.fh->channels); } else if (ringback.audio_buffer) { if ((write_frame.datalen = (uint32_t) switch_buffer_read_loop(ringback.audio_buffer, write_frame.data, @@ -3188,7 +3188,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess break; } } - write_frame.datalen = (uint32_t) (ringback.asis ? olen : olen * 2 ( ringback.fh.channels); + write_frame.datalen = (uint32_t) (ringback.asis ? olen : olen * 2 * ringback.fh->channels); write_frame.samples = (uint32_t) olen; } else if (ringback.audio_buffer) { From 0f62c4cd624a396b1a183d2e1d61279b50d49265 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Fri, 13 Jun 2014 05:46:40 +0500 Subject: [PATCH 034/231] FS-6440 --resolve --- src/switch_core_session.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/switch_core_session.c b/src/switch_core_session.c index 61c8ac54e2..6df3632cb3 100644 --- a/src/switch_core_session.c +++ b/src/switch_core_session.c @@ -1827,10 +1827,17 @@ static void *SWITCH_THREAD_FUNC switch_core_session_thread_pool_manager(switch_t while(session_manager.ready) { int check = 1; + int ttl = 0; - switch_mutex_lock(session_manager.cond2_mutex); - switch_thread_cond_timedwait(session_manager.cond, session_manager.cond_mutex, sleep); - switch_mutex_unlock(session_manager.cond2_mutex); + switch_mutex_lock(session_manager.mutex); + ttl = switch_queue_size(session_manager.thread_queue); + switch_mutex_unlock(session_manager.mutex); + + if (!ttl) { + switch_mutex_lock(session_manager.cond2_mutex); + switch_thread_cond_timedwait(session_manager.cond, session_manager.cond_mutex, sleep); + switch_mutex_unlock(session_manager.cond2_mutex); + } if (switch_micro_time_now() >= next) { if (session_manager.popping) { From bb6869b7ab670f049e71cb19986d404ad242ce48 Mon Sep 17 00:00:00 2001 From: Chris Rienzo Date: Thu, 12 Jun 2014 22:55:26 -0400 Subject: [PATCH 035/231] FS-6535 --resolve mod_rayo: allow multiple grammars (including dtmf) when using unimrcp --- src/include/switch_ivr.h | 2 +- .../mod_rayo/rayo_input_component.c | 228 ++++++++++++------ src/switch_ivr_async.c | 2 +- 3 files changed, 155 insertions(+), 77 deletions(-) diff --git a/src/include/switch_ivr.h b/src/include/switch_ivr.h index 01c82f4f31..f8e18b3d92 100644 --- a/src/include/switch_ivr.h +++ b/src/include/switch_ivr.h @@ -238,7 +238,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_resume_detect_speech(switch_core_sess \param name the grammar name \return SWITCH_STATUS_SUCCESS if all is well */ -SWITCH_DECLARE(switch_status_t) switch_ivr_detect_speech_load_grammar(switch_core_session_t *session, char *grammar, char *name); +SWITCH_DECLARE(switch_status_t) switch_ivr_detect_speech_load_grammar(switch_core_session_t *session, const char *grammar, const char *name); /*! \brief Unload a grammar on a background speech detection handle diff --git a/src/mod/event_handlers/mod_rayo/rayo_input_component.c b/src/mod/event_handlers/mod_rayo/rayo_input_component.c index a9412ee2b6..b4549b454f 100644 --- a/src/mod/event_handlers/mod_rayo/rayo_input_component.c +++ b/src/mod/event_handlers/mod_rayo/rayo_input_component.c @@ -413,14 +413,141 @@ static int validate_call_input(iks *input, const char **error) return 1; } +static char *setup_grammars_pocketsphinx(struct input_component *component, switch_core_session_t *session, iks *input, const struct xmpp_error **stanza_error, const char **error_detail) +{ + const char *jsgf_path; + switch_stream_handle_t grammar = { 0 }; + SWITCH_STANDARD_STREAM(grammar); + + /* transform SRGS grammar to JSGF */ + if (!(component->grammar = srgs_parse(globals.parser, iks_find_cdata(input, "grammar")))) { + *stanza_error = STANZA_ERROR_BAD_REQUEST; + *error_detail = "Failed to parse grammar body"; + return NULL; + } + + jsgf_path = srgs_grammar_to_jsgf_file(component->grammar, SWITCH_GLOBAL_dirs.grammar_dir, "gram"); + if (!jsgf_path) { + *stanza_error = STANZA_ERROR_BAD_REQUEST; + *error_detail = "Grammar conversion to JSGF error"; + return NULL; + } + + /* build pocketsphinx grammar string */ + grammar.write_function(&grammar, + "{start-input-timers=%s,no-input-timeout=%d,speech-timeout=%d,confidence-threshold=%d}%s", + component->start_timers ? "true" : "false", + component->initial_timeout, + component->max_silence, + (int)ceil(component->min_confidence * 100.0), + jsgf_path); + + return (char *)grammar.data; +} + +static char *setup_grammars_unimrcp(struct input_component *component, switch_core_session_t *session, iks *input, const struct xmpp_error **stanza_error, const char **error_detail) +{ + iks *grammar_tag; + switch_stream_handle_t grammar_uri_list = { 0 }; + SWITCH_STANDARD_STREAM(grammar_uri_list); + + /* unlock handler mutex, otherwise deadlock will happen when switch_ivr_detect_speech_init adds a new media bug */ + switch_mutex_unlock(component->handler->mutex); + if (switch_ivr_detect_speech_init(session, component->recognizer, "", NULL) != SWITCH_STATUS_SUCCESS) { + switch_mutex_lock(component->handler->mutex); + *stanza_error = STANZA_ERROR_INTERNAL_SERVER_ERROR; + *error_detail = "Failed to initialize recognizer"; + return NULL; + } + switch_mutex_lock(component->handler->mutex); + + /* load unimrcp grammars and return uri-list */ + grammar_uri_list.write_function(&grammar_uri_list, "{start-recognize=true,start-input-timers=%s,confidence-threshold=%f,sensitivity-level=%f", + component->start_timers ? "true" : "false", + component->min_confidence, + component->sensitivity); + if (component->initial_timeout > 0) { + grammar_uri_list.write_function(&grammar_uri_list, ",no-input-timeout=%d", + component->initial_timeout); + } + + if (component->max_silence > 0) { + grammar_uri_list.write_function(&grammar_uri_list, ",speech-complete-timeout=%d,speech-incomplete-timeout=%d", + component->max_silence, + component->max_silence); + } + + if (!zstr(component->language)) { + grammar_uri_list.write_function(&grammar_uri_list, ",speech-language=%s", component->language); + } + + if (!strcmp(iks_find_attrib_soft(input, "mode"), "any") || !strcmp(iks_find_attrib_soft(input, "mode"), "dtmf")) { + /* set dtmf params */ + if (component->inter_digit_timeout > 0) { + grammar_uri_list.write_function(&grammar_uri_list, ",dtmf-interdigit-timeout=%d", component->inter_digit_timeout); + } + if (component->term_digit) { + grammar_uri_list.write_function(&grammar_uri_list, ",dtmf-term-char=%c", component->term_digit); + } + } + grammar_uri_list.write_function(&grammar_uri_list, "}"); + + for (grammar_tag = iks_find(input, "grammar"); grammar_tag; grammar_tag = iks_next_tag(grammar_tag)) { + const char *grammar_name; + iks *grammar_cdata; + const char *grammar; + + /* is this a grammar? */ + if (strcmp("grammar", iks_name(grammar_tag))) { + continue; + } + + /* get the srgs contained in this grammar */ + if (!(grammar_cdata = iks_child(grammar_tag)) || iks_type(grammar_cdata) != IKS_CDATA) { + *stanza_error = STANZA_ERROR_BAD_REQUEST; + *error_detail = "Missing grammar"; + switch_safe_free(grammar_uri_list.data); + return NULL; + } + + /* load the grammar */ + grammar = switch_core_sprintf(RAYO_POOL(component), "{start-recognize=false}inline:%s", iks_cdata(grammar_cdata)); + grammar_name = switch_core_sprintf(RAYO_POOL(component), "grammar-%d", rayo_actor_seq_next(RAYO_ACTOR(component))); + /* unlock handler mutex, otherwise deadlock will happen if switch_ivr_detect_speech_load_grammar removes the media bug */ + switch_mutex_unlock(component->handler->mutex); + if (switch_ivr_detect_speech_load_grammar(session, grammar, grammar_name) != SWITCH_STATUS_SUCCESS) { + switch_mutex_lock(component->handler->mutex); + *stanza_error = STANZA_ERROR_INTERNAL_SERVER_ERROR; + *error_detail = "Failed to load grammar"; + switch_safe_free(grammar_uri_list.data); + return NULL; + } + switch_mutex_lock(component->handler->mutex); + + /* add grammar to uri-list */ + grammar_uri_list.write_function(&grammar_uri_list, "session:%s\r\n", grammar_name); + } + + return (char *)grammar_uri_list.data; +} + +static char *setup_grammars_unknown(struct input_component *component, switch_core_session_t *session, iks *input, const struct xmpp_error **stanza_error, const char **error_detail) +{ + switch_stream_handle_t grammar = { 0 }; + SWITCH_STANDARD_STREAM(grammar); + grammar.write_function(&grammar, "%s", iks_find_cdata(input, "grammar")); + return (char *)grammar.data; +} + /** * Start call input on voice resource */ -static iks *start_call_voice_input(struct input_component *component, switch_core_session_t *session, iks *input, iks *iq, const char *output_file, int barge_in) +static iks *start_call_voice_input(struct input_component *component, switch_core_session_t *session, iks *input, iks *iq, int barge_in) { struct input_handler *handler = component->handler; - switch_stream_handle_t grammar = { 0 }; - SWITCH_STANDARD_STREAM(grammar); + char *grammar = NULL; + const struct xmpp_error *stanza_error = NULL; + const char *error_detail = NULL; if (component->speech_mode && handler->voice_component) { /* don't allow multi voice input */ @@ -441,72 +568,23 @@ static iks *start_call_voice_input(struct input_component *component, switch_cor RAYO_UNLOCK(component); RAYO_DESTROY(component); return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "Must use the same recognizer for the entire call"); + } else if (zstr(handler->last_recognizer)) { + handler->last_recognizer = switch_core_session_strdup(session, component->recognizer); } - handler->last_recognizer = switch_core_session_strdup(session, component->recognizer); if (!strcmp(component->recognizer, "pocketsphinx")) { - const char *jsgf_path; - - /* transform SRGS grammar to JSGF */ - if (!(component->grammar = srgs_parse(globals.parser, iks_find_cdata(input, "grammar")))) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Failed to parse grammar body\n"); - handler->voice_component = NULL; - RAYO_UNLOCK(component); - RAYO_DESTROY(component); - return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "Failed to parse grammar body"); - } - jsgf_path = srgs_grammar_to_jsgf_file(component->grammar, SWITCH_GLOBAL_dirs.grammar_dir, "gram"); - if (!jsgf_path) { - handler->voice_component = NULL; - RAYO_UNLOCK(component); - RAYO_DESTROY(component); - return iks_new_error_detailed(iq, STANZA_ERROR_INTERNAL_SERVER_ERROR, "Grammar conversion to JSGF error"); - } - - /* build pocketsphinx grammar string */ - grammar.write_function(&grammar, - "{start-input-timers=%s,no-input-timeout=%d,speech-timeout=%d,confidence-threshold=%d}%s", - component->start_timers ? "true" : "false", - component->initial_timeout, - component->max_silence, - (int)ceil(component->min_confidence * 100.0), - jsgf_path); - } else if (!strncmp(component->recognizer, "unimrcp", strlen("unimrcp"))) { - /* send inline grammar to unimrcp */ - grammar.write_function(&grammar, "{start-input-timers=%s,confidence-threshold=%f,sensitivity-level=%f", - component->start_timers ? "true" : "false", - component->min_confidence, - component->sensitivity); - - if (component->initial_timeout > 0) { - grammar.write_function(&grammar, ",no-input-timeout=%d", - component->initial_timeout); - } - - if (component->max_silence > 0) { - grammar.write_function(&grammar, ",speech-complete-timeout=%d,speech-incomplete-timeout=%d", - component->max_silence, - component->max_silence); - } - - if (!zstr(component->language)) { - grammar.write_function(&grammar, ",speech-language=%s", component->language); - } - - if (!strcmp(iks_find_attrib_soft(input, "mode"), "any")) { - /* set dtmf params */ - if (component->inter_digit_timeout > 0) { - grammar.write_function(&grammar, ",dtmf-interdigit-timeout=%d", component->inter_digit_timeout); - } - if (component->term_digit) { - grammar.write_function(&grammar, ",dtmf-term-char=%c", component->term_digit); - } - } - - grammar.write_function(&grammar, "}inline:%s", iks_find_cdata(input, "grammar")); + grammar = setup_grammars_pocketsphinx(component, session, input, &stanza_error, &error_detail); + } else if (!strcmp(component->recognizer, "unimrcp")) { + grammar = setup_grammars_unimrcp(component, session, input, &stanza_error, &error_detail); } else { - /* passthrough to unknown ASR module */ - grammar.write_function(&grammar, "%s", iks_find_cdata(input, "grammar")); + grammar = setup_grammars_unknown(component, session, input, &stanza_error, &error_detail); + } + + if (!grammar) { + handler->voice_component = NULL; + RAYO_UNLOCK(component); + RAYO_DESTROY(component); + return iks_new_error_detailed(iq, stanza_error, error_detail); } /* acknowledge command */ @@ -514,15 +592,15 @@ static iks *start_call_voice_input(struct input_component *component, switch_cor /* start speech detection */ switch_channel_set_variable(switch_core_session_get_channel(session), "fire_asr_events", "true"); - switch_mutex_unlock(handler->mutex); /* unlock handler mutex, otherwise deadlock will happen when switch_ivr_detect_speech adds a new media bug */ - if (switch_ivr_detect_speech(session, component->recognizer, grammar.data, "mod_rayo_grammar", "", NULL) != SWITCH_STATUS_SUCCESS) { + /* unlock handler mutex, otherwise deadlock will happen if switch_ivr_detect_speech adds a media bug */ + switch_mutex_unlock(handler->mutex); + if (switch_ivr_detect_speech(session, component->recognizer, grammar, "mod_rayo_grammar", "", NULL) != SWITCH_STATUS_SUCCESS) { switch_mutex_lock(handler->mutex); handler->voice_component = NULL; rayo_component_send_complete(RAYO_COMPONENT(component), COMPONENT_COMPLETE_ERROR); - } else { - switch_mutex_lock(handler->mutex); } - switch_safe_free(grammar.data); + switch_mutex_lock(handler->mutex); + switch_safe_free(grammar); return NULL; } @@ -530,7 +608,7 @@ static iks *start_call_voice_input(struct input_component *component, switch_cor /** * Start call input on DTMF resource */ -static iks *start_call_dtmf_input(struct input_component *component, switch_core_session_t *session, iks *input, iks *iq, const char *output_file, int barge_in) +static iks *start_call_dtmf_input(struct input_component *component, switch_core_session_t *session, iks *input, iks *iq, int barge_in) { /* parse the grammar */ if (!(component->grammar = srgs_parse(globals.parser, iks_find_cdata(input, "grammar")))) { @@ -558,7 +636,7 @@ static iks *start_call_dtmf_input(struct input_component *component, switch_core * @param input the input request * @param iq the original input/prompt request */ -static iks *start_call_input(struct input_component *component, switch_core_session_t *session, iks *input, iks *iq, const char *output_file, int barge_in) +static iks *start_call_input(struct input_component *component, switch_core_session_t *session, iks *input, iks *iq, int barge_in) { iks *result = NULL; @@ -610,9 +688,9 @@ static iks *start_call_input(struct input_component *component, switch_core_sess component->speech_mode = strcmp(iks_find_attrib_soft(input, "mode"), "dtmf"); if (component->speech_mode) { - result = start_call_voice_input(component, session, input, iq, output_file, barge_in); + result = start_call_voice_input(component, session, input, iq, barge_in); } else { - result = start_call_dtmf_input(component, session, input, iq, output_file, barge_in); + result = start_call_dtmf_input(component, session, input, iq, barge_in); } switch_mutex_unlock(handler->mutex); @@ -671,7 +749,7 @@ static iks *start_call_input_component(struct rayo_actor *call, struct rayo_mess switch_core_destroy_memory_pool(&pool); return iks_new_error_detailed(iq, STANZA_ERROR_INTERNAL_SERVER_ERROR, "Failed to create input entity"); } - return start_call_input(input_component, session, input, iq, NULL, 0); + return start_call_input(input_component, session, input, iq, 0); } /** diff --git a/src/switch_ivr_async.c b/src/switch_ivr_async.c index 95b167af27..ea034e8e50 100644 --- a/src/switch_ivr_async.c +++ b/src/switch_ivr_async.c @@ -4042,7 +4042,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_resume_detect_speech(switch_core_sess return SWITCH_STATUS_FALSE; } -SWITCH_DECLARE(switch_status_t) switch_ivr_detect_speech_load_grammar(switch_core_session_t *session, char *grammar, char *name) +SWITCH_DECLARE(switch_status_t) switch_ivr_detect_speech_load_grammar(switch_core_session_t *session, const char *grammar, const char *name) { switch_channel_t *channel = switch_core_session_get_channel(session); struct speech_thread_handle *sth = switch_channel_get_private(channel, SWITCH_SPEECH_KEY); From c82ac3afbf0ab9377e2354ce9ed7abd47766c4f9 Mon Sep 17 00:00:00 2001 From: Chris Rienzo Date: Thu, 12 Jun 2014 23:24:35 -0400 Subject: [PATCH 036/231] FS-6535 mod_rayo: fix double lock on speech detection failure --- src/mod/event_handlers/mod_rayo/rayo_input_component.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mod/event_handlers/mod_rayo/rayo_input_component.c b/src/mod/event_handlers/mod_rayo/rayo_input_component.c index b4549b454f..cd9c092dbb 100644 --- a/src/mod/event_handlers/mod_rayo/rayo_input_component.c +++ b/src/mod/event_handlers/mod_rayo/rayo_input_component.c @@ -598,8 +598,9 @@ static iks *start_call_voice_input(struct input_component *component, switch_cor switch_mutex_lock(handler->mutex); handler->voice_component = NULL; rayo_component_send_complete(RAYO_COMPONENT(component), COMPONENT_COMPLETE_ERROR); + } else { + switch_mutex_lock(handler->mutex); } - switch_mutex_lock(handler->mutex); switch_safe_free(grammar); return NULL; From 56ef59e9ad410cdcaa25e4213b7e2521acf2ff27 Mon Sep 17 00:00:00 2001 From: Jeff Lenk Date: Thu, 12 Jun 2014 22:48:21 -0500 Subject: [PATCH 037/231] vs2010 reswig and fix mod_rss for recent stereo changes --- src/mod/applications/mod_rss/mod_rss.c | 5 +- .../mod_managed/freeswitch_wrap.2010.cxx | 218 ++++++++++++++++-- .../mod_managed/managed/swig.2010.cs | 174 ++++++++++++-- 3 files changed, 357 insertions(+), 40 deletions(-) diff --git a/src/mod/applications/mod_rss/mod_rss.c b/src/mod/applications/mod_rss/mod_rss.c index adb5cd4fd7..c17e0a53aa 100644 --- a/src/mod/applications/mod_rss/mod_rss.c +++ b/src/mod/applications/mod_rss/mod_rss.c @@ -185,7 +185,7 @@ SWITCH_STANDARD_APP(rss_function) const char *vcf = NULL; char *chanvars = switch_channel_build_param_string(channel, NULL, NULL); switch_codec_implementation_t read_impl = { 0 }; - uint32_t rate, interval; + uint32_t rate, interval, channels; switch_core_session_get_read_impl(session, &read_impl); interval = read_impl.microseconds_per_packet / 1000; @@ -257,13 +257,14 @@ SWITCH_STANDARD_APP(rss_function) if (switch_channel_media_ready(channel)) { rate = read_impl.actual_samples_per_second; + channels = read_impl.number_of_channels; } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Codec Error!\n"); return; } memset(&sh, 0, sizeof(sh)); - if (switch_core_speech_open(&sh, engine, voice, rate, interval, &flags, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) { + if (switch_core_speech_open(&sh, engine, voice, rate, interval, channels, &flags, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Invalid TTS module!\n"); return; } diff --git a/src/mod/languages/mod_managed/freeswitch_wrap.2010.cxx b/src/mod/languages/mod_managed/freeswitch_wrap.2010.cxx index 91dbe0900d..02cdabd75b 100644 --- a/src/mod/languages/mod_managed/freeswitch_wrap.2010.cxx +++ b/src/mod/languages/mod_managed/freeswitch_wrap.2010.cxx @@ -8044,6 +8044,72 @@ SWIGEXPORT unsigned long SWIGSTDCALL CSharp_switch_device_stats_t_held_out_get(v } +SWIGEXPORT void SWIGSTDCALL CSharp_switch_device_stats_t_unheld_set(void * jarg1, unsigned long jarg2) { + switch_device_stats_t *arg1 = (switch_device_stats_t *) 0 ; + uint32_t arg2 ; + + arg1 = (switch_device_stats_t *)jarg1; + arg2 = (uint32_t)jarg2; + if (arg1) (arg1)->unheld = arg2; +} + + +SWIGEXPORT unsigned long SWIGSTDCALL CSharp_switch_device_stats_t_unheld_get(void * jarg1) { + unsigned long jresult ; + switch_device_stats_t *arg1 = (switch_device_stats_t *) 0 ; + uint32_t result; + + arg1 = (switch_device_stats_t *)jarg1; + result = (uint32_t) ((arg1)->unheld); + jresult = (unsigned long)result; + return jresult; +} + + +SWIGEXPORT void SWIGSTDCALL CSharp_switch_device_stats_t_unheld_in_set(void * jarg1, unsigned long jarg2) { + switch_device_stats_t *arg1 = (switch_device_stats_t *) 0 ; + uint32_t arg2 ; + + arg1 = (switch_device_stats_t *)jarg1; + arg2 = (uint32_t)jarg2; + if (arg1) (arg1)->unheld_in = arg2; +} + + +SWIGEXPORT unsigned long SWIGSTDCALL CSharp_switch_device_stats_t_unheld_in_get(void * jarg1) { + unsigned long jresult ; + switch_device_stats_t *arg1 = (switch_device_stats_t *) 0 ; + uint32_t result; + + arg1 = (switch_device_stats_t *)jarg1; + result = (uint32_t) ((arg1)->unheld_in); + jresult = (unsigned long)result; + return jresult; +} + + +SWIGEXPORT void SWIGSTDCALL CSharp_switch_device_stats_t_unheld_out_set(void * jarg1, unsigned long jarg2) { + switch_device_stats_t *arg1 = (switch_device_stats_t *) 0 ; + uint32_t arg2 ; + + arg1 = (switch_device_stats_t *)jarg1; + arg2 = (uint32_t)jarg2; + if (arg1) (arg1)->unheld_out = arg2; +} + + +SWIGEXPORT unsigned long SWIGSTDCALL CSharp_switch_device_stats_t_unheld_out_get(void * jarg1) { + unsigned long jresult ; + switch_device_stats_t *arg1 = (switch_device_stats_t *) 0 ; + uint32_t result; + + arg1 = (switch_device_stats_t *)jarg1; + result = (uint32_t) ((arg1)->unheld_out); + jresult = (unsigned long)result; + return jresult; +} + + SWIGEXPORT void SWIGSTDCALL CSharp_switch_device_stats_t_hup_set(void * jarg1, unsigned long jarg2) { switch_device_stats_t *arg1 = (switch_device_stats_t *) 0 ; uint32_t arg2 ; @@ -11936,17 +12002,19 @@ SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_hash_destroy(void * jarg1) { } -SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_hash_insert(void * jarg1, char * jarg2, void * jarg3) { +SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_hash_insert_destructor(void * jarg1, char * jarg2, void * jarg3, void * jarg4) { int jresult ; switch_hash_t *arg1 = (switch_hash_t *) 0 ; char *arg2 = (char *) 0 ; void *arg3 = (void *) 0 ; + hashtable_destructor_t arg4 = (hashtable_destructor_t) 0 ; switch_status_t result; arg1 = (switch_hash_t *)jarg1; arg2 = (char *)jarg2; arg3 = (void *)jarg3; - result = (switch_status_t)switch_core_hash_insert(arg1,(char const *)arg2,(void const *)arg3); + arg4 = (hashtable_destructor_t)jarg4; + result = (switch_status_t)switch_core_hash_insert_destructor(arg1,(char const *)arg2,(void const *)arg3,arg4); jresult = result; return jresult; } @@ -12849,15 +12917,16 @@ SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_file_truncate(void * jarg1, long l } -SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_speech_open(void * jarg1, char * jarg2, char * jarg3, unsigned int jarg4, unsigned int jarg5, void * jarg6, void * jarg7) { +SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_speech_open(void * jarg1, char * jarg2, char * jarg3, unsigned int jarg4, unsigned int jarg5, unsigned int jarg6, void * jarg7, void * jarg8) { int jresult ; switch_speech_handle_t *arg1 = (switch_speech_handle_t *) 0 ; char *arg2 = (char *) 0 ; char *arg3 = (char *) 0 ; unsigned int arg4 ; unsigned int arg5 ; - switch_speech_flag_t *arg6 = (switch_speech_flag_t *) 0 ; - switch_memory_pool_t *arg7 = (switch_memory_pool_t *) 0 ; + unsigned int arg6 ; + switch_speech_flag_t *arg7 = (switch_speech_flag_t *) 0 ; + switch_memory_pool_t *arg8 = (switch_memory_pool_t *) 0 ; switch_status_t result; arg1 = (switch_speech_handle_t *)jarg1; @@ -12865,9 +12934,10 @@ SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_speech_open(void * jarg1, char * j arg3 = (char *)jarg3; arg4 = (unsigned int)jarg4; arg5 = (unsigned int)jarg5; - arg6 = (switch_speech_flag_t *)jarg6; - arg7 = (switch_memory_pool_t *)jarg7; - result = (switch_status_t)switch_core_speech_open(arg1,(char const *)arg2,(char const *)arg3,arg4,arg5,arg6,arg7); + arg6 = (unsigned int)jarg6; + arg7 = (switch_speech_flag_t *)jarg7; + arg8 = (switch_memory_pool_t *)jarg8; + result = (switch_status_t)switch_core_speech_open(arg1,(char const *)arg2,(char const *)arg3,arg4,arg5,arg6,arg7,arg8); jresult = result; return jresult; } @@ -22807,6 +22877,28 @@ SWIGEXPORT unsigned long SWIGSTDCALL CSharp_switch_file_handle_channels_get(void } +SWIGEXPORT void SWIGSTDCALL CSharp_switch_file_handle_real_channels_set(void * jarg1, unsigned long jarg2) { + switch_file_handle *arg1 = (switch_file_handle *) 0 ; + uint32_t arg2 ; + + arg1 = (switch_file_handle *)jarg1; + arg2 = (uint32_t)jarg2; + if (arg1) (arg1)->real_channels = arg2; +} + + +SWIGEXPORT unsigned long SWIGSTDCALL CSharp_switch_file_handle_real_channels_get(void * jarg1) { + unsigned long jresult ; + switch_file_handle *arg1 = (switch_file_handle *) 0 ; + uint32_t result; + + arg1 = (switch_file_handle *)jarg1; + result = (uint32_t) ((arg1)->real_channels); + jresult = (unsigned long)result; + return jresult; +} + + SWIGEXPORT void SWIGSTDCALL CSharp_switch_file_handle_format_set(void * jarg1, unsigned int jarg2) { switch_file_handle *arg1 = (switch_file_handle *) 0 ; unsigned int arg2 ; @@ -24662,10 +24754,10 @@ SWIGEXPORT char * SWIGSTDCALL CSharp_switch_speech_interface_interface_name_get( SWIGEXPORT void SWIGSTDCALL CSharp_switch_speech_interface_speech_open_set(void * jarg1, void * jarg2) { switch_speech_interface *arg1 = (switch_speech_interface *) 0 ; - switch_status_t (*arg2)(switch_speech_handle_t *,char const *,int,switch_speech_flag_t *) = (switch_status_t (*)(switch_speech_handle_t *,char const *,int,switch_speech_flag_t *)) 0 ; + switch_status_t (*arg2)(switch_speech_handle_t *,char const *,int,int,switch_speech_flag_t *) = (switch_status_t (*)(switch_speech_handle_t *,char const *,int,int,switch_speech_flag_t *)) 0 ; arg1 = (switch_speech_interface *)jarg1; - arg2 = (switch_status_t (*)(switch_speech_handle_t *,char const *,int,switch_speech_flag_t *))jarg2; + arg2 = (switch_status_t (*)(switch_speech_handle_t *,char const *,int,int,switch_speech_flag_t *))jarg2; if (arg1) (arg1)->speech_open = arg2; } @@ -24673,10 +24765,10 @@ SWIGEXPORT void SWIGSTDCALL CSharp_switch_speech_interface_speech_open_set(void SWIGEXPORT void * SWIGSTDCALL CSharp_switch_speech_interface_speech_open_get(void * jarg1) { void * jresult ; switch_speech_interface *arg1 = (switch_speech_interface *) 0 ; - switch_status_t (*result)(switch_speech_handle_t *,char const *,int,switch_speech_flag_t *) = 0 ; + switch_status_t (*result)(switch_speech_handle_t *,char const *,int,int,switch_speech_flag_t *) = 0 ; arg1 = (switch_speech_interface *)jarg1; - result = (switch_status_t (*)(switch_speech_handle_t *,char const *,int,switch_speech_flag_t *)) ((arg1)->speech_open); + result = (switch_status_t (*)(switch_speech_handle_t *,char const *,int,int,switch_speech_flag_t *)) ((arg1)->speech_open); jresult = (void *)result; return jresult; } @@ -25104,6 +25196,50 @@ SWIGEXPORT unsigned long SWIGSTDCALL CSharp_switch_speech_handle_samples_get(voi } +SWIGEXPORT void SWIGSTDCALL CSharp_switch_speech_handle_channels_set(void * jarg1, unsigned long jarg2) { + switch_speech_handle *arg1 = (switch_speech_handle *) 0 ; + uint32_t arg2 ; + + arg1 = (switch_speech_handle *)jarg1; + arg2 = (uint32_t)jarg2; + if (arg1) (arg1)->channels = arg2; +} + + +SWIGEXPORT unsigned long SWIGSTDCALL CSharp_switch_speech_handle_channels_get(void * jarg1) { + unsigned long jresult ; + switch_speech_handle *arg1 = (switch_speech_handle *) 0 ; + uint32_t result; + + arg1 = (switch_speech_handle *)jarg1; + result = (uint32_t) ((arg1)->channels); + jresult = (unsigned long)result; + return jresult; +} + + +SWIGEXPORT void SWIGSTDCALL CSharp_switch_speech_handle_real_channels_set(void * jarg1, unsigned long jarg2) { + switch_speech_handle *arg1 = (switch_speech_handle *) 0 ; + uint32_t arg2 ; + + arg1 = (switch_speech_handle *)jarg1; + arg2 = (uint32_t)jarg2; + if (arg1) (arg1)->real_channels = arg2; +} + + +SWIGEXPORT unsigned long SWIGSTDCALL CSharp_switch_speech_handle_real_channels_get(void * jarg1) { + unsigned long jresult ; + switch_speech_handle *arg1 = (switch_speech_handle *) 0 ; + uint32_t result; + + arg1 = (switch_speech_handle *)jarg1; + result = (uint32_t) ((arg1)->real_channels); + jresult = (unsigned long)result; + return jresult; +} + + SWIGEXPORT void SWIGSTDCALL CSharp_switch_speech_handle_voice_set(void * jarg1, char * jarg2) { switch_speech_handle *arg1 = (switch_speech_handle *) 0 ; char *arg2 ; @@ -26720,6 +26856,28 @@ SWIGEXPORT int SWIGSTDCALL CSharp_switch_codec_fmtp_microseconds_per_packet_get( } +SWIGEXPORT void SWIGSTDCALL CSharp_switch_codec_fmtp_stereo_set(void * jarg1, int jarg2) { + switch_codec_fmtp *arg1 = (switch_codec_fmtp *) 0 ; + int arg2 ; + + arg1 = (switch_codec_fmtp *)jarg1; + arg2 = (int)jarg2; + if (arg1) (arg1)->stereo = arg2; +} + + +SWIGEXPORT int SWIGSTDCALL CSharp_switch_codec_fmtp_stereo_get(void * jarg1) { + int jresult ; + switch_codec_fmtp *arg1 = (switch_codec_fmtp *) 0 ; + int result; + + arg1 = (switch_codec_fmtp *)jarg1; + result = (int) ((arg1)->stereo); + jresult = result; + return jresult; +} + + SWIGEXPORT void SWIGSTDCALL CSharp_switch_codec_fmtp_private_info_set(void * jarg1, void * jarg2) { switch_codec_fmtp *arg1 = (switch_codec_fmtp *) 0 ; void *arg2 = (void *) 0 ; @@ -33404,6 +33562,28 @@ SWIGEXPORT unsigned long SWIGSTDCALL CSharp_switch_audio_resampler_t_to_size_get } +SWIGEXPORT void SWIGSTDCALL CSharp_switch_audio_resampler_t_channels_set(void * jarg1, int jarg2) { + switch_audio_resampler_t *arg1 = (switch_audio_resampler_t *) 0 ; + int arg2 ; + + arg1 = (switch_audio_resampler_t *)jarg1; + arg2 = (int)jarg2; + if (arg1) (arg1)->channels = arg2; +} + + +SWIGEXPORT int SWIGSTDCALL CSharp_switch_audio_resampler_t_channels_get(void * jarg1) { + int jresult ; + switch_audio_resampler_t *arg1 = (switch_audio_resampler_t *) 0 ; + int result; + + arg1 = (switch_audio_resampler_t *)jarg1; + result = (int) ((arg1)->channels); + jresult = result; + return jresult; +} + + SWIGEXPORT void * SWIGSTDCALL CSharp_new_switch_audio_resampler_t() { void * jresult ; switch_audio_resampler_t *result = 0 ; @@ -33554,15 +33734,17 @@ SWIGEXPORT void SWIGSTDCALL CSharp_switch_swap_linear(void * jarg1, int jarg2) { } -SWIGEXPORT void SWIGSTDCALL CSharp_switch_generate_sln_silence(void * jarg1, unsigned long jarg2, unsigned long jarg3) { +SWIGEXPORT void SWIGSTDCALL CSharp_switch_generate_sln_silence(void * jarg1, unsigned long jarg2, unsigned long jarg3, unsigned long jarg4) { int16_t *arg1 = (int16_t *) 0 ; uint32_t arg2 ; uint32_t arg3 ; + uint32_t arg4 ; arg1 = (int16_t *)jarg1; arg2 = (uint32_t)jarg2; arg3 = (uint32_t)jarg3; - switch_generate_sln_silence(arg1,arg2,arg3); + arg4 = (uint32_t)jarg4; + switch_generate_sln_silence(arg1,arg2,arg3,arg4); } @@ -33626,10 +33808,11 @@ SWIGEXPORT unsigned long SWIGSTDCALL CSharp_switch_unmerge_sln(void * jarg1, uns } -SWIGEXPORT void SWIGSTDCALL CSharp_switch_mux_channels(void * jarg1, void * jarg2, unsigned long jarg3) { +SWIGEXPORT void SWIGSTDCALL CSharp_switch_mux_channels(void * jarg1, void * jarg2, unsigned long jarg3, unsigned long jarg4) { int16_t *arg1 = (int16_t *) 0 ; switch_size_t arg2 ; uint32_t arg3 ; + uint32_t arg4 ; switch_size_t *argp2 ; arg1 = (int16_t *)jarg1; @@ -33640,7 +33823,8 @@ SWIGEXPORT void SWIGSTDCALL CSharp_switch_mux_channels(void * jarg1, void * jarg } arg2 = *argp2; arg3 = (uint32_t)jarg3; - switch_mux_channels(arg1,arg2,arg3); + arg4 = (uint32_t)jarg4; + switch_mux_channels(arg1,arg2,arg3,arg4); } @@ -34408,7 +34592,7 @@ SWIGEXPORT int SWIGSTDCALL CSharp_switch_ivr_detect_speech_load_grammar(void * j arg1 = (switch_core_session_t *)jarg1; arg2 = (char *)jarg2; arg3 = (char *)jarg3; - result = (switch_status_t)switch_ivr_detect_speech_load_grammar(arg1,arg2,arg3); + result = (switch_status_t)switch_ivr_detect_speech_load_grammar(arg1,(char const *)arg2,(char const *)arg3); jresult = result; return jresult; } diff --git a/src/mod/languages/mod_managed/managed/swig.2010.cs b/src/mod/languages/mod_managed/managed/swig.2010.cs index 8ae5f05b07..7fc9e3148a 100644 --- a/src/mod/languages/mod_managed/managed/swig.2010.cs +++ b/src/mod/languages/mod_managed/managed/swig.2010.cs @@ -2078,8 +2078,8 @@ public class freeswitch { return ret; } - public static switch_status_t switch_core_hash_insert(SWIGTYPE_p_switch_hashtable hash, string key, SWIGTYPE_p_void data) { - switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_core_hash_insert(SWIGTYPE_p_switch_hashtable.getCPtr(hash), key, SWIGTYPE_p_void.getCPtr(data)); + public static switch_status_t switch_core_hash_insert_destructor(SWIGTYPE_p_switch_hashtable hash, string key, SWIGTYPE_p_void data, SWIGTYPE_p_f_p_void__void destructor) { + switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_core_hash_insert_destructor(SWIGTYPE_p_switch_hashtable.getCPtr(hash), key, SWIGTYPE_p_void.getCPtr(data), SWIGTYPE_p_f_p_void__void.getCPtr(destructor)); return ret; } @@ -2396,8 +2396,8 @@ public class freeswitch { return ret; } - public static switch_status_t switch_core_speech_open(switch_speech_handle sh, string module_name, string voice_name, uint rate, uint interval, SWIGTYPE_p_unsigned_long flags, SWIGTYPE_p_apr_pool_t pool) { - switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_core_speech_open(switch_speech_handle.getCPtr(sh), module_name, voice_name, rate, interval, SWIGTYPE_p_unsigned_long.getCPtr(flags), SWIGTYPE_p_apr_pool_t.getCPtr(pool)); + public static switch_status_t switch_core_speech_open(switch_speech_handle sh, string module_name, string voice_name, uint rate, uint interval, uint channels, SWIGTYPE_p_unsigned_long flags, SWIGTYPE_p_apr_pool_t pool) { + switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_core_speech_open(switch_speech_handle.getCPtr(sh), module_name, voice_name, rate, interval, channels, SWIGTYPE_p_unsigned_long.getCPtr(flags), SWIGTYPE_p_apr_pool_t.getCPtr(pool)); return ret; } @@ -5268,8 +5268,8 @@ public class freeswitch { freeswitchPINVOKE.switch_swap_linear(SWIGTYPE_p_short.getCPtr(buf), len); } - public static void switch_generate_sln_silence(SWIGTYPE_p_short data, uint samples, uint divisor) { - freeswitchPINVOKE.switch_generate_sln_silence(SWIGTYPE_p_short.getCPtr(data), samples, divisor); + public static void switch_generate_sln_silence(SWIGTYPE_p_short data, uint samples, uint channels, uint divisor) { + freeswitchPINVOKE.switch_generate_sln_silence(SWIGTYPE_p_short.getCPtr(data), samples, channels, divisor); } public static void switch_change_sln_volume(SWIGTYPE_p_short data, uint samples, int vol) { @@ -5290,8 +5290,8 @@ public class freeswitch { return ret; } - public static void switch_mux_channels(SWIGTYPE_p_short data, SWIGTYPE_p_switch_size_t samples, uint channels) { - freeswitchPINVOKE.switch_mux_channels(SWIGTYPE_p_short.getCPtr(data), SWIGTYPE_p_switch_size_t.getCPtr(samples), channels); + public static void switch_mux_channels(SWIGTYPE_p_short data, SWIGTYPE_p_switch_size_t samples, uint orig_channels, uint channels) { + freeswitchPINVOKE.switch_mux_channels(SWIGTYPE_p_short.getCPtr(data), SWIGTYPE_p_switch_size_t.getCPtr(samples), orig_channels, channels); if (freeswitchPINVOKE.SWIGPendingException.Pending) throw freeswitchPINVOKE.SWIGPendingException.Retrieve(); } @@ -9381,6 +9381,24 @@ class freeswitchPINVOKE { [DllImport("mod_managed", EntryPoint="CSharp_switch_device_stats_t_held_out_get")] public static extern uint switch_device_stats_t_held_out_get(HandleRef jarg1); + [DllImport("mod_managed", EntryPoint="CSharp_switch_device_stats_t_unheld_set")] + public static extern void switch_device_stats_t_unheld_set(HandleRef jarg1, uint jarg2); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_device_stats_t_unheld_get")] + public static extern uint switch_device_stats_t_unheld_get(HandleRef jarg1); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_device_stats_t_unheld_in_set")] + public static extern void switch_device_stats_t_unheld_in_set(HandleRef jarg1, uint jarg2); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_device_stats_t_unheld_in_get")] + public static extern uint switch_device_stats_t_unheld_in_get(HandleRef jarg1); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_device_stats_t_unheld_out_set")] + public static extern void switch_device_stats_t_unheld_out_set(HandleRef jarg1, uint jarg2); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_device_stats_t_unheld_out_get")] + public static extern uint switch_device_stats_t_unheld_out_get(HandleRef jarg1); + [DllImport("mod_managed", EntryPoint="CSharp_switch_device_stats_t_hup_set")] public static extern void switch_device_stats_t_hup_set(HandleRef jarg1, uint jarg2); @@ -10293,8 +10311,8 @@ class freeswitchPINVOKE { [DllImport("mod_managed", EntryPoint="CSharp_switch_core_hash_destroy")] public static extern int switch_core_hash_destroy(HandleRef jarg1); - [DllImport("mod_managed", EntryPoint="CSharp_switch_core_hash_insert")] - public static extern int switch_core_hash_insert(HandleRef jarg1, string jarg2, HandleRef jarg3); + [DllImport("mod_managed", EntryPoint="CSharp_switch_core_hash_insert_destructor")] + public static extern int switch_core_hash_insert_destructor(HandleRef jarg1, string jarg2, HandleRef jarg3, HandleRef jarg4); [DllImport("mod_managed", EntryPoint="CSharp_switch_core_hash_insert_locked")] public static extern int switch_core_hash_insert_locked(HandleRef jarg1, string jarg2, HandleRef jarg3, HandleRef jarg4); @@ -10483,7 +10501,7 @@ class freeswitchPINVOKE { public static extern int switch_core_file_truncate(HandleRef jarg1, long jarg2); [DllImport("mod_managed", EntryPoint="CSharp_switch_core_speech_open")] - public static extern int switch_core_speech_open(HandleRef jarg1, string jarg2, string jarg3, uint jarg4, uint jarg5, HandleRef jarg6, HandleRef jarg7); + public static extern int switch_core_speech_open(HandleRef jarg1, string jarg2, string jarg3, uint jarg4, uint jarg5, uint jarg6, HandleRef jarg7, HandleRef jarg8); [DllImport("mod_managed", EntryPoint="CSharp_switch_core_speech_feed_tts")] public static extern int switch_core_speech_feed_tts(HandleRef jarg1, string jarg2, HandleRef jarg3); @@ -12873,6 +12891,12 @@ class freeswitchPINVOKE { [DllImport("mod_managed", EntryPoint="CSharp_switch_file_handle_channels_get")] public static extern uint switch_file_handle_channels_get(HandleRef jarg1); + [DllImport("mod_managed", EntryPoint="CSharp_switch_file_handle_real_channels_set")] + public static extern void switch_file_handle_real_channels_set(HandleRef jarg1, uint jarg2); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_file_handle_real_channels_get")] + public static extern uint switch_file_handle_real_channels_get(HandleRef jarg1); + [DllImport("mod_managed", EntryPoint="CSharp_switch_file_handle_format_set")] public static extern void switch_file_handle_format_set(HandleRef jarg1, uint jarg2); @@ -13467,6 +13491,18 @@ class freeswitchPINVOKE { [DllImport("mod_managed", EntryPoint="CSharp_switch_speech_handle_samples_get")] public static extern uint switch_speech_handle_samples_get(HandleRef jarg1); + [DllImport("mod_managed", EntryPoint="CSharp_switch_speech_handle_channels_set")] + public static extern void switch_speech_handle_channels_set(HandleRef jarg1, uint jarg2); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_speech_handle_channels_get")] + public static extern uint switch_speech_handle_channels_get(HandleRef jarg1); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_speech_handle_real_channels_set")] + public static extern void switch_speech_handle_real_channels_set(HandleRef jarg1, uint jarg2); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_speech_handle_real_channels_get")] + public static extern uint switch_speech_handle_real_channels_get(HandleRef jarg1); + [DllImport("mod_managed", EntryPoint="CSharp_switch_speech_handle_voice_set")] public static extern void switch_speech_handle_voice_set(HandleRef jarg1, string jarg2); @@ -13899,6 +13935,12 @@ class freeswitchPINVOKE { [DllImport("mod_managed", EntryPoint="CSharp_switch_codec_fmtp_microseconds_per_packet_get")] public static extern int switch_codec_fmtp_microseconds_per_packet_get(HandleRef jarg1); + [DllImport("mod_managed", EntryPoint="CSharp_switch_codec_fmtp_stereo_set")] + public static extern void switch_codec_fmtp_stereo_set(HandleRef jarg1, int jarg2); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_codec_fmtp_stereo_get")] + public static extern int switch_codec_fmtp_stereo_get(HandleRef jarg1); + [DllImport("mod_managed", EntryPoint="CSharp_switch_codec_fmtp_private_info_set")] public static extern void switch_codec_fmtp_private_info_set(HandleRef jarg1, HandleRef jarg2); @@ -15489,6 +15531,12 @@ class freeswitchPINVOKE { [DllImport("mod_managed", EntryPoint="CSharp_switch_audio_resampler_t_to_size_get")] public static extern uint switch_audio_resampler_t_to_size_get(HandleRef jarg1); + [DllImport("mod_managed", EntryPoint="CSharp_switch_audio_resampler_t_channels_set")] + public static extern void switch_audio_resampler_t_channels_set(HandleRef jarg1, int jarg2); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_audio_resampler_t_channels_get")] + public static extern int switch_audio_resampler_t_channels_get(HandleRef jarg1); + [DllImport("mod_managed", EntryPoint="CSharp_new_switch_audio_resampler_t")] public static extern IntPtr new_switch_audio_resampler_t(); @@ -15520,7 +15568,7 @@ class freeswitchPINVOKE { public static extern void switch_swap_linear(HandleRef jarg1, int jarg2); [DllImport("mod_managed", EntryPoint="CSharp_switch_generate_sln_silence")] - public static extern void switch_generate_sln_silence(HandleRef jarg1, uint jarg2, uint jarg3); + public static extern void switch_generate_sln_silence(HandleRef jarg1, uint jarg2, uint jarg3, uint jarg4); [DllImport("mod_managed", EntryPoint="CSharp_switch_change_sln_volume")] public static extern void switch_change_sln_volume(HandleRef jarg1, uint jarg2, int jarg3); @@ -15535,7 +15583,7 @@ class freeswitchPINVOKE { public static extern uint switch_unmerge_sln(HandleRef jarg1, uint jarg2, HandleRef jarg3, uint jarg4); [DllImport("mod_managed", EntryPoint="CSharp_switch_mux_channels")] - public static extern void switch_mux_channels(HandleRef jarg1, HandleRef jarg2, uint jarg3); + public static extern void switch_mux_channels(HandleRef jarg1, HandleRef jarg2, uint jarg3, uint jarg4); [DllImport("mod_managed", EntryPoint="CSharp_switch_unicast_conninfo_session_set")] public static extern void switch_unicast_conninfo_session_set(HandleRef jarg1, HandleRef jarg2); @@ -21231,18 +21279,18 @@ namespace FreeSWITCH.Native { using System; using System.Runtime.InteropServices; -public class SWIGTYPE_p_f_p_switch_speech_handle_p_q_const__char_int_p_unsigned_long__switch_status_t { +public class SWIGTYPE_p_f_p_switch_speech_handle_p_q_const__char_int_int_p_unsigned_long__switch_status_t { private HandleRef swigCPtr; - internal SWIGTYPE_p_f_p_switch_speech_handle_p_q_const__char_int_p_unsigned_long__switch_status_t(IntPtr cPtr, bool futureUse) { + internal SWIGTYPE_p_f_p_switch_speech_handle_p_q_const__char_int_int_p_unsigned_long__switch_status_t(IntPtr cPtr, bool futureUse) { swigCPtr = new HandleRef(this, cPtr); } - protected SWIGTYPE_p_f_p_switch_speech_handle_p_q_const__char_int_p_unsigned_long__switch_status_t() { + protected SWIGTYPE_p_f_p_switch_speech_handle_p_q_const__char_int_int_p_unsigned_long__switch_status_t() { swigCPtr = new HandleRef(null, IntPtr.Zero); } - internal static HandleRef getCPtr(SWIGTYPE_p_f_p_switch_speech_handle_p_q_const__char_int_p_unsigned_long__switch_status_t obj) { + internal static HandleRef getCPtr(SWIGTYPE_p_f_p_switch_speech_handle_p_q_const__char_int_int_p_unsigned_long__switch_status_t obj) { return (obj == null) ? new HandleRef(null, IntPtr.Zero) : obj.swigCPtr; } } @@ -25764,6 +25812,16 @@ public class switch_audio_resampler_t : IDisposable { } } + public int channels { + set { + freeswitchPINVOKE.switch_audio_resampler_t_channels_set(swigCPtr, value); + } + get { + int ret = freeswitchPINVOKE.switch_audio_resampler_t_channels_get(swigCPtr); + return ret; + } + } + public switch_audio_resampler_t() : this(freeswitchPINVOKE.new_switch_audio_resampler_t(), true) { } @@ -27232,7 +27290,7 @@ public enum switch_channel_callstate_t { CCS_HELD, CCS_RING_WAIT, CCS_HANGUP, - CCS_UNHOLD + CCS_UNHELD } } @@ -28190,6 +28248,16 @@ public class switch_codec_fmtp : IDisposable { } } + public int stereo { + set { + freeswitchPINVOKE.switch_codec_fmtp_stereo_set(swigCPtr, value); + } + get { + int ret = freeswitchPINVOKE.switch_codec_fmtp_stereo_get(swigCPtr); + return ret; + } + } + public SWIGTYPE_p_void private_info { set { freeswitchPINVOKE.switch_codec_fmtp_private_info_set(swigCPtr, SWIGTYPE_p_void.getCPtr(value)); @@ -29352,11 +29420,13 @@ public enum switch_core_session_message_types_t { SWITCH_MESSAGE_INDICATE_BLIND_TRANSFER_RESPONSE, SWITCH_MESSAGE_INDICATE_STUN_ERROR, SWITCH_MESSAGE_INDICATE_MEDIA_RENEG, + SWITCH_MESSAGE_INDICATE_KEEPALIVE, SWITCH_MESSAGE_REFER_EVENT, SWITCH_MESSAGE_ANSWER_EVENT, SWITCH_MESSAGE_PROGRESS_EVENT, SWITCH_MESSAGE_RING_EVENT, SWITCH_MESSAGE_RESAMPLE_EVENT, + SWITCH_MESSAGE_HEARTBEAT_EVENT, SWITCH_MESSAGE_INVALID } @@ -30016,6 +30086,7 @@ public enum switch_device_state_t { SDS_ACTIVE, SDS_ACTIVE_MULTI, SDS_HELD, + SDS_UNHELD, SDS_HANGUP } @@ -30183,6 +30254,36 @@ public class switch_device_stats_t : IDisposable { } } + public uint unheld { + set { + freeswitchPINVOKE.switch_device_stats_t_unheld_set(swigCPtr, value); + } + get { + uint ret = freeswitchPINVOKE.switch_device_stats_t_unheld_get(swigCPtr); + return ret; + } + } + + public uint unheld_in { + set { + freeswitchPINVOKE.switch_device_stats_t_unheld_in_set(swigCPtr, value); + } + get { + uint ret = freeswitchPINVOKE.switch_device_stats_t_unheld_in_get(swigCPtr); + return ret; + } + } + + public uint unheld_out { + set { + freeswitchPINVOKE.switch_device_stats_t_unheld_out_set(swigCPtr, value); + } + get { + uint ret = freeswitchPINVOKE.switch_device_stats_t_unheld_out_get(swigCPtr); + return ret; + } + } + public uint hup { set { freeswitchPINVOKE.switch_device_stats_t_hup_set(swigCPtr, value); @@ -31815,6 +31916,16 @@ public class switch_file_handle : IDisposable { } } + public uint real_channels { + set { + freeswitchPINVOKE.switch_file_handle_real_channels_set(swigCPtr, value); + } + get { + uint ret = freeswitchPINVOKE.switch_file_handle_real_channels_get(swigCPtr); + return ret; + } + } + public uint format { set { freeswitchPINVOKE.switch_file_handle_format_set(swigCPtr, value); @@ -37364,6 +37475,7 @@ public enum switch_session_ctl_t { SCSC_DEBUG_LEVEL, SCSC_FLUSH_DB_HANDLES, SCSC_SHUTDOWN_NOW, + SCSC_REINCARNATE_NOW, SCSC_CALIBRATE_CLOCK, SCSC_SAVE_HISTORY, SCSC_CRASH, @@ -37623,6 +37735,26 @@ public class switch_speech_handle : IDisposable { } } + public uint channels { + set { + freeswitchPINVOKE.switch_speech_handle_channels_set(swigCPtr, value); + } + get { + uint ret = freeswitchPINVOKE.switch_speech_handle_channels_get(swigCPtr); + return ret; + } + } + + public uint real_channels { + set { + freeswitchPINVOKE.switch_speech_handle_real_channels_set(swigCPtr, value); + } + get { + uint ret = freeswitchPINVOKE.switch_speech_handle_real_channels_get(swigCPtr); + return ret; + } + } + public string voice { set { freeswitchPINVOKE.switch_speech_handle_voice_set(swigCPtr, value); @@ -37799,13 +37931,13 @@ public class switch_speech_interface : IDisposable { } } - public SWIGTYPE_p_f_p_switch_speech_handle_p_q_const__char_int_p_unsigned_long__switch_status_t speech_open { + public SWIGTYPE_p_f_p_switch_speech_handle_p_q_const__char_int_int_p_unsigned_long__switch_status_t speech_open { set { - freeswitchPINVOKE.switch_speech_interface_speech_open_set(swigCPtr, SWIGTYPE_p_f_p_switch_speech_handle_p_q_const__char_int_p_unsigned_long__switch_status_t.getCPtr(value)); + freeswitchPINVOKE.switch_speech_interface_speech_open_set(swigCPtr, SWIGTYPE_p_f_p_switch_speech_handle_p_q_const__char_int_int_p_unsigned_long__switch_status_t.getCPtr(value)); } get { IntPtr cPtr = freeswitchPINVOKE.switch_speech_interface_speech_open_get(swigCPtr); - SWIGTYPE_p_f_p_switch_speech_handle_p_q_const__char_int_p_unsigned_long__switch_status_t ret = (cPtr == IntPtr.Zero) ? null : new SWIGTYPE_p_f_p_switch_speech_handle_p_q_const__char_int_p_unsigned_long__switch_status_t(cPtr, false); + SWIGTYPE_p_f_p_switch_speech_handle_p_q_const__char_int_int_p_unsigned_long__switch_status_t ret = (cPtr == IntPtr.Zero) ? null : new SWIGTYPE_p_f_p_switch_speech_handle_p_q_const__char_int_int_p_unsigned_long__switch_status_t(cPtr, false); return ret; } } From 4ffbf23ffaba47f430bc59dc93cc3815647217b8 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Fri, 13 Jun 2014 01:49:10 -0400 Subject: [PATCH 038/231] stereo refactoring --- src/include/switch_core_media.h | 3 +- src/include/switch_frame.h | 2 + src/include/switch_loadable_module.h | 2 +- src/mod/codecs/mod_opus/mod_opus.c | 7 ++- src/mod/endpoints/mod_loopback/mod_loopback.c | 4 +- src/mod/endpoints/mod_verto/mod_verto.c | 4 +- src/switch_core_io.c | 39 ++++++++++----- src/switch_core_media.c | 47 ++++++++++++++----- src/switch_ivr_async.c | 7 ++- src/switch_loadable_module.c | 38 +++++++++++---- 10 files changed, 109 insertions(+), 44 deletions(-) diff --git a/src/include/switch_core_media.h b/src/include/switch_core_media.h index 312937756e..0de6a28859 100644 --- a/src/include/switch_core_media.h +++ b/src/include/switch_core_media.h @@ -264,7 +264,8 @@ SWITCH_DECLARE(payload_map_t *) switch_core_media_add_payload_map(switch_core_se switch_sdp_type_t sdp_type, uint32_t pt, uint32_t rate, - uint32_t ptime, + uint32_t ptime, + uint32_t channels, uint8_t negotiated); diff --git a/src/include/switch_frame.h b/src/include/switch_frame.h index bbbca0917b..51800df6c1 100644 --- a/src/include/switch_frame.h +++ b/src/include/switch_frame.h @@ -61,6 +61,8 @@ SWITCH_BEGIN_EXTERN_C uint32_t samples; /*! the rate of the frame */ uint32_t rate; + /*! the number of channels in the frame */ + uint32_t channels; /*! the payload of the frame */ switch_payload_t payload; /*! the timestamp of the frame */ diff --git a/src/include/switch_loadable_module.h b/src/include/switch_loadable_module.h index ef27e75758..644887a931 100644 --- a/src/include/switch_loadable_module.h +++ b/src/include/switch_loadable_module.h @@ -117,7 +117,7 @@ SWITCH_DECLARE(switch_endpoint_interface_t *) switch_loadable_module_get_endpoin */ SWITCH_DECLARE(switch_codec_interface_t *) switch_loadable_module_get_codec_interface(const char *name); -SWITCH_DECLARE(char *) switch_parse_codec_buf(char *buf, uint32_t *interval, uint32_t *rate, uint32_t *bit); +SWITCH_DECLARE(char *) switch_parse_codec_buf(char *buf, uint32_t *interval, uint32_t *rate, uint32_t *bit, uint32_t *channels); /*! \brief Retrieve the dialplan interface by it's registered name diff --git a/src/mod/codecs/mod_opus/mod_opus.c b/src/mod/codecs/mod_opus/mod_opus.c index af10ca3371..62ab8dbcbc 100644 --- a/src/mod/codecs/mod_opus/mod_opus.c +++ b/src/mod/codecs/mod_opus/mod_opus.c @@ -266,6 +266,8 @@ static switch_status_t switch_opus_init(switch_codec_t *codec, switch_codec_flag switch_opus_fmtp_parse(codec->fmtp_in, &codec_fmtp); codec->fmtp_out = gen_fmtp(&opus_codec_settings, codec->memory_pool); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "OPUS init %d %d\n", codec->implementation->actual_samples_per_second, codec->implementation->number_of_channels); + if (encoding) { /* come up with a way to specify these */ int bitrate_bps = OPUS_AUTO; @@ -472,6 +474,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_opus_load) settings.maxptime = settings.ptime; settings.minptime = settings.ptime; settings.samplerate = rate; + settings.stereo = 0; dft_fmtp = gen_fmtp(&settings, pool); switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */ @@ -493,8 +496,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_opus_load) switch_opus_destroy); /* deinitalize a codec handle using this implementation */ settings.stereo = 1; + if (x < 2) { dft_fmtp = gen_fmtp(&settings, pool); - switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */ 116, /* the IANA code number */ "opus",/* the IANA code name */ @@ -512,7 +515,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_opus_load) switch_opus_encode, /* function to encode raw data into encoded data */ switch_opus_decode, /* function to decode encoded data into raw data */ switch_opus_destroy); /* deinitalize a codec handle using this implementation */ - + } bytes *= 2; samples *= 2; mss *= 2; diff --git a/src/mod/endpoints/mod_loopback/mod_loopback.c b/src/mod/endpoints/mod_loopback/mod_loopback.c index 8c0dd8c92e..b0cde67f07 100644 --- a/src/mod/endpoints/mod_loopback/mod_loopback.c +++ b/src/mod/endpoints/mod_loopback/mod_loopback.c @@ -140,8 +140,8 @@ static switch_status_t tech_init(loopback_private_t *tech_pvt, switch_core_sessi if ((var = switch_channel_get_variable(channel, "loopback_initial_codec"))) { char *dup = switch_core_session_strdup(session, var); - uint32_t bit; - iananame = switch_parse_codec_buf(dup, &interval, &rate, &bit); + uint32_t bit, channels; + iananame = switch_parse_codec_buf(dup, &interval, &rate, &bit, &channels); } } diff --git a/src/mod/endpoints/mod_verto/mod_verto.c b/src/mod/endpoints/mod_verto/mod_verto.c index 7d30e7dc84..748c98067c 100644 --- a/src/mod/endpoints/mod_verto/mod_verto.c +++ b/src/mod/endpoints/mod_verto/mod_verto.c @@ -1441,10 +1441,12 @@ static switch_status_t verto_connect(switch_core_session_t *session, const char verto_set_media_options(tech_pvt, jsock->profile); - switch_core_media_prepare_codecs(tech_pvt->session, SWITCH_TRUE); + switch_channel_set_variable(tech_pvt->channel, "verto_profile_name", jsock->profile->name); if (!switch_channel_test_flag(tech_pvt->channel, CF_RECOVERING)) { + switch_core_media_prepare_codecs(tech_pvt->session, SWITCH_TRUE); + if ((status = switch_core_media_choose_ports(tech_pvt->session, SWITCH_TRUE, SWITCH_TRUE)) != SWITCH_STATUS_SUCCESS) { //if ((status = switch_core_media_choose_port(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO, 0)) != SWITCH_STATUS_SUCCESS) { switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); diff --git a/src/switch_core_io.c b/src/switch_core_io.c index 430993df1f..bb99c3eb39 100644 --- a/src/switch_core_io.c +++ b/src/switch_core_io.c @@ -405,6 +405,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi tmp_frame.codec = (*frame)->codec; tmp_frame.datalen = (*frame)->codec->implementation->encoded_bytes_per_packet; tmp_frame.samples = (*frame)->codec->implementation->samples_per_packet; + tmp_frame.channels = (*frame)->codec->implementation->number_of_channels; tmp_frame.data = data; switch_core_gen_encoded_silence(data, (*frame)->codec->implementation, tmp_frame.datalen); @@ -510,7 +511,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi session->raw_read_frame.timestamp = 0; session->raw_read_frame.datalen = read_frame->codec->implementation->decoded_bytes_per_packet; - session->raw_read_frame.samples = session->raw_read_frame.datalen / sizeof(int16_t); + session->raw_read_frame.samples = session->raw_read_frame.datalen / sizeof(int16_t) / session->read_impl.number_of_channels; + session->raw_read_frame.channels = read_frame->codec->implementation->number_of_channels; read_frame = &session->raw_read_frame; status = SWITCH_STATUS_SUCCESS; } else { @@ -547,7 +549,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi if (switch_test_flag(read_frame, SFF_PLC)) { session->raw_read_frame.datalen = read_frame->codec->implementation->decoded_bytes_per_packet; - session->raw_read_frame.samples = session->raw_read_frame.datalen / sizeof(int16_t); + session->raw_read_frame.samples = session->raw_read_frame.datalen / sizeof(int16_t) / session->read_impl.number_of_channels; + session->raw_read_frame.channels = session->read_impl.number_of_channels; memset(session->raw_read_frame.data, 255, session->raw_read_frame.datalen); status = SWITCH_STATUS_SUCCESS; } else { @@ -632,7 +635,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi } } case SWITCH_STATUS_SUCCESS: - session->raw_read_frame.samples = session->raw_read_frame.datalen / sizeof(int16_t); + session->raw_read_frame.samples = session->raw_read_frame.datalen / sizeof(int16_t) / session->read_impl.number_of_channels; + session->raw_read_frame.channels = session->read_impl.number_of_channels; session->raw_read_frame.rate = read_frame->rate; if (read_frame->codec->implementation->samples_per_packet != session->read_impl.samples_per_packet) { session->raw_read_frame.timestamp = 0; @@ -670,7 +674,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi case SWITCH_STATUS_BREAK: memset(session->raw_read_frame.data, 255, read_frame->codec->implementation->decoded_bytes_per_packet); session->raw_read_frame.datalen = read_frame->codec->implementation->decoded_bytes_per_packet; - session->raw_read_frame.samples = session->raw_read_frame.datalen / sizeof(int16_t); + session->raw_read_frame.samples = session->raw_read_frame.datalen / sizeof(int16_t) / session->read_impl.number_of_channels; + session->raw_read_frame.channels = session->read_impl.number_of_channels; session->raw_read_frame.timestamp = read_frame->timestamp; session->raw_read_frame.rate = read_frame->rate; session->raw_read_frame.ssrc = read_frame->ssrc; @@ -820,6 +825,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi switch_resample_process(session->read_resampler, data, (int) read_frame->datalen / 2 / session->read_resampler->channels); memcpy(data, session->read_resampler->to, session->read_resampler->to_len * 2 * session->read_resampler->channels); read_frame->samples = session->read_resampler->to_len; + read_frame->channels = session->read_resampler->channels; read_frame->datalen = session->read_resampler->to_len * 2 * session->read_resampler->channels; read_frame->rate = session->read_resampler->to_rate; switch_mutex_unlock(session->resample_mutex); @@ -872,7 +878,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi case SWITCH_STATUS_RESAMPLE: switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Fixme 1\n"); case SWITCH_STATUS_SUCCESS: - session->enc_read_frame.samples = session->read_impl.decoded_bytes_per_packet / sizeof(int16_t); + session->enc_read_frame.samples = session->read_impl.decoded_bytes_per_packet / sizeof(int16_t) / session->read_impl.number_of_channels; + session->enc_read_frame.channels = session->read_impl.number_of_channels; if (perfect) { if (enc_frame->codec->implementation->samples_per_packet != session->read_impl.samples_per_packet) { session->enc_read_frame.timestamp = 0; @@ -889,6 +896,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi break; case SWITCH_STATUS_NOOP: session->raw_read_frame.samples = enc_frame->codec->implementation->samples_per_packet; + session->raw_read_frame.channels = enc_frame->codec->implementation->number_of_channels; session->raw_read_frame.timestamp = read_frame->timestamp; session->raw_read_frame.payload = enc_frame->codec->implementation->ianacode; session->raw_read_frame.m = read_frame->m; @@ -1251,7 +1259,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_frame(switch_core_sess } break; case SWITCH_STATUS_SUCCESS: - session->raw_write_frame.samples = session->raw_write_frame.datalen / sizeof(int16_t); + session->raw_write_frame.samples = session->raw_write_frame.datalen / sizeof(int16_t) / session->write_impl.number_of_channels; + session->raw_write_frame.channels = session->write_impl.number_of_channels; session->raw_write_frame.timestamp = frame->timestamp; session->raw_write_frame.rate = frame->rate; session->raw_write_frame.m = frame->m; @@ -1317,7 +1326,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_frame(switch_core_sess memcpy(data, session->write_resampler->to, session->write_resampler->to_len * 2 * session->write_resampler->channels); write_frame->samples = session->write_resampler->to_len; - + write_frame->channels = session->write_resampler->channels; write_frame->datalen = write_frame->samples * 2 * session->write_resampler->channels; write_frame->rate = session->write_resampler->to_rate; @@ -1431,7 +1440,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_frame(switch_core_sess /* switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Fixme 2\n"); */ case SWITCH_STATUS_SUCCESS: session->enc_write_frame.codec = session->write_codec; - session->enc_write_frame.samples = enc_frame->datalen / sizeof(int16_t); + session->enc_write_frame.samples = enc_frame->datalen / sizeof(int16_t) / session->write_impl.number_of_channels; + session->enc_write_frame.channels = session->write_impl.number_of_channels; if (frame->codec->implementation->samples_per_packet != session->write_impl.samples_per_packet) { session->enc_write_frame.timestamp = 0; } else { @@ -1446,7 +1456,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_frame(switch_core_sess break; case SWITCH_STATUS_NOOP: enc_frame->codec = session->write_codec; - enc_frame->samples = enc_frame->datalen / sizeof(int16_t); + enc_frame->samples = enc_frame->datalen / sizeof(int16_t) / session->write_impl.number_of_channels; + enc_frame->channels = session->write_impl.number_of_channels; enc_frame->timestamp = frame->timestamp; enc_frame->m = frame->m; enc_frame->seq = frame->seq; @@ -1534,7 +1545,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_frame(switch_core_sess case SWITCH_STATUS_RESAMPLE: resample++; session->enc_write_frame.codec = session->write_codec; - session->enc_write_frame.samples = enc_frame->datalen / sizeof(int16_t); + session->enc_write_frame.samples = enc_frame->datalen / sizeof(int16_t) / session->write_impl.number_of_channels; + session->enc_write_frame.channels = session->write_impl.number_of_channels; session->enc_write_frame.m = frame->m; session->enc_write_frame.ssrc = frame->ssrc; session->enc_write_frame.payload = session->write_impl.ianacode; @@ -1567,7 +1579,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_frame(switch_core_sess break; case SWITCH_STATUS_SUCCESS: session->enc_write_frame.codec = session->write_codec; - session->enc_write_frame.samples = enc_frame->datalen / sizeof(int16_t); + session->enc_write_frame.samples = enc_frame->datalen / sizeof(int16_t) / session->write_impl.number_of_channels; + session->enc_write_frame.channels = session->write_impl.number_of_channels; session->enc_write_frame.m = frame->m; session->enc_write_frame.ssrc = frame->ssrc; session->enc_write_frame.payload = session->write_impl.ianacode; @@ -1595,7 +1608,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_frame(switch_core_sess } enc_frame->codec = session->write_codec; - enc_frame->samples = enc_frame->datalen / sizeof(int16_t); + enc_frame->samples = enc_frame->datalen / sizeof(int16_t) / session->read_impl.number_of_channels; + enc_frame->channels = session->read_impl.number_of_channels; enc_frame->m = frame->m; enc_frame->ssrc = frame->ssrc; enc_frame->payload = enc_frame->codec->implementation->ianacode; @@ -1620,6 +1634,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_frame(switch_core_sess switch_resample_process(session->read_resampler, data, write_frame->datalen / 2 / session->read_resampler->channels); memcpy(data, session->read_resampler->to, session->read_resampler->to_len * 2 * session->read_resampler->channels); write_frame->samples = session->read_resampler->to_len; + write_frame->channels = session->read_resampler->channels; write_frame->datalen = session->read_resampler->to_len * 2 * session->read_resampler->channels; write_frame->rate = session->read_resampler->to_rate; } diff --git a/src/switch_core_media.c b/src/switch_core_media.c index 2c4da7c4cd..0bbef216b4 100644 --- a/src/switch_core_media.c +++ b/src/switch_core_media.c @@ -577,7 +577,8 @@ SWITCH_DECLARE(payload_map_t *) switch_core_media_add_payload_map(switch_core_se switch_sdp_type_t sdp_type, uint32_t pt, uint32_t rate, - uint32_t ptime, + uint32_t ptime, + uint32_t channels, uint8_t negotiated) { payload_map_t *pmap; @@ -628,6 +629,7 @@ SWITCH_DECLARE(payload_map_t *) switch_core_media_add_payload_map(switch_core_se pmap->iananame = switch_core_strdup(session->pool, name); pmap->rm_encoding = pmap->iananame; pmap->hash = switch_ci_hashfunc_default(pmap->iananame, &hlen); + pmap->channels = 1; } pmap->sdp_type = sdp_type; @@ -640,6 +642,10 @@ SWITCH_DECLARE(payload_map_t *) switch_core_media_add_payload_map(switch_core_se pmap->rate = rate; } + if (channels) { + pmap->channels = channels; + } + if (!zstr(fmtp) && (zstr(pmap->rm_fmtp) || strcmp(pmap->rm_fmtp, fmtp))) { pmap->rm_fmtp = switch_core_strdup(session->pool, fmtp); } @@ -2310,8 +2316,9 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_set_codec(switch_core_session_ switch_channel_set_variable(session->channel, "rtp_use_codec_fmtp", a_engine->cur_payload_map->rm_fmtp); switch_channel_set_variable_printf(session->channel, "rtp_use_codec_rate", "%d", a_engine->cur_payload_map->rm_rate); switch_channel_set_variable_printf(session->channel, "rtp_use_codec_ptime", "%d", a_engine->cur_payload_map->codec_ms); - switch_channel_set_variable_printf(session->channel, "rtp_last_audio_codec_string", "%s@%dh@%di", - a_engine->cur_payload_map->iananame, a_engine->cur_payload_map->rm_rate, a_engine->cur_payload_map->codec_ms); + switch_channel_set_variable_printf(session->channel, "rtp_use_codec_channels", "%d", a_engine->cur_payload_map->channels); + switch_channel_set_variable_printf(session->channel, "rtp_last_audio_codec_string", "%s@%dh@%di@%dc", + a_engine->cur_payload_map->iananame, a_engine->cur_payload_map->rm_rate, a_engine->cur_payload_map->codec_ms, a_engine->cur_payload_map->channels); switch_assert(a_engine->read_codec.implementation); switch_assert(a_engine->write_codec.implementation); @@ -2345,7 +2352,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_set_codec(switch_core_session_ a_engine->cur_payload_map->codec_ms, a_engine->read_impl.samples_per_packet, a_engine->read_impl.bits_per_second); a_engine->read_frame.codec = &a_engine->read_codec; - + a_engine->read_frame.channels = a_engine->read_impl.number_of_channels; a_engine->write_codec.agreed_pt = a_engine->cur_payload_map->agreed_pt; a_engine->read_codec.agreed_pt = a_engine->cur_payload_map->agreed_pt; @@ -3066,6 +3073,10 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s reneg = 0; } + if (switch_channel_test_flag(session->channel, CF_RECOVERING)) { + reneg = 0; + } + if (!reneg && smh->num_negotiated_codecs) { codec_array = smh->negotiated_codecs; total_codecs = smh->num_negotiated_codecs; @@ -3520,6 +3531,7 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s matches[j].map->rm_pt, matches[j].imp->samples_per_second, matches[j].imp->microseconds_per_packet / 1000, + matches[j].imp->number_of_channels, SWITCH_TRUE); mimp = matches[j].imp; mmap = matches[j].map; @@ -3789,6 +3801,7 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s matches[j].map->rm_pt, matches[j].imp->samples_per_second, matches[j].imp->microseconds_per_packet / 1000, + matches[j].imp->number_of_channels, SWITCH_TRUE); if (j == 0) { v_engine->cur_payload_map = pmap; @@ -6137,7 +6150,6 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess smh->ianacodes[i] = (switch_payload_t)smh->payload_space++; } } - switch_core_media_add_payload_map(session, imp->codec_type == SWITCH_CODEC_TYPE_AUDIO ? SWITCH_MEDIA_TYPE_AUDIO : SWITCH_MEDIA_TYPE_VIDEO, @@ -6147,6 +6159,7 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess smh->ianacodes[i], imp->samples_per_second, imp->microseconds_per_packet / 1000, + imp->number_of_channels, SWITCH_FALSE); } @@ -8125,7 +8138,7 @@ SWITCH_DECLARE(void) switch_core_media_set_sdp_codec_string(switch_core_session_ static void add_audio_codec(sdp_rtpmap_t *map, int ptime, char *buf, switch_size_t buflen) { int codec_ms = ptime; - uint32_t map_bit_rate = 0; + uint32_t map_bit_rate = 0, map_channels = 1; char ptstr[20] = ""; char ratestr[20] = ""; char bitstr[20] = ""; @@ -8135,6 +8148,7 @@ static void add_audio_codec(sdp_rtpmap_t *map, int ptime, char *buf, switch_size codec_ms = switch_default_ptime(map->rm_encoding, map->rm_pt); } + map_channels = map->rm_params ? atoi(map->rm_params) : 1; map_bit_rate = switch_known_bitrate((switch_payload_t)map->rm_pt); if (!ptime && !strcasecmp(map->rm_encoding, "g723")) { @@ -8172,6 +8186,10 @@ static void add_audio_codec(sdp_rtpmap_t *map, int ptime, char *buf, switch_size switch_snprintf(bitstr, sizeof(bitstr), "@%db", map_bit_rate); } + if (map_channels > 1) { + switch_snprintf(bitstr, sizeof(bitstr), "@%dc", map_channels); + } + switch_snprintf(buf + strlen(buf), buflen - strlen(buf), ",%s%s%s%s", map->rm_encoding, ratestr, ptstr, bitstr); } @@ -8257,6 +8275,7 @@ static void switch_core_media_set_r_sdp_codec_string(switch_core_session_t *sess map->rm_pt, map->rm_rate, ptime, + map->rm_params ? atoi(map->rm_params) : 1, SWITCH_FALSE); } } @@ -8355,6 +8374,7 @@ static void switch_core_media_set_r_sdp_codec_string(switch_core_session_t *sess } for (i = 0; i < num_codecs; i++) { const switch_codec_implementation_t *imp = codecs[i]; + int channels; if (imp->codec_type != SWITCH_CODEC_TYPE_VIDEO || imp->ianacode > 127 || already_did[imp->ianacode]) { continue; @@ -8381,11 +8401,12 @@ static void switch_core_media_set_r_sdp_codec_string(switch_core_session_t *sess } if (match) { + channels = map->rm_params ? atoi(map->rm_params) : 1; if (ptime > 0) { - switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ",%s@%uh@%di", imp->iananame, (unsigned int) map->rm_rate, - ptime); + switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ",%s@%uh@%di@%dc", imp->iananame, (unsigned int) map->rm_rate, + ptime, channels); } else { - switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ",%s@%uh", imp->iananame, (unsigned int) map->rm_rate); + switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ",%s@%uh@%dc", imp->iananame, (unsigned int) map->rm_rate, channels); } already_did[imp->ianacode] = 1; break; @@ -8611,6 +8632,10 @@ SWITCH_DECLARE (void) switch_core_media_recover_session(switch_core_session_t *s a_engine->cur_payload_map->codec_ms = atoi(tmp); } + if ((tmp = switch_channel_get_variable(session->channel, "rtp_use_codec_channels"))) { + a_engine->cur_payload_map->channels = atoi(tmp); + } + if ((tmp = switch_channel_get_variable(session->channel, "rtp_use_pt"))) { a_engine->cur_payload_map->pt = a_engine->cur_payload_map->agreed_pt = (switch_payload_t)atoi(tmp); } @@ -8618,8 +8643,8 @@ SWITCH_DECLARE (void) switch_core_media_recover_session(switch_core_session_t *s if ((tmp = switch_channel_get_variable(session->channel, "rtp_audio_recv_pt"))) { a_engine->cur_payload_map->recv_pt = (switch_payload_t)atoi(tmp); } - - switch_core_media_set_codec(session, 1, smh->mparams->codec_flags); + + switch_core_media_set_codec(session, 0, smh->mparams->codec_flags); a_engine->adv_sdp_ip = smh->mparams->extrtpip = (char *) ip; a_engine->adv_sdp_port = a_engine->local_sdp_port = (switch_port_t)atoi(port); diff --git a/src/switch_ivr_async.c b/src/switch_ivr_async.c index ea034e8e50..ff87e35ed6 100644 --- a/src/switch_ivr_async.c +++ b/src/switch_ivr_async.c @@ -761,7 +761,7 @@ static switch_bool_t write_displace_callback(switch_media_bug_t *bug, void *user len = rframe->samples; if (dh->mux) { - int16_t buf[SWITCH_RECOMMENDED_BUFFER_SIZE / 2]; + int16_t buf[SWITCH_RECOMMENDED_BUFFER_SIZE]; int16_t *fp = rframe->data; uint32_t x; @@ -775,13 +775,12 @@ static switch_bool_t write_displace_callback(switch_media_bug_t *bug, void *user } else { st = switch_core_file_read(&dh->fh, rframe->data, &len); if (len < rframe->samples) { - memset((char *)rframe->data + len * 2, 0, rframe->datalen - len * 2); + memset((char *)rframe->data + len * 2 * dh->fh.channels, 0, (rframe->datalen - len) * 2 * dh->fh.channels); } } rframe->datalen = rframe->samples * 2 * dh->fh.channels; - if (st != SWITCH_STATUS_SUCCESS || len == 0) { if (dh->loop) { uint32_t pos = 0; @@ -845,7 +844,7 @@ static switch_bool_t read_displace_callback(switch_media_bug_t *bug, void *user_ len = rframe->samples; if (dh->mux) { - int16_t buf[SWITCH_RECOMMENDED_BUFFER_SIZE / 2]; + int16_t buf[SWITCH_RECOMMENDED_BUFFER_SIZE]; int16_t *fp = rframe->data; uint32_t x; diff --git a/src/switch_loadable_module.c b/src/switch_loadable_module.c index bd49e877a0..f9bda289f2 100644 --- a/src/switch_loadable_module.c +++ b/src/switch_loadable_module.c @@ -2230,12 +2230,14 @@ SWITCH_DECLARE(int) switch_loadable_module_get_codecs(const switch_codec_impleme } -SWITCH_DECLARE(char *) switch_parse_codec_buf(char *buf, uint32_t *interval, uint32_t *rate, uint32_t *bit) +SWITCH_DECLARE(char *) switch_parse_codec_buf(char *buf, uint32_t *interval, uint32_t *rate, uint32_t *bit, uint32_t *channels) { char *cur, *next = NULL, *name, *p; name = next = cur = buf; + *channels = 1; + for (;;) { if (!next) { break; @@ -2253,8 +2255,10 @@ SWITCH_DECLARE(char *) switch_parse_codec_buf(char *buf, uint32_t *interval, uin *rate = atoi(cur); } else if (strchr(cur, 'b')) { *bit = atoi(cur); + } else if (strchr(cur, 'c')) { + *channels = atoi(cur); } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Bad syntax for codec string. Missing qualifier [h|k|i|b] for part [%s]!\n", cur); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Bad syntax for codec string. Missing qualifier [h|k|i|b|c] for part [%s]!\n", cur); } } cur = next; @@ -2273,15 +2277,15 @@ SWITCH_DECLARE(int) switch_loadable_module_get_codecs_sorted(const switch_codec_ for (x = 0; x < preflen; x++) { char *name, buf[256], jbuf[256]; - uint32_t interval = 0, rate = 0, bit = 0; + uint32_t interval = 0, rate = 0, bit = 0, channels = 1; switch_copy_string(buf, prefs[x], sizeof(buf)); - name = switch_parse_codec_buf(buf, &interval, &rate, &bit); + name = switch_parse_codec_buf(buf, &interval, &rate, &bit, &channels); for(j = 0; j < x; j++) { char *jname; - uint32_t jinterval = 0, jrate = 0, jbit = 0; - uint32_t ointerval = interval, orate = rate; + uint32_t jinterval = 0, jrate = 0, jbit = 0, jchannels = 1; + uint32_t ointerval = interval, orate = rate, ochannels = channels; if (ointerval == 0) { ointerval = switch_default_ptime(name, 0); @@ -2291,8 +2295,12 @@ SWITCH_DECLARE(int) switch_loadable_module_get_codecs_sorted(const switch_codec_ orate = switch_default_rate(name, 0); } + if (ochannels == 0) { + ochannels = 1; + } + switch_copy_string(jbuf, prefs[j], sizeof(jbuf)); - jname = switch_parse_codec_buf(jbuf, &jinterval, &jrate, &jbit); + jname = switch_parse_codec_buf(jbuf, &jinterval, &jrate, &jbit, &jchannels); if (jinterval == 0) { jinterval = switch_default_ptime(jname, 0); @@ -2302,7 +2310,11 @@ SWITCH_DECLARE(int) switch_loadable_module_get_codecs_sorted(const switch_codec_ jrate = switch_default_rate(jname, 0); } - if (!strcasecmp(name, jname) && ointerval == jinterval && orate == jrate) { + if (jchannels == 0) { + jchannels = 1; + } + + if (!strcasecmp(name, jname) && ointerval == jinterval && orate == jrate && ochannels == jchannels) { goto next_x; } } @@ -2320,7 +2332,7 @@ SWITCH_DECLARE(int) switch_loadable_module_get_codecs_sorted(const switch_codec_ (interval && (uint32_t) (imp->microseconds_per_packet / 1000) != interval)) { continue; } - + if (((!rate && crate != default_rate) || (rate && (uint32_t) imp->actual_samples_per_second != rate))) { continue; } @@ -2329,6 +2341,9 @@ SWITCH_DECLARE(int) switch_loadable_module_get_codecs_sorted(const switch_codec_ continue; } + if (channels && imp->number_of_channels != channels) { + continue; + } } @@ -2353,7 +2368,10 @@ SWITCH_DECLARE(int) switch_loadable_module_get_codecs_sorted(const switch_codec_ if (bit && (uint32_t) imp->bits_per_second != bit) { continue; } - + + if (channels && imp->number_of_channels != channels) { + continue; + } } array[i++] = imp; From 33541dcfd9fac10c139965de9040aebde873d3a2 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Fri, 13 Jun 2014 03:02:09 -0400 Subject: [PATCH 039/231] add logging --- src/mod/endpoints/mod_verto/mod_verto.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/mod/endpoints/mod_verto/mod_verto.c b/src/mod/endpoints/mod_verto/mod_verto.c index 748c98067c..5c85427052 100644 --- a/src/mod/endpoints/mod_verto/mod_verto.c +++ b/src/mod/endpoints/mod_verto/mod_verto.c @@ -92,6 +92,10 @@ static void json_cleanup(void) const void *var; cJSON *json; + if (!json_GLOBALS.store_hash) { + return; + } + switch_mutex_lock(json_GLOBALS.store_mutex); top: @@ -963,6 +967,9 @@ static void tech_reattach(verto_pvt_t *tech_pvt, jsock_t *jsock) switch_set_flag(tech_pvt, TFLAG_ATTACH_REQ); msg = jrpc_new_req("verto.attach", tech_pvt->call_id, ¶ms); cJSON_AddItemToObject(params, "sdp", cJSON_CreateString(tech_pvt->mparams->local_sdp_str)); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "Local attach SDP %s:\n%s\n", + switch_channel_get_name(tech_pvt->channel), + tech_pvt->mparams->local_sdp_str); set_call_params(params, tech_pvt); ws_write_json(jsock, &msg, SWITCH_TRUE); } From 4e5ecdf9957f89bd3aca9441155ad308d4462482 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Fri, 13 Jun 2014 03:02:12 -0400 Subject: [PATCH 040/231] only run plc on mono channels --- src/switch_core_io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/switch_core_io.c b/src/switch_core_io.c index bb99c3eb39..1c2d0dbf14 100644 --- a/src/switch_core_io.c +++ b/src/switch_core_io.c @@ -576,7 +576,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_frame(switch_core_sessi } - if (status == SWITCH_STATUS_SUCCESS) { + if (status == SWITCH_STATUS_SUCCESS && session->read_impl.number_of_channels == 1) { if ((switch_channel_test_flag(session->channel, CF_JITTERBUFFER_PLC) || switch_channel_test_flag(session->channel, CF_CNG_PLC)) && !session->plc) { session->plc = plc_init(NULL); From 41cea5c75145306c61de0b5ab1116edd83f44dc8 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Fri, 13 Jun 2014 05:01:37 -0400 Subject: [PATCH 041/231] remove debug --- src/mod/codecs/mod_opus/mod_opus.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/mod/codecs/mod_opus/mod_opus.c b/src/mod/codecs/mod_opus/mod_opus.c index 62ab8dbcbc..5a9593463f 100644 --- a/src/mod/codecs/mod_opus/mod_opus.c +++ b/src/mod/codecs/mod_opus/mod_opus.c @@ -266,8 +266,6 @@ static switch_status_t switch_opus_init(switch_codec_t *codec, switch_codec_flag switch_opus_fmtp_parse(codec->fmtp_in, &codec_fmtp); codec->fmtp_out = gen_fmtp(&opus_codec_settings, codec->memory_pool); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "OPUS init %d %d\n", codec->implementation->actual_samples_per_second, codec->implementation->number_of_channels); - if (encoding) { /* come up with a way to specify these */ int bitrate_bps = OPUS_AUTO; From c375e336bc21ff9c09646a6449d70120399e1ac3 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Fri, 13 Jun 2014 06:06:14 -0400 Subject: [PATCH 042/231] add debugging --- src/include/switch_core_media.h | 4 +- src/mod/endpoints/mod_verto/mod_verto.c | 1 + src/switch_core_media.c | 130 ++++++++++++++++++------ src/switch_rtp.c | 45 ++++++-- 4 files changed, 140 insertions(+), 40 deletions(-) diff --git a/src/include/switch_core_media.h b/src/include/switch_core_media.h index 0de6a28859..1dfc4688c9 100644 --- a/src/include/switch_core_media.h +++ b/src/include/switch_core_media.h @@ -243,7 +243,9 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_codec_chosen(switch_core_sessi SWITCH_DECLARE (void) switch_core_media_recover_session(switch_core_session_t *session); SWITCH_DECLARE(switch_status_t) switch_core_media_add_ice_acl(switch_core_session_t *session, switch_media_type_t type, const char *acl_name); SWITCH_DECLARE(void) switch_core_session_set_ice(switch_core_session_t *session); - +SWITCH_DECLARE(void) switch_core_media_clear_ice(switch_core_session_t *session); +SWITCH_DECLARE(void) switch_core_media_pause(switch_core_session_t *session); +SWITCH_DECLARE(void) switch_core_media_resume(switch_core_session_t *session); SWITCH_DECLARE(void) switch_core_media_init(void); SWITCH_DECLARE(void) switch_core_media_deinit(void); SWITCH_DECLARE(void) switch_core_media_set_stats(switch_core_session_t *session); diff --git a/src/mod/endpoints/mod_verto/mod_verto.c b/src/mod/endpoints/mod_verto/mod_verto.c index 5c85427052..2a8662615e 100644 --- a/src/mod/endpoints/mod_verto/mod_verto.c +++ b/src/mod/endpoints/mod_verto/mod_verto.c @@ -2379,6 +2379,7 @@ static switch_bool_t verto__attach_func(const char *method, cJSON *params, jsock switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Remote SDP %s:\n%s\n", switch_channel_get_name(tech_pvt->channel), tech_pvt->r_sdp); + switch_core_media_clear_ice(tech_pvt->session); switch_channel_set_flag(tech_pvt->channel, CF_REINVITE); if ((match = switch_core_media_negotiate_sdp(tech_pvt->session, tech_pvt->r_sdp, &p, SDP_TYPE_RESPONSE))) { diff --git a/src/switch_core_media.c b/src/switch_core_media.c index 0bbef216b4..f2eaa03cd0 100644 --- a/src/switch_core_media.c +++ b/src/switch_core_media.c @@ -2376,6 +2376,81 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_set_codec(switch_core_session_ return status; } +static void clear_ice(switch_core_session_t *session, switch_media_type_t type) +{ + switch_media_handle_t *smh; + switch_rtp_engine_t *engine; + + switch_assert(session); + + if (!(smh = session->media_handle)) { + return; + } + + engine = &smh->engines[type]; + + engine->ice_in.chosen[0] = 0; + engine->ice_in.chosen[1] = 0; + engine->ice_in.cand_idx = 0; + memset(&engine->ice_in, 0, sizeof(engine->ice_in)); + engine->remote_rtcp_port = 0; + +} + +//? +SWITCH_DECLARE(void) switch_core_media_clear_ice(switch_core_session_t *session) +{ + clear_ice(session, SWITCH_MEDIA_TYPE_AUDIO); + clear_ice(session, SWITCH_MEDIA_TYPE_VIDEO); + +} + +SWITCH_DECLARE(void) switch_core_media_pause(switch_core_session_t *session) +{ + switch_rtp_engine_t *a_engine, *v_engine; + switch_media_handle_t *smh; + + switch_assert(session); + + if (!(smh = session->media_handle)) { + return; + } + + a_engine = &smh->engines[SWITCH_MEDIA_TYPE_AUDIO]; + v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO]; + + if (a_engine->rtp_session) { + switch_rtp_set_flag(a_engine->rtp_session, SWITCH_RTP_FLAG_PAUSE); + } + + if (v_engine->rtp_session) { + switch_rtp_set_flag(v_engine->rtp_session, SWITCH_RTP_FLAG_PAUSE); + } +} + +SWITCH_DECLARE(void) switch_core_media_resume(switch_core_session_t *session) +{ + switch_rtp_engine_t *a_engine, *v_engine; + switch_media_handle_t *smh; + + switch_assert(session); + + if (!(smh = session->media_handle)) { + return; + } + + a_engine = &smh->engines[SWITCH_MEDIA_TYPE_AUDIO]; + v_engine = &smh->engines[SWITCH_MEDIA_TYPE_VIDEO]; + + if (a_engine->rtp_session) { + switch_rtp_clear_flag(a_engine->rtp_session, SWITCH_RTP_FLAG_PAUSE); + } + + if (v_engine->rtp_session) { + switch_rtp_clear_flag(v_engine->rtp_session, SWITCH_RTP_FLAG_PAUSE); + } +} + //? SWITCH_DECLARE(switch_status_t) switch_core_media_add_ice_acl(switch_core_session_t *session, switch_media_type_t type, const char *acl_name) @@ -2748,8 +2823,6 @@ static void check_ice(switch_media_handle_t *smh, switch_media_type_t type, sdp_ engine->rtcp_mux = -1; } - - if (switch_channel_test_flag(smh->session->channel, CF_REINVITE)) { if (switch_rtp_ready(engine->rtp_session) && engine->ice_in.cands[engine->ice_in.chosen[0]][0].ready) { @@ -2781,29 +2854,25 @@ static void check_ice(switch_media_handle_t *smh, switch_media_type_t type, sdp_ "rtcp_video_interval_msec" : "rtcp_audio_interval_msec")) || (val = type == SWITCH_MEDIA_TYPE_VIDEO ? smh->mparams->rtcp_video_interval_msec : smh->mparams->rtcp_audio_interval_msec))) { - - const char *rport = switch_channel_get_variable(smh->session->channel, - type == SWITCH_MEDIA_TYPE_VIDEO ? "rtp_remote_video_rtcp_port" : "rtp_remote_audio_rtcp_port"); + switch_port_t remote_rtcp_port = engine->remote_rtcp_port; - if (!remote_rtcp_port && rport) { - remote_rtcp_port = (switch_port_t)atoi(rport); - } - - if (!strcasecmp(val, "passthru")) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_INFO, "Activating %s RTCP PASSTHRU PORT %d\n", - type2str(type), remote_rtcp_port); - switch_rtp_activate_rtcp(engine->rtp_session, -1, remote_rtcp_port, engine->rtcp_mux > 0); - } else { - int interval = atoi(val); - if (interval < 100 || interval > 500000) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_ERROR, - "Invalid rtcp interval spec [%d] must be between 100 and 500000\n", interval); - interval = 10000; - } + if (remote_rtcp_port) { + if (!strcasecmp(val, "passthru")) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_INFO, "Activating %s RTCP PASSTHRU PORT %d\n", + type2str(type), remote_rtcp_port); + switch_rtp_activate_rtcp(engine->rtp_session, -1, remote_rtcp_port, engine->rtcp_mux > 0); + } else { + int interval = atoi(val); + if (interval < 100 || interval > 500000) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_ERROR, + "Invalid rtcp interval spec [%d] must be between 100 and 500000\n", interval); + interval = 10000; + } - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_INFO, "Activating %s RTCP PORT %d\n", type2str(type), remote_rtcp_port); - switch_rtp_activate_rtcp(engine->rtp_session, interval, remote_rtcp_port, engine->rtcp_mux > 0); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_INFO, "Activating %s RTCP PORT %d\n", type2str(type), remote_rtcp_port); + switch_rtp_activate_rtcp(engine->rtp_session, interval, remote_rtcp_port, engine->rtcp_mux > 0); + } } } @@ -2834,7 +2903,6 @@ static void check_ice(switch_media_handle_t *smh, switch_media_type_t type, sdp_ } } - } #ifdef _MSC_VER #pragma warning(pop) @@ -3855,14 +3923,17 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s if (switch_core_media_set_video_codec(session, 0) == SWITCH_STATUS_SUCCESS) { check_ice(smh, SWITCH_MEDIA_TYPE_VIDEO, sdp, m); } - - } } } done: + + + + + if (parser) { sdp_parser_free(parser); } @@ -5287,10 +5358,10 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi if (!switch_channel_test_flag(session->channel, CF_PROXY_MEDIA)) { if (switch_rtp_ready(v_engine->rtp_session)) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, - "VIDEO RTP [%s] %s port %d -> %s port %d codec: %u ms: %d\n", switch_channel_get_name(session->channel), - a_engine->cur_payload_map->remote_sdp_ip, v_engine->local_sdp_port, v_engine->cur_payload_map->remote_sdp_ip, - v_engine->cur_payload_map->remote_sdp_port, v_engine->cur_payload_map->agreed_pt, - a_engine->read_impl.microseconds_per_packet / 1000); + "VIDEO RTP [%s] %s port %d -> %s port %d codec: %u\n", switch_channel_get_name(session->channel), + v_engine->local_sdp_ip, v_engine->local_sdp_port, v_engine->cur_payload_map->remote_sdp_ip, + v_engine->cur_payload_map->remote_sdp_port, v_engine->cur_payload_map->agreed_pt); + start_video_thread(session); switch_rtp_set_default_payload(v_engine->rtp_session, v_engine->cur_payload_map->agreed_pt); @@ -8692,6 +8763,7 @@ SWITCH_DECLARE (void) switch_core_media_recover_session(switch_core_session_t *s } v_engine->adv_sdp_port = v_engine->local_sdp_port = (switch_port_t)atoi(port); + v_engine->local_sdp_ip = smh->mparams->rtpip; if (r_ip && r_port) { v_engine->cur_payload_map->remote_sdp_ip = (char *) r_ip; diff --git a/src/switch_rtp.c b/src/switch_rtp.c index 9034bb9af7..b68534114c 100644 --- a/src/switch_rtp.c +++ b/src/switch_rtp.c @@ -33,7 +33,7 @@ //#define DEBUG_2833 //#define RTP_DEBUG_WRITE_DELTA //#define DEBUG_MISSED_SEQ - +//#define DEBUG_EXTRA #include #ifndef _MSC_VER #include @@ -1513,9 +1513,17 @@ static void send_fir(switch_rtp_t *rtp_session) #endif #ifdef DEBUG_EXTRA - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_CRIT, "%s SEND %s RTCP %ld\n", - rtp_session_name(rtp_session), - rtp_session->flags[SWITCH_RTP_FLAG_VIDEO] ? "video" : "audio", rtcp_bytes); + { + const char *old_host; + char bufb[30]; + old_host = switch_get_addr(bufb, sizeof(bufb), rtp_session->rtcp_remote_addr); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_CRIT, "%s SEND %s RTCP %s:%d %ld\n", + rtp_session_name(rtp_session), + rtp_session->flags[SWITCH_RTP_FLAG_VIDEO] ? "video" : "audio", + old_host, + switch_sockaddr_get_port(rtp_session->rtcp_remote_addr), + rtcp_bytes); + } #endif if (switch_socket_sendto(rtp_session->rtcp_sock_output, rtp_session->rtcp_remote_addr, 0, (void *)&rtp_session->rtcp_ext_send_msg, &rtcp_bytes ) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG,"RTCP packet not written\n"); @@ -1599,9 +1607,18 @@ static void send_pli(switch_rtp_t *rtp_session) #endif #ifdef DEBUG_EXTRA - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_CRIT, "%s SEND %s RTCP %ld\n", - rtp_session_name(rtp_session), - rtp_session->flags[SWITCH_RTP_FLAG_VIDEO] ? "video" : "audio", rtcp_bytes); + { + const char *old_host; + char bufb[30]; + old_host = switch_get_addr(bufb, sizeof(bufb), rtp_session->rtcp_remote_addr); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_CRIT, "%s SEND %s RTCP %s:%d %ld\n", + rtp_session_name(rtp_session), + rtp_session->flags[SWITCH_RTP_FLAG_VIDEO] ? "video" : "audio", + old_host, + switch_sockaddr_get_port(rtp_session->rtcp_remote_addr), + rtcp_bytes); + } + #endif if (switch_socket_sendto(rtp_session->rtcp_sock_output, rtp_session->rtcp_remote_addr, 0, (void *)&rtp_session->rtcp_ext_send_msg, &rtcp_bytes ) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG,"RTCP packet not written\n"); @@ -1974,9 +1991,17 @@ static int check_rtcp_and_ice(switch_rtp_t *rtp_session) #endif #ifdef DEBUG_EXTRA - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_CRIT, "%s SEND %s RTCP %ld\n", - rtp_session_name(rtp_session), - rtp_session->flags[SWITCH_RTP_FLAG_VIDEO] ? "video" : "audio", rtcp_bytes); + { + const char *old_host; + char bufb[30]; + old_host = switch_get_addr(bufb, sizeof(bufb), rtp_session->rtcp_remote_addr); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_CRIT, "%s SEND %s RTCP %s:%d %ld\n", + rtp_session_name(rtp_session), + rtp_session->flags[SWITCH_RTP_FLAG_VIDEO] ? "video" : "audio", + old_host, + switch_sockaddr_get_port(rtp_session->rtcp_remote_addr), + rtcp_bytes); + } #endif if (switch_socket_sendto(rtp_session->rtcp_sock_output, rtp_session->rtcp_remote_addr, 0, (void *)&rtp_session->rtcp_send_msg, &rtcp_bytes ) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG,"RTCP packet not written\n"); From 950de7fc5c77c55de304a8fca5c38792fd017506 Mon Sep 17 00:00:00 2001 From: Brian West Date: Fri, 13 Jun 2014 07:49:34 -0500 Subject: [PATCH 043/231] reswig --- .../languages/mod_managed/freeswitch_wrap.cxx | 246 ++++++++++++++++-- src/mod/languages/mod_managed/managed/swig.cs | 196 ++++++++++++-- 2 files changed, 399 insertions(+), 43 deletions(-) diff --git a/src/mod/languages/mod_managed/freeswitch_wrap.cxx b/src/mod/languages/mod_managed/freeswitch_wrap.cxx index f200f1a4f8..b9e57c42f9 100644 --- a/src/mod/languages/mod_managed/freeswitch_wrap.cxx +++ b/src/mod/languages/mod_managed/freeswitch_wrap.cxx @@ -8044,6 +8044,72 @@ SWIGEXPORT unsigned long SWIGSTDCALL CSharp_switch_device_stats_t_held_out_get(v } +SWIGEXPORT void SWIGSTDCALL CSharp_switch_device_stats_t_unheld_set(void * jarg1, unsigned long jarg2) { + switch_device_stats_s *arg1 = (switch_device_stats_s *) 0 ; + uint32_t arg2 ; + + arg1 = (switch_device_stats_s *)jarg1; + arg2 = (uint32_t)jarg2; + if (arg1) (arg1)->unheld = arg2; +} + + +SWIGEXPORT unsigned long SWIGSTDCALL CSharp_switch_device_stats_t_unheld_get(void * jarg1) { + unsigned long jresult ; + switch_device_stats_s *arg1 = (switch_device_stats_s *) 0 ; + uint32_t result; + + arg1 = (switch_device_stats_s *)jarg1; + result = (uint32_t) ((arg1)->unheld); + jresult = (unsigned long)result; + return jresult; +} + + +SWIGEXPORT void SWIGSTDCALL CSharp_switch_device_stats_t_unheld_in_set(void * jarg1, unsigned long jarg2) { + switch_device_stats_s *arg1 = (switch_device_stats_s *) 0 ; + uint32_t arg2 ; + + arg1 = (switch_device_stats_s *)jarg1; + arg2 = (uint32_t)jarg2; + if (arg1) (arg1)->unheld_in = arg2; +} + + +SWIGEXPORT unsigned long SWIGSTDCALL CSharp_switch_device_stats_t_unheld_in_get(void * jarg1) { + unsigned long jresult ; + switch_device_stats_s *arg1 = (switch_device_stats_s *) 0 ; + uint32_t result; + + arg1 = (switch_device_stats_s *)jarg1; + result = (uint32_t) ((arg1)->unheld_in); + jresult = (unsigned long)result; + return jresult; +} + + +SWIGEXPORT void SWIGSTDCALL CSharp_switch_device_stats_t_unheld_out_set(void * jarg1, unsigned long jarg2) { + switch_device_stats_s *arg1 = (switch_device_stats_s *) 0 ; + uint32_t arg2 ; + + arg1 = (switch_device_stats_s *)jarg1; + arg2 = (uint32_t)jarg2; + if (arg1) (arg1)->unheld_out = arg2; +} + + +SWIGEXPORT unsigned long SWIGSTDCALL CSharp_switch_device_stats_t_unheld_out_get(void * jarg1) { + unsigned long jresult ; + switch_device_stats_s *arg1 = (switch_device_stats_s *) 0 ; + uint32_t result; + + arg1 = (switch_device_stats_s *)jarg1; + result = (uint32_t) ((arg1)->unheld_out); + jresult = (unsigned long)result; + return jresult; +} + + SWIGEXPORT void SWIGSTDCALL CSharp_switch_device_stats_t_hup_set(void * jarg1, unsigned long jarg2) { switch_device_stats_s *arg1 = (switch_device_stats_s *) 0 ; uint32_t arg2 ; @@ -11936,17 +12002,19 @@ SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_hash_destroy(void * jarg1) { } -SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_hash_insert(void * jarg1, char * jarg2, void * jarg3) { +SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_hash_insert_destructor(void * jarg1, char * jarg2, void * jarg3, void * jarg4) { int jresult ; switch_hash_t *arg1 = (switch_hash_t *) 0 ; char *arg2 = (char *) 0 ; void *arg3 = (void *) 0 ; + hashtable_destructor_t arg4 = (hashtable_destructor_t) 0 ; switch_status_t result; arg1 = (switch_hash_t *)jarg1; arg2 = (char *)jarg2; arg3 = (void *)jarg3; - result = (switch_status_t)switch_core_hash_insert(arg1,(char const *)arg2,(void const *)arg3); + arg4 = (hashtable_destructor_t)jarg4; + result = (switch_status_t)switch_core_hash_insert_destructor(arg1,(char const *)arg2,(void const *)arg3,arg4); jresult = result; return jresult; } @@ -12849,15 +12917,16 @@ SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_file_truncate(void * jarg1, long l } -SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_speech_open(void * jarg1, char * jarg2, char * jarg3, unsigned int jarg4, unsigned int jarg5, void * jarg6, void * jarg7) { +SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_speech_open(void * jarg1, char * jarg2, char * jarg3, unsigned int jarg4, unsigned int jarg5, unsigned int jarg6, void * jarg7, void * jarg8) { int jresult ; switch_speech_handle_t *arg1 = (switch_speech_handle_t *) 0 ; char *arg2 = (char *) 0 ; char *arg3 = (char *) 0 ; unsigned int arg4 ; unsigned int arg5 ; - switch_speech_flag_t *arg6 = (switch_speech_flag_t *) 0 ; - switch_memory_pool_t *arg7 = (switch_memory_pool_t *) 0 ; + unsigned int arg6 ; + switch_speech_flag_t *arg7 = (switch_speech_flag_t *) 0 ; + switch_memory_pool_t *arg8 = (switch_memory_pool_t *) 0 ; switch_status_t result; arg1 = (switch_speech_handle_t *)jarg1; @@ -12865,9 +12934,10 @@ SWIGEXPORT int SWIGSTDCALL CSharp_switch_core_speech_open(void * jarg1, char * j arg3 = (char *)jarg3; arg4 = (unsigned int)jarg4; arg5 = (unsigned int)jarg5; - arg6 = (switch_speech_flag_t *)jarg6; - arg7 = (switch_memory_pool_t *)jarg7; - result = (switch_status_t)switch_core_speech_open(arg1,(char const *)arg2,(char const *)arg3,arg4,arg5,arg6,arg7); + arg6 = (unsigned int)jarg6; + arg7 = (switch_speech_flag_t *)jarg7; + arg8 = (switch_memory_pool_t *)jarg8; + result = (switch_status_t)switch_core_speech_open(arg1,(char const *)arg2,(char const *)arg3,arg4,arg5,arg6,arg7,arg8); jresult = result; return jresult; } @@ -15899,19 +15969,21 @@ SWIGEXPORT void * SWIGSTDCALL CSharp_switch_loadable_module_get_codec_interface( } -SWIGEXPORT char * SWIGSTDCALL CSharp_switch_parse_codec_buf(char * jarg1, void * jarg2, void * jarg3, void * jarg4) { +SWIGEXPORT char * SWIGSTDCALL CSharp_switch_parse_codec_buf(char * jarg1, void * jarg2, void * jarg3, void * jarg4, void * jarg5) { char * jresult ; char *arg1 = (char *) 0 ; uint32_t *arg2 = (uint32_t *) 0 ; uint32_t *arg3 = (uint32_t *) 0 ; uint32_t *arg4 = (uint32_t *) 0 ; + uint32_t *arg5 = (uint32_t *) 0 ; char *result = 0 ; arg1 = (char *)jarg1; arg2 = (uint32_t *)jarg2; arg3 = (uint32_t *)jarg3; arg4 = (uint32_t *)jarg4; - result = (char *)switch_parse_codec_buf(arg1,arg2,arg3,arg4); + arg5 = (uint32_t *)jarg5; + result = (char *)switch_parse_codec_buf(arg1,arg2,arg3,arg4,arg5); jresult = SWIG_csharp_string_callback((const char *)result); return jresult; } @@ -20235,6 +20307,28 @@ SWIGEXPORT unsigned long SWIGSTDCALL CSharp_switch_frame_rate_get(void * jarg1) } +SWIGEXPORT void SWIGSTDCALL CSharp_switch_frame_channels_set(void * jarg1, unsigned long jarg2) { + switch_frame *arg1 = (switch_frame *) 0 ; + uint32_t arg2 ; + + arg1 = (switch_frame *)jarg1; + arg2 = (uint32_t)jarg2; + if (arg1) (arg1)->channels = arg2; +} + + +SWIGEXPORT unsigned long SWIGSTDCALL CSharp_switch_frame_channels_get(void * jarg1) { + unsigned long jresult ; + switch_frame *arg1 = (switch_frame *) 0 ; + uint32_t result; + + arg1 = (switch_frame *)jarg1; + result = (uint32_t) ((arg1)->channels); + jresult = (unsigned long)result; + return jresult; +} + + SWIGEXPORT void SWIGSTDCALL CSharp_switch_frame_payload_set(void * jarg1, unsigned char jarg2) { switch_frame *arg1 = (switch_frame *) 0 ; switch_payload_t arg2 ; @@ -22807,6 +22901,28 @@ SWIGEXPORT unsigned long SWIGSTDCALL CSharp_switch_file_handle_channels_get(void } +SWIGEXPORT void SWIGSTDCALL CSharp_switch_file_handle_real_channels_set(void * jarg1, unsigned long jarg2) { + switch_file_handle *arg1 = (switch_file_handle *) 0 ; + uint32_t arg2 ; + + arg1 = (switch_file_handle *)jarg1; + arg2 = (uint32_t)jarg2; + if (arg1) (arg1)->real_channels = arg2; +} + + +SWIGEXPORT unsigned long SWIGSTDCALL CSharp_switch_file_handle_real_channels_get(void * jarg1) { + unsigned long jresult ; + switch_file_handle *arg1 = (switch_file_handle *) 0 ; + uint32_t result; + + arg1 = (switch_file_handle *)jarg1; + result = (uint32_t) ((arg1)->real_channels); + jresult = (unsigned long)result; + return jresult; +} + + SWIGEXPORT void SWIGSTDCALL CSharp_switch_file_handle_format_set(void * jarg1, unsigned int jarg2) { switch_file_handle *arg1 = (switch_file_handle *) 0 ; unsigned int arg2 ; @@ -24662,10 +24778,10 @@ SWIGEXPORT char * SWIGSTDCALL CSharp_switch_speech_interface_interface_name_get( SWIGEXPORT void SWIGSTDCALL CSharp_switch_speech_interface_speech_open_set(void * jarg1, void * jarg2) { switch_speech_interface *arg1 = (switch_speech_interface *) 0 ; - switch_status_t (*arg2)(switch_speech_handle_t *,char const *,int,switch_speech_flag_t *) = (switch_status_t (*)(switch_speech_handle_t *,char const *,int,switch_speech_flag_t *)) 0 ; + switch_status_t (*arg2)(switch_speech_handle_t *,char const *,int,int,switch_speech_flag_t *) = (switch_status_t (*)(switch_speech_handle_t *,char const *,int,int,switch_speech_flag_t *)) 0 ; arg1 = (switch_speech_interface *)jarg1; - arg2 = (switch_status_t (*)(switch_speech_handle_t *,char const *,int,switch_speech_flag_t *))jarg2; + arg2 = (switch_status_t (*)(switch_speech_handle_t *,char const *,int,int,switch_speech_flag_t *))jarg2; if (arg1) (arg1)->speech_open = arg2; } @@ -24673,10 +24789,10 @@ SWIGEXPORT void SWIGSTDCALL CSharp_switch_speech_interface_speech_open_set(void SWIGEXPORT void * SWIGSTDCALL CSharp_switch_speech_interface_speech_open_get(void * jarg1) { void * jresult ; switch_speech_interface *arg1 = (switch_speech_interface *) 0 ; - switch_status_t (*result)(switch_speech_handle_t *,char const *,int,switch_speech_flag_t *) = 0 ; + switch_status_t (*result)(switch_speech_handle_t *,char const *,int,int,switch_speech_flag_t *) = 0 ; arg1 = (switch_speech_interface *)jarg1; - result = (switch_status_t (*)(switch_speech_handle_t *,char const *,int,switch_speech_flag_t *)) ((arg1)->speech_open); + result = (switch_status_t (*)(switch_speech_handle_t *,char const *,int,int,switch_speech_flag_t *)) ((arg1)->speech_open); jresult = (void *)result; return jresult; } @@ -25104,6 +25220,50 @@ SWIGEXPORT unsigned long SWIGSTDCALL CSharp_switch_speech_handle_samples_get(voi } +SWIGEXPORT void SWIGSTDCALL CSharp_switch_speech_handle_channels_set(void * jarg1, unsigned long jarg2) { + switch_speech_handle *arg1 = (switch_speech_handle *) 0 ; + uint32_t arg2 ; + + arg1 = (switch_speech_handle *)jarg1; + arg2 = (uint32_t)jarg2; + if (arg1) (arg1)->channels = arg2; +} + + +SWIGEXPORT unsigned long SWIGSTDCALL CSharp_switch_speech_handle_channels_get(void * jarg1) { + unsigned long jresult ; + switch_speech_handle *arg1 = (switch_speech_handle *) 0 ; + uint32_t result; + + arg1 = (switch_speech_handle *)jarg1; + result = (uint32_t) ((arg1)->channels); + jresult = (unsigned long)result; + return jresult; +} + + +SWIGEXPORT void SWIGSTDCALL CSharp_switch_speech_handle_real_channels_set(void * jarg1, unsigned long jarg2) { + switch_speech_handle *arg1 = (switch_speech_handle *) 0 ; + uint32_t arg2 ; + + arg1 = (switch_speech_handle *)jarg1; + arg2 = (uint32_t)jarg2; + if (arg1) (arg1)->real_channels = arg2; +} + + +SWIGEXPORT unsigned long SWIGSTDCALL CSharp_switch_speech_handle_real_channels_get(void * jarg1) { + unsigned long jresult ; + switch_speech_handle *arg1 = (switch_speech_handle *) 0 ; + uint32_t result; + + arg1 = (switch_speech_handle *)jarg1; + result = (uint32_t) ((arg1)->real_channels); + jresult = (unsigned long)result; + return jresult; +} + + SWIGEXPORT void SWIGSTDCALL CSharp_switch_speech_handle_voice_set(void * jarg1, char * jarg2) { switch_speech_handle *arg1 = (switch_speech_handle *) 0 ; char *arg2 ; @@ -26720,6 +26880,28 @@ SWIGEXPORT int SWIGSTDCALL CSharp_switch_codec_fmtp_microseconds_per_packet_get( } +SWIGEXPORT void SWIGSTDCALL CSharp_switch_codec_fmtp_stereo_set(void * jarg1, int jarg2) { + switch_codec_fmtp *arg1 = (switch_codec_fmtp *) 0 ; + int arg2 ; + + arg1 = (switch_codec_fmtp *)jarg1; + arg2 = (int)jarg2; + if (arg1) (arg1)->stereo = arg2; +} + + +SWIGEXPORT int SWIGSTDCALL CSharp_switch_codec_fmtp_stereo_get(void * jarg1) { + int jresult ; + switch_codec_fmtp *arg1 = (switch_codec_fmtp *) 0 ; + int result; + + arg1 = (switch_codec_fmtp *)jarg1; + result = (int) ((arg1)->stereo); + jresult = result; + return jresult; +} + + SWIGEXPORT void SWIGSTDCALL CSharp_switch_codec_fmtp_private_info_set(void * jarg1, void * jarg2) { switch_codec_fmtp *arg1 = (switch_codec_fmtp *) 0 ; void *arg2 = (void *) 0 ; @@ -33404,6 +33586,28 @@ SWIGEXPORT unsigned long SWIGSTDCALL CSharp_switch_audio_resampler_t_to_size_get } +SWIGEXPORT void SWIGSTDCALL CSharp_switch_audio_resampler_t_channels_set(void * jarg1, int jarg2) { + switch_audio_resampler_t *arg1 = (switch_audio_resampler_t *) 0 ; + int arg2 ; + + arg1 = (switch_audio_resampler_t *)jarg1; + arg2 = (int)jarg2; + if (arg1) (arg1)->channels = arg2; +} + + +SWIGEXPORT int SWIGSTDCALL CSharp_switch_audio_resampler_t_channels_get(void * jarg1) { + int jresult ; + switch_audio_resampler_t *arg1 = (switch_audio_resampler_t *) 0 ; + int result; + + arg1 = (switch_audio_resampler_t *)jarg1; + result = (int) ((arg1)->channels); + jresult = result; + return jresult; +} + + SWIGEXPORT void * SWIGSTDCALL CSharp_new_switch_audio_resampler_t() { void * jresult ; switch_audio_resampler_t *result = 0 ; @@ -33554,15 +33758,17 @@ SWIGEXPORT void SWIGSTDCALL CSharp_switch_swap_linear(void * jarg1, int jarg2) { } -SWIGEXPORT void SWIGSTDCALL CSharp_switch_generate_sln_silence(void * jarg1, unsigned long jarg2, unsigned long jarg3) { +SWIGEXPORT void SWIGSTDCALL CSharp_switch_generate_sln_silence(void * jarg1, unsigned long jarg2, unsigned long jarg3, unsigned long jarg4) { int16_t *arg1 = (int16_t *) 0 ; uint32_t arg2 ; uint32_t arg3 ; + uint32_t arg4 ; arg1 = (int16_t *)jarg1; arg2 = (uint32_t)jarg2; arg3 = (uint32_t)jarg3; - switch_generate_sln_silence(arg1,arg2,arg3); + arg4 = (uint32_t)jarg4; + switch_generate_sln_silence(arg1,arg2,arg3,arg4); } @@ -33626,10 +33832,11 @@ SWIGEXPORT unsigned long SWIGSTDCALL CSharp_switch_unmerge_sln(void * jarg1, uns } -SWIGEXPORT void SWIGSTDCALL CSharp_switch_mux_channels(void * jarg1, void * jarg2, unsigned long jarg3) { +SWIGEXPORT void SWIGSTDCALL CSharp_switch_mux_channels(void * jarg1, void * jarg2, unsigned long jarg3, unsigned long jarg4) { int16_t *arg1 = (int16_t *) 0 ; switch_size_t arg2 ; uint32_t arg3 ; + uint32_t arg4 ; switch_size_t *argp2 ; arg1 = (int16_t *)jarg1; @@ -33640,7 +33847,8 @@ SWIGEXPORT void SWIGSTDCALL CSharp_switch_mux_channels(void * jarg1, void * jarg } arg2 = *argp2; arg3 = (uint32_t)jarg3; - switch_mux_channels(arg1,arg2,arg3); + arg4 = (uint32_t)jarg4; + switch_mux_channels(arg1,arg2,arg3,arg4); } @@ -34408,7 +34616,7 @@ SWIGEXPORT int SWIGSTDCALL CSharp_switch_ivr_detect_speech_load_grammar(void * j arg1 = (switch_core_session_t *)jarg1; arg2 = (char *)jarg2; arg3 = (char *)jarg3; - result = (switch_status_t)switch_ivr_detect_speech_load_grammar(arg1,arg2,arg3); + result = (switch_status_t)switch_ivr_detect_speech_load_grammar(arg1,(char const *)arg2,(char const *)arg3); jresult = result; return jresult; } diff --git a/src/mod/languages/mod_managed/managed/swig.cs b/src/mod/languages/mod_managed/managed/swig.cs index c0ed651a48..14f55d9848 100644 --- a/src/mod/languages/mod_managed/managed/swig.cs +++ b/src/mod/languages/mod_managed/managed/swig.cs @@ -2078,8 +2078,8 @@ public class freeswitch { return ret; } - public static switch_status_t switch_core_hash_insert(SWIGTYPE_p_switch_hashtable hash, string key, SWIGTYPE_p_void data) { - switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_core_hash_insert(SWIGTYPE_p_switch_hashtable.getCPtr(hash), key, SWIGTYPE_p_void.getCPtr(data)); + public static switch_status_t switch_core_hash_insert_destructor(SWIGTYPE_p_switch_hashtable hash, string key, SWIGTYPE_p_void data, SWIGTYPE_p_f_p_void__void destructor) { + switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_core_hash_insert_destructor(SWIGTYPE_p_switch_hashtable.getCPtr(hash), key, SWIGTYPE_p_void.getCPtr(data), SWIGTYPE_p_f_p_void__void.getCPtr(destructor)); return ret; } @@ -2396,8 +2396,8 @@ public class freeswitch { return ret; } - public static switch_status_t switch_core_speech_open(switch_speech_handle sh, string module_name, string voice_name, uint rate, uint interval, SWIGTYPE_p_unsigned_long flags, SWIGTYPE_p_apr_pool_t pool) { - switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_core_speech_open(switch_speech_handle.getCPtr(sh), module_name, voice_name, rate, interval, SWIGTYPE_p_unsigned_long.getCPtr(flags), SWIGTYPE_p_apr_pool_t.getCPtr(pool)); + public static switch_status_t switch_core_speech_open(switch_speech_handle sh, string module_name, string voice_name, uint rate, uint interval, uint channels, SWIGTYPE_p_unsigned_long flags, SWIGTYPE_p_apr_pool_t pool) { + switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_core_speech_open(switch_speech_handle.getCPtr(sh), module_name, voice_name, rate, interval, channels, SWIGTYPE_p_unsigned_long.getCPtr(flags), SWIGTYPE_p_apr_pool_t.getCPtr(pool)); return ret; } @@ -3230,8 +3230,8 @@ public class freeswitch { return ret; } - public static string switch_parse_codec_buf(string buf, SWIGTYPE_p_unsigned_long interval, SWIGTYPE_p_unsigned_long rate, SWIGTYPE_p_unsigned_long bit) { - string ret = freeswitchPINVOKE.switch_parse_codec_buf(buf, SWIGTYPE_p_unsigned_long.getCPtr(interval), SWIGTYPE_p_unsigned_long.getCPtr(rate), SWIGTYPE_p_unsigned_long.getCPtr(bit)); + public static string switch_parse_codec_buf(string buf, SWIGTYPE_p_unsigned_long interval, SWIGTYPE_p_unsigned_long rate, SWIGTYPE_p_unsigned_long bit, SWIGTYPE_p_unsigned_long channels) { + string ret = freeswitchPINVOKE.switch_parse_codec_buf(buf, SWIGTYPE_p_unsigned_long.getCPtr(interval), SWIGTYPE_p_unsigned_long.getCPtr(rate), SWIGTYPE_p_unsigned_long.getCPtr(bit), SWIGTYPE_p_unsigned_long.getCPtr(channels)); return ret; } @@ -5268,8 +5268,8 @@ public class freeswitch { freeswitchPINVOKE.switch_swap_linear(SWIGTYPE_p_short.getCPtr(buf), len); } - public static void switch_generate_sln_silence(SWIGTYPE_p_short data, uint samples, uint divisor) { - freeswitchPINVOKE.switch_generate_sln_silence(SWIGTYPE_p_short.getCPtr(data), samples, divisor); + public static void switch_generate_sln_silence(SWIGTYPE_p_short data, uint samples, uint channels, uint divisor) { + freeswitchPINVOKE.switch_generate_sln_silence(SWIGTYPE_p_short.getCPtr(data), samples, channels, divisor); } public static void switch_change_sln_volume(SWIGTYPE_p_short data, uint samples, int vol) { @@ -5290,8 +5290,8 @@ public class freeswitch { return ret; } - public static void switch_mux_channels(SWIGTYPE_p_short data, SWIGTYPE_p_switch_size_t samples, uint channels) { - freeswitchPINVOKE.switch_mux_channels(SWIGTYPE_p_short.getCPtr(data), SWIGTYPE_p_switch_size_t.getCPtr(samples), channels); + public static void switch_mux_channels(SWIGTYPE_p_short data, SWIGTYPE_p_switch_size_t samples, uint orig_channels, uint channels) { + freeswitchPINVOKE.switch_mux_channels(SWIGTYPE_p_short.getCPtr(data), SWIGTYPE_p_switch_size_t.getCPtr(samples), orig_channels, channels); if (freeswitchPINVOKE.SWIGPendingException.Pending) throw freeswitchPINVOKE.SWIGPendingException.Retrieve(); } @@ -9381,6 +9381,24 @@ class freeswitchPINVOKE { [DllImport("mod_managed", EntryPoint="CSharp_switch_device_stats_t_held_out_get")] public static extern uint switch_device_stats_t_held_out_get(HandleRef jarg1); + [DllImport("mod_managed", EntryPoint="CSharp_switch_device_stats_t_unheld_set")] + public static extern void switch_device_stats_t_unheld_set(HandleRef jarg1, uint jarg2); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_device_stats_t_unheld_get")] + public static extern uint switch_device_stats_t_unheld_get(HandleRef jarg1); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_device_stats_t_unheld_in_set")] + public static extern void switch_device_stats_t_unheld_in_set(HandleRef jarg1, uint jarg2); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_device_stats_t_unheld_in_get")] + public static extern uint switch_device_stats_t_unheld_in_get(HandleRef jarg1); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_device_stats_t_unheld_out_set")] + public static extern void switch_device_stats_t_unheld_out_set(HandleRef jarg1, uint jarg2); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_device_stats_t_unheld_out_get")] + public static extern uint switch_device_stats_t_unheld_out_get(HandleRef jarg1); + [DllImport("mod_managed", EntryPoint="CSharp_switch_device_stats_t_hup_set")] public static extern void switch_device_stats_t_hup_set(HandleRef jarg1, uint jarg2); @@ -10293,8 +10311,8 @@ class freeswitchPINVOKE { [DllImport("mod_managed", EntryPoint="CSharp_switch_core_hash_destroy")] public static extern int switch_core_hash_destroy(HandleRef jarg1); - [DllImport("mod_managed", EntryPoint="CSharp_switch_core_hash_insert")] - public static extern int switch_core_hash_insert(HandleRef jarg1, string jarg2, HandleRef jarg3); + [DllImport("mod_managed", EntryPoint="CSharp_switch_core_hash_insert_destructor")] + public static extern int switch_core_hash_insert_destructor(HandleRef jarg1, string jarg2, HandleRef jarg3, HandleRef jarg4); [DllImport("mod_managed", EntryPoint="CSharp_switch_core_hash_insert_locked")] public static extern int switch_core_hash_insert_locked(HandleRef jarg1, string jarg2, HandleRef jarg3, HandleRef jarg4); @@ -10483,7 +10501,7 @@ class freeswitchPINVOKE { public static extern int switch_core_file_truncate(HandleRef jarg1, long jarg2); [DllImport("mod_managed", EntryPoint="CSharp_switch_core_speech_open")] - public static extern int switch_core_speech_open(HandleRef jarg1, string jarg2, string jarg3, uint jarg4, uint jarg5, HandleRef jarg6, HandleRef jarg7); + public static extern int switch_core_speech_open(HandleRef jarg1, string jarg2, string jarg3, uint jarg4, uint jarg5, uint jarg6, HandleRef jarg7, HandleRef jarg8); [DllImport("mod_managed", EntryPoint="CSharp_switch_core_speech_feed_tts")] public static extern int switch_core_speech_feed_tts(HandleRef jarg1, string jarg2, HandleRef jarg3); @@ -11230,7 +11248,7 @@ class freeswitchPINVOKE { public static extern IntPtr switch_loadable_module_get_codec_interface(string jarg1); [DllImport("mod_managed", EntryPoint="CSharp_switch_parse_codec_buf")] - public static extern string switch_parse_codec_buf(string jarg1, HandleRef jarg2, HandleRef jarg3, HandleRef jarg4); + public static extern string switch_parse_codec_buf(string jarg1, HandleRef jarg2, HandleRef jarg3, HandleRef jarg4, HandleRef jarg5); [DllImport("mod_managed", EntryPoint="CSharp_switch_loadable_module_get_dialplan_interface")] public static extern IntPtr switch_loadable_module_get_dialplan_interface(string jarg1); @@ -12183,6 +12201,12 @@ class freeswitchPINVOKE { [DllImport("mod_managed", EntryPoint="CSharp_switch_frame_rate_get")] public static extern uint switch_frame_rate_get(HandleRef jarg1); + [DllImport("mod_managed", EntryPoint="CSharp_switch_frame_channels_set")] + public static extern void switch_frame_channels_set(HandleRef jarg1, uint jarg2); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_frame_channels_get")] + public static extern uint switch_frame_channels_get(HandleRef jarg1); + [DllImport("mod_managed", EntryPoint="CSharp_switch_frame_payload_set")] public static extern void switch_frame_payload_set(HandleRef jarg1, byte jarg2); @@ -12873,6 +12897,12 @@ class freeswitchPINVOKE { [DllImport("mod_managed", EntryPoint="CSharp_switch_file_handle_channels_get")] public static extern uint switch_file_handle_channels_get(HandleRef jarg1); + [DllImport("mod_managed", EntryPoint="CSharp_switch_file_handle_real_channels_set")] + public static extern void switch_file_handle_real_channels_set(HandleRef jarg1, uint jarg2); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_file_handle_real_channels_get")] + public static extern uint switch_file_handle_real_channels_get(HandleRef jarg1); + [DllImport("mod_managed", EntryPoint="CSharp_switch_file_handle_format_set")] public static extern void switch_file_handle_format_set(HandleRef jarg1, uint jarg2); @@ -13467,6 +13497,18 @@ class freeswitchPINVOKE { [DllImport("mod_managed", EntryPoint="CSharp_switch_speech_handle_samples_get")] public static extern uint switch_speech_handle_samples_get(HandleRef jarg1); + [DllImport("mod_managed", EntryPoint="CSharp_switch_speech_handle_channels_set")] + public static extern void switch_speech_handle_channels_set(HandleRef jarg1, uint jarg2); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_speech_handle_channels_get")] + public static extern uint switch_speech_handle_channels_get(HandleRef jarg1); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_speech_handle_real_channels_set")] + public static extern void switch_speech_handle_real_channels_set(HandleRef jarg1, uint jarg2); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_speech_handle_real_channels_get")] + public static extern uint switch_speech_handle_real_channels_get(HandleRef jarg1); + [DllImport("mod_managed", EntryPoint="CSharp_switch_speech_handle_voice_set")] public static extern void switch_speech_handle_voice_set(HandleRef jarg1, string jarg2); @@ -13899,6 +13941,12 @@ class freeswitchPINVOKE { [DllImport("mod_managed", EntryPoint="CSharp_switch_codec_fmtp_microseconds_per_packet_get")] public static extern int switch_codec_fmtp_microseconds_per_packet_get(HandleRef jarg1); + [DllImport("mod_managed", EntryPoint="CSharp_switch_codec_fmtp_stereo_set")] + public static extern void switch_codec_fmtp_stereo_set(HandleRef jarg1, int jarg2); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_codec_fmtp_stereo_get")] + public static extern int switch_codec_fmtp_stereo_get(HandleRef jarg1); + [DllImport("mod_managed", EntryPoint="CSharp_switch_codec_fmtp_private_info_set")] public static extern void switch_codec_fmtp_private_info_set(HandleRef jarg1, HandleRef jarg2); @@ -15489,6 +15537,12 @@ class freeswitchPINVOKE { [DllImport("mod_managed", EntryPoint="CSharp_switch_audio_resampler_t_to_size_get")] public static extern uint switch_audio_resampler_t_to_size_get(HandleRef jarg1); + [DllImport("mod_managed", EntryPoint="CSharp_switch_audio_resampler_t_channels_set")] + public static extern void switch_audio_resampler_t_channels_set(HandleRef jarg1, int jarg2); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_audio_resampler_t_channels_get")] + public static extern int switch_audio_resampler_t_channels_get(HandleRef jarg1); + [DllImport("mod_managed", EntryPoint="CSharp_new_switch_audio_resampler_t")] public static extern IntPtr new_switch_audio_resampler_t(); @@ -15520,7 +15574,7 @@ class freeswitchPINVOKE { public static extern void switch_swap_linear(HandleRef jarg1, int jarg2); [DllImport("mod_managed", EntryPoint="CSharp_switch_generate_sln_silence")] - public static extern void switch_generate_sln_silence(HandleRef jarg1, uint jarg2, uint jarg3); + public static extern void switch_generate_sln_silence(HandleRef jarg1, uint jarg2, uint jarg3, uint jarg4); [DllImport("mod_managed", EntryPoint="CSharp_switch_change_sln_volume")] public static extern void switch_change_sln_volume(HandleRef jarg1, uint jarg2, int jarg3); @@ -15535,7 +15589,7 @@ class freeswitchPINVOKE { public static extern uint switch_unmerge_sln(HandleRef jarg1, uint jarg2, HandleRef jarg3, uint jarg4); [DllImport("mod_managed", EntryPoint="CSharp_switch_mux_channels")] - public static extern void switch_mux_channels(HandleRef jarg1, HandleRef jarg2, uint jarg3); + public static extern void switch_mux_channels(HandleRef jarg1, HandleRef jarg2, uint jarg3, uint jarg4); [DllImport("mod_managed", EntryPoint="CSharp_switch_unicast_conninfo_session_set")] public static extern void switch_unicast_conninfo_session_set(HandleRef jarg1, HandleRef jarg2); @@ -21231,18 +21285,18 @@ namespace FreeSWITCH.Native { using System; using System.Runtime.InteropServices; -public class SWIGTYPE_p_f_p_switch_speech_handle_p_q_const__char_int_p_unsigned_long__switch_status_t { +public class SWIGTYPE_p_f_p_switch_speech_handle_p_q_const__char_int_int_p_unsigned_long__switch_status_t { private HandleRef swigCPtr; - internal SWIGTYPE_p_f_p_switch_speech_handle_p_q_const__char_int_p_unsigned_long__switch_status_t(IntPtr cPtr, bool futureUse) { + internal SWIGTYPE_p_f_p_switch_speech_handle_p_q_const__char_int_int_p_unsigned_long__switch_status_t(IntPtr cPtr, bool futureUse) { swigCPtr = new HandleRef(this, cPtr); } - protected SWIGTYPE_p_f_p_switch_speech_handle_p_q_const__char_int_p_unsigned_long__switch_status_t() { + protected SWIGTYPE_p_f_p_switch_speech_handle_p_q_const__char_int_int_p_unsigned_long__switch_status_t() { swigCPtr = new HandleRef(null, IntPtr.Zero); } - internal static HandleRef getCPtr(SWIGTYPE_p_f_p_switch_speech_handle_p_q_const__char_int_p_unsigned_long__switch_status_t obj) { + internal static HandleRef getCPtr(SWIGTYPE_p_f_p_switch_speech_handle_p_q_const__char_int_int_p_unsigned_long__switch_status_t obj) { return (obj == null) ? new HandleRef(null, IntPtr.Zero) : obj.swigCPtr; } } @@ -25764,6 +25818,16 @@ public class switch_audio_resampler_t : IDisposable { } } + public int channels { + set { + freeswitchPINVOKE.switch_audio_resampler_t_channels_set(swigCPtr, value); + } + get { + int ret = freeswitchPINVOKE.switch_audio_resampler_t_channels_get(swigCPtr); + return ret; + } + } + public switch_audio_resampler_t() : this(freeswitchPINVOKE.new_switch_audio_resampler_t(), true) { } @@ -27232,7 +27296,7 @@ public enum switch_channel_callstate_t { CCS_HELD, CCS_RING_WAIT, CCS_HANGUP, - CCS_UNHOLD + CCS_UNHELD } } @@ -28190,6 +28254,16 @@ public class switch_codec_fmtp : IDisposable { } } + public int stereo { + set { + freeswitchPINVOKE.switch_codec_fmtp_stereo_set(swigCPtr, value); + } + get { + int ret = freeswitchPINVOKE.switch_codec_fmtp_stereo_get(swigCPtr); + return ret; + } + } + public SWIGTYPE_p_void private_info { set { freeswitchPINVOKE.switch_codec_fmtp_private_info_set(swigCPtr, SWIGTYPE_p_void.getCPtr(value)); @@ -29352,11 +29426,13 @@ public enum switch_core_session_message_types_t { SWITCH_MESSAGE_INDICATE_BLIND_TRANSFER_RESPONSE, SWITCH_MESSAGE_INDICATE_STUN_ERROR, SWITCH_MESSAGE_INDICATE_MEDIA_RENEG, + SWITCH_MESSAGE_INDICATE_KEEPALIVE, SWITCH_MESSAGE_REFER_EVENT, SWITCH_MESSAGE_ANSWER_EVENT, SWITCH_MESSAGE_PROGRESS_EVENT, SWITCH_MESSAGE_RING_EVENT, SWITCH_MESSAGE_RESAMPLE_EVENT, + SWITCH_MESSAGE_HEARTBEAT_EVENT, SWITCH_MESSAGE_INVALID } @@ -30016,6 +30092,7 @@ public enum switch_device_state_t { SDS_ACTIVE, SDS_ACTIVE_MULTI, SDS_HELD, + SDS_UNHELD, SDS_HANGUP } @@ -30183,6 +30260,36 @@ public class switch_device_stats_t : IDisposable { } } + public uint unheld { + set { + freeswitchPINVOKE.switch_device_stats_t_unheld_set(swigCPtr, value); + } + get { + uint ret = freeswitchPINVOKE.switch_device_stats_t_unheld_get(swigCPtr); + return ret; + } + } + + public uint unheld_in { + set { + freeswitchPINVOKE.switch_device_stats_t_unheld_in_set(swigCPtr, value); + } + get { + uint ret = freeswitchPINVOKE.switch_device_stats_t_unheld_in_get(swigCPtr); + return ret; + } + } + + public uint unheld_out { + set { + freeswitchPINVOKE.switch_device_stats_t_unheld_out_set(swigCPtr, value); + } + get { + uint ret = freeswitchPINVOKE.switch_device_stats_t_unheld_out_get(swigCPtr); + return ret; + } + } + public uint hup { set { freeswitchPINVOKE.switch_device_stats_t_hup_set(swigCPtr, value); @@ -31756,6 +31863,16 @@ public class switch_file_handle : IDisposable { } } + public uint real_channels { + set { + freeswitchPINVOKE.switch_file_handle_real_channels_set(swigCPtr, value); + } + get { + uint ret = freeswitchPINVOKE.switch_file_handle_real_channels_get(swigCPtr); + return ret; + } + } + public uint format { set { freeswitchPINVOKE.switch_file_handle_format_set(swigCPtr, value); @@ -32580,6 +32697,16 @@ public class switch_frame : IDisposable { } } + public uint channels { + set { + freeswitchPINVOKE.switch_frame_channels_set(swigCPtr, value); + } + get { + uint ret = freeswitchPINVOKE.switch_frame_channels_get(swigCPtr); + return ret; + } + } + public byte payload { set { freeswitchPINVOKE.switch_frame_payload_set(swigCPtr, value); @@ -37364,6 +37491,7 @@ public enum switch_session_ctl_t { SCSC_DEBUG_LEVEL, SCSC_FLUSH_DB_HANDLES, SCSC_SHUTDOWN_NOW, + SCSC_REINCARNATE_NOW, SCSC_CALIBRATE_CLOCK, SCSC_SAVE_HISTORY, SCSC_CRASH, @@ -37623,6 +37751,26 @@ public class switch_speech_handle : IDisposable { } } + public uint channels { + set { + freeswitchPINVOKE.switch_speech_handle_channels_set(swigCPtr, value); + } + get { + uint ret = freeswitchPINVOKE.switch_speech_handle_channels_get(swigCPtr); + return ret; + } + } + + public uint real_channels { + set { + freeswitchPINVOKE.switch_speech_handle_real_channels_set(swigCPtr, value); + } + get { + uint ret = freeswitchPINVOKE.switch_speech_handle_real_channels_get(swigCPtr); + return ret; + } + } + public string voice { set { freeswitchPINVOKE.switch_speech_handle_voice_set(swigCPtr, value); @@ -37799,13 +37947,13 @@ public class switch_speech_interface : IDisposable { } } - public SWIGTYPE_p_f_p_switch_speech_handle_p_q_const__char_int_p_unsigned_long__switch_status_t speech_open { + public SWIGTYPE_p_f_p_switch_speech_handle_p_q_const__char_int_int_p_unsigned_long__switch_status_t speech_open { set { - freeswitchPINVOKE.switch_speech_interface_speech_open_set(swigCPtr, SWIGTYPE_p_f_p_switch_speech_handle_p_q_const__char_int_p_unsigned_long__switch_status_t.getCPtr(value)); + freeswitchPINVOKE.switch_speech_interface_speech_open_set(swigCPtr, SWIGTYPE_p_f_p_switch_speech_handle_p_q_const__char_int_int_p_unsigned_long__switch_status_t.getCPtr(value)); } get { IntPtr cPtr = freeswitchPINVOKE.switch_speech_interface_speech_open_get(swigCPtr); - SWIGTYPE_p_f_p_switch_speech_handle_p_q_const__char_int_p_unsigned_long__switch_status_t ret = (cPtr == IntPtr.Zero) ? null : new SWIGTYPE_p_f_p_switch_speech_handle_p_q_const__char_int_p_unsigned_long__switch_status_t(cPtr, false); + SWIGTYPE_p_f_p_switch_speech_handle_p_q_const__char_int_int_p_unsigned_long__switch_status_t ret = (cPtr == IntPtr.Zero) ? null : new SWIGTYPE_p_f_p_switch_speech_handle_p_q_const__char_int_int_p_unsigned_long__switch_status_t(cPtr, false); return ret; } } From 4c54f45f4ae68c18bb3e5fef56fcc1d98129e227 Mon Sep 17 00:00:00 2001 From: Chris Rienzo Date: Fri, 13 Jun 2014 10:05:53 -0400 Subject: [PATCH 044/231] FS-6535 mod_rayo: allow unimrcp recognizer w/ profile specified --- src/mod/event_handlers/mod_rayo/rayo_input_component.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mod/event_handlers/mod_rayo/rayo_input_component.c b/src/mod/event_handlers/mod_rayo/rayo_input_component.c index cd9c092dbb..464f8bc70b 100644 --- a/src/mod/event_handlers/mod_rayo/rayo_input_component.c +++ b/src/mod/event_handlers/mod_rayo/rayo_input_component.c @@ -574,7 +574,7 @@ static iks *start_call_voice_input(struct input_component *component, switch_cor if (!strcmp(component->recognizer, "pocketsphinx")) { grammar = setup_grammars_pocketsphinx(component, session, input, &stanza_error, &error_detail); - } else if (!strcmp(component->recognizer, "unimrcp")) { + } else if (!strncmp(component->recognizer, "unimrcp", strlen("unimrcp")) { grammar = setup_grammars_unimrcp(component, session, input, &stanza_error, &error_detail); } else { grammar = setup_grammars_unknown(component, session, input, &stanza_error, &error_detail); From 9aa51021420d75a80ed49e42acf448e2923eda84 Mon Sep 17 00:00:00 2001 From: Chris Rienzo Date: Fri, 13 Jun 2014 10:08:49 -0400 Subject: [PATCH 045/231] FS-6535 mod_rayo: compile error --- src/mod/event_handlers/mod_rayo/rayo_input_component.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mod/event_handlers/mod_rayo/rayo_input_component.c b/src/mod/event_handlers/mod_rayo/rayo_input_component.c index 464f8bc70b..1435b90a27 100644 --- a/src/mod/event_handlers/mod_rayo/rayo_input_component.c +++ b/src/mod/event_handlers/mod_rayo/rayo_input_component.c @@ -574,7 +574,7 @@ static iks *start_call_voice_input(struct input_component *component, switch_cor if (!strcmp(component->recognizer, "pocketsphinx")) { grammar = setup_grammars_pocketsphinx(component, session, input, &stanza_error, &error_detail); - } else if (!strncmp(component->recognizer, "unimrcp", strlen("unimrcp")) { + } else if (!strncmp(component->recognizer, "unimrcp", strlen("unimrcp"))) { grammar = setup_grammars_unimrcp(component, session, input, &stanza_error, &error_detail); } else { grammar = setup_grammars_unknown(component, session, input, &stanza_error, &error_detail); From 730d2f88ba18662401f4ca66ba4ea5c317a94777 Mon Sep 17 00:00:00 2001 From: Chris Rienzo Date: Fri, 13 Jun 2014 11:33:33 -0400 Subject: [PATCH 046/231] mod_rayo: rename reference counting functions to something more sensible --- src/mod/event_handlers/mod_rayo/mod_rayo.c | 98 +++++++++---------- src/mod/event_handlers/mod_rayo/mod_rayo.h | 8 +- .../event_handlers/mod_rayo/rayo_components.c | 4 +- .../mod_rayo/rayo_cpa_component.c | 12 +-- .../mod_rayo/rayo_fax_components.c | 10 +- .../mod_rayo/rayo_input_component.c | 22 +++-- .../mod_rayo/rayo_output_component.c | 8 +- .../mod_rayo/rayo_prompt_component.c | 4 +- .../mod_rayo/rayo_record_component.c | 10 +- 9 files changed, 90 insertions(+), 86 deletions(-) diff --git a/src/mod/event_handlers/mod_rayo/mod_rayo.c b/src/mod/event_handlers/mod_rayo/mod_rayo.c index 75ee53a506..1d46fdb2a5 100644 --- a/src/mod/event_handlers/mod_rayo/mod_rayo.c +++ b/src/mod/event_handlers/mod_rayo/mod_rayo.c @@ -775,7 +775,7 @@ static void *SWITCH_THREAD_FUNC deliver_message_thread(switch_thread_t *thread, switch_log_printf(SWITCH_CHANNEL_ID_LOG, msg->file, "", msg->line, "", SWITCH_LOG_DEBUG, "Deliver %s => %s %s\n", msg->from_jid, msg->to_jid, iks_string(iks_stack(msg->payload), msg->payload)); actor->send_fn(actor, msg); switch_mutex_unlock(actor->mutex); - RAYO_UNLOCK(actor); + RAYO_RELEASE(actor); } else if (!msg->is_reply) { /* unknown actor */ RAYO_SEND_REPLY(globals.server, msg->from_jid, iks_new_error(msg->payload, STANZA_ERROR_ITEM_NOT_FOUND)); @@ -877,7 +877,7 @@ void rayo_message_send(struct rayo_actor *from, const char *to, iks *payload, in /** * Get access to Rayo actor with JID. * @param jid the JID - * @return the actor or NULL. Call RAYO_UNLOCK() when done with pointer. + * @return the actor or NULL. Call RAYO_RELEASE() when done with pointer. */ struct rayo_actor *rayo_actor_locate(const char *jid, const char *file, int line) { @@ -903,7 +903,7 @@ struct rayo_actor *rayo_actor_locate(const char *jid, const char *file, int line /** * Get exclusive access to Rayo actor with internal ID * @param id the internal ID - * @return the actor or NULL. Call RAYO_UNLOCK() when done with pointer. + * @return the actor or NULL. Call RAYO_RELEASE() when done with pointer. */ struct rayo_actor *rayo_actor_locate_by_id(const char *id, const char *file, int line) { @@ -961,7 +961,7 @@ void rayo_actor_destroy(struct rayo_actor *actor, const char *file, int line) /** * Increment actor ref count - locks from destruction. */ -void rayo_actor_rdlock(struct rayo_actor *actor, const char *file, int line) +void rayo_actor_retain(struct rayo_actor *actor, const char *file, int line) { if (actor) { switch_mutex_lock(globals.actors_mutex); @@ -972,18 +972,18 @@ void rayo_actor_rdlock(struct rayo_actor *actor, const char *file, int line) } /** - * Unlock rayo actor + * Release rayo actor reference */ -void rayo_actor_unlock(struct rayo_actor *actor, const char *file, int line) +void rayo_actor_release(struct rayo_actor *actor, const char *file, int line) { if (actor) { switch_mutex_lock(globals.actors_mutex); actor->ref_count--; if (actor->ref_count < 0) { /* too many unlocks detected! */ - switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, "", line, "", SWITCH_LOG_WARNING, "Unlock %s: ref count = %i\n", RAYO_JID(actor), actor->ref_count); + switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, "", line, "", SWITCH_LOG_WARNING, "Release %s: ref count = %i\n", RAYO_JID(actor), actor->ref_count); } else { - switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, "", line, "", SWITCH_LOG_DEBUG, "Unlock %s: ref count = %i\n", RAYO_JID(actor), actor->ref_count); + switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, "", line, "", SWITCH_LOG_DEBUG, "Release %s: ref count = %i\n", RAYO_JID(actor), actor->ref_count); } if (actor->ref_count <= 0 && actor->destroy) { rayo_actor_destroy(actor, file, line); @@ -1016,7 +1016,7 @@ static struct rayo_call *rayo_call_locate(const char *call_uri, const char *file if (actor && is_call_actor(actor)) { return RAYO_CALL(actor); } else if (actor) { - RAYO_UNLOCK(actor); + RAYO_RELEASE(actor); } return NULL; } @@ -1033,7 +1033,7 @@ static struct rayo_call *rayo_call_locate_by_id(const char *call_uuid, const cha if (actor && is_call_actor(actor)) { return RAYO_CALL(actor); } else if (actor) { - RAYO_UNLOCK(actor); + RAYO_RELEASE(actor); } return NULL; } @@ -1203,7 +1203,7 @@ void rayo_call_set_faxing(struct rayo_call *call, int faxing) /** * Get access to Rayo mixer data. * @param mixer_name the mixer name - * @return the mixer or NULL. Call RAYO_UNLOCK() when done with mixer pointer. + * @return the mixer or NULL. Call RAYO_RELEASE() when done with mixer pointer. */ static struct rayo_mixer *rayo_mixer_locate(const char *mixer_name, const char *file, int line) { @@ -1211,7 +1211,7 @@ static struct rayo_mixer *rayo_mixer_locate(const char *mixer_name, const char * if (actor && !strcmp(RAT_MIXER, actor->type)) { return RAYO_MIXER(actor); } else if (actor) { - RAYO_UNLOCK(actor); + RAYO_RELEASE(actor); } return NULL; } @@ -1407,7 +1407,7 @@ static void rayo_component_cleanup(struct rayo_actor *actor) } /* parent can now be destroyed */ - RAYO_UNLOCK(RAYO_COMPONENT(actor)->parent); + RAYO_RELEASE(RAYO_COMPONENT(actor)->parent); } /** @@ -1432,7 +1432,7 @@ struct rayo_component *_rayo_component_init(struct rayo_component *component, sw component = RAYO_COMPONENT(rayo_actor_init(RAYO_ACTOR(component), pool, type, subtype, id, jid, rayo_component_cleanup, rayo_component_send, file, line)); if (component) { - RAYO_RDLOCK(parent); + RAYO_RETAIN(parent); component->client_jid = switch_core_strdup(pool, client_jid); component->ref = switch_core_strdup(pool, ref); component->parent = parent; @@ -1562,7 +1562,7 @@ static void rayo_peer_server_cleanup(struct rayo_actor *actor) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Removing %s from peer server %s\n", RAYO_JID(client), RAYO_JID(rserver)); switch_core_hash_delete(rserver->clients, key); RAYO_CLIENT(client)->peer_server = NULL; - RAYO_UNLOCK(client); + RAYO_RELEASE(client); RAYO_DESTROY(client); } switch_core_hash_destroy(&rserver->clients); @@ -1719,7 +1719,7 @@ void rayo_server_send(struct rayo_actor *server, struct rayo_message *msg) if (!strcmp(RAT_CLIENT, client->type)) { on_client_presence(RAYO_CLIENT(client), iq); } - RAYO_UNLOCK(client); + RAYO_RELEASE(client); } return; } @@ -2080,7 +2080,7 @@ static iks *join_call(struct rayo_call *call, switch_core_session_t *session, st } else if (b_call->joined) { /* don't support multiple joined calls */ response = iks_new_error_detailed(node, STANZA_ERROR_CONFLICT, "multiple joined calls not supported"); - RAYO_UNLOCK(b_call); + RAYO_RELEASE(b_call); } else { /* bridge this call to call-uri */ switch_channel_set_variable(switch_core_session_get_channel(session), "bypass_media", bypass); @@ -2095,7 +2095,7 @@ static iks *join_call(struct rayo_call *call, switch_core_session_t *session, st RAYO_SEND_REPLY(call, iks_find_attrib_soft(request, "from"), result); iks_delete(call->pending_join_request); } - RAYO_UNLOCK(b_call); + RAYO_RELEASE(b_call); } return response; } @@ -2690,12 +2690,12 @@ static void *SWITCH_THREAD_FUNC rayo_dial_thread(switch_thread_t *thread, void * goto done; } else if (b_call->joined) { response = iks_new_error_detailed(iq, STANZA_ERROR_SERVICE_UNAVAILABLE, "b-leg already joined to another call"); - RAYO_UNLOCK(b_call); + RAYO_RELEASE(b_call); goto done; } app = "bridge"; app_args = switch_core_strdup(dtdata->pool, rayo_call_get_uuid(b_call)); - RAYO_UNLOCK(b_call); + RAYO_RELEASE(b_call); } else { /* conference */ app = "conference"; @@ -2757,7 +2757,7 @@ static void *SWITCH_THREAD_FUNC rayo_dial_thread(switch_thread_t *thread, void * /* destroy call */ RAYO_DESTROY(call); - RAYO_UNLOCK(call); + RAYO_RELEASE(call); break; } case SWITCH_CAUSE_EXCHANGE_ROUTING_ERROR: @@ -2812,7 +2812,7 @@ done: /* destroy call */ if (call) { RAYO_DESTROY(call); - RAYO_UNLOCK(call); + RAYO_RELEASE(call); } } @@ -3024,7 +3024,7 @@ static void on_client_presence(struct rayo_client *rclient, iks *node) /* destroy if not a local client (connected via peer_server) and is OFFLINE */ if (rclient->peer_server && rclient->availability == PS_OFFLINE) { RAYO_DESTROY(rclient); - RAYO_UNLOCK(rclient); + RAYO_RELEASE(rclient); } pause_when_offline(); @@ -3119,7 +3119,7 @@ static void on_mixer_delete_member_event(struct rayo_mixer *mixer, switch_event_ call->joined = 0; call->joined_id = NULL; switch_mutex_unlock(RAYO_ACTOR(call)->mutex); - RAYO_UNLOCK(call); + RAYO_RELEASE(call); } /* send mixer unjoined event to member DCP */ @@ -3164,7 +3164,7 @@ static void on_mixer_destroy_event(struct rayo_mixer *mixer, switch_event_t *eve /* remove from hash and destroy */ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, destroying mixer: %s\n", RAYO_JID(mixer), rayo_mixer_get_name(mixer)); - RAYO_UNLOCK(mixer); /* release original lock */ + RAYO_RELEASE(mixer); /* release original lock */ RAYO_DESTROY(mixer); } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "destroy: NULL mixer\n"); @@ -3257,7 +3257,7 @@ static void on_mixer_add_member_event(struct rayo_mixer *mixer, switch_event_t * iks_insert_attrib(x, "mixer-name", rayo_mixer_get_name(mixer)); RAYO_SEND_MESSAGE(call, call->dcp_jid, add_member_event); - RAYO_UNLOCK(call); + RAYO_RELEASE(call); } /* broadcast member joined event to subscribers */ @@ -3268,7 +3268,7 @@ static void on_mixer_add_member_event(struct rayo_mixer *mixer, switch_event_t * iks_delete(add_member_event); if (lmixer) { - RAYO_UNLOCK(lmixer); + RAYO_RELEASE(lmixer); } } @@ -3301,7 +3301,7 @@ static void route_mixer_event(switch_event_t *event) /* TODO speaking events */ done: - RAYO_UNLOCK(mixer); + RAYO_RELEASE(mixer); } /** @@ -3336,7 +3336,7 @@ static void on_call_originate_event(struct rayo_client *rclient, switch_event_t } switch_mutex_unlock(RAYO_ACTOR(call)->mutex); } - RAYO_UNLOCK(call); + RAYO_RELEASE(call); } /** @@ -3361,10 +3361,10 @@ static void on_call_end_event(switch_event_t *event) if (zstr(call->dial_request_id) && !call->dial_request_failed) { switch_event_dup(&call->end_event, event); RAYO_DESTROY(call); - RAYO_UNLOCK(call); /* decrement ref from creation */ + RAYO_RELEASE(call); /* decrement ref from creation */ } switch_mutex_unlock(RAYO_ACTOR(call)->mutex); - RAYO_UNLOCK(call); /* decrement this ref */ + RAYO_RELEASE(call); /* decrement this ref */ } } @@ -3381,7 +3381,7 @@ static void on_call_answer_event(struct rayo_client *rclient, switch_event_t *ev switch_event_get_header(event, "variable_rayo_call_jid"), switch_event_get_header(event, "variable_rayo_dcp_jid")); RAYO_SEND_MESSAGE(call, RAYO_JID(rclient), revent); - RAYO_UNLOCK(call); + RAYO_RELEASE(call); } } @@ -3405,7 +3405,7 @@ static void on_call_ringing_event(struct rayo_client *rclient, switch_event_t *e RAYO_SEND_MESSAGE(call, RAYO_JID(rclient), revent); } switch_mutex_unlock(RAYO_ACTOR(call)->mutex); - RAYO_UNLOCK(call); + RAYO_RELEASE(call); } } } @@ -3458,7 +3458,7 @@ static void on_call_bridge_event(struct rayo_client *rclient, switch_event_t *ev iks_insert_attrib_printf(joined, "call-uri", "%s", b_call->joined_id); RAYO_SEND_MESSAGE(b_call, rayo_call_get_dcp_jid(b_call), revent); - RAYO_UNLOCK(b_call); + RAYO_RELEASE(b_call); } /* send A-leg event */ @@ -3470,7 +3470,7 @@ static void on_call_bridge_event(struct rayo_client *rclient, switch_event_t *ev RAYO_SEND_MESSAGE(call, RAYO_JID(rclient), revent); - RAYO_UNLOCK(call); + RAYO_RELEASE(call); } } @@ -3510,7 +3510,7 @@ static void on_call_park_event(struct rayo_client *rclient, switch_event_t *even iks_insert_attrib_printf(unjoined, "call-uri", "%s", joined_id); RAYO_SEND_MESSAGE(call, RAYO_JID(rclient), revent); } - RAYO_UNLOCK(call); + RAYO_RELEASE(call); } } @@ -3524,7 +3524,7 @@ static void on_call_execute_event(struct rayo_client *rclient, switch_event_t *e struct rayo_call *call = RAYO_CALL_LOCATE_BY_ID(switch_event_get_header(event, "Unique-ID")); if (call) { switch_log_printf(SWITCH_CHANNEL_UUID_LOG(RAYO_ID(call)), SWITCH_LOG_DEBUG, "Application %s execute\n", switch_event_get_header(event, "Application")); - RAYO_UNLOCK(call); + RAYO_RELEASE(call); } } @@ -3541,7 +3541,7 @@ static void on_call_execute_complete_event(struct rayo_client *rclient, switch_e switch_log_printf(SWITCH_CHANNEL_UUID_LOG(RAYO_ID(call)), SWITCH_LOG_DEBUG, "Application %s execute complete: %s \n", app, switch_event_get_header(event, "Application-Response")); - RAYO_UNLOCK(call); + RAYO_RELEASE(call); } } @@ -3608,7 +3608,7 @@ static void route_call_event(switch_event_t *event) /* TODO orphaned call... maybe allow events to queue so they can be delivered on reconnect? */ switch_log_printf(SWITCH_CHANNEL_UUID_LOG(uuid), SWITCH_LOG_DEBUG, "Orphaned call event %s to %s\n", switch_event_name(event->event_id), dcp_jid); } - RAYO_UNLOCK(actor); + RAYO_RELEASE(actor); } } @@ -3737,7 +3737,7 @@ SWITCH_STANDARD_APP(rayo_app) /* don't need to keep call reference count incremented in session- call is destroyed after all apps finish */ if (call) { - RAYO_UNLOCK(call); + RAYO_RELEASE(call); } /* is outbound call already under control? */ @@ -3847,15 +3847,15 @@ static struct rayo_actor *xmpp_stream_client_locate(struct xmpp_stream *stream, /* previously unknown client - add it */ struct rayo_peer_server *rserver = RAYO_PEER_SERVER(xmpp_stream_get_private(stream)); actor = RAYO_ACTOR(rayo_client_create(jid, xmpp_stream_get_jid(stream), PS_UNKNOWN, rayo_client_send, rserver)); - RAYO_RDLOCK(actor); + RAYO_RETAIN(actor); } else if (strcmp(RAT_CLIENT, actor->type)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, not a client: %s\n", xmpp_stream_get_jid(stream), jid); - RAYO_UNLOCK(actor); + RAYO_RELEASE(actor); actor = NULL; } } else { actor = RAYO_ACTOR(xmpp_stream_get_private(stream)); - RAYO_RDLOCK(actor); + RAYO_RETAIN(actor); } return actor; } @@ -3926,14 +3926,14 @@ static void on_xmpp_stream_recv(struct xmpp_stream *stream, iks *stanza) if (actor) { rayo_client_presence_check(RAYO_CLIENT(actor)); rayo_client_command_recv(RAYO_CLIENT(actor), stanza); - RAYO_UNLOCK(actor); + RAYO_RELEASE(actor); } } else if (!strcmp("presence", name)) { const char *from = iks_find_attrib_soft(stanza, "from"); struct rayo_actor *actor = xmpp_stream_client_locate(stream, from); if (actor) { on_client_presence(RAYO_CLIENT(actor), stanza); - RAYO_UNLOCK(actor); + RAYO_RELEASE(actor); } } else if (!strcmp("message", name)) { const char *from = iks_find_attrib_soft(stanza, "from"); @@ -3941,7 +3941,7 @@ static void on_xmpp_stream_recv(struct xmpp_stream *stream, iks *stanza) if (actor) { rayo_client_presence_check(RAYO_CLIENT(actor)); on_client_message(RAYO_CLIENT(actor), stanza); - RAYO_UNLOCK(actor); + RAYO_RELEASE(actor); } } } @@ -3954,7 +3954,7 @@ static void on_xmpp_stream_destroy(struct xmpp_stream *stream) /* destroy peer server / client associated with this stream */ void *actor = xmpp_stream_get_private(stream); if (actor) { - RAYO_UNLOCK(actor); + RAYO_RELEASE(actor); RAYO_DESTROY(actor); } } @@ -4836,13 +4836,13 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_rayo_shutdown) stop_deliver_message_threads(); if (globals.console) { - RAYO_UNLOCK(globals.console); + RAYO_RELEASE(globals.console); RAYO_DESTROY(globals.console); globals.console = NULL; } if (globals.server) { - RAYO_UNLOCK(globals.server); + RAYO_RELEASE(globals.server); RAYO_DESTROY(globals.server); globals.server = NULL; } diff --git a/src/mod/event_handlers/mod_rayo/mod_rayo.h b/src/mod/event_handlers/mod_rayo/mod_rayo.h index 43ed7d3dbc..074e32fd5e 100644 --- a/src/mod/event_handlers/mod_rayo/mod_rayo.h +++ b/src/mod/event_handlers/mod_rayo/mod_rayo.h @@ -142,8 +142,8 @@ extern iks *rayo_message_remove_payload(struct rayo_message *msg); extern struct rayo_actor *rayo_actor_locate(const char *jid, const char *file, int line); extern struct rayo_actor *rayo_actor_locate_by_id(const char *id, const char *file, int line); extern int rayo_actor_seq_next(struct rayo_actor *actor); -extern void rayo_actor_rdlock(struct rayo_actor *actor, const char *file, int line); -extern void rayo_actor_unlock(struct rayo_actor *actor, const char *file, int line); +extern void rayo_actor_retain(struct rayo_actor *actor, const char *file, int line); +extern void rayo_actor_release(struct rayo_actor *actor, const char *file, int line); extern void rayo_actor_destroy(struct rayo_actor *actor, const char *file, int line); #define RAYO_LOCATE(jid) rayo_actor_locate(jid, __FILE__, __LINE__) @@ -153,8 +153,8 @@ extern void rayo_actor_destroy(struct rayo_actor *actor, const char *file, int l #define RAYO_JID(x) RAYO_ACTOR(x)->jid #define RAYO_ID(x) RAYO_ACTOR(x)->id #define RAYO_POOL(x) RAYO_ACTOR(x)->pool -#define RAYO_RDLOCK(x) rayo_actor_rdlock(RAYO_ACTOR(x), __FILE__, __LINE__) -#define RAYO_UNLOCK(x) rayo_actor_unlock(RAYO_ACTOR(x), __FILE__, __LINE__) +#define RAYO_RETAIN(x) rayo_actor_retain(RAYO_ACTOR(x), __FILE__, __LINE__) +#define RAYO_RELEASE(x) rayo_actor_release(RAYO_ACTOR(x), __FILE__, __LINE__) #define RAYO_DESTROY(x) rayo_actor_destroy(RAYO_ACTOR(x), __FILE__, __LINE__) #define RAYO_SEQ_NEXT(x) rayo_actor_seq_next(RAYO_ACTOR(x)) diff --git a/src/mod/event_handlers/mod_rayo/rayo_components.c b/src/mod/event_handlers/mod_rayo/rayo_components.c index ac1c66175d..1232bee47a 100644 --- a/src/mod/event_handlers/mod_rayo/rayo_components.c +++ b/src/mod/event_handlers/mod_rayo/rayo_components.c @@ -43,7 +43,7 @@ struct rayo_component *rayo_component_locate(const char *id, const char *file, i if (actor && is_component_actor(actor)) { return RAYO_COMPONENT(actor); } else if (actor) { - RAYO_UNLOCK(actor); + RAYO_RELEASE(actor); } return NULL; } @@ -114,7 +114,7 @@ void rayo_component_send_complete_event(struct rayo_component *component, iks *r { component->complete = 1; RAYO_SEND_REPLY(component, iks_find_attrib(response, "to"), response); - RAYO_UNLOCK(component); + RAYO_RELEASE(component); RAYO_DESTROY(component); } diff --git a/src/mod/event_handlers/mod_rayo/rayo_cpa_component.c b/src/mod/event_handlers/mod_rayo/rayo_cpa_component.c index 364a6b6176..634968d4a8 100644 --- a/src/mod/event_handlers/mod_rayo/rayo_cpa_component.c +++ b/src/mod/event_handlers/mod_rayo/rayo_cpa_component.c @@ -236,7 +236,7 @@ static void rayo_cpa_detector_event(const char *jid, void *user_data) } else { switch_log_printf(SWITCH_CHANNEL_UUID_LOG(RAYO_COMPONENT(component)->parent->id), SWITCH_LOG_DEBUG, "Skipping CPA event\n"); } - RAYO_UNLOCK(component); + RAYO_RELEASE(component); } } @@ -257,7 +257,7 @@ static void rayo_cpa_component_hangup(const char *jid, void *user_data) if (component) { stop_cpa_detectors(CPA_COMPONENT(component)); rayo_component_send_complete(RAYO_COMPONENT(component), COMPONENT_COMPLETE_HANGUP); - RAYO_UNLOCK(component); + RAYO_RELEASE(component); } } @@ -303,7 +303,7 @@ iks *rayo_cpa_component_start(struct rayo_actor *call, struct rayo_message *msg, if (zstr(url)) { stop_cpa_detectors(component); - RAYO_UNLOCK(component); + RAYO_RELEASE(component); RAYO_DESTROY(component); return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "Missing grammar URL"); } @@ -318,7 +318,7 @@ iks *rayo_cpa_component_start(struct rayo_actor *call, struct rayo_message *msg, if (switch_core_hash_find(component->signals, url)) { free(url_dup); stop_cpa_detectors(component); - RAYO_UNLOCK(component); + RAYO_RELEASE(component); RAYO_DESTROY(component); return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "Duplicate URL"); } @@ -334,7 +334,7 @@ iks *rayo_cpa_component_start(struct rayo_actor *call, struct rayo_message *msg, } else { free(url_dup); stop_cpa_detectors(component); - RAYO_UNLOCK(component); + RAYO_RELEASE(component); RAYO_DESTROY(component); return iks_new_error_detailed(iq, STANZA_ERROR_INTERNAL_SERVER_ERROR, error_str); } @@ -345,7 +345,7 @@ iks *rayo_cpa_component_start(struct rayo_actor *call, struct rayo_message *msg, if (!have_grammar) { stop_cpa_detectors(component); - RAYO_UNLOCK(component); + RAYO_RELEASE(component); RAYO_DESTROY(component); return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "No grammar defined"); } diff --git a/src/mod/event_handlers/mod_rayo/rayo_fax_components.c b/src/mod/event_handlers/mod_rayo/rayo_fax_components.c index f47d9c1cf7..0ceb0532b7 100644 --- a/src/mod/event_handlers/mod_rayo/rayo_fax_components.c +++ b/src/mod/event_handlers/mod_rayo/rayo_fax_components.c @@ -217,7 +217,7 @@ static iks *start_sendfax_component(struct rayo_actor *call, struct rayo_message switch_event_destroy(&execute_event); } rayo_call_set_faxing(RAYO_CALL(call), 0); - RAYO_UNLOCK(sendfax_component); + RAYO_RELEASE(sendfax_component); } else { /* component starting... */ rayo_component_send_start(RAYO_COMPONENT(sendfax_component), iq); @@ -225,7 +225,7 @@ static iks *start_sendfax_component(struct rayo_actor *call, struct rayo_message } else { response = iks_new_error_detailed(iq, STANZA_ERROR_INTERNAL_SERVER_ERROR, "failed to create txfax event"); rayo_call_set_faxing(RAYO_CALL(call), 0); - RAYO_UNLOCK(sendfax_component); + RAYO_RELEASE(sendfax_component); } return response; @@ -320,7 +320,7 @@ static iks *start_receivefax_component(struct rayo_actor *call, struct rayo_mess switch_event_destroy(&execute_event); } rayo_call_set_faxing(RAYO_CALL(call), 0); - RAYO_UNLOCK(receivefax_component); + RAYO_RELEASE(receivefax_component); } else { /* component starting... */ rayo_component_send_start(RAYO_COMPONENT(receivefax_component), iq); @@ -328,7 +328,7 @@ static iks *start_receivefax_component(struct rayo_actor *call, struct rayo_mess } else { response = iks_new_error_detailed(iq, STANZA_ERROR_INTERNAL_SERVER_ERROR, "failed to create rxfax event"); rayo_call_set_faxing(RAYO_CALL(call), 0); - RAYO_UNLOCK(receivefax_component); + RAYO_RELEASE(receivefax_component); } return response; @@ -463,7 +463,7 @@ static void on_execute_complete_event(switch_event_t *event) rayo_component_send_complete_event(RAYO_COMPONENT(component), result); - RAYO_UNLOCK(component); + RAYO_RELEASE(component); } } } diff --git a/src/mod/event_handlers/mod_rayo/rayo_input_component.c b/src/mod/event_handlers/mod_rayo/rayo_input_component.c index 1435b90a27..4bcab10b0d 100644 --- a/src/mod/event_handlers/mod_rayo/rayo_input_component.c +++ b/src/mod/event_handlers/mod_rayo/rayo_input_component.c @@ -551,7 +551,7 @@ static iks *start_call_voice_input(struct input_component *component, switch_cor if (component->speech_mode && handler->voice_component) { /* don't allow multi voice input */ - RAYO_UNLOCK(component); + RAYO_RELEASE(component); RAYO_DESTROY(component); return iks_new_error_detailed(iq, STANZA_ERROR_CONFLICT, "Multiple voice input is not allowed"); } @@ -565,7 +565,7 @@ static iks *start_call_voice_input(struct input_component *component, switch_cor /* if recognition engine is different, we can't handle this request */ if (!zstr(handler->last_recognizer) && strcmp(component->recognizer, handler->last_recognizer)) { handler->voice_component = NULL; - RAYO_UNLOCK(component); + RAYO_RELEASE(component); RAYO_DESTROY(component); return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "Must use the same recognizer for the entire call"); } else if (zstr(handler->last_recognizer)) { @@ -582,7 +582,7 @@ static iks *start_call_voice_input(struct input_component *component, switch_cor if (!grammar) { handler->voice_component = NULL; - RAYO_UNLOCK(component); + RAYO_RELEASE(component); RAYO_DESTROY(component); return iks_new_error_detailed(iq, stanza_error, error_detail); } @@ -614,7 +614,7 @@ static iks *start_call_dtmf_input(struct input_component *component, switch_core /* parse the grammar */ if (!(component->grammar = srgs_parse(globals.parser, iks_find_cdata(input, "grammar")))) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Failed to parse grammar body\n"); - RAYO_UNLOCK(component); + RAYO_RELEASE(component); RAYO_DESTROY(component); return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "Failed to parse grammar body"); } @@ -654,7 +654,7 @@ static iks *start_call_input(struct input_component *component, switch_core_sess /* fire up media bug to monitor lifecycle */ if (switch_core_media_bug_add(session, "rayo_input_component", NULL, input_handler_bug_callback, handler, 0, SMBF_READ_REPLACE, &handler->bug) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Failed to create input handler media bug\n"); - RAYO_UNLOCK(component); + RAYO_RELEASE(component); RAYO_DESTROY(component); return iks_new_error_detailed(iq, STANZA_ERROR_INTERNAL_SERVER_ERROR, "Failed to create input handler media bug"); } @@ -666,7 +666,7 @@ static iks *start_call_input(struct input_component *component, switch_core_sess /* handler bug was destroyed */ switch_mutex_unlock(handler->mutex); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Input handler media bug is closed\n"); - RAYO_UNLOCK(component); + RAYO_RELEASE(component); RAYO_DESTROY(component); return iks_new_error_detailed(iq, STANZA_ERROR_INTERNAL_SERVER_ERROR, "Input handler media bug is closed\n"); } @@ -767,7 +767,9 @@ static iks *stop_call_input_component(struct rayo_actor *component, struct rayo_ switch_mutex_lock(input_component->handler->mutex); input_component->stop = 1; if (input_component->speech_mode) { + switch_mutex_unlock(input_component->handler->mutex); switch_ivr_stop_detect_speech(session); + switch_mutex_lock(input_component->handler->mutex); rayo_component_send_complete(RAYO_COMPONENT(component), COMPONENT_COMPLETE_STOP); } switch_mutex_unlock(input_component->handler->mutex); @@ -789,7 +791,9 @@ static iks *start_timers_call_input_component(struct rayo_actor *component, stru if (session) { switch_mutex_lock(input_component->handler->mutex); if (input_component->speech_mode) { + switch_mutex_unlock(input_component->handler->mutex); switch_ivr_detect_speech_start_input_timers(session); + switch_mutex_lock(input_component->handler->mutex); } else { input_component->last_digit_time = switch_micro_time_now(); input_component->start_timers = 1; @@ -861,7 +865,7 @@ static void on_detected_speech_event(switch_event_t *event) rayo_component_send_complete(component, INPUT_NOMATCH); } } - RAYO_UNLOCK(component); + RAYO_RELEASE(component); } } else if (!strcasecmp("begin-speaking", speech_type)) { char *component_id = switch_mprintf("%s-input-voice", uuid); @@ -870,7 +874,7 @@ static void on_detected_speech_event(switch_event_t *event) if (component && INPUT_COMPONENT(component)->barge_event) { send_barge_event(component); } - RAYO_UNLOCK(component); + RAYO_RELEASE(component); } else if (!strcasecmp("closed", speech_type)) { char *component_id = switch_mprintf("%s-input-voice", uuid); struct rayo_component *component = RAYO_COMPONENT_LOCATE(component_id); @@ -887,7 +891,7 @@ static void on_detected_speech_event(switch_event_t *event) /* shouldn't get here... */ rayo_component_send_complete(component, COMPONENT_COMPLETE_ERROR); } - RAYO_UNLOCK(component); + RAYO_RELEASE(component); } } switch_safe_free(event_str); diff --git a/src/mod/event_handlers/mod_rayo/rayo_output_component.c b/src/mod/event_handlers/mod_rayo/rayo_output_component.c index 9a19b1753e..82cf3a0272 100644 --- a/src/mod/event_handlers/mod_rayo/rayo_output_component.c +++ b/src/mod/event_handlers/mod_rayo/rayo_output_component.c @@ -112,11 +112,11 @@ static iks *start_call_output(struct rayo_component *component, switch_core_sess stream.write_function(&stream, "}fileman://rayo://%s", RAYO_JID(component)); if (switch_ivr_displace_session(session, stream.data, 0, "m") == SWITCH_STATUS_SUCCESS) { - RAYO_UNLOCK(component); + RAYO_RELEASE(component); } else { if (component->complete) { /* component is already destroyed */ - RAYO_UNLOCK(component); + RAYO_RELEASE(component); } else { /* need to destroy component */ if (OUTPUT_COMPONENT(component)->document) { @@ -210,7 +210,7 @@ static iks *start_mixer_output_component(struct rayo_actor *mixer, struct rayo_m rayo_component_api_execute_async(component, "conference", stream.data); switch_safe_free(stream.data); - RAYO_UNLOCK(component); + RAYO_RELEASE(component); return NULL; } @@ -512,7 +512,7 @@ static switch_status_t rayo_file_open(switch_file_handle_t *handle, const char * if (status != SWITCH_STATUS_SUCCESS && context->component) { /* complete error event will be sent by calling thread */ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Status = %i\n", status); - RAYO_UNLOCK(context->component); + RAYO_RELEASE(context->component); } return status; diff --git a/src/mod/event_handlers/mod_rayo/rayo_prompt_component.c b/src/mod/event_handlers/mod_rayo/rayo_prompt_component.c index 7431558a0a..7003762839 100644 --- a/src/mod/event_handlers/mod_rayo/rayo_prompt_component.c +++ b/src/mod/event_handlers/mod_rayo/rayo_prompt_component.c @@ -288,7 +288,7 @@ static iks *prompt_component_handle_input_error(struct rayo_actor *prompt, struc /* done */ iks_delete(PROMPT_COMPONENT(prompt)->iq); - RAYO_UNLOCK(prompt); + RAYO_RELEASE(prompt); RAYO_DESTROY(prompt); break; @@ -357,7 +357,7 @@ static iks *prompt_component_handle_output_error(struct rayo_actor *prompt, stru /* done */ iks_delete(PROMPT_COMPONENT(prompt)->iq); - RAYO_UNLOCK(prompt); + RAYO_RELEASE(prompt); RAYO_DESTROY(prompt); break; diff --git a/src/mod/event_handlers/mod_rayo/rayo_record_component.c b/src/mod/event_handlers/mod_rayo/rayo_record_component.c index 2dfd817364..d9474022f2 100644 --- a/src/mod/event_handlers/mod_rayo/rayo_record_component.c +++ b/src/mod/event_handlers/mod_rayo/rayo_record_component.c @@ -141,7 +141,7 @@ static void on_call_record_stop_event(switch_event_t *event) /* TODO assume final timeout, for now */ complete_record(component, RECORD_COMPLETE_FINAL_TIMEOUT); } - RAYO_UNLOCK(component); + RAYO_RELEASE(component); } } @@ -282,7 +282,7 @@ static iks *start_call_record_component(struct rayo_actor *call, struct rayo_mes if (start_call_record(session, component)) { rayo_component_send_start(component, iq); } else { - RAYO_UNLOCK(component); + RAYO_RELEASE(component); RAYO_DESTROY(component); return iks_new_error(iq, STANZA_ERROR_INTERNAL_SERVER_ERROR); } @@ -369,7 +369,7 @@ static void on_mixer_record_event(switch_event_t *event) complete_record(component, RECORD_COMPLETE_FINAL_TIMEOUT); } } - RAYO_UNLOCK(component); + RAYO_RELEASE(component); } } @@ -412,7 +412,7 @@ static iks *start_mixer_record_component(struct rayo_actor *mixer, struct rayo_m /* mixer doesn't allow "send" */ if (!strcmp("send", iks_find_attrib_soft(record, "direction"))) { - RAYO_UNLOCK(component); + RAYO_RELEASE(component); RAYO_DESTROY(component); return iks_new_error(iq, STANZA_ERROR_BAD_REQUEST); } @@ -420,7 +420,7 @@ static iks *start_mixer_record_component(struct rayo_actor *mixer, struct rayo_m if (start_mixer_record(component)) { rayo_component_send_start(component, iq); } else { - RAYO_UNLOCK(component); + RAYO_RELEASE(component); RAYO_DESTROY(component); return iks_new_error(iq, STANZA_ERROR_INTERNAL_SERVER_ERROR); } From 1511fe3ee803276dd4b679650a9249667d4c6a11 Mon Sep 17 00:00:00 2001 From: Chris Rienzo Date: Fri, 13 Jun 2014 12:16:26 -0400 Subject: [PATCH 047/231] mod_rayo: rework component inheritance- component now inherits parent call/mixer mutex and parent reference counting moved to base class --- src/mod/event_handlers/mod_rayo/mod_rayo.c | 50 +++++++++++-------- src/mod/event_handlers/mod_rayo/mod_rayo.h | 6 +-- .../mod_rayo/rayo_cpa_component.c | 10 ++-- .../mod_rayo/rayo_fax_components.c | 4 +- .../mod_rayo/rayo_input_component.c | 4 +- .../mod_rayo/rayo_output_component.c | 2 +- .../mod_rayo/rayo_prompt_component.c | 10 ++-- .../mod_rayo/rayo_record_component.c | 8 +-- 8 files changed, 49 insertions(+), 45 deletions(-) diff --git a/src/mod/event_handlers/mod_rayo/mod_rayo.c b/src/mod/event_handlers/mod_rayo/mod_rayo.c index 1d46fdb2a5..1506113808 100644 --- a/src/mod/event_handlers/mod_rayo/mod_rayo.c +++ b/src/mod/event_handlers/mod_rayo/mod_rayo.c @@ -950,6 +950,10 @@ void rayo_actor_destroy(struct rayo_actor *actor, const char *file, int line) if (actor->cleanup_fn) { actor->cleanup_fn(actor); } + if (actor->parent) { + /* safe to destroy parent now */ + RAYO_RELEASE(actor->parent); + } switch_core_hash_delete(globals.destroy_actors, RAYO_JID(actor)); switch_core_destroy_memory_pool(&pool); } else { @@ -1224,10 +1228,12 @@ void rayo_actor_send_ignore(struct rayo_actor *to, struct rayo_message *msg) switch_log_printf(SWITCH_CHANNEL_ID_LOG, msg->file, "", msg->line, "", SWITCH_LOG_WARNING, "%s, dropping unexpected message to %s.\n", msg->from_jid, RAYO_JID(to)); } -#define RAYO_ACTOR_INIT(actor, pool, type, subtype, id, jid, cleanup, send) rayo_actor_init(actor, pool, type, subtype, id, jid, cleanup, send, __FILE__, __LINE__) +#define RAYO_ACTOR_INIT(actor, pool, type, subtype, id, jid, cleanup, send) rayo_actor_init(actor, pool, type, subtype, id, jid, cleanup, send, NULL, __FILE__, __LINE__) +#define RAYO_ACTOR_INIT_PARENT(actor, pool, type, subtype, id, jid, cleanup, send, parent) rayo_actor_init(actor, pool, type, subtype, id, jid, cleanup, send, parent, __FILE__, __LINE__) /** * Initialize a rayo actor + * @param actor to initialize * @param pool to use * @param type of actor (MIXER, CALL, SERVER, COMPONENT) * @param subtype of actor (input/output/prompt) @@ -1235,11 +1241,12 @@ void rayo_actor_send_ignore(struct rayo_actor *to, struct rayo_message *msg) * @param jid external ID * @param cleanup function * @param send sent message handler + * @param parent of actor * @param file that called this function * @param line that called this function * @return the actor or NULL if JID conflict */ -static struct rayo_actor *rayo_actor_init(struct rayo_actor *actor, switch_memory_pool_t *pool, const char *type, const char *subtype, const char *id, const char *jid, rayo_actor_cleanup_fn cleanup, rayo_actor_send_fn send, const char *file, int line) +static struct rayo_actor *rayo_actor_init(struct rayo_actor *actor, switch_memory_pool_t *pool, const char *type, const char *subtype, const char *id, const char *jid, rayo_actor_cleanup_fn cleanup, rayo_actor_send_fn send, struct rayo_actor *parent, const char *file, int line) { char *domain; actor->type = switch_core_strdup(pool, type); @@ -1265,7 +1272,6 @@ static struct rayo_actor *rayo_actor_init(struct rayo_actor *actor, switch_memor actor->seq = 1; actor->ref_count = 1; actor->destroy = 0; - switch_mutex_init(&actor->mutex, SWITCH_MUTEX_NESTED, pool); actor->cleanup_fn = cleanup; if (send == NULL) { actor->send_fn = rayo_actor_send_ignore; @@ -1273,6 +1279,17 @@ static struct rayo_actor *rayo_actor_init(struct rayo_actor *actor, switch_memor actor->send_fn = send; } + actor->parent = parent; + if (!actor->parent) { + switch_mutex_init(&actor->mutex, SWITCH_MUTEX_NESTED, pool); + } else { + /* inherit mutex from parent */ + actor->mutex = actor->parent->mutex; + + /* prevent parent destruction */ + RAYO_RETAIN(actor->parent); + } + /* add to hash of actors, so commands can route to call */ switch_mutex_lock(globals.actors_mutex); if (!zstr(jid)) { @@ -1280,6 +1297,11 @@ static struct rayo_actor *rayo_actor_init(struct rayo_actor *actor, switch_memor /* duplicate JID, give up! */ switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, "", line, "", SWITCH_LOG_NOTICE, "JID conflict! %s\n", RAYO_JID(actor)); switch_mutex_unlock(globals.actors_mutex); + if (actor->parent) { + /* unlink from parent */ + RAYO_RELEASE(actor->parent); + actor->parent = NULL; + } return NULL; } switch_core_hash_insert(globals.actors, RAYO_JID(actor), actor); @@ -1313,7 +1335,7 @@ static struct rayo_call *rayo_call_init(struct rayo_call *call, switch_memory_po } call_jid = switch_mprintf("%s@%s", uuid, RAYO_JID(globals.server)); - call = RAYO_CALL(rayo_actor_init(RAYO_ACTOR(call), pool, RAT_CALL, "", uuid, call_jid, rayo_call_cleanup, rayo_call_send, file, line)); + call = RAYO_CALL(rayo_actor_init(RAYO_ACTOR(call), pool, RAT_CALL, "", uuid, call_jid, rayo_call_cleanup, rayo_call_send, NULL, file, line)); if (call) { call->dcp_jid = ""; call->idle_start_time = switch_micro_time_now(); @@ -1370,7 +1392,7 @@ static void rayo_mixer_cleanup(struct rayo_actor *actor) static struct rayo_mixer *rayo_mixer_init(struct rayo_mixer *mixer, switch_memory_pool_t *pool, const char *name, const char *file, int line) { char *mixer_jid = switch_mprintf("%s@%s", name, RAYO_JID(globals.server)); - mixer = RAYO_MIXER(rayo_actor_init(RAYO_ACTOR(mixer), pool, RAT_MIXER, "", name, mixer_jid, rayo_mixer_cleanup, rayo_mixer_send, file, line)); + mixer = RAYO_MIXER(rayo_actor_init(RAYO_ACTOR(mixer), pool, RAT_MIXER, "", name, mixer_jid, rayo_mixer_cleanup, rayo_mixer_send, NULL, file, line)); if (mixer) { switch_core_hash_init(&mixer->members); switch_core_hash_init(&mixer->subscribers); @@ -1397,19 +1419,6 @@ static struct rayo_mixer *_rayo_mixer_create(const char *name, const char *file, return mixer; } -/** - * Clean up component before destruction - */ -static void rayo_component_cleanup(struct rayo_actor *actor) -{ - if (RAYO_COMPONENT(actor)->cleanup_fn) { - RAYO_COMPONENT(actor)->cleanup_fn(actor); - } - - /* parent can now be destroyed */ - RAYO_RELEASE(RAYO_COMPONENT(actor)->parent); -} - /** * Initialize Rayo component * @param type of this component @@ -1430,13 +1439,10 @@ struct rayo_component *_rayo_component_init(struct rayo_component *component, sw id = jid; } - component = RAYO_COMPONENT(rayo_actor_init(RAYO_ACTOR(component), pool, type, subtype, id, jid, rayo_component_cleanup, rayo_component_send, file, line)); + component = RAYO_COMPONENT(rayo_actor_init(RAYO_ACTOR(component), pool, type, subtype, id, jid, cleanup, rayo_component_send, parent, file, line)); if (component) { - RAYO_RETAIN(parent); component->client_jid = switch_core_strdup(pool, client_jid); component->ref = switch_core_strdup(pool, ref); - component->parent = parent; - component->cleanup_fn = cleanup; } switch_safe_free(ref); diff --git a/src/mod/event_handlers/mod_rayo/mod_rayo.h b/src/mod/event_handlers/mod_rayo/mod_rayo.h index 074e32fd5e..cefd4e1782 100644 --- a/src/mod/event_handlers/mod_rayo/mod_rayo.h +++ b/src/mod/event_handlers/mod_rayo/mod_rayo.h @@ -106,6 +106,8 @@ struct rayo_actor { rayo_actor_send_fn send_fn; /** optional cleanup */ rayo_actor_cleanup_fn cleanup_fn; + /** optional parent */ + struct rayo_actor *parent; }; /** @@ -114,16 +116,12 @@ struct rayo_actor { struct rayo_component { /** base actor class */ struct rayo_actor base; - /** parent to this component */ - struct rayo_actor *parent; /** owning client JID */ const char *client_jid; /** external ref */ const char *ref; /** true if component has completed */ int complete; - /** optional cleanup */ - rayo_actor_cleanup_fn cleanup_fn; }; #define RAYO_ACTOR(x) ((struct rayo_actor *)x) diff --git a/src/mod/event_handlers/mod_rayo/rayo_cpa_component.c b/src/mod/event_handlers/mod_rayo/rayo_cpa_component.c index 634968d4a8..fb271bd03e 100644 --- a/src/mod/event_handlers/mod_rayo/rayo_cpa_component.c +++ b/src/mod/event_handlers/mod_rayo/rayo_cpa_component.c @@ -166,14 +166,14 @@ static void stop_cpa_detectors(struct cpa_component *cpa) void *cpa_signal = NULL; switch_core_hash_this(hi, &signal_type, NULL, &cpa_signal); if (cpa_signal) { - rayo_cpa_detector_stop(RAYO_COMPONENT(cpa)->parent->id, ((struct cpa_signal *)cpa_signal)->name); - unsubscribe(RAYO_COMPONENT(cpa)->parent->id, ((struct cpa_signal *)cpa_signal)->name, RAYO_JID(cpa)); + rayo_cpa_detector_stop(RAYO_ACTOR(cpa)->parent->id, ((struct cpa_signal *)cpa_signal)->name); + unsubscribe(RAYO_ACTOR(cpa)->parent->id, ((struct cpa_signal *)cpa_signal)->name, RAYO_JID(cpa)); } } switch_core_hash_destroy(&cpa->signals); cpa->signals = NULL; } - unsubscribe(RAYO_COMPONENT(cpa)->parent->id, "hangup", RAYO_JID(cpa)); + unsubscribe(RAYO_ACTOR(cpa)->parent->id, "hangup", RAYO_JID(cpa)); } /** @@ -197,7 +197,7 @@ static void rayo_cpa_detector_event(const char *jid, void *user_data) switch_event_t *event = (switch_event_t *)user_data; const char *signal_type = switch_event_get_header(event, "signal-type"); struct cpa_signal *cpa_signal = switch_core_hash_find(CPA_COMPONENT(component)->signals, signal_type); - switch_log_printf(SWITCH_CHANNEL_UUID_LOG(RAYO_COMPONENT(component)->parent->id), SWITCH_LOG_DEBUG, "Handling CPA event\n"); + switch_log_printf(SWITCH_CHANNEL_UUID_LOG(component->parent->id), SWITCH_LOG_DEBUG, "Handling CPA event\n"); if (cpa_signal) { const char *value = switch_event_get_header(event, "value"); const char *duration = switch_event_get_header(event, "duration"); @@ -234,7 +234,7 @@ static void rayo_cpa_detector_event(const char *jid, void *user_data) } } } else { - switch_log_printf(SWITCH_CHANNEL_UUID_LOG(RAYO_COMPONENT(component)->parent->id), SWITCH_LOG_DEBUG, "Skipping CPA event\n"); + switch_log_printf(SWITCH_CHANNEL_UUID_LOG(component->parent->id), SWITCH_LOG_DEBUG, "Skipping CPA event\n"); } RAYO_RELEASE(component); } diff --git a/src/mod/event_handlers/mod_rayo/rayo_fax_components.c b/src/mod/event_handlers/mod_rayo/rayo_fax_components.c index 0ceb0532b7..b605702005 100644 --- a/src/mod/event_handlers/mod_rayo/rayo_fax_components.c +++ b/src/mod/event_handlers/mod_rayo/rayo_fax_components.c @@ -340,7 +340,7 @@ static iks *start_receivefax_component(struct rayo_actor *call, struct rayo_mess static iks *stop_fax_component(struct rayo_actor *component, struct rayo_message *msg, void *data) { iks *iq = msg->payload; - switch_core_session_t *session = switch_core_session_locate(RAYO_COMPONENT(component)->parent->id); + switch_core_session_t *session = switch_core_session_locate(component->parent->id); FAX_COMPONENT(component)->stop = 1; if (session) { switch_core_session_execute_application_async(session, "stopfax", ""); @@ -459,7 +459,7 @@ static void on_execute_complete_event(switch_event_t *event) insert_fax_metadata(event, "fax_remote_station_id", complete); /* flag faxing as done */ - rayo_call_set_faxing(RAYO_CALL(RAYO_COMPONENT(component)->parent), 0); + rayo_call_set_faxing(RAYO_CALL(component->parent), 0); rayo_component_send_complete_event(RAYO_COMPONENT(component), result); diff --git a/src/mod/event_handlers/mod_rayo/rayo_input_component.c b/src/mod/event_handlers/mod_rayo/rayo_input_component.c index 4bcab10b0d..cfada79370 100644 --- a/src/mod/event_handlers/mod_rayo/rayo_input_component.c +++ b/src/mod/event_handlers/mod_rayo/rayo_input_component.c @@ -762,7 +762,7 @@ static iks *stop_call_input_component(struct rayo_actor *component, struct rayo_ struct input_component *input_component = INPUT_COMPONENT(component); if (input_component && !input_component->stop) { - switch_core_session_t *session = switch_core_session_locate(RAYO_COMPONENT(component)->parent->id); + switch_core_session_t *session = switch_core_session_locate(component->parent->id); if (session) { switch_mutex_lock(input_component->handler->mutex); input_component->stop = 1; @@ -787,7 +787,7 @@ static iks *start_timers_call_input_component(struct rayo_actor *component, stru iks *iq = msg->payload; struct input_component *input_component = INPUT_COMPONENT(component); if (input_component) { - switch_core_session_t *session = switch_core_session_locate(RAYO_COMPONENT(component)->parent->id); + switch_core_session_t *session = switch_core_session_locate(component->parent->id); if (session) { switch_mutex_lock(input_component->handler->mutex); if (input_component->speech_mode) { diff --git a/src/mod/event_handlers/mod_rayo/rayo_output_component.c b/src/mod/event_handlers/mod_rayo/rayo_output_component.c index 82cf3a0272..9d075dc6ae 100644 --- a/src/mod/event_handlers/mod_rayo/rayo_output_component.c +++ b/src/mod/event_handlers/mod_rayo/rayo_output_component.c @@ -536,7 +536,7 @@ static switch_status_t rayo_file_close(switch_file_handle_t *handle) } else { if (!strcmp(RAYO_ACTOR(context->component)->type, RAT_CALL_COMPONENT)) { /* call output... check for hangup */ - switch_core_session_t *session = switch_core_session_locate(context->component->parent->id); + switch_core_session_t *session = switch_core_session_locate(RAYO_ACTOR(context->component)->parent->id); if (session) { if (switch_channel_get_state(switch_core_session_get_channel(session)) >= CS_HANGUP) { rayo_component_send_complete(context->component, COMPONENT_COMPLETE_HANGUP); diff --git a/src/mod/event_handlers/mod_rayo/rayo_prompt_component.c b/src/mod/event_handlers/mod_rayo/rayo_prompt_component.c index 7003762839..33042ed19d 100644 --- a/src/mod/event_handlers/mod_rayo/rayo_prompt_component.c +++ b/src/mod/event_handlers/mod_rayo/rayo_prompt_component.c @@ -126,14 +126,14 @@ static void start_input(struct prompt_component *prompt, int start_timers, int b iks *input = iks_find(PROMPT_COMPONENT(prompt)->iq, "prompt"); input = iks_find(input, "input"); iks_insert_attrib(iq, "from", RAYO_JID(prompt)); - iks_insert_attrib(iq, "to", RAYO_JID(RAYO_COMPONENT(prompt)->parent)); + iks_insert_attrib(iq, "to", RAYO_JID(RAYO_ACTOR(prompt)->parent)); iks_insert_attrib_printf(iq, "id", "mod_rayo-prompt-%d", RAYO_SEQ_NEXT(prompt)); iks_insert_attrib(iq, "type", "set"); input = iks_copy_within(input, iks_stack(iq)); iks_insert_attrib(input, "start-timers", start_timers ? "true" : "false"); iks_insert_attrib(input, "barge-event", barge_event ? "true" : "false"); iks_insert_node(iq, input); - RAYO_SEND_MESSAGE(prompt, RAYO_JID(RAYO_COMPONENT(prompt)->parent), iq); + RAYO_SEND_MESSAGE(prompt, RAYO_JID(RAYO_ACTOR(prompt)->parent), iq); } /** @@ -281,7 +281,7 @@ static iks *prompt_component_handle_input_error(struct rayo_actor *prompt, struc /* forward IQ error to client */ iq = PROMPT_COMPONENT(prompt)->iq; - iks_insert_attrib(iq, "from", RAYO_JID(RAYO_COMPONENT(prompt)->parent)); + iks_insert_attrib(iq, "from", RAYO_JID(prompt->parent)); iks_insert_attrib(iq, "to", RAYO_COMPONENT(prompt)->client_jid); iks_insert_node(iq, iks_copy_within(error, iks_stack(iq))); RAYO_SEND_REPLY(prompt, RAYO_COMPONENT(prompt)->client_jid, iq); @@ -309,7 +309,7 @@ static iks *prompt_component_handle_input_error(struct rayo_actor *prompt, struc /* forward IQ error to client */ iq = PROMPT_COMPONENT(prompt)->iq; - iks_insert_attrib(iq, "from", RAYO_JID(RAYO_COMPONENT(prompt)->parent)); + iks_insert_attrib(iq, "from", RAYO_JID(prompt->parent)); iks_insert_attrib(iq, "to", RAYO_COMPONENT(prompt)->client_jid); iks_insert_node(iq, iks_copy_within(error, iks_stack(iq))); PROMPT_COMPONENT(prompt)->complete = iks_copy(iq); @@ -350,7 +350,7 @@ static iks *prompt_component_handle_output_error(struct rayo_actor *prompt, stru /* forward IQ error to client */ iq = PROMPT_COMPONENT(prompt)->iq; - iks_insert_attrib(iq, "from", RAYO_JID(RAYO_COMPONENT(prompt)->parent)); + iks_insert_attrib(iq, "from", RAYO_JID(prompt->parent)); iks_insert_attrib(iq, "to", RAYO_COMPONENT(prompt)->client_jid); iks_insert_node(iq, iks_copy_within(error, iks_stack(iq))); RAYO_SEND_REPLY(prompt, RAYO_COMPONENT(prompt)->client_jid, iq); diff --git a/src/mod/event_handlers/mod_rayo/rayo_record_component.c b/src/mod/event_handlers/mod_rayo/rayo_record_component.c index d9474022f2..20d857377c 100644 --- a/src/mod/event_handlers/mod_rayo/rayo_record_component.c +++ b/src/mod/event_handlers/mod_rayo/rayo_record_component.c @@ -84,7 +84,7 @@ struct record_component { static void complete_record(struct rayo_component *component, const char *reason, const char *reason_namespace) { switch_core_session_t *session = NULL; - const char *uuid = component->parent->id; + const char *uuid = RAYO_ACTOR(component)->parent->id; const char *uri = RECORD_COMPONENT(component)->local_file_path; iks *recording; switch_size_t file_size = 0; @@ -296,7 +296,7 @@ static iks *start_call_record_component(struct rayo_actor *call, struct rayo_mes static iks *stop_call_record_component(struct rayo_actor *component, struct rayo_message *msg, void *data) { iks *iq = msg->payload; - switch_core_session_t *session = switch_core_session_locate(RAYO_COMPONENT(component)->parent->id); + switch_core_session_t *session = switch_core_session_locate(component->parent->id); if (session) { RECORD_COMPONENT(component)->stop = 1; switch_ivr_stop_record_session(session, RAYO_ID(component)); @@ -383,7 +383,7 @@ static int start_mixer_record(struct rayo_component *component) char *args; SWITCH_STANDARD_STREAM(stream); - args = switch_mprintf("%s recording start %s", component->parent->id, RAYO_ID(component)); + args = switch_mprintf("%s recording start %s", RAYO_ACTOR(component)->parent->id, RAYO_ID(component)); switch_api_execute("conference", args, NULL, &stream); switch_safe_free(args); switch_safe_free(stream.data); @@ -439,7 +439,7 @@ static iks *stop_mixer_record_component(struct rayo_actor *component, struct ray SWITCH_STANDARD_STREAM(stream); RECORD_COMPONENT(component)->stop = 1; - args = switch_mprintf("%s recording stop %s", RAYO_COMPONENT(component)->parent->id, RAYO_ID(component)); + args = switch_mprintf("%s recording stop %s", component->parent->id, RAYO_ID(component)); switch_api_execute("conference", args, NULL, &stream); switch_safe_free(args); switch_safe_free(stream.data); From 633dfe2a56fea01c41b610c5c6a2161ef2019176 Mon Sep 17 00:00:00 2001 From: Chris Rienzo Date: Fri, 13 Jun 2014 12:34:19 -0400 Subject: [PATCH 048/231] FS-6535 mod_rayo: close recognizer when input component is complete --- .../mod_rayo/rayo_input_component.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/mod/event_handlers/mod_rayo/rayo_input_component.c b/src/mod/event_handlers/mod_rayo/rayo_input_component.c index cfada79370..76bffff055 100644 --- a/src/mod/event_handlers/mod_rayo/rayo_input_component.c +++ b/src/mod/event_handlers/mod_rayo/rayo_input_component.c @@ -720,6 +720,22 @@ static char *create_input_component_id(switch_core_session_t *session, iks *inpu return switch_core_session_sprintf(session, "%s-input-%s", switch_core_session_get_uuid(session), mode); } +/** + * Release any resources consumed by this input component + */ +static void input_component_cleanup(struct rayo_actor *component) +{ + switch_mutex_lock(component->mutex); + if (INPUT_COMPONENT(component)->speech_mode) { + switch_core_session_t *session = switch_core_session_locate(component->parent->id); + if (session) { + switch_ivr_stop_detect_speech(session); + switch_core_session_rwunlock(session); + } + } + switch_mutex_unlock(component->mutex); +} + /** * Start execution of input component */ @@ -745,7 +761,7 @@ static iks *start_call_input_component(struct rayo_actor *call, struct rayo_mess switch_core_new_memory_pool(&pool); input_component = switch_core_alloc(pool, sizeof(*input_component)); - input_component = INPUT_COMPONENT(rayo_component_init(RAYO_COMPONENT(input_component), pool, RAT_CALL_COMPONENT, "input", component_id, call, iks_find_attrib(iq, "from"))); + input_component = INPUT_COMPONENT(rayo_component_init_cleanup(RAYO_COMPONENT(input_component), pool, RAT_CALL_COMPONENT, "input", component_id, call, iks_find_attrib(iq, "from"), input_component_cleanup)); if (!input_component) { switch_core_destroy_memory_pool(&pool); return iks_new_error_detailed(iq, STANZA_ERROR_INTERNAL_SERVER_ERROR, "Failed to create input entity"); From 9108a08a47d7488c9ff2aa5c77d7b32ca8effcf2 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Fri, 13 Jun 2014 23:15:36 +0500 Subject: [PATCH 049/231] fix build --- src/mod/endpoints/mod_verto/mod_verto.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mod/endpoints/mod_verto/mod_verto.c b/src/mod/endpoints/mod_verto/mod_verto.c index 2a8662615e..34a67b3866 100644 --- a/src/mod/endpoints/mod_verto/mod_verto.c +++ b/src/mod/endpoints/mod_verto/mod_verto.c @@ -833,7 +833,7 @@ static switch_bool_t check_auth(jsock_t *jsock, cJSON *params, int *code, char * verto_dialplan = val; } - switch_event_add_header(jsock->params, SWITCH_STACK_BOTTOM, var, val); + switch_event_add_header_string(jsock->params, SWITCH_STACK_BOTTOM, var, val); } } @@ -842,7 +842,7 @@ static switch_bool_t check_auth(jsock_t *jsock, cJSON *params, int *code, char * const char *var = switch_xml_attr_soft(x_param, "name"); const char *val = switch_xml_attr_soft(x_param, "value"); - switch_event_add_header(jsock->vars, SWITCH_STACK_BOTTOM, var, val); + switch_event_add_header_string(jsock->vars, SWITCH_STACK_BOTTOM, var, val); } } From 280e816a90d0360c0d3347c5882617f6af9de92a Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Sat, 14 Jun 2014 04:56:55 +0500 Subject: [PATCH 050/231] FS-6590 --resolve --- src/mod/formats/mod_shout/mod_shout.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/mod/formats/mod_shout/mod_shout.c b/src/mod/formats/mod_shout/mod_shout.c index 68ea6b77b0..a99a299479 100644 --- a/src/mod/formats/mod_shout/mod_shout.c +++ b/src/mod/formats/mod_shout/mod_shout.c @@ -901,7 +901,7 @@ static switch_status_t shout_file_seek(switch_file_handle_t *handle, unsigned in static switch_status_t shout_file_read(switch_file_handle_t *handle, void *data, size_t *len) { shout_context_t *context = handle->private_info; - size_t rb = 0, bytes = *len * sizeof(int16_t) * handle->channels, newbytes = 0; + size_t rb = 0, bytes = *len * sizeof(int16_t) * handle->real_channels, newbytes = 0; *len = 0; @@ -923,7 +923,7 @@ static switch_status_t shout_file_read(switch_file_handle_t *handle, void *data, /* switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "rb: %d, bytes: %d\n", (int) rb, (int) bytes); */ if (rb) { - *len = rb / sizeof(int16_t) / handle->channels; + *len = rb / sizeof(int16_t) / handle->real_channels; } else { /* no data, so insert 1 second of silence */ newbytes = 2 * handle->samplerate; @@ -933,7 +933,7 @@ static switch_status_t shout_file_read(switch_file_handle_t *handle, void *data, switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Padding mp3 stream with 1s of empty audio. (%s)\n", context->stream_url); memset(data, 255, bytes); - *len = bytes / sizeof(int16_t) / handle->channels; + *len = bytes / sizeof(int16_t) / handle->real_channels; } handle->sample_count += *len; @@ -980,7 +980,7 @@ static switch_status_t shout_file_write(switch_file_handle_t *handle, void *data if (handle->handler && context->audio_mutex) { switch_mutex_lock(context->audio_mutex); if (context->audio_buffer) { - if (!switch_buffer_write(context->audio_buffer, data, (nsamples * sizeof(int16_t) * handle->channels))) { + if (!switch_buffer_write(context->audio_buffer, data, (nsamples * sizeof(int16_t) * handle->real_channels))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Buffer error\n"); context->err++; } @@ -1008,7 +1008,7 @@ static switch_status_t shout_file_write(switch_file_handle_t *handle, void *data context->mp3buf = switch_core_alloc(context->memory_pool, context->mp3buflen); } - if (handle->channels == 2) { + if (handle->real_channels == 2) { switch_size_t i, j = 0; if (context->llen < nsamples) { @@ -1027,7 +1027,7 @@ static switch_status_t shout_file_write(switch_file_handle_t *handle, void *data return SWITCH_STATUS_FALSE; } - } else if (handle->channels == 1) { + } else if (handle->real_channels == 1) { if ((rlen = lame_encode_buffer(context->gfp, audio, NULL, (int)nsamples, context->mp3buf, (int)context->mp3buflen)) < 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "MP3 encode error %d!\n", rlen); return SWITCH_STATUS_FALSE; From c0e7e7b88c4f9b82787eb3c9d8d987d28c29c135 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Sat, 14 Jun 2014 07:05:00 +0500 Subject: [PATCH 051/231] add reset function to clear some state data in the rtp session --- src/include/switch_rtp.h | 1 + src/mod/endpoints/mod_verto/mod_verto.c | 5 ++++- src/switch_core_media.c | 4 ++++ src/switch_rtp.c | 14 ++++++++++++-- 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/include/switch_rtp.h b/src/include/switch_rtp.h index c6082fa9c5..9de008ce07 100644 --- a/src/include/switch_rtp.h +++ b/src/include/switch_rtp.h @@ -218,6 +218,7 @@ SWITCH_DECLARE(void) switch_rtp_reset_media_timer(switch_rtp_t *rtp_session); SWITCH_DECLARE(void) switch_rtp_set_max_missed_packets(switch_rtp_t *rtp_session, uint32_t max); SWITCH_DECLARE(switch_status_t) switch_rtp_udptl_mode(switch_rtp_t *rtp_session); +SWITCH_DECLARE(void) switch_rtp_reset(switch_rtp_t *rtp_session); /*! \brief Assign a local address to the RTP session diff --git a/src/mod/endpoints/mod_verto/mod_verto.c b/src/mod/endpoints/mod_verto/mod_verto.c index 34a67b3866..ca260be05b 100644 --- a/src/mod/endpoints/mod_verto/mod_verto.c +++ b/src/mod/endpoints/mod_verto/mod_verto.c @@ -1634,7 +1634,6 @@ static void verto_set_media_options(verto_pvt_t *tech_pvt, verto_profile_t *prof //tech_pvt->mparams->manual_rtp_bugs = profile->manual_rtp_bugs; //tech_pvt->mparams->manual_video_rtp_bugs = profile->manual_video_rtp_bugs; - tech_pvt->mparams->local_network = switch_core_session_strdup(tech_pvt->session, profile->local_network); @@ -2382,6 +2381,10 @@ static switch_bool_t verto__attach_func(const char *method, cJSON *params, jsock switch_core_media_clear_ice(tech_pvt->session); switch_channel_set_flag(tech_pvt->channel, CF_REINVITE); + //switch_channel_audio_sync(tech_pvt->channel); + //switch_channel_set_flag(tech_pvt->channel, CF_VIDEO_BREAK); + //switch_core_session_kill_channel(tech_pvt->session, SWITCH_SIG_BREAK); + if ((match = switch_core_media_negotiate_sdp(tech_pvt->session, tech_pvt->r_sdp, &p, SDP_TYPE_RESPONSE))) { if (switch_core_media_activate_rtp(tech_pvt->session) != SWITCH_STATUS_SUCCESS) { switch_channel_set_variable(tech_pvt->channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "MEDIA ERROR"); diff --git a/src/switch_core_media.c b/src/switch_core_media.c index f2eaa03cd0..0533781aab 100644 --- a/src/switch_core_media.c +++ b/src/switch_core_media.c @@ -2395,6 +2395,10 @@ static void clear_ice(switch_core_session_t *session, switch_media_type_t type) memset(&engine->ice_in, 0, sizeof(engine->ice_in)); engine->remote_rtcp_port = 0; + if (engine->rtp_session) { + switch_rtp_reset(engine->rtp_session); + } + } //? diff --git a/src/switch_rtp.c b/src/switch_rtp.c index b68534114c..0eb3c03516 100644 --- a/src/switch_rtp.c +++ b/src/switch_rtp.c @@ -543,8 +543,6 @@ static handle_rfc2833_result_t handle_rfc2833(switch_rtp_t *rtp_session, switch_ rtp_session->stats.inbound.last_processed_seq = 0; if (!(packet[0] || packet[1] || packet[2] || packet[3]) && len >= 8) { - - packet += 4; len -= 4; switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_WARNING, "DTMF payload offset by 4 bytes.\n"); @@ -2458,6 +2456,18 @@ SWITCH_DECLARE(void) switch_rtp_set_max_missed_packets(switch_rtp_t *rtp_session rtp_session->max_missed_packets = max; } +SWITCH_DECLARE(void) switch_rtp_reset(switch_rtp_t *rtp_session) +{ + if (!rtp_session) { + return; + } + + rtp_session->seq = (uint16_t) rand(); + rtp_session->ts = 0; + memset(&rtp_session->ts_norm, 0, sizeof(rtp_session->ts_norm)); + +} + SWITCH_DECLARE(void) switch_rtp_reset_media_timer(switch_rtp_t *rtp_session) { rtp_session->missed_count = 0; From 43770aa862bfdee2b4b9c18a0071c3c042a4f0f9 Mon Sep 17 00:00:00 2001 From: Jeff Lenk Date: Fri, 13 Jun 2014 22:34:50 -0500 Subject: [PATCH 052/231] FS-6583 --resolve --- Freeswitch.2012.sln | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Freeswitch.2012.sln b/Freeswitch.2012.sln index c0183a33db..fb3536036b 100644 --- a/Freeswitch.2012.sln +++ b/Freeswitch.2012.sln @@ -4132,11 +4132,13 @@ Global {5BE9A596-F11F-4379-928C-412F81AE182B}.Debug|Win32.ActiveCfg = Debug|Win32 {5BE9A596-F11F-4379-928C-412F81AE182B}.Debug|Win32.Build.0 = Debug|Win32 {5BE9A596-F11F-4379-928C-412F81AE182B}.Debug|x64.ActiveCfg = Debug|Win32 + {5BE9A596-F11F-4379-928C-412F81AE182B}.Debug|x64.Build.0 = Debug|Win32 {5BE9A596-F11F-4379-928C-412F81AE182B}.Debug|x64 Setup.ActiveCfg = Debug|Win32 {5BE9A596-F11F-4379-928C-412F81AE182B}.Debug|x86 Setup.ActiveCfg = Debug|Win32 {5BE9A596-F11F-4379-928C-412F81AE182B}.Release|Win32.ActiveCfg = Release|Win32 {5BE9A596-F11F-4379-928C-412F81AE182B}.Release|Win32.Build.0 = Release|Win32 {5BE9A596-F11F-4379-928C-412F81AE182B}.Release|x64.ActiveCfg = Release|Win32 + {5BE9A596-F11F-4379-928C-412F81AE182B}.Release|x64.Build.0 = Release|Win32 {5BE9A596-F11F-4379-928C-412F81AE182B}.Release|x64 Setup.ActiveCfg = Release|Win32 {5BE9A596-F11F-4379-928C-412F81AE182B}.Release|x86 Setup.ActiveCfg = Release|Win32 EndGlobalSection From dc2f5cc491d52076c20144042d97ffe71af6fe15 Mon Sep 17 00:00:00 2001 From: Jeff Lenk Date: Fri, 13 Jun 2014 22:41:37 -0500 Subject: [PATCH 053/231] vs2010 reswig --- .../mod_managed/freeswitch_wrap.2010.cxx | 36 +++++++++++++++++-- .../mod_managed/managed/swig.2010.cs | 29 +++++++++++++-- 2 files changed, 60 insertions(+), 5 deletions(-) diff --git a/src/mod/languages/mod_managed/freeswitch_wrap.2010.cxx b/src/mod/languages/mod_managed/freeswitch_wrap.2010.cxx index 02cdabd75b..7abcde3a4f 100644 --- a/src/mod/languages/mod_managed/freeswitch_wrap.2010.cxx +++ b/src/mod/languages/mod_managed/freeswitch_wrap.2010.cxx @@ -15969,19 +15969,21 @@ SWIGEXPORT void * SWIGSTDCALL CSharp_switch_loadable_module_get_codec_interface( } -SWIGEXPORT char * SWIGSTDCALL CSharp_switch_parse_codec_buf(char * jarg1, void * jarg2, void * jarg3, void * jarg4) { +SWIGEXPORT char * SWIGSTDCALL CSharp_switch_parse_codec_buf(char * jarg1, void * jarg2, void * jarg3, void * jarg4, void * jarg5) { char * jresult ; char *arg1 = (char *) 0 ; uint32_t *arg2 = (uint32_t *) 0 ; uint32_t *arg3 = (uint32_t *) 0 ; uint32_t *arg4 = (uint32_t *) 0 ; + uint32_t *arg5 = (uint32_t *) 0 ; char *result = 0 ; arg1 = (char *)jarg1; arg2 = (uint32_t *)jarg2; arg3 = (uint32_t *)jarg3; arg4 = (uint32_t *)jarg4; - result = (char *)switch_parse_codec_buf(arg1,arg2,arg3,arg4); + arg5 = (uint32_t *)jarg5; + result = (char *)switch_parse_codec_buf(arg1,arg2,arg3,arg4,arg5); jresult = SWIG_csharp_string_callback((const char *)result); return jresult; } @@ -20305,6 +20307,28 @@ SWIGEXPORT unsigned long SWIGSTDCALL CSharp_switch_frame_rate_get(void * jarg1) } +SWIGEXPORT void SWIGSTDCALL CSharp_switch_frame_channels_set(void * jarg1, unsigned long jarg2) { + switch_frame *arg1 = (switch_frame *) 0 ; + uint32_t arg2 ; + + arg1 = (switch_frame *)jarg1; + arg2 = (uint32_t)jarg2; + if (arg1) (arg1)->channels = arg2; +} + + +SWIGEXPORT unsigned long SWIGSTDCALL CSharp_switch_frame_channels_get(void * jarg1) { + unsigned long jresult ; + switch_frame *arg1 = (switch_frame *) 0 ; + uint32_t result; + + arg1 = (switch_frame *)jarg1; + result = (uint32_t) ((arg1)->channels); + jresult = (unsigned long)result; + return jresult; +} + + SWIGEXPORT void SWIGSTDCALL CSharp_switch_frame_payload_set(void * jarg1, unsigned char jarg2) { switch_frame *arg1 = (switch_frame *) 0 ; switch_payload_t arg2 ; @@ -37631,6 +37655,14 @@ SWIGEXPORT int SWIGSTDCALL CSharp_switch_rtp_udptl_mode(void * jarg1) { } +SWIGEXPORT void SWIGSTDCALL CSharp_switch_rtp_reset(void * jarg1) { + switch_rtp_t *arg1 = (switch_rtp_t *) 0 ; + + arg1 = (switch_rtp_t *)jarg1; + switch_rtp_reset(arg1); +} + + SWIGEXPORT int SWIGSTDCALL CSharp_switch_rtp_set_local_address(void * jarg1, char * jarg2, unsigned short jarg3, void * jarg4) { int jresult ; switch_rtp_t *arg1 = (switch_rtp_t *) 0 ; diff --git a/src/mod/languages/mod_managed/managed/swig.2010.cs b/src/mod/languages/mod_managed/managed/swig.2010.cs index 7fc9e3148a..b589f88cba 100644 --- a/src/mod/languages/mod_managed/managed/swig.2010.cs +++ b/src/mod/languages/mod_managed/managed/swig.2010.cs @@ -3230,8 +3230,8 @@ public class freeswitch { return ret; } - public static string switch_parse_codec_buf(string buf, SWIGTYPE_p_unsigned_long interval, SWIGTYPE_p_unsigned_long rate, SWIGTYPE_p_unsigned_long bit) { - string ret = freeswitchPINVOKE.switch_parse_codec_buf(buf, SWIGTYPE_p_unsigned_long.getCPtr(interval), SWIGTYPE_p_unsigned_long.getCPtr(rate), SWIGTYPE_p_unsigned_long.getCPtr(bit)); + public static string switch_parse_codec_buf(string buf, SWIGTYPE_p_unsigned_long interval, SWIGTYPE_p_unsigned_long rate, SWIGTYPE_p_unsigned_long bit, SWIGTYPE_p_unsigned_long channels) { + string ret = freeswitchPINVOKE.switch_parse_codec_buf(buf, SWIGTYPE_p_unsigned_long.getCPtr(interval), SWIGTYPE_p_unsigned_long.getCPtr(rate), SWIGTYPE_p_unsigned_long.getCPtr(bit), SWIGTYPE_p_unsigned_long.getCPtr(channels)); return ret; } @@ -6104,6 +6104,10 @@ public class freeswitch { return ret; } + public static void switch_rtp_reset(SWIGTYPE_p_switch_rtp rtp_session) { + freeswitchPINVOKE.switch_rtp_reset(SWIGTYPE_p_switch_rtp.getCPtr(rtp_session)); + } + public static switch_status_t switch_rtp_set_local_address(SWIGTYPE_p_switch_rtp rtp_session, string host, ushort port, ref string err) { switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_rtp_set_local_address(SWIGTYPE_p_switch_rtp.getCPtr(rtp_session), host, port, ref err); return ret; @@ -11248,7 +11252,7 @@ class freeswitchPINVOKE { public static extern IntPtr switch_loadable_module_get_codec_interface(string jarg1); [DllImport("mod_managed", EntryPoint="CSharp_switch_parse_codec_buf")] - public static extern string switch_parse_codec_buf(string jarg1, HandleRef jarg2, HandleRef jarg3, HandleRef jarg4); + public static extern string switch_parse_codec_buf(string jarg1, HandleRef jarg2, HandleRef jarg3, HandleRef jarg4, HandleRef jarg5); [DllImport("mod_managed", EntryPoint="CSharp_switch_loadable_module_get_dialplan_interface")] public static extern IntPtr switch_loadable_module_get_dialplan_interface(string jarg1); @@ -12201,6 +12205,12 @@ class freeswitchPINVOKE { [DllImport("mod_managed", EntryPoint="CSharp_switch_frame_rate_get")] public static extern uint switch_frame_rate_get(HandleRef jarg1); + [DllImport("mod_managed", EntryPoint="CSharp_switch_frame_channels_set")] + public static extern void switch_frame_channels_set(HandleRef jarg1, uint jarg2); + + [DllImport("mod_managed", EntryPoint="CSharp_switch_frame_channels_get")] + public static extern uint switch_frame_channels_get(HandleRef jarg1); + [DllImport("mod_managed", EntryPoint="CSharp_switch_frame_payload_set")] public static extern void switch_frame_payload_set(HandleRef jarg1, byte jarg2); @@ -16368,6 +16378,9 @@ class freeswitchPINVOKE { [DllImport("mod_managed", EntryPoint="CSharp_switch_rtp_udptl_mode")] public static extern int switch_rtp_udptl_mode(HandleRef jarg1); + [DllImport("mod_managed", EntryPoint="CSharp_switch_rtp_reset")] + public static extern void switch_rtp_reset(HandleRef jarg1); + [DllImport("mod_managed", EntryPoint="CSharp_switch_rtp_set_local_address")] public static extern int switch_rtp_set_local_address(HandleRef jarg1, string jarg2, ushort jarg3, ref string jarg4); @@ -32691,6 +32704,16 @@ public class switch_frame : IDisposable { } } + public uint channels { + set { + freeswitchPINVOKE.switch_frame_channels_set(swigCPtr, value); + } + get { + uint ret = freeswitchPINVOKE.switch_frame_channels_get(swigCPtr); + return ret; + } + } + public byte payload { set { freeswitchPINVOKE.switch_frame_payload_set(swigCPtr, value); From 9e600ec938c8517293bfbc830285b0ad9b325b6d Mon Sep 17 00:00:00 2001 From: Jeff Lenk Date: Fri, 13 Jun 2014 22:49:01 -0500 Subject: [PATCH 054/231] FS-6591 --resolve If you are still using spidermonkey you should migrate to v8 --- src/mod/legacy/languages/mod_spidermonkey/mod_spidermonkey.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/mod/legacy/languages/mod_spidermonkey/mod_spidermonkey.c b/src/mod/legacy/languages/mod_spidermonkey/mod_spidermonkey.c index 20fc464420..e86eed40d6 100644 --- a/src/mod/legacy/languages/mod_spidermonkey/mod_spidermonkey.c +++ b/src/mod/legacy/languages/mod_spidermonkey/mod_spidermonkey.c @@ -1901,12 +1901,13 @@ static switch_status_t init_speech_engine(struct js_session *jss, char *engine, { switch_codec_t *read_codec; switch_speech_flag_t flags = SWITCH_SPEECH_FLAG_NONE; - uint32_t rate = 0; + uint32_t rate = 0, channels; int interval = 0; read_codec = switch_core_session_get_read_codec(jss->session); rate = read_codec->implementation->actual_samples_per_second; interval = read_codec->implementation->microseconds_per_packet / 1000; + channels = read_codec->implementation->number_of_channels; if (switch_core_codec_init(&jss->speech->codec, "L16", @@ -1921,7 +1922,7 @@ static switch_status_t init_speech_engine(struct js_session *jss, char *engine, return SWITCH_STATUS_FALSE; } - if (switch_core_speech_open(&jss->speech->sh, engine, voice, rate, interval, + if (switch_core_speech_open(&jss->speech->sh, engine, voice, rate, interval, channels, &flags, switch_core_session_get_pool(jss->session)) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid TTS module!\n"); switch_core_codec_destroy(&jss->speech->codec); From fc7a74905b3285022ba9c51b0279ced2060eb5e7 Mon Sep 17 00:00:00 2001 From: Steve Underwood Date: Sat, 14 Jun 2014 19:49:05 +0800 Subject: [PATCH 055/231] Various little memory leak possibilities in spandsp sorts, and the spandsp test suite is now mostly OK with valgrind. --- libs/spandsp/spandsp-sim/g1050.c | 57 ++++++++++-------- libs/spandsp/spandsp-sim/line_model.c | 18 ++++-- libs/spandsp/spandsp-sim/make_line_models.c | 9 ++- libs/spandsp/spandsp-sim/rfc2198_sim.c | 16 ++++- libs/spandsp/spandsp-sim/spandsp/g1050.h | 2 + libs/spandsp/spandsp-sim/spandsp/line_model.h | 4 +- .../spandsp/spandsp-sim/spandsp/rfc2198_sim.h | 2 + libs/spandsp/spandsp-sim/spandsp/test_utils.h | 4 +- libs/spandsp/spandsp-sim/test_utils.c | 25 +++++--- libs/spandsp/src/bell_r2_mf.c | 2 + libs/spandsp/src/dtmf.c | 2 + libs/spandsp/src/fax.c | 3 +- libs/spandsp/src/image_translate.c | 9 +-- libs/spandsp/src/t30.c | 6 +- libs/spandsp/src/t31.c | 5 ++ libs/spandsp/src/t4_tx.c | 59 +++++++++++-------- libs/spandsp/src/t85_decode.c | 12 ++-- libs/spandsp/src/t85_encode.c | 12 ++-- libs/spandsp/src/time_scale.c | 2 +- libs/spandsp/src/v18.c | 2 + libs/spandsp/src/v8.c | 3 +- libs/spandsp/tests/ademco_contactid_tests.c | 8 ++- libs/spandsp/tests/at_interpreter_tests.c | 1 + libs/spandsp/tests/awgn_tests.c | 15 ++++- libs/spandsp/tests/bell_mf_rx_tests.c | 2 + libs/spandsp/tests/bell_mf_tx_tests.c | 1 + libs/spandsp/tests/bert_tests.c | 31 +++++++++- libs/spandsp/tests/dc_restore_tests.c | 1 + libs/spandsp/tests/dtmf_rx_tests.c | 5 ++ libs/spandsp/tests/dtmf_tx_tests.c | 1 + libs/spandsp/tests/fax_decode.c | 2 +- libs/spandsp/tests/fax_tests.c | 26 ++++---- libs/spandsp/tests/fsk_tests.c | 16 +++++ libs/spandsp/tests/g1050_tests.c | 2 + libs/spandsp/tests/g168_tests.c | 9 +++ libs/spandsp/tests/g711_tests.c | 6 +- libs/spandsp/tests/g722_tests.c | 9 +++ libs/spandsp/tests/g726_tests.c | 14 +++-- libs/spandsp/tests/gsm0610_tests.c | 12 ++-- libs/spandsp/tests/ima_adpcm_tests.c | 4 +- libs/spandsp/tests/image_translate_tests.c | 2 + libs/spandsp/tests/line_model_tests.c | 6 +- libs/spandsp/tests/logging_tests.c | 2 + libs/spandsp/tests/lpc10_tests.c | 4 +- libs/spandsp/tests/oki_adpcm_tests.c | 6 +- libs/spandsp/tests/power_meter_tests.c | 2 + libs/spandsp/tests/r2_mf_rx_tests.c | 7 ++- libs/spandsp/tests/rfc2198_sim_tests.c | 4 ++ libs/spandsp/tests/sig_tone_tests.c | 2 + libs/spandsp/tests/swept_tone_tests.c | 4 ++ libs/spandsp/tests/t31_tests.c | 7 ++- libs/spandsp/tests/t38_non_ecm_buffer_tests.c | 7 +++ libs/spandsp/tests/t42_tests.c | 18 +++++- libs/spandsp/tests/t43_tests.c | 9 ++- libs/spandsp/tests/t4_t6_tests.c | 4 +- libs/spandsp/tests/t4_tests.c | 6 +- .../tests/t81_t82_arith_coding_tests.c | 3 +- libs/spandsp/tests/t85_tests.c | 9 +-- libs/spandsp/tests/time_scale_tests.c | 2 + libs/spandsp/tests/tone_detect_tests.c | 2 + libs/spandsp/tests/tone_generate_tests.c | 16 ++--- libs/spandsp/tests/tsb85_tests.c | 24 ++++++++ libs/spandsp/tests/v17_tests.c | 7 ++- libs/spandsp/tests/v22bis_tests.c | 1 + libs/spandsp/tests/v27ter_tests.c | 9 ++- libs/spandsp/tests/v29_tests.c | 8 ++- 66 files changed, 419 insertions(+), 171 deletions(-) diff --git a/libs/spandsp/spandsp-sim/g1050.c b/libs/spandsp/spandsp-sim/g1050.c index c1e8b9d415..ed7d8e900b 100644 --- a/libs/spandsp/spandsp-sim/g1050.c +++ b/libs/spandsp/spandsp-sim/g1050.c @@ -41,6 +41,11 @@ #define GEN_CONST #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" #include "spandsp.h" @@ -48,9 +53,6 @@ #define PACKET_LOSS_TIME -1 -#define FALSE 0 -#define TRUE (!FALSE) - g1050_constants_t g1050_constants[1] = { { @@ -746,7 +748,7 @@ static void g1050_segment_init(g1050_segment_state_t *s, s->max_jitter = parms->max_jitter; /* The following is common state information to all links. */ - s->high_loss = FALSE; + s->high_loss = false; s->congestion_delay = 0.0; s->last_arrival_time = 0.0; @@ -797,7 +799,7 @@ static void g1050_core_init(g1050_core_state_t *s, g1050_core_model_t *parms, in static void g1050_segment_model(g1050_segment_state_t *s, double delays[], int len) { int i; - int lose; + bool lose; int was_high_loss; double impulse; double slice_delay; @@ -805,7 +807,7 @@ static void g1050_segment_model(g1050_segment_state_t *s, double delays[], int l /* Compute delay and loss value for each time slice. */ for (i = 0; i < len; i++) { - lose = FALSE; + lose = false; /* Initialize delay to the serial delay plus some jitter. */ slice_delay = s->serial_delay + s->max_jitter*q1050_rand(); /* If no QoS, do congestion delay and packet loss analysis. */ @@ -826,14 +828,14 @@ static void g1050_segment_model(g1050_segment_state_t *s, double delays[], int l } if (was_high_loss && q1050_rand() < s->prob_packet_loss) - lose = TRUE; + lose = true; /* Single pole LPF for the congestion delay impulses. */ s->congestion_delay = s->congestion_delay*s->impulse_coeff + impulse*(1.0 - s->impulse_coeff); slice_delay += s->congestion_delay; } /* If duplex mismatch on LAN, packet loss based on loss probability. */ if (s->multiple_access && (q1050_rand() < s->prob_packet_collision_loss)) - lose = TRUE; + lose = true; /* Put computed delay into time slice array. */ if (lose) { @@ -851,12 +853,12 @@ static void g1050_segment_model(g1050_segment_state_t *s, double delays[], int l static void g1050_core_model(g1050_core_state_t *s, double delays[], int len) { int32_t i; - int lose; + bool lose; double jitter_delay; for (i = 0; i < len; i++) { - lose = FALSE; + lose = false; jitter_delay = s->base_delay + s->max_jitter*q1050_rand(); /* Route flapping */ if (--s->route_flap_counter <= 0) @@ -866,18 +868,18 @@ static void g1050_core_model(g1050_core_state_t *s, double delays[], int len) s->route_flap_counter = s->route_flap_interval; } if (q1050_rand() < s->prob_packet_loss) - lose = TRUE; + lose = true; /* Link failures */ if (--s->link_failure_counter <= 0) { /* We are in a link failure */ - lose = TRUE; + lose = true; if (--s->link_recovery_counter <= 0) { /* Leave failure state. */ s->link_failure_counter = s->link_failure_interval_ticks; s->link_recovery_counter = s->link_failure_duration_ticks; - lose = FALSE; + lose = false; } } if (lose) @@ -1056,23 +1058,23 @@ static void g1050_simulate_chunk(g1050_state_t *s) s->base_time += 1.0; - memcpy(&s->segment[0].delays[0], &s->segment[0].delays[G1050_TICKS_PER_SEC], 2*G1050_TICKS_PER_SEC*sizeof(s->segment[0].delays[0])); + memmove(&s->segment[0].delays[0], &s->segment[0].delays[G1050_TICKS_PER_SEC], 2*G1050_TICKS_PER_SEC*sizeof(s->segment[0].delays[0])); g1050_segment_model(&s->segment[0], &s->segment[0].delays[2*G1050_TICKS_PER_SEC], G1050_TICKS_PER_SEC); - memcpy(&s->segment[1].delays[0], &s->segment[1].delays[G1050_TICKS_PER_SEC], 2*G1050_TICKS_PER_SEC*sizeof(s->segment[1].delays[0])); + memmove(&s->segment[1].delays[0], &s->segment[1].delays[G1050_TICKS_PER_SEC], 2*G1050_TICKS_PER_SEC*sizeof(s->segment[1].delays[0])); g1050_segment_model(&s->segment[1], &s->segment[1].delays[2*G1050_TICKS_PER_SEC], G1050_TICKS_PER_SEC); - memcpy(&s->core.delays[0], &s->core.delays[G1050_TICKS_PER_SEC], 2*G1050_TICKS_PER_SEC*sizeof(s->core.delays[0])); + memmove(&s->core.delays[0], &s->core.delays[G1050_TICKS_PER_SEC], 2*G1050_TICKS_PER_SEC*sizeof(s->core.delays[0])); g1050_core_model(&s->core, &s->core.delays[2*G1050_TICKS_PER_SEC], G1050_TICKS_PER_SEC); - memcpy(&s->segment[2].delays[0], &s->segment[2].delays[G1050_TICKS_PER_SEC], 2*G1050_TICKS_PER_SEC*sizeof(s->segment[2].delays[0])); + memmove(&s->segment[2].delays[0], &s->segment[2].delays[G1050_TICKS_PER_SEC], 2*G1050_TICKS_PER_SEC*sizeof(s->segment[2].delays[0])); g1050_segment_model(&s->segment[2], &s->segment[2].delays[2*G1050_TICKS_PER_SEC], G1050_TICKS_PER_SEC); - memcpy(&s->segment[3].delays[0], &s->segment[3].delays[G1050_TICKS_PER_SEC], 2*G1050_TICKS_PER_SEC*sizeof(s->segment[3].delays[0])); + memmove(&s->segment[3].delays[0], &s->segment[3].delays[G1050_TICKS_PER_SEC], 2*G1050_TICKS_PER_SEC*sizeof(s->segment[3].delays[0])); g1050_segment_model(&s->segment[3], &s->segment[3].delays[2*G1050_TICKS_PER_SEC], G1050_TICKS_PER_SEC); - memcpy(&s->arrival_times_1[0], &s->arrival_times_1[s->packet_rate], 2*s->packet_rate*sizeof(s->arrival_times_1[0])); - memcpy(&s->arrival_times_2[0], &s->arrival_times_2[s->packet_rate], 2*s->packet_rate*sizeof(s->arrival_times_2[0])); + memmove(&s->arrival_times_1[0], &s->arrival_times_1[s->packet_rate], 2*s->packet_rate*sizeof(s->arrival_times_1[0])); + memmove(&s->arrival_times_2[0], &s->arrival_times_2[s->packet_rate], 2*s->packet_rate*sizeof(s->arrival_times_2[0])); for (i = 0; i < s->packet_rate; i++) { s->arrival_times_1[2*s->packet_rate + i] = s->base_time + 2.0 + (double) i/(double) s->packet_rate; @@ -1126,7 +1128,7 @@ SPAN_DECLARE(g1050_state_t *) g1050_init(int model, &mo->sidea_lan, sp->sidea_lan_bit_rate, sp->sidea_lan_multiple_access, - FALSE, + false, packet_size, packet_rate); g1050_segment_init(&s->segment[1], @@ -1134,7 +1136,7 @@ SPAN_DECLARE(g1050_state_t *) g1050_init(int model, &constants->segment[1], &mo->sidea_access_link, sp->sidea_access_link_bit_rate_ab, - FALSE, + false, sp->sidea_access_link_qos_enabled, packet_size, packet_rate); @@ -1144,7 +1146,7 @@ SPAN_DECLARE(g1050_state_t *) g1050_init(int model, &constants->segment[2], &mo->sideb_access_link, sp->sideb_access_link_bit_rate_ba, - FALSE, + false, sp->sideb_access_link_qos_enabled, packet_size, packet_rate); @@ -1154,7 +1156,7 @@ SPAN_DECLARE(g1050_state_t *) g1050_init(int model, &mo->sideb_lan, sp->sideb_lan_bit_rate, sp->sideb_lan_multiple_access, - FALSE, + false, packet_size, packet_rate); @@ -1186,6 +1188,13 @@ SPAN_DECLARE(g1050_state_t *) g1050_init(int model, } /*- End of function --------------------------------------------------------*/ +SPAN_DECLARE(int) g1050_free(g1050_state_t *s) +{ + free(s); + return 0; +} +/*- End of function --------------------------------------------------------*/ + SPAN_DECLARE(void) g1050_dump_parms(int model, int speed_pattern) { g1050_channel_speeds_t *sp; diff --git a/libs/spandsp/spandsp-sim/line_model.c b/libs/spandsp/spandsp-sim/line_model.c index 4326ae7d29..9da1f15495 100644 --- a/libs/spandsp/spandsp-sim/line_model.c +++ b/libs/spandsp/spandsp-sim/line_model.c @@ -41,6 +41,11 @@ #define GEN_CONST #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" #define SPANDSP_EXPOSE_INTERNAL_STRUCTURES @@ -345,7 +350,7 @@ SPAN_DECLARE(void) one_way_line_model_set_mains_pickup(one_way_line_model_state_ if (f) { - tone_gen_descriptor_init(&mains_tone_desc, f, (int) (level - 10.0f), f*3, (int) level, 1, 0, 0, 0, TRUE); + tone_gen_descriptor_init(&mains_tone_desc, f, (int) (level - 10.0f), f*3, (int) level, 1, 0, 0, 0, true); tone_gen_init(&s->mains_tone, &mains_tone_desc); } s->mains_interference = f; @@ -454,9 +459,9 @@ SPAN_DECLARE(void) both_ways_line_model_set_mains_pickup(both_ways_line_model_st if (f) { - tone_gen_descriptor_init(&mains_tone_desc, f, (int) (level1 - 10.0f), f*3, (int) level1, 1, 0, 0, 0, TRUE); + tone_gen_descriptor_init(&mains_tone_desc, f, (int) (level1 - 10.0f), f*3, (int) level1, 1, 0, 0, 0, true); tone_gen_init(&s->line1.mains_tone, &mains_tone_desc); - tone_gen_descriptor_init(&mains_tone_desc, f, (int) (level2 - 10.0f), f*3, (int) level2, 1, 0, 0, 0, TRUE); + tone_gen_descriptor_init(&mains_tone_desc, f, (int) (level2 - 10.0f), f*3, (int) level2, 1, 0, 0, 0, true); tone_gen_init(&s->line2.mains_tone, &mains_tone_desc); } s->line1.mains_interference = f; @@ -494,8 +499,9 @@ SPAN_DECLARE(one_way_line_model_state_t *) one_way_line_model_init(int model, fl } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(int) one_way_line_model_release(one_way_line_model_state_t *s) +SPAN_DECLARE(int) one_way_line_model_free(one_way_line_model_state_t *s) { + codec_munge_free(s->munge); free(s); return 0; } @@ -559,8 +565,10 @@ SPAN_DECLARE(both_ways_line_model_state_t *) both_ways_line_model_init(int model } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(int) both_ways_line_model_release(both_ways_line_model_state_t *s) +SPAN_DECLARE(int) both_ways_line_model_free(both_ways_line_model_state_t *s) { + codec_munge_free(s->line1.munge); + codec_munge_free(s->line2.munge); free(s); return 0; } diff --git a/libs/spandsp/spandsp-sim/make_line_models.c b/libs/spandsp/spandsp-sim/make_line_models.c index ed7cfe934e..8c5e1f2b5b 100644 --- a/libs/spandsp/spandsp-sim/make_line_models.c +++ b/libs/spandsp/spandsp-sim/make_line_models.c @@ -40,17 +40,16 @@ #include #include #include -#include "floating_fudge.h" #if defined(HAVE_FFTW3_H) #include #else #include #endif -#if defined(HAVE_TGMATH_H) -#include -#endif -#if defined(HAVE_MATH_H) #include +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" #endif #include "spandsp.h" diff --git a/libs/spandsp/spandsp-sim/rfc2198_sim.c b/libs/spandsp/spandsp-sim/rfc2198_sim.c index 6ecba89214..9e286b5dbd 100644 --- a/libs/spandsp/spandsp-sim/rfc2198_sim.c +++ b/libs/spandsp/spandsp-sim/rfc2198_sim.c @@ -41,6 +41,11 @@ #define GEN_CONST #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" #include "spandsp.h" @@ -49,9 +54,6 @@ #define PACKET_LOSS_TIME -1 -#define FALSE 0 -#define TRUE (!FALSE) - SPAN_DECLARE(rfc2198_sim_state_t *) rfc2198_sim_init(int model, int speed_pattern, int packet_size, @@ -70,6 +72,14 @@ SPAN_DECLARE(rfc2198_sim_state_t *) rfc2198_sim_init(int model, } /*- End of function --------------------------------------------------------*/ +SPAN_DECLARE(int) rfc2198_sim_free(rfc2198_sim_state_t *s) +{ + g1050_free(s->g1050); + free(s); + return 0; +} +/*- End of function --------------------------------------------------------*/ + SPAN_DECLARE(int) rfc2198_sim_put(rfc2198_sim_state_t *s, const uint8_t buf[], int len, diff --git a/libs/spandsp/spandsp-sim/spandsp/g1050.h b/libs/spandsp/spandsp-sim/spandsp/g1050.h index 687630e834..d9d62bc23c 100644 --- a/libs/spandsp/spandsp-sim/spandsp/g1050.h +++ b/libs/spandsp/spandsp-sim/spandsp/g1050.h @@ -272,6 +272,8 @@ SPAN_DECLARE(g1050_state_t *) g1050_init(int model, int packet_size, int packet_rate); +SPAN_DECLARE(int) g1050_free(g1050_state_t *s); + SPAN_DECLARE(void) g1050_dump_parms(int model, int speed_pattern); SPAN_DECLARE(int) g1050_put(g1050_state_t *s, diff --git a/libs/spandsp/spandsp-sim/spandsp/line_model.h b/libs/spandsp/spandsp-sim/spandsp/line_model.h index 8465d4b457..72fe4811c9 100644 --- a/libs/spandsp/spandsp-sim/spandsp/line_model.h +++ b/libs/spandsp/spandsp-sim/spandsp/line_model.h @@ -154,7 +154,7 @@ SPAN_DECLARE(both_ways_line_model_state_t *) both_ways_line_model_init(int model int codec, int rbs_pattern); -SPAN_DECLARE(int) both_ways_line_model_release(both_ways_line_model_state_t *s); +SPAN_DECLARE(int) both_ways_line_model_free(both_ways_line_model_state_t *s); SPAN_DECLARE(void) one_way_line_model(one_way_line_model_state_t *s, int16_t output[], @@ -167,7 +167,7 @@ SPAN_DECLARE(void) one_way_line_model_set_mains_pickup(one_way_line_model_state_ SPAN_DECLARE(one_way_line_model_state_t *) one_way_line_model_init(int model, float noise, int codec, int rbs_pattern); -SPAN_DECLARE(int) one_way_line_model_release(one_way_line_model_state_t *s); +SPAN_DECLARE(int) one_way_line_model_free(one_way_line_model_state_t *s); #ifdef __cplusplus } diff --git a/libs/spandsp/spandsp-sim/spandsp/rfc2198_sim.h b/libs/spandsp/spandsp-sim/spandsp/rfc2198_sim.h index a0c3d64b62..5aaa495ba1 100644 --- a/libs/spandsp/spandsp-sim/spandsp/rfc2198_sim.h +++ b/libs/spandsp/spandsp-sim/spandsp/rfc2198_sim.h @@ -73,6 +73,8 @@ SPAN_DECLARE(rfc2198_sim_state_t *) rfc2198_sim_init(int model, int packet_rate, int redundancy_depth); +SPAN_DECLARE(int) rfc2198_sim_free(rfc2198_sim_state_t *s); + SPAN_DECLARE(int) rfc2198_sim_put(rfc2198_sim_state_t *s, const uint8_t buf[], int len, diff --git a/libs/spandsp/spandsp-sim/spandsp/test_utils.h b/libs/spandsp/spandsp-sim/spandsp/test_utils.h index 6144f64d0e..407b800048 100644 --- a/libs/spandsp/spandsp-sim/spandsp/test_utils.h +++ b/libs/spandsp/spandsp-sim/spandsp/test_utils.h @@ -51,7 +51,7 @@ extern "C" { SPAN_DECLARE(complexify_state_t *) complexify_init(void); -SPAN_DECLARE(void) complexify_release(complexify_state_t *s); +SPAN_DECLARE(int) complexify_free(complexify_state_t *s); SPAN_DECLARE(complexf_t) complexify(complexify_state_t *s, int16_t amp); @@ -61,7 +61,7 @@ SPAN_DECLARE(void) ifft(complex_t data[], int len); SPAN_DECLARE(codec_munge_state_t *) codec_munge_init(int codec, int info); -SPAN_DECLARE(void) codec_munge_release(codec_munge_state_t *s); +SPAN_DECLARE(void) codec_munge_free(codec_munge_state_t *s); SPAN_DECLARE(void) codec_munge(codec_munge_state_t *s, int16_t amp[], int len); diff --git a/libs/spandsp/spandsp-sim/test_utils.c b/libs/spandsp/spandsp-sim/test_utils.c index d37c8977bb..69394702c0 100644 --- a/libs/spandsp/spandsp-sim/test_utils.c +++ b/libs/spandsp/spandsp-sim/test_utils.c @@ -39,6 +39,11 @@ #if defined(HAVE_MATH_H) #include #endif +#if defined(HAVE_STDBOOL_H) +#include +#else +#include "spandsp/stdbool.h" +#endif #include "floating_fudge.h" #include #include @@ -66,12 +71,14 @@ struct complexify_state_s }; static complex_t circle[MAX_FFT_LEN/2]; -static int circle_init = FALSE; +static int circle_init = false; static complex_t icircle[MAX_FFT_LEN/2]; -static int icircle_init = FALSE; +static int icircle_init = false; #define SF_MAX_HANDLE 32 -static int sf_close_at_exit_registered = FALSE; + +static int sf_close_at_exit_registered = false; + static SNDFILE *sf_close_at_exit_list[SF_MAX_HANDLE] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -95,9 +102,10 @@ SPAN_DECLARE(complexify_state_t *) complexify_init(void) } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(void) complexify_release(complexify_state_t *s) +SPAN_DECLARE(int) complexify_free(complexify_state_t *s) { free(s); + return 0; } /*- End of function --------------------------------------------------------*/ @@ -243,7 +251,7 @@ SPAN_DECLARE(void) fft(complex_t data[], int len) x = -(2.0*3.1415926535*i)/(double) MAX_FFT_LEN; circle[i] = expj(x); } - circle_init = TRUE; + circle_init = true; } fftx(data, temp, len); } @@ -263,7 +271,7 @@ SPAN_DECLARE(void) ifft(complex_t data[], int len) x = (2.0*3.1415926535*i)/(double) MAX_FFT_LEN; icircle[i] = expj(x); } - icircle_init = TRUE; + icircle_init = true; } ifftx(data, temp, len); } @@ -308,7 +316,7 @@ SPAN_DECLARE(codec_munge_state_t *) codec_munge_init(int codec, int info) } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(void) codec_munge_release(codec_munge_state_t *s) +SPAN_DECLARE(void) codec_munge_free(codec_munge_state_t *s) { free(s); } @@ -389,7 +397,7 @@ static int sf_record_handle(SNDFILE *handle) if (!sf_close_at_exit_registered) { atexit(sf_close_at_exit); - sf_close_at_exit_registered = TRUE; + sf_close_at_exit_registered = true; } return 0; } @@ -455,7 +463,6 @@ SPAN_DECLARE(int) sf_close_telephony(SNDFILE *handle) { if (sf_close_at_exit_list[i] == handle) { - sf_close(sf_close_at_exit_list[i]); sf_close_at_exit_list[i] = NULL; break; } diff --git a/libs/spandsp/src/bell_r2_mf.c b/libs/spandsp/src/bell_r2_mf.c index b8e507026e..41c11674b4 100644 --- a/libs/spandsp/src/bell_r2_mf.c +++ b/libs/spandsp/src/bell_r2_mf.c @@ -348,12 +348,14 @@ SPAN_DECLARE(bell_mf_tx_state_t *) bell_mf_tx_init(bell_mf_tx_state_t *s) SPAN_DECLARE(int) bell_mf_tx_release(bell_mf_tx_state_t *s) { + queue_release(&s->queue.queue); return 0; } /*- End of function --------------------------------------------------------*/ SPAN_DECLARE(int) bell_mf_tx_free(bell_mf_tx_state_t *s) { + queue_release(&s->queue.queue); span_free(s); return 0; } diff --git a/libs/spandsp/src/dtmf.c b/libs/spandsp/src/dtmf.c index 1f4e012dd3..fe235f45a1 100644 --- a/libs/spandsp/src/dtmf.c +++ b/libs/spandsp/src/dtmf.c @@ -597,12 +597,14 @@ SPAN_DECLARE(dtmf_tx_state_t *) dtmf_tx_init(dtmf_tx_state_t *s, SPAN_DECLARE(int) dtmf_tx_release(dtmf_tx_state_t *s) { + queue_release(&s->queue.queue); return 0; } /*- End of function --------------------------------------------------------*/ SPAN_DECLARE(int) dtmf_tx_free(dtmf_tx_state_t *s) { + queue_release(&s->queue.queue); span_free(s); return 0; } diff --git a/libs/spandsp/src/fax.c b/libs/spandsp/src/fax.c index 998af14177..ea6a1d523a 100644 --- a/libs/spandsp/src/fax.c +++ b/libs/spandsp/src/fax.c @@ -515,13 +515,14 @@ SPAN_DECLARE(fax_state_t *) fax_init(fax_state_t *s, int calling_party) SPAN_DECLARE(int) fax_release(fax_state_t *s) { t30_release(&s->t30); + v8_release(&s->v8); return 0; } /*- End of function --------------------------------------------------------*/ SPAN_DECLARE(int) fax_free(fax_state_t *s) { - t30_release(&s->t30); + fax_release(s); span_free(s); return 0; } diff --git a/libs/spandsp/src/image_translate.c b/libs/spandsp/src/image_translate.c index d337ee98a2..64a45d0495 100644 --- a/libs/spandsp/src/image_translate.c +++ b/libs/spandsp/src/image_translate.c @@ -546,7 +546,7 @@ static int floyd_steinberg_dither_row(image_translate_state_t *s, uint8_t buf[]) s->pixel_row[0][x - 1] = saturateu8(s->pixel_row[0][x - 1] + (7*quant_error)/16); s->pixel_row[1][x + 0] = saturateu8(s->pixel_row[1][x + 0] + (5*quant_error)/16); s->pixel_row[1][x - 1] = saturateu8(s->pixel_row[1][x - 1] + (1*quant_error)/16); - for ( ; x > 0; x--) + while (--x > 0) { old_pixel = s->pixel_row[0][x]; new_pixel = find_closest_palette_color(old_pixel); @@ -574,7 +574,7 @@ static int floyd_steinberg_dither_row(image_translate_state_t *s, uint8_t buf[]) s->pixel_row[0][x + 1] = saturateu8(s->pixel_row[0][x + 1] + (7*quant_error)/16); s->pixel_row[1][x + 0] = saturateu8(s->pixel_row[1][x + 0] + (5*quant_error)/16); s->pixel_row[1][x + 1] = saturateu8(s->pixel_row[1][x + 1] + (1*quant_error)/16); - for ( ; x < s->output_width - 1; x++) + while (++x < s->output_width - 1) { old_pixel = s->pixel_row[0][x]; new_pixel = find_closest_palette_color(old_pixel); @@ -772,10 +772,7 @@ SPAN_DECLARE(image_translate_state_t *) image_translate_init(image_translate_sta s->output_bytes_per_pixel = image_format_to_bytes_per_pixel(s->output_format); s->resize = (output_width > 0); - if (s->resize) - s->output_width = output_width; - else - s->output_width = s->input_width; + s->output_width = (s->resize) ? output_width : s->input_width; if (image_translate_restart(s, input_length)) return NULL; diff --git a/libs/spandsp/src/t30.c b/libs/spandsp/src/t30.c index 39c972a350..dadb9b50ef 100644 --- a/libs/spandsp/src/t30.c +++ b/libs/spandsp/src/t30.c @@ -3619,7 +3619,7 @@ static void process_state_f_doc_non_ecm(t30_state_t *s, const uint8_t *msg, int /* Treat this as a bad quality page. */ if (s->phase_d_handler) s->phase_d_handler(s->phase_d_user_data, fcf); - s->next_rx_step = msg[2] & 0xFE; + s->next_rx_step = fcf; queue_phase(s, T30_PHASE_D_TX); set_state(s, T30_STATE_III_Q_RTN); send_simple_frame(s, T30_RTN); @@ -3634,7 +3634,7 @@ static void process_state_f_doc_non_ecm(t30_state_t *s, const uint8_t *msg, int /* Treat this as a bad quality page. */ if (s->phase_d_handler) s->phase_d_handler(s->phase_d_user_data, fcf); - s->next_rx_step = msg[2] & 0xFE; + s->next_rx_step = fcf; /* Return to phase B */ queue_phase(s, T30_PHASE_B_TX); set_state(s, T30_STATE_III_Q_RTN); @@ -3649,7 +3649,7 @@ static void process_state_f_doc_non_ecm(t30_state_t *s, const uint8_t *msg, int /* Treat this as a bad quality page. */ if (s->phase_d_handler) s->phase_d_handler(s->phase_d_user_data, fcf); - s->next_rx_step = msg[2] & 0xFE; + s->next_rx_step = fcf; queue_phase(s, T30_PHASE_D_TX); set_state(s, T30_STATE_III_Q_RTN); send_simple_frame(s, T30_RTN); diff --git a/libs/spandsp/src/t31.c b/libs/spandsp/src/t31.c index ef8dcd16f6..ddc330694d 100644 --- a/libs/spandsp/src/t31.c +++ b/libs/spandsp/src/t31.c @@ -3045,6 +3045,8 @@ SPAN_DECLARE(t31_state_t *) t31_init(t31_state_t *s, s->modem = FAX_MODEM_NONE; s->at_state.transmit = true; + if (s->rx_queue) + queue_free(s->rx_queue); if ((s->rx_queue = queue_init(NULL, 4096, QUEUE_WRITE_ATOMIC | QUEUE_READ_ATOMIC)) == NULL) { if (alloced) @@ -3070,6 +3072,9 @@ SPAN_DECLARE(t31_state_t *) t31_init(t31_state_t *s, SPAN_DECLARE(int) t31_release(t31_state_t *s) { at_reset_call_info(&s->at_state); + v8_release(&s->audio.v8); + fax_modems_release(&s->audio.modems); + queue_free(s->rx_queue); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/t4_tx.c b/libs/spandsp/src/t4_tx.c index c944f6d8b1..c273326fdb 100644 --- a/libs/spandsp/src/t4_tx.c +++ b/libs/spandsp/src/t4_tx.c @@ -1644,6 +1644,35 @@ SPAN_DECLARE(int) t4_tx_set_row_read_handler(t4_tx_state_t *s, t4_row_read_handl } /*- End of function --------------------------------------------------------*/ +static int release_encoder(t4_tx_state_t *s) +{ + switch (s->metadata.compression) + { + case T4_COMPRESSION_T4_1D: + case T4_COMPRESSION_T4_2D: + case T4_COMPRESSION_T6: + return t4_t6_encode_release(&s->encoder.t4_t6); + case T4_COMPRESSION_T85: + case T4_COMPRESSION_T85_L0: + return t85_encode_release(&s->encoder.t85); +#if defined(SPANDSP_SUPPORT_T88) + case T4_COMPRESSION_T88: + return t88_encode_release(&s->encoder.t88); +#endif + case T4_COMPRESSION_T42_T81: + case T4_COMPRESSION_SYCC_T81: + return t42_encode_release(&s->encoder.t42); + case T4_COMPRESSION_T43: + return t43_encode_release(&s->encoder.t43); +#if defined(SPANDSP_SUPPORT_T45) + case T4_COMPRESSION_T45: + return t45_encode_release(&s->encoder.t45); +#endif + } + return -1; +} +/*- End of function --------------------------------------------------------*/ + SPAN_DECLARE(int) t4_tx_set_tx_image_format(t4_tx_state_t *s, int supported_compressions, int supported_image_sizes, @@ -2002,6 +2031,7 @@ SPAN_DECLARE(int) t4_tx_set_tx_image_format(t4_tx_state_t *s, case T4_COMPRESSION_T6: break; default: + release_encoder(s); t4_t6_encode_init(&s->encoder.t4_t6, compression, s->metadata.image_width, s->metadata.image_length, s->row_handler, s->row_handler_user_data); break; } @@ -2018,6 +2048,7 @@ SPAN_DECLARE(int) t4_tx_set_tx_image_format(t4_tx_state_t *s, case T4_COMPRESSION_T85_L0: break; default: + release_encoder(s); t85_encode_init(&s->encoder.t85, s->metadata.image_width, s->metadata.image_length, s->row_handler, s->row_handler_user_data); break; } @@ -2046,6 +2077,7 @@ SPAN_DECLARE(int) t4_tx_set_tx_image_format(t4_tx_state_t *s, case T4_COMPRESSION_SYCC_T81: break; default: + release_encoder(s); t42_encode_init(&s->encoder.t42, s->metadata.image_width, s->metadata.image_length, s->row_handler, s->row_handler_user_data); break; } @@ -2058,6 +2090,7 @@ SPAN_DECLARE(int) t4_tx_set_tx_image_format(t4_tx_state_t *s, case T4_COMPRESSION_T43: break; default: + release_encoder(s); t43_encode_init(&s->encoder.t43, s->metadata.image_width, s->metadata.image_length, s->row_handler, s->row_handler_user_data); break; } @@ -2071,6 +2104,7 @@ SPAN_DECLARE(int) t4_tx_set_tx_image_format(t4_tx_state_t *s, case T4_COMPRESSION_T45: break; default: + release_encoder(s); t45_encode_init(&s->encoder.t45, s->metadata.image_width, s->metadata.image_length, s->row_handler, s->row_handler_user_data); break; } @@ -2603,30 +2637,7 @@ SPAN_DECLARE(int) t4_tx_release(t4_tx_state_t *s) span_free(s->colour_map); s->colour_map = NULL; } - switch (s->metadata.compression) - { - case T4_COMPRESSION_T4_1D: - case T4_COMPRESSION_T4_2D: - case T4_COMPRESSION_T6: - return t4_t6_encode_release(&s->encoder.t4_t6); - case T4_COMPRESSION_T85: - case T4_COMPRESSION_T85_L0: - return t85_encode_release(&s->encoder.t85); -#if defined(SPANDSP_SUPPORT_T88) - case T4_COMPRESSION_T88: - return t88_encode_release(&s->encoder.t88); -#endif - case T4_COMPRESSION_T42_T81: - case T4_COMPRESSION_SYCC_T81: - return t42_encode_release(&s->encoder.t42); - case T4_COMPRESSION_T43: - return t43_encode_release(&s->encoder.t43); -#if defined(SPANDSP_SUPPORT_T45) - case T4_COMPRESSION_T45: - return t45_encode_release(&s->encoder.t45); -#endif - } - return -1; + return release_encoder(s); } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/src/t85_decode.c b/libs/spandsp/src/t85_decode.c index a687961c02..2bc32e7212 100644 --- a/libs/spandsp/src/t85_decode.c +++ b/libs/spandsp/src/t85_decode.c @@ -853,6 +853,12 @@ SPAN_DECLARE(int) t85_decode_new_plane(t85_decode_state_t *s) } /*- End of function --------------------------------------------------------*/ +SPAN_DECLARE(logging_state_t *) t85_decode_get_logging_state(t85_decode_state_t *s) +{ + return &s->logging; +} +/*- End of function --------------------------------------------------------*/ + SPAN_DECLARE(int) t85_decode_restart(t85_decode_state_t *s) { s->xd = 0; @@ -888,12 +894,6 @@ SPAN_DECLARE(int) t85_decode_restart(t85_decode_state_t *s) } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(logging_state_t *) t85_decode_get_logging_state(t85_decode_state_t *s) -{ - return &s->logging; -} -/*- End of function --------------------------------------------------------*/ - SPAN_DECLARE(t85_decode_state_t *) t85_decode_init(t85_decode_state_t *s, t4_row_write_handler_t handler, void *user_data) diff --git a/libs/spandsp/src/t85_encode.c b/libs/spandsp/src/t85_encode.c index ed4d1adaff..8c35c5465b 100644 --- a/libs/spandsp/src/t85_encode.c +++ b/libs/spandsp/src/t85_encode.c @@ -645,6 +645,12 @@ SPAN_DECLARE(int) t85_encode_set_row_read_handler(t85_encode_state_t *s, } /*- End of function --------------------------------------------------------*/ +SPAN_DECLARE(logging_state_t *) t85_encode_get_logging_state(t85_encode_state_t *s) +{ + return &s->logging; +} +/*- End of function --------------------------------------------------------*/ + SPAN_DECLARE(int) t85_encode_restart(t85_encode_state_t *s, uint32_t image_width, uint32_t image_length) { int bytes_per_row; @@ -681,12 +687,6 @@ SPAN_DECLARE(int) t85_encode_restart(t85_encode_state_t *s, uint32_t image_width } /*- End of function --------------------------------------------------------*/ -SPAN_DECLARE(logging_state_t *) t85_encode_get_logging_state(t85_encode_state_t *s) -{ - return &s->logging; -} -/*- End of function --------------------------------------------------------*/ - SPAN_DECLARE(t85_encode_state_t *) t85_encode_init(t85_encode_state_t *s, uint32_t image_width, uint32_t image_length, diff --git a/libs/spandsp/src/time_scale.c b/libs/spandsp/src/time_scale.c index 2378b4f1c8..6d0ae51071 100644 --- a/libs/spandsp/src/time_scale.c +++ b/libs/spandsp/src/time_scale.c @@ -220,7 +220,7 @@ SPAN_DECLARE(int) time_scale(time_scale_state_t *s, int16_t out[], int16_t in[], { memcpy(&out[out_len], s->buf, sizeof(int16_t)*s->lcp); out_len += s->lcp; - memcpy(s->buf, &s->buf[s->lcp], sizeof(int16_t)*(s->buf_len - s->lcp)); + memmove(s->buf, &s->buf[s->lcp], sizeof(int16_t)*(s->buf_len - s->lcp)); if (len - in_len < s->lcp) { /* Cannot continue without more samples */ diff --git a/libs/spandsp/src/v18.c b/libs/spandsp/src/v18.c index 0af5a6313a..3b72b296e1 100644 --- a/libs/spandsp/src/v18.c +++ b/libs/spandsp/src/v18.c @@ -1220,12 +1220,14 @@ SPAN_DECLARE(v18_state_t *) v18_init(v18_state_t *s, SPAN_DECLARE(int) v18_release(v18_state_t *s) { + queue_release(&s->queue.queue); return 0; } /*- End of function --------------------------------------------------------*/ SPAN_DECLARE(int) v18_free(v18_state_t *s) { + queue_release(&s->queue.queue); span_free(s); return 0; } diff --git a/libs/spandsp/src/v8.c b/libs/spandsp/src/v8.c index 5052e45d68..c9c2e3a144 100644 --- a/libs/spandsp/src/v8.c +++ b/libs/spandsp/src/v8.c @@ -1104,7 +1104,8 @@ SPAN_DECLARE(int) v8_restart(v8_state_t *s, bool calling_party, v8_parms_t *parm modem_connect_tones_tx_init(&s->ansam_tx, s->parms.modem_connect_tone); s->modem_connect_tone_tx_on = ms_to_samples(75) + 1; } - + if (s->tx_queue) + queue_free(s->tx_queue); if ((s->tx_queue = queue_init(NULL, 1024, 0)) == NULL) return -1; return 0; diff --git a/libs/spandsp/tests/ademco_contactid_tests.c b/libs/spandsp/tests/ademco_contactid_tests.c index 936fd557de..b1c9c4f42d 100644 --- a/libs/spandsp/tests/ademco_contactid_tests.c +++ b/libs/spandsp/tests/ademco_contactid_tests.c @@ -106,7 +106,7 @@ static int mitel_cm7291_side_2_and_bellcore_tests(void) /* The remainder of the Mitel tape is the talk-off test */ /* Here we use the Bellcore test tapes (much tougher), in six - files - 1 from each side of the original 3 cassette tapes */ + files - 1 from each side of the original 3 cassette tapes */ /* Bellcore say you should get no more than 470 false detections with a good receiver. Dialogic claim 20. Of course, we can do better than that, eh? */ @@ -135,6 +135,7 @@ static int mitel_cm7291_side_2_and_bellcore_tests(void) return -1; } printf(" Passed\n"); + ademco_contactid_sender_free(sender); return 0; } /*- End of function --------------------------------------------------------*/ @@ -254,6 +255,7 @@ static int end_to_end_tests(void) sf_writef_short(outhandle, sndfile_buf, SAMPLES_PER_CHUNK); } + codec_munge_free(munge); if (!rx_callback_reported) { fprintf(stderr, " Report not received\n"); @@ -266,6 +268,8 @@ static int end_to_end_tests(void) return -1; } printf(" Passed\n"); + ademco_contactid_sender_free(sender); + ademco_contactid_receiver_free(receiver); return 0; } /*- End of function --------------------------------------------------------*/ @@ -323,6 +327,8 @@ static int encode_decode_tests(void) printf("'%s'\n", buf); printf("\n"); printf(" Passed\n"); + ademco_contactid_sender_free(sender); + ademco_contactid_receiver_free(receiver); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/tests/at_interpreter_tests.c b/libs/spandsp/tests/at_interpreter_tests.c index 6826e030db..d771afecf2 100644 --- a/libs/spandsp/tests/at_interpreter_tests.c +++ b/libs/spandsp/tests/at_interpreter_tests.c @@ -564,6 +564,7 @@ int main(int argc, char *argv[]) exit(2); } printf("Tests passed.\n"); + at_free(at_state); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/tests/awgn_tests.c b/libs/spandsp/tests/awgn_tests.c index f5ba0c71ac..c105a9b243 100644 --- a/libs/spandsp/tests/awgn_tests.c +++ b/libs/spandsp/tests/awgn_tests.c @@ -75,7 +75,11 @@ int main(int argc, char *argv[]) clip_high = 0; clip_low = 0; total = 0.0; - noise_source = awgn_init_dbm0(NULL, idum, (float) j); + if ((noise_source = awgn_init_dbm0(NULL, idum, (float) j)) == NULL) + { + printf("Failed to allocation AWGN source\n"); + exit(2); + } total_samples = 1000000; for (i = 0; i < total_samples; i++) { @@ -99,6 +103,7 @@ int main(int argc, char *argv[]) printf("Test failed.\n"); exit(2); } + awgn_free(noise_source); } /* Now look at the statistical spread of the results, by collecting data in bins from a large number of samples. Use a fairly high noise level, but @@ -107,7 +112,11 @@ int main(int argc, char *argv[]) memset(bins, 0, sizeof(bins)); clip_high = 0; clip_low = 0; - awgn_init_dbm0(noise_source, idum, -15); + if ((noise_source = awgn_init_dbm0(NULL, idum, -15.0)) == NULL) + { + printf("Failed to allocation AWGN source\n"); + exit(2); + } total_samples = 10000000; for (i = 0; i < total_samples; i++) { @@ -134,7 +143,7 @@ int main(int argc, char *argv[]) /* Now send it out for graphing. */ printf("%6d %.7f %.7f\n", i - 32768, x, p); } - + awgn_free(noise_source); printf("Tests passed.\n"); return 0; } diff --git a/libs/spandsp/tests/bell_mf_rx_tests.c b/libs/spandsp/tests/bell_mf_rx_tests.c index 678c4f8e62..31fbd4068a 100644 --- a/libs/spandsp/tests/bell_mf_rx_tests.c +++ b/libs/spandsp/tests/bell_mf_rx_tests.c @@ -512,6 +512,7 @@ int main(int argc, char *argv[]) printf(" Failed\n"); exit(2); } + bell_mf_rx_free(mf_state); printf(" Passed\n"); /* The remainder of the Mitel tape is the talk-off test. This is @@ -540,6 +541,7 @@ int main(int argc, char *argv[]) printf(" Failed\n"); exit(2); } + bell_mf_rx_free(mf_state); printf(" Passed\n"); duration = time (NULL) - now; diff --git a/libs/spandsp/tests/bell_mf_tx_tests.c b/libs/spandsp/tests/bell_mf_tx_tests.c index 69f6c77a2d..6c88f985ff 100644 --- a/libs/spandsp/tests/bell_mf_tx_tests.c +++ b/libs/spandsp/tests/bell_mf_tx_tests.c @@ -157,6 +157,7 @@ int main(int argc, char *argv[]) fprintf(stderr, " Cannot close audio file '%s'\n", OUTPUT_FILE_NAME); exit (2); } + bell_mf_tx_free(gen); return 0; } diff --git a/libs/spandsp/tests/bert_tests.c b/libs/spandsp/tests/bert_tests.c index 5b6bb6151f..214815d6f2 100644 --- a/libs/spandsp/tests/bert_tests.c +++ b/libs/spandsp/tests/bert_tests.c @@ -97,9 +97,11 @@ int main(int argc, char *argv[]) printf("Test failed.\n"); exit(2); } + bert_free(tx_bert); + bert_free(rx_bert); - bert_init(tx_bert, 0, BERT_PATTERN_ONES, 300, 20); - bert_init(rx_bert, 0, BERT_PATTERN_ONES, 300, 20); + tx_bert = bert_init(NULL, 0, BERT_PATTERN_ONES, 300, 20); + rx_bert = bert_init(NULL, 0, BERT_PATTERN_ONES, 300, 20); for (i = 0; i < 511*2; i++) { bit = bert_get_bit(tx_bert); @@ -112,6 +114,8 @@ int main(int argc, char *argv[]) printf("Test failed.\n"); exit(2); } + bert_free(tx_bert); + bert_free(rx_bert); tx_bert = bert_init(NULL, 0, BERT_PATTERN_1_TO_7, 300, 20); rx_bert = bert_init(NULL, 0, BERT_PATTERN_1_TO_7, 300, 20); @@ -127,6 +131,8 @@ int main(int argc, char *argv[]) printf("Test failed.\n"); exit(2); } + bert_free(tx_bert); + bert_free(rx_bert); tx_bert = bert_init(NULL, 0, BERT_PATTERN_1_TO_3, 300, 20); rx_bert = bert_init(NULL, 0, BERT_PATTERN_1_TO_3, 300, 20); @@ -142,6 +148,8 @@ int main(int argc, char *argv[]) printf("Test failed.\n"); exit(2); } + bert_free(tx_bert); + bert_free(rx_bert); tx_bert = bert_init(NULL, 0, BERT_PATTERN_1_TO_1, 300, 20); rx_bert = bert_init(NULL, 0, BERT_PATTERN_1_TO_1, 300, 20); @@ -157,6 +165,8 @@ int main(int argc, char *argv[]) printf("Test failed.\n"); exit(2); } + bert_free(tx_bert); + bert_free(rx_bert); tx_bert = bert_init(NULL, 0, BERT_PATTERN_3_TO_1, 300, 20); rx_bert = bert_init(NULL, 0, BERT_PATTERN_3_TO_1, 300, 20); @@ -172,6 +182,8 @@ int main(int argc, char *argv[]) printf("Test failed.\n"); exit(2); } + bert_free(tx_bert); + bert_free(rx_bert); tx_bert = bert_init(NULL, 0, BERT_PATTERN_7_TO_1, 300, 20); rx_bert = bert_init(NULL, 0, BERT_PATTERN_7_TO_1, 300, 20); @@ -187,6 +199,8 @@ int main(int argc, char *argv[]) printf("Test failed.\n"); exit(2); } + bert_free(tx_bert); + bert_free(rx_bert); tx_bert = bert_init(NULL, 0, BERT_PATTERN_ITU_O153_9, 300, 20); rx_bert = bert_init(NULL, 0, BERT_PATTERN_ITU_O153_9, 300, 20); @@ -231,6 +245,8 @@ int main(int argc, char *argv[]) printf("Test failed.\n"); exit(2); } + bert_free(tx_bert); + bert_free(rx_bert); tx_bert = bert_init(NULL, 0, BERT_PATTERN_ITU_O152_11, 300, 20); rx_bert = bert_init(NULL, 0, BERT_PATTERN_ITU_O152_11, 300, 20); @@ -275,6 +291,8 @@ int main(int argc, char *argv[]) printf("Test failed.\n"); exit(2); } + bert_free(tx_bert); + bert_free(rx_bert); tx_bert = bert_init(NULL, 0, BERT_PATTERN_ITU_O151_15, 300, 20); rx_bert = bert_init(NULL, 0, BERT_PATTERN_ITU_O151_15, 300, 20); @@ -319,6 +337,8 @@ int main(int argc, char *argv[]) printf("Test failed.\n"); exit(2); } + bert_free(tx_bert); + bert_free(rx_bert); tx_bert = bert_init(NULL, 0, BERT_PATTERN_ITU_O151_20, 300, 20); rx_bert = bert_init(NULL, 0, BERT_PATTERN_ITU_O151_20, 300, 20); @@ -360,6 +380,8 @@ int main(int argc, char *argv[]) printf("Test failed.\n"); exit(2); } + bert_free(tx_bert); + bert_free(rx_bert); tx_bert = bert_init(NULL, 0, BERT_PATTERN_ITU_O151_23, 300, 20); rx_bert = bert_init(NULL, 0, BERT_PATTERN_ITU_O151_23, 300, 20); @@ -401,6 +423,8 @@ int main(int argc, char *argv[]) printf("Test failed.\n"); exit(2); } + bert_free(tx_bert); + bert_free(rx_bert); tx_bert = bert_init(NULL, 0, BERT_PATTERN_QBF, 300, 20); rx_bert = bert_init(NULL, 0, BERT_PATTERN_QBF, 300, 20); @@ -416,6 +440,8 @@ int main(int argc, char *argv[]) printf("Test failed.\n"); exit(2); } + bert_free(tx_bert); + bert_free(rx_bert); /* Test the mechanism for categorising the error rate into <10^x bands */ /* TODO: The result of this test is not checked automatically */ @@ -447,6 +473,7 @@ int main(int argc, char *argv[]) // bert_put_bit(bert, bit); bert_put_bit(bert, bit); } + bert_free(bert); printf("Tests passed.\n"); return 0; diff --git a/libs/spandsp/tests/dc_restore_tests.c b/libs/spandsp/tests/dc_restore_tests.c index 6fae1458a7..0150aa02ad 100644 --- a/libs/spandsp/tests/dc_restore_tests.c +++ b/libs/spandsp/tests/dc_restore_tests.c @@ -84,6 +84,7 @@ int main (int argc, char *argv[]) printf("Test failed.\n"); exit(2); } + awgn_free(noise_source); printf("Test passed.\n"); return 0; } diff --git a/libs/spandsp/tests/dtmf_rx_tests.c b/libs/spandsp/tests/dtmf_rx_tests.c index 947f80589f..d0fa87a3b1 100644 --- a/libs/spandsp/tests/dtmf_rx_tests.c +++ b/libs/spandsp/tests/dtmf_rx_tests.c @@ -613,6 +613,7 @@ static void mitel_cm7291_side_1_tests(void) printf(" Failed\n"); exit(2); } + dtmf_rx_free(dtmf_state); printf(" Passed\n"); } /*- End of function --------------------------------------------------------*/ @@ -686,6 +687,7 @@ static void mitel_cm7291_side_2_and_bellcore_tests(void) exit(2); } printf(" Passed\n"); + dtmf_rx_free(dtmf_state); } /*- End of function --------------------------------------------------------*/ @@ -741,6 +743,7 @@ static void dial_tone_tolerance_tests(void) exit(2); } printf(" Passed\n"); + dtmf_rx_free(dtmf_state); } /*- End of function --------------------------------------------------------*/ @@ -817,6 +820,7 @@ static void callback_function_tests(void) printf(" Failed\n"); exit(2); } + dtmf_rx_free(dtmf_state); } /*- End of function --------------------------------------------------------*/ @@ -915,6 +919,7 @@ int main(int argc, char *argv[]) printf("Tests passed in %ds\n", duration); } + codec_munge_free(munge); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/tests/dtmf_tx_tests.c b/libs/spandsp/tests/dtmf_tx_tests.c index 3f6f234ce7..1d0ad29178 100644 --- a/libs/spandsp/tests/dtmf_tx_tests.c +++ b/libs/spandsp/tests/dtmf_tx_tests.c @@ -211,6 +211,7 @@ int main(int argc, char *argv[]) fprintf(stderr, " Cannot close audio file '%s'\n", OUTPUT_FILE_NAME); exit(2); } + dtmf_tx_free(gen); return 0; } diff --git a/libs/spandsp/tests/fax_decode.c b/libs/spandsp/tests/fax_decode.c index 12cc11bb92..7b624bd6f8 100644 --- a/libs/spandsp/tests/fax_decode.c +++ b/libs/spandsp/tests/fax_decode.c @@ -356,7 +356,7 @@ static void v21_put_bit(void *user_data, int bit) } return; } - fprintf(stderr, "V.21 Rx bit %d - %d\n", rx_bits++, bit); + //fprintf(stderr, "V.21 Rx bit %d - %d\n", rx_bits++, bit); if (fast_trained == FAX_NONE) hdlc_rx_put_bit(&hdlcrx, bit); } diff --git a/libs/spandsp/tests/fax_tests.c b/libs/spandsp/tests/fax_tests.c index 96105edcae..9dbf6ce4e6 100644 --- a/libs/spandsp/tests/fax_tests.c +++ b/libs/spandsp/tests/fax_tests.c @@ -116,13 +116,14 @@ enum int mode[2] = {AUDIO_FAX, AUDIO_FAX}; -t30_state_t *t30_state[2]; -fax_state_t *fax_state[2]; -t38_gateway_state_t *t38_gateway_state[2]; -t38_terminal_state_t *t38_state[2]; -t38_core_state_t *t38_core_state[2]; -g1050_state_t *g1050_path[2]; -awgn_state_t *awgn_state[2]; +t30_state_t *t30_state[2] = {NULL, NULL}; +fax_state_t *fax_state[2] = {NULL, NULL}; +t38_gateway_state_t *t38_gateway_state[2] = {NULL, NULL}; +t38_terminal_state_t *t38_state[2] = {NULL, NULL}; +t38_core_state_t *t38_core_state[2] = {NULL, NULL}; +faxtester_state_t *faxtester[2] = {NULL, NULL}; +g1050_state_t *g1050_path[2] = {NULL, NULL}; +awgn_state_t *awgn_state[2] = {NULL, NULL}; int16_t audio_buffer[2*2][SAMPLES_PER_CHUNK]; int t38_subst_seq[2] = {0, 0}; @@ -1264,11 +1265,16 @@ int main(int argc, char *argv[]) break; } if (mode[i] == T38_TERMINAL_FAX) - t38_terminal_release(t38_state[i]); + t38_terminal_free(t38_state[i]); else - fax_release(fax_state[i]); + fax_free(fax_state[i]); if (mode[i] == T38_GATEWAY_FAX) - t38_gateway_release(t38_gateway_state[i]); + t38_gateway_free(t38_gateway_state[i]); + if (g1050_path[i]) + { + g1050_free(g1050_path[i]); + g1050_path[i] = NULL; + } } if (i < 2) { diff --git a/libs/spandsp/tests/fsk_tests.c b/libs/spandsp/tests/fsk_tests.c index db8a1335a7..1dc3e6cc12 100644 --- a/libs/spandsp/tests/fsk_tests.c +++ b/libs/spandsp/tests/fsk_tests.c @@ -296,6 +296,7 @@ int main(int argc, char *argv[]) fprintf(stderr, " Cannot close audio file '%s'\n", decode_test_file); exit(2); } + fsk_rx_free(caller_rx); } else { @@ -357,6 +358,7 @@ int main(int argc, char *argv[]) printf("Tests failed.\n"); exit(2); } + fsk_rx_free(caller_rx); printf("Test with BERT\n"); test_bps = preset_fsk_specs[modem_under_test_1].baud_rate; @@ -491,6 +493,7 @@ int main(int argc, char *argv[]) fsk_rx_set_modem_status_handler(caller_rx, rx_status, (void *) &caller_rx); } noise_level++; + both_ways_line_model_free(model); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, line_model_no, @@ -511,6 +514,19 @@ int main(int argc, char *argv[]) bert_set_report(&answerer_bert, 100000, reporter, (void *) (intptr_t) 2); } } + bert_release(&caller_bert); + bert_release(&answerer_bert); + if (modem_under_test_1 >= 0) + { + fsk_tx_free(caller_tx); + fsk_rx_free(answerer_rx); + } + if (modem_under_test_2 >= 0) + { + fsk_tx_free(answerer_tx); + fsk_rx_free(caller_rx); + } + both_ways_line_model_free(model); printf("Tests passed.\n"); } if (log_audio) diff --git a/libs/spandsp/tests/g1050_tests.c b/libs/spandsp/tests/g1050_tests.c index a7919e9575..397a2c6225 100644 --- a/libs/spandsp/tests/g1050_tests.c +++ b/libs/spandsp/tests/g1050_tests.c @@ -233,6 +233,8 @@ int main(int argc, char *argv[]) exit(2); } printf("%.3f%% of packets lost\n", 100.0*(packets_put - packets_really_put)/packets_put); + g1050_free(s); + free(packet_arrival_times); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/tests/g168_tests.c b/libs/spandsp/tests/g168_tests.c index 41351496c6..6eb9d7b48f 100644 --- a/libs/spandsp/tests/g168_tests.c +++ b/libs/spandsp/tests/g168_tests.c @@ -309,6 +309,15 @@ int main(int argc, char *argv[]) printf("%d\n", css_c3[i]); signal_free(&local_css); signal_free(&far_css); + fir32_free(&line_model_d2); + fir32_free(&line_model_d3); + fir32_free(&line_model_d4); + fir32_free(&line_model_d5); + fir32_free(&line_model_d6); + fir32_free(&line_model_d7); + fir32_free(&line_model_d8); + fir32_free(&line_model_d9); + fir_float_free(&level_measurement_bp); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/tests/g711_tests.c b/libs/spandsp/tests/g711_tests.c index c6ef2b1f78..9efb8ebaaa 100644 --- a/libs/spandsp/tests/g711_tests.c +++ b/libs/spandsp/tests/g711_tests.c @@ -314,9 +314,9 @@ static void compliance_tests(int log_audio) } } } - g711_release(enc_state); - g711_release(transcode); - g711_release(dec_state); + g711_free(enc_state); + g711_free(transcode); + g711_free(dec_state); if (log_audio) { diff --git a/libs/spandsp/tests/g722_tests.c b/libs/spandsp/tests/g722_tests.c index ac72e4c7b6..6a4251bb1b 100644 --- a/libs/spandsp/tests/g722_tests.c +++ b/libs/spandsp/tests/g722_tests.c @@ -278,6 +278,7 @@ static void itu_compliance_tests(void) exit(2); } printf("Test passed\n"); + g722_encode_free(enc_state); } #endif #if 1 @@ -346,6 +347,7 @@ static void itu_compliance_tests(void) exit(2); } printf("Test passed\n"); + g722_decode_free(dec_state); } } #endif @@ -403,6 +405,11 @@ static void signal_to_distortion_tests(void) printf("%10d, %10d, %f\n", in_level, out_level, (float) out_level/in_level); } while (len > 0); + swept_tone_free(swept); + g722_encode_free(enc_state); + g722_decode_free(dec_state); + power_meter_free(in_meter); + power_meter_free(out_meter); } /*- End of function --------------------------------------------------------*/ @@ -657,6 +664,7 @@ int main(int argc, char *argv[]) fprintf(stderr, " Cannot close audio file '%s'\n", IN_FILE_NAME); exit(2); } + g722_encode_free(enc_state); } else { @@ -669,6 +677,7 @@ int main(int argc, char *argv[]) fprintf(stderr, " Cannot close audio file '%s'\n", OUT_FILE_NAME); exit(2); } + g722_decode_free(dec_state); } else { diff --git a/libs/spandsp/tests/g726_tests.c b/libs/spandsp/tests/g726_tests.c index 0bba6e2fcc..75d1a542cd 100644 --- a/libs/spandsp/tests/g726_tests.c +++ b/libs/spandsp/tests/g726_tests.c @@ -1193,8 +1193,8 @@ static void itu_compliance_tests(void) int main(int argc, char *argv[]) { - g726_state_t enc_state; - g726_state_t dec_state; + g726_state_t *enc_state; + g726_state_t *dec_state; int opt; bool itutests; int bit_rate; @@ -1251,13 +1251,13 @@ int main(int argc, char *argv[]) } printf("ADPCM packing is %d\n", packing); - g726_init(&enc_state, bit_rate, G726_ENCODING_LINEAR, packing); - g726_init(&dec_state, bit_rate, G726_ENCODING_LINEAR, packing); + enc_state = g726_init(NULL, bit_rate, G726_ENCODING_LINEAR, packing); + dec_state = g726_init(NULL, bit_rate, G726_ENCODING_LINEAR, packing); while ((frames = sf_readf_short(inhandle, amp, 159))) { - adpcm = g726_encode(&enc_state, adpcmdata, amp, frames); - frames = g726_decode(&dec_state, amp, adpcmdata, adpcm); + adpcm = g726_encode(enc_state, adpcmdata, amp, frames); + frames = g726_decode(dec_state, amp, adpcmdata, adpcm); sf_writef_short(outhandle, amp, frames); } if (sf_close_telephony(inhandle)) @@ -1271,6 +1271,8 @@ int main(int argc, char *argv[]) exit(2); } printf("'%s' transcoded to '%s' at %dbps.\n", IN_FILE_NAME, OUT_FILE_NAME, bit_rate); + g726_free(enc_state); + g726_free(dec_state); } return 0; } diff --git a/libs/spandsp/tests/gsm0610_tests.c b/libs/spandsp/tests/gsm0610_tests.c index 346f574e99..06177fd9fd 100644 --- a/libs/spandsp/tests/gsm0610_tests.c +++ b/libs/spandsp/tests/gsm0610_tests.c @@ -321,7 +321,7 @@ static int perform_linear_test(int full, int disk, const char *name) mismatches++; } } - gsm0610_release(gsm0610_enc_state); + gsm0610_free(gsm0610_enc_state); if (mismatches) { printf("Test failed: %d of %d samples mismatch\n", mismatches, xxx); @@ -350,7 +350,7 @@ static int perform_linear_test(int full, int disk, const char *name) printf("Test failed: %d of %d samples mismatch\n", mismatches, vector_len); exit(2); } - gsm0610_release(gsm0610_dec_state); + gsm0610_free(gsm0610_dec_state); printf("Test passed\n"); return 0; } @@ -405,7 +405,7 @@ static int perform_law_test(int full, int law, const char *name) exit(2); } printf("Test passed\n"); - gsm0610_release(gsm0610_enc_state); + gsm0610_free(gsm0610_enc_state); } if ((gsm0610_dec_state = gsm0610_init(NULL, GSM0610_PACKING_NONE)) == NULL) @@ -438,7 +438,7 @@ static int perform_law_test(int full, int law, const char *name) printf("Test failed: %d of %d samples mismatch\n", mismatches, vector_len); exit(2); } - gsm0610_release(gsm0610_dec_state); + gsm0610_free(gsm0610_dec_state); printf("Test passed\n"); return 0; } @@ -613,8 +613,8 @@ int main(int argc, char *argv[]) fprintf(stderr, " Cannot close audio file '%s'\n", OUT_FILE_NAME); exit(2); } - gsm0610_release(gsm0610_enc_state); - gsm0610_release(gsm0610_dec_state); + gsm0610_free(gsm0610_enc_state); + gsm0610_free(gsm0610_dec_state); } return 0; } diff --git a/libs/spandsp/tests/ima_adpcm_tests.c b/libs/spandsp/tests/ima_adpcm_tests.c index e080330313..46645f09f0 100644 --- a/libs/spandsp/tests/ima_adpcm_tests.c +++ b/libs/spandsp/tests/ima_adpcm_tests.c @@ -187,8 +187,8 @@ int main(int argc, char *argv[]) fprintf(stderr, " Cannot close audio file '%s'\n", OUT_FILE_NAME); exit(2); } - ima_adpcm_release(ima_enc_state); - ima_adpcm_release(ima_dec_state); + ima_adpcm_free(ima_enc_state); + ima_adpcm_free(ima_dec_state); printf("Pre samples: %d\n", total_pre_samples); printf("Compressed bytes: %d\n", total_compressed_bytes); diff --git a/libs/spandsp/tests/image_translate_tests.c b/libs/spandsp/tests/image_translate_tests.c index 7b4fa9d3d3..9ec0691fbe 100644 --- a/libs/spandsp/tests/image_translate_tests.c +++ b/libs/spandsp/tests/image_translate_tests.c @@ -811,6 +811,8 @@ static void lenna_tests(int output_width, int output_length_scaling, const char TIFFWriteDirectory(out_file); TIFFClose(out_file); image_translate_free(s); + free(image); + free(image2); } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/tests/line_model_tests.c b/libs/spandsp/tests/line_model_tests.c index 8d31413cd4..b44f9771de 100644 --- a/libs/spandsp/tests/line_model_tests.c +++ b/libs/spandsp/tests/line_model_tests.c @@ -88,6 +88,8 @@ static void complexify_tests(void) out[2*i] = cc.re; out[2*i + 1] = cc.im; } + awgn_release(&noise1); + complexify_free(s); outframes = sf_writef_short(outhandle, out, 20000); if (outframes != 20000) { @@ -183,7 +185,7 @@ static void test_one_way_model(int line_model_no, int speech_test) fprintf(stderr, " Cannot close audio file '%s'\n", OUT_FILE_NAME1); exit(2); } - one_way_line_model_release(model); + one_way_line_model_free(model); } /*- End of function --------------------------------------------------------*/ @@ -302,7 +304,7 @@ static void test_both_ways_model(int line_model_no, int speech_test) fprintf(stderr, " Cannot close audio file '%s'\n", OUT_FILE_NAME2); exit(2); } - both_ways_line_model_release(model); + both_ways_line_model_free(model); } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/tests/logging_tests.c b/libs/spandsp/tests/logging_tests.c index 666fc1e9bb..2ba4bac9db 100644 --- a/libs/spandsp/tests/logging_tests.c +++ b/libs/spandsp/tests/logging_tests.c @@ -203,6 +203,8 @@ int main(int argc, char *argv[]) span_log_set_message_handler(log, &message_handler, NULL); + span_log_free(log); + printf("Tests passed.\n"); return 0; } diff --git a/libs/spandsp/tests/lpc10_tests.c b/libs/spandsp/tests/lpc10_tests.c index 0ecacfb847..a733659bc2 100644 --- a/libs/spandsp/tests/lpc10_tests.c +++ b/libs/spandsp/tests/lpc10_tests.c @@ -236,8 +236,8 @@ int main(int argc, char *argv[]) close(compress_file); if (decompress) close(decompress_file); - lpc10_encode_release(lpc10_enc_state); - lpc10_decode_release(lpc10_dec_state); + lpc10_encode_free(lpc10_enc_state); + lpc10_decode_free(lpc10_dec_state); if (!decompress) { diff --git a/libs/spandsp/tests/oki_adpcm_tests.c b/libs/spandsp/tests/oki_adpcm_tests.c index f41208239c..84604b69be 100644 --- a/libs/spandsp/tests/oki_adpcm_tests.c +++ b/libs/spandsp/tests/oki_adpcm_tests.c @@ -276,15 +276,15 @@ int main(int argc, char *argv[]) } - oki_adpcm_release(oki_enc_state); + oki_adpcm_free(oki_enc_state); if (sf_close_telephony(inhandle)) { fprintf(stderr, " Cannot close audio file '%s'\n", in_file_name); exit(2); } } - oki_adpcm_release(oki_dec_state); - oki_adpcm_release(oki_dec_state2); + oki_adpcm_free(oki_dec_state); + oki_adpcm_free(oki_dec_state2); if (sf_close_telephony(outhandle)) { fprintf(stderr, " Cannot close audio file '%s'\n", OUT_FILE_NAME); diff --git a/libs/spandsp/tests/power_meter_tests.c b/libs/spandsp/tests/power_meter_tests.c index 518fa3a694..59287b7d21 100644 --- a/libs/spandsp/tests/power_meter_tests.c +++ b/libs/spandsp/tests/power_meter_tests.c @@ -147,6 +147,8 @@ static int power_surge_detector_tests(void) exit(2); } printf("Min on %d, max on %d, min off %d, max off %d\n", extremes[0], extremes[1], extremes[2], extremes[3]); + power_surge_detector_free(sig); + awgn_free(awgnx); return 0; } /*- End of function --------------------------------------------------------*/ diff --git a/libs/spandsp/tests/r2_mf_rx_tests.c b/libs/spandsp/tests/r2_mf_rx_tests.c index bc4c5b4840..da244336c5 100644 --- a/libs/spandsp/tests/r2_mf_rx_tests.c +++ b/libs/spandsp/tests/r2_mf_rx_tests.c @@ -181,6 +181,7 @@ static int my_mf_generate(int16_t amp[], char digit) { tone = tone_gen_init(NULL, &my_mf_digit_tones[cp - r2_mf_tone_codes]); len += tone_gen(tone, amp + len, 9999); + tone_gen_free(tone); } return len; } @@ -524,6 +525,7 @@ static int test_a_tone_set(int fwd) if (r2_mf_rx_get(mf_state) != digit) break; } + awgn_free(noise_source); if (j < 500) break; } @@ -541,7 +543,7 @@ static int test_a_tone_set(int fwd) printf("Test 8: Callback digit delivery mode.\n"); callback_ok = false; callback_roll = 0; - mf_state = r2_mf_rx_init(NULL, fwd, digit_delivery, (void *) 0x12345678); + mf_state = r2_mf_rx_init(mf_state, fwd, digit_delivery, (void *) 0x12345678); my_mf_gen_init(0.0, -3, 0.0, -3, 68, fwd); s = r2_mf_tone_codes; noise_source = awgn_init_dbm0(NULL, 1234567, -40.0f); @@ -560,6 +562,7 @@ static int test_a_tone_set(int fwd) codec_munge(amp, len); r2_mf_rx(mf_state, amp, len); } + awgn_free(noise_source); if (!callback_ok) { printf(" Failed\n"); @@ -567,6 +570,8 @@ static int test_a_tone_set(int fwd) } printf(" Passed\n"); + r2_mf_rx_free(mf_state); + /* The remainder of the Mitel tape is the talk-off test. This is meaningless for R2 MF. However the decoder's tolerance of out of band noise is significant. */ diff --git a/libs/spandsp/tests/rfc2198_sim_tests.c b/libs/spandsp/tests/rfc2198_sim_tests.c index 95d8f6b971..fe210a2555 100644 --- a/libs/spandsp/tests/rfc2198_sim_tests.c +++ b/libs/spandsp/tests/rfc2198_sim_tests.c @@ -229,6 +229,10 @@ int main(int argc, char *argv[]) fclose(out_file); + rfc2198_sim_free(s); + + free(packet_arrival_times); + printf("Put %d packets. Really put %d packets. Got %d packets.\n", packets_put, packets_really_put, packets_got); printf("%d OOS packets, %d missing packets\n", oos_packets_got, missing_packets_got - oos_packets_got); printf("%d packets queued, %d received\n", packets_really_put, packets_got); diff --git a/libs/spandsp/tests/sig_tone_tests.c b/libs/spandsp/tests/sig_tone_tests.c index 00af89eeba..61f93ccb0e 100644 --- a/libs/spandsp/tests/sig_tone_tests.c +++ b/libs/spandsp/tests/sig_tone_tests.c @@ -648,6 +648,8 @@ int main(int argc, char *argv[]) speech_immunity_tests(&rx_state); level_and_ratio_tests(&rx_state, fc); sequence_tests(&tx_state, &rx_state, munge); + if (munge) + codec_munge_free(munge); } /*endfor*/ diff --git a/libs/spandsp/tests/swept_tone_tests.c b/libs/spandsp/tests/swept_tone_tests.c index aebc54a409..8fef132295 100644 --- a/libs/spandsp/tests/swept_tone_tests.c +++ b/libs/spandsp/tests/swept_tone_tests.c @@ -92,6 +92,10 @@ int main(int argc, char *argv[]) exit(2); } + swept_tone_free(s); + + power_meter_release(&meter); + printf("Tests passed.\n"); return 0; } diff --git a/libs/spandsp/tests/t31_tests.c b/libs/spandsp/tests/t31_tests.c index d9356296e9..beff7f9cce 100644 --- a/libs/spandsp/tests/t31_tests.c +++ b/libs/spandsp/tests/t31_tests.c @@ -852,8 +852,13 @@ static int t30_tests(int t38_mode, int use_gui, int log_audio, int test_sending, span_log_bump_samples(at_get_logging_state(t31_get_at_state(t31_state)), SAMPLES_PER_CHUNK); } + g1050_free(path_a_to_b); + g1050_free(path_b_to_a); if (t38_mode) - t38_terminal_release(t38_state); + t38_terminal_free(t38_state); + else + fax_free(fax_state); + t31_free(t31_state); if (decode_test_file) { diff --git a/libs/spandsp/tests/t38_non_ecm_buffer_tests.c b/libs/spandsp/tests/t38_non_ecm_buffer_tests.c index 9b4cb4039c..4ed2bcf7d2 100644 --- a/libs/spandsp/tests/t38_non_ecm_buffer_tests.c +++ b/libs/spandsp/tests/t38_non_ecm_buffer_tests.c @@ -168,6 +168,7 @@ int main(int argc, char *argv[]) printf(" Done\n"); t38_non_ecm_buffer_report_input_status(&buffer, &logging); t38_non_ecm_buffer_report_output_status(&buffer, &logging); + t38_non_ecm_buffer_release(&buffer); printf("2 - Impose no minimum for the bits per row, different alignment\n"); t38_non_ecm_buffer_init(&buffer, true, 0); @@ -233,6 +234,7 @@ int main(int argc, char *argv[]) } t38_non_ecm_buffer_report_input_status(&buffer, &logging); t38_non_ecm_buffer_report_output_status(&buffer, &logging); + t38_non_ecm_buffer_release(&buffer); printf("3 - Demand a fairly high minimum for the bits per row\n"); t38_non_ecm_buffer_init(&buffer, true, 400); @@ -298,6 +300,7 @@ int main(int argc, char *argv[]) } t38_non_ecm_buffer_report_input_status(&buffer, &logging); t38_non_ecm_buffer_report_output_status(&buffer, &logging); + t38_non_ecm_buffer_release(&buffer); printf("4 - Take some time to get to the first row of the image, output ahead\n"); t38_non_ecm_buffer_init(&buffer, true, 400); @@ -446,6 +449,7 @@ int main(int argc, char *argv[]) printf(" RTC output OK\n"); t38_non_ecm_buffer_report_input_status(&buffer, &logging); t38_non_ecm_buffer_report_output_status(&buffer, &logging); + t38_non_ecm_buffer_release(&buffer); printf("5 - Take some time to get to the first row of the image, output behind\n"); t38_non_ecm_buffer_init(&buffer, true, 400); @@ -583,6 +587,7 @@ int main(int argc, char *argv[]) printf(" RTC output OK\n"); t38_non_ecm_buffer_report_input_status(&buffer, &logging); t38_non_ecm_buffer_report_output_status(&buffer, &logging); + t38_non_ecm_buffer_release(&buffer); printf("6 - TCF without leading ones\n"); t38_non_ecm_buffer_init(&buffer, false, 400); @@ -628,6 +633,7 @@ int main(int argc, char *argv[]) printf(" End of data seen OK\n"); t38_non_ecm_buffer_report_input_status(&buffer, &logging); t38_non_ecm_buffer_report_output_status(&buffer, &logging); + t38_non_ecm_buffer_release(&buffer); printf("7 - TCF with leading ones\n"); t38_non_ecm_buffer_init(&buffer, false, 400); @@ -695,6 +701,7 @@ int main(int argc, char *argv[]) printf(" End of data seen OK\n"); t38_non_ecm_buffer_report_input_status(&buffer, &logging); t38_non_ecm_buffer_report_output_status(&buffer, &logging); + t38_non_ecm_buffer_release(&buffer); printf("Tests passed\n"); return 0; diff --git a/libs/spandsp/tests/t42_tests.c b/libs/spandsp/tests/t42_tests.c index bfdaf80b8e..d9f80da5b5 100644 --- a/libs/spandsp/tests/t42_tests.c +++ b/libs/spandsp/tests/t42_tests.c @@ -287,7 +287,11 @@ int main(int argc, char *argv[]) for (i = 0, total_image_len = 0; i < nstrips; i++) total_image_len += TIFFRawStripSize(tif, i); - data = malloc(total_image_len); + if ((data = malloc(total_image_len)) == NULL) + { + printf("Failed to allocate buffer\n"); + exit(2); + } for (i = 0, total_len = 0; i < nstrips; i++, total_len += len) { if ((len = TIFFReadRawStrip(tif, i, &data[total_len], total_image_len - total_len)) < 0) @@ -439,7 +443,11 @@ int main(int argc, char *argv[]) printf("total %d\n", totdata); /* Read the image into memory. */ - data = malloc(totdata); + if ((data = malloc(totdata)) == NULL) + { + printf("Failed to allocate buffer\n"); + exit(2); + } off = 0; for (row = 0; row < h; row++) { @@ -561,7 +569,11 @@ int main(int argc, char *argv[]) } free(data); #else - data2 = malloc(totdata); + if ((data2 = malloc(totdata)) == NULL) + { + printf("Failed to allocate buffer\n"); + exit(2); + } start = rdtscll(); //if (!t42_itulab_jpeg_to_srgb(logging, &lab_param, data2, &off, data, off, &w, &h, &samples_per_pixel)) { diff --git a/libs/spandsp/tests/t43_tests.c b/libs/spandsp/tests/t43_tests.c index bc9242d044..3df17ea7f2 100644 --- a/libs/spandsp/tests/t43_tests.c +++ b/libs/spandsp/tests/t43_tests.c @@ -486,8 +486,7 @@ int read_file(meta_t *meta, int page) if (TIFFGetField(tif, TIFFTAG_COLORMAP, &map_L, &map_a, &map_b, &map_z)) { entries = 1 << meta->bits_per_sample; - meta->colour_map = malloc(3*entries); - if (meta->colour_map) + if ((meta->colour_map = malloc(3*entries))) { #if 0 /* Sweep the colormap in the proper order */ @@ -1349,7 +1348,11 @@ int main(int argc, char *argv[]) free(data); data = data2; #elif 1 - data2 = malloc(totdata); + if ((data2 = malloc(totdata)) == NULL) + { + printf("Failed to allocate buffer\n"); + exit(2); + } start = rdtscll(); //if (!t42_itulab_jpeg_to_srgb(&logging2, &lab_param, data2, &off, data, off, &meta.image_width, &meta.image_length, &meta.samples_per_pixel)) { diff --git a/libs/spandsp/tests/t4_t6_tests.c b/libs/spandsp/tests/t4_t6_tests.c index 0e583ab059..476f737530 100644 --- a/libs/spandsp/tests/t4_t6_tests.c +++ b/libs/spandsp/tests/t4_t6_tests.c @@ -412,8 +412,8 @@ int main(int argc, char *argv[]) if (compression_step < 0) break; } - t4_t6_encode_release(send_state); - t4_t6_decode_release(receive_state); + t4_t6_encode_free(send_state); + t4_t6_decode_free(receive_state); #endif printf("Tests passed\n"); return 0; diff --git a/libs/spandsp/tests/t4_tests.c b/libs/spandsp/tests/t4_tests.c index 98a57cfe54..4599e0c449 100644 --- a/libs/spandsp/tests/t4_tests.c +++ b/libs/spandsp/tests/t4_tests.c @@ -454,7 +454,7 @@ int main(int argc, char *argv[]) dump_image_as_xxx(receive_state); t4_rx_end_page(receive_state); display_page_stats(receive_state); - t4_rx_release(receive_state); + t4_rx_free(receive_state); } else { @@ -621,8 +621,8 @@ int main(int argc, char *argv[]) t4_rx_end_page(receive_state); sends++; } - t4_tx_release(send_state); - t4_rx_release(receive_state); + t4_tx_free(send_state); + t4_rx_free(receive_state); /* And we should now have a matching received TIFF file. Note this will only match at the image level. TIFF files allow a lot of ways to express the same thing, so bit matching of the files is not the normal case. */ diff --git a/libs/spandsp/tests/t81_t82_arith_coding_tests.c b/libs/spandsp/tests/t81_t82_arith_coding_tests.c index 8de5749928..84a61a5df1 100644 --- a/libs/spandsp/tests/t81_t82_arith_coding_tests.c +++ b/libs/spandsp/tests/t81_t82_arith_coding_tests.c @@ -225,7 +225,8 @@ int main(int argc, char *argv[]) exit(2); } printf("Test passed\n"); - + t81_t82_arith_encode_free(se); + t81_t82_arith_encode_free(sd); printf("Tests passed\n"); return 0; } diff --git a/libs/spandsp/tests/t85_tests.c b/libs/spandsp/tests/t85_tests.c index 8acca038c5..338fe30caf 100644 --- a/libs/spandsp/tests/t85_tests.c +++ b/libs/spandsp/tests/t85_tests.c @@ -228,7 +228,6 @@ static int test_cycle(const char *test_id, if (comment && testbuf_len == 1000) t85_encode_comment(t85_enc, comment, strlen((const char *) comment) + 1); } - t85_encode_release(t85_enc); printf("Encoded BIE has %lu bytes\n", (unsigned long int) testbuf_len); if (correct_length > 0) { @@ -241,6 +240,9 @@ static int test_cycle(const char *test_id, printf("Test passed\n"); } + cnt_a = t85_encode_get_compressed_image_size(t85_enc); + t85_encode_free(t85_enc); + printf("%s.2: Decode in one big chunk\n", test_id); if ((decoded_image = (uint8_t *) malloc(image_size)) == NULL) { @@ -254,7 +256,6 @@ static int test_cycle(const char *test_id, result = t85_decode_put(t85_dec, testbuf, testbuf_len); if (result == T4_DECODE_MORE_DATA) result = t85_decode_put(t85_dec, NULL, 0); - cnt_a = t85_encode_get_compressed_image_size(t85_enc); cnt_b = t85_decode_get_compressed_image_size(t85_dec); if (cnt_a != cnt_b || cnt_a != testbuf_len*8 || result != T4_DECODE_OK) { @@ -274,7 +275,7 @@ static int test_cycle(const char *test_id, exit(2); } free(decoded_image); - t85_decode_release(t85_dec); + t85_decode_free(t85_dec); printf("Test passed\n"); printf("%s.3: Decode byte by byte\n", test_id); @@ -316,7 +317,7 @@ static int test_cycle(const char *test_id, exit(2); } free(decoded_image); - t85_decode_release(t85_dec); + t85_decode_free(t85_dec); printf("Test passed\n"); return 0; diff --git a/libs/spandsp/tests/time_scale_tests.c b/libs/spandsp/tests/time_scale_tests.c index 3400b5f9b2..abd5300fdf 100644 --- a/libs/spandsp/tests/time_scale_tests.c +++ b/libs/spandsp/tests/time_scale_tests.c @@ -94,6 +94,7 @@ int main(int argc, char *argv[]) break; } } + memset(&info, 0, sizeof(info)); if ((inhandle = sf_open(in_file_name, SFM_READ, &info)) == NULL) { printf(" Cannot open audio file '%s'\n", in_file_name); @@ -151,6 +152,7 @@ int main(int argc, char *argv[]) count = 0; } } + time_scale_release(&state); if (sf_close(inhandle)) { printf(" Cannot close audio file '%s'\n", in_file_name); diff --git a/libs/spandsp/tests/tone_detect_tests.c b/libs/spandsp/tests/tone_detect_tests.c index fd62c932b9..016e0096e3 100644 --- a/libs/spandsp/tests/tone_detect_tests.c +++ b/libs/spandsp/tests/tone_detect_tests.c @@ -122,6 +122,8 @@ static int periodogram_tests(void) return -1; } } + awgn_free(noise_source_re); + awgn_free(noise_source_im); } return 0; } diff --git a/libs/spandsp/tests/tone_generate_tests.c b/libs/spandsp/tests/tone_generate_tests.c index 6f1f8af4ea..ffa87eb3ad 100644 --- a/libs/spandsp/tests/tone_generate_tests.c +++ b/libs/spandsp/tests/tone_generate_tests.c @@ -70,7 +70,6 @@ int main(int argc, char *argv[]) 400, false); tone_gen_init(&tone_state, &tone_desc); - for (i = 0; i < 1000; i++) { len = tone_gen(&tone_state, amp, 160); @@ -79,6 +78,7 @@ int main(int argc, char *argv[]) break; sf_writef_short(outhandle, amp, len); } + tone_gen_release(&tone_state); /* Try a different tone pair */ tone_gen_descriptor_init(&tone_desc, @@ -92,7 +92,6 @@ int main(int argc, char *argv[]) 100, true); tone_gen_init(&tone_state, &tone_desc); - for (i = 0; i < 1000; i++) { len = tone_gen(&tone_state, amp, 160); @@ -101,6 +100,7 @@ int main(int argc, char *argv[]) break; sf_writef_short(outhandle, amp, len); } + tone_gen_release(&tone_state); /* Try a different tone pair */ tone_gen_descriptor_init(&tone_desc, @@ -114,7 +114,6 @@ int main(int argc, char *argv[]) 400, true); tone_gen_init(&tone_state, &tone_desc); - for (i = 0; i < 1000; i++) { len = tone_gen(&tone_state, amp, 160); @@ -123,6 +122,7 @@ int main(int argc, char *argv[]) break; sf_writef_short(outhandle, amp, len); } + tone_gen_release(&tone_state); /* Try a single tone */ tone_gen_descriptor_init(&tone_desc, @@ -136,7 +136,6 @@ int main(int argc, char *argv[]) 400, true); tone_gen_init(&tone_state, &tone_desc); - for (i = 0; i < 1000; i++) { len = tone_gen(&tone_state, amp, 160); @@ -145,6 +144,7 @@ int main(int argc, char *argv[]) break; sf_writef_short(outhandle, amp, len); } + tone_gen_release(&tone_state); /* Try a single non-repeating tone */ tone_gen_descriptor_init(&tone_desc, @@ -158,7 +158,6 @@ int main(int argc, char *argv[]) 0, false); tone_gen_init(&tone_state, &tone_desc); - for (i = 0; i < 1000; i++) { len = tone_gen(&tone_state, amp, 160); @@ -167,6 +166,7 @@ int main(int argc, char *argv[]) break; sf_writef_short(outhandle, amp, len); } + tone_gen_release(&tone_state); /* Try a single non-repeating tone at 0dBm0 */ tone_gen_descriptor_init(&tone_desc, @@ -180,7 +180,6 @@ int main(int argc, char *argv[]) 0, false); tone_gen_init(&tone_state, &tone_desc); - for (i = 0; i < 1000; i++) { len = tone_gen(&tone_state, amp, 160); @@ -189,6 +188,7 @@ int main(int argc, char *argv[]) break; sf_writef_short(outhandle, amp, len); } + tone_gen_release(&tone_state); /* Try an AM modulated tone at a modest modulation level (25%) */ tone_gen_descriptor_init(&tone_desc, @@ -202,7 +202,6 @@ int main(int argc, char *argv[]) 400, true); tone_gen_init(&tone_state, &tone_desc); - for (i = 0; i < 1000; i++) { len = tone_gen(&tone_state, amp, 160); @@ -211,6 +210,7 @@ int main(int argc, char *argv[]) break; sf_writef_short(outhandle, amp, len); } + tone_gen_release(&tone_state); /* Try an AM modulated tone at maximum modulation level (100%) */ tone_gen_descriptor_init(&tone_desc, @@ -224,7 +224,6 @@ int main(int argc, char *argv[]) 400, true); tone_gen_init(&tone_state, &tone_desc); - for (i = 0; i < 1000; i++) { len = tone_gen(&tone_state, amp, 160); @@ -233,6 +232,7 @@ int main(int argc, char *argv[]) break; sf_writef_short(outhandle, amp, len); } + tone_gen_release(&tone_state); if (sf_close_telephony(outhandle)) { diff --git a/libs/spandsp/tests/tsb85_tests.c b/libs/spandsp/tests/tsb85_tests.c index f383eb8f47..a7c02a6b86 100644 --- a/libs/spandsp/tests/tsb85_tests.c +++ b/libs/spandsp/tests/tsb85_tests.c @@ -94,6 +94,8 @@ char next_tx_file[1000]; static int next_step(faxtester_state_t *s); +static bool test_for_call_drop = false; + static int phase_b_handler(void *user_data, int result) { int ch; @@ -641,6 +643,7 @@ static int next_step(faxtester_state_t *s) t4_tx_state_t t4_tx_state; t30_state_t *t30; + test_for_call_drop = false; if (s->cur == NULL) { if (!s->final_delayed) @@ -798,6 +801,11 @@ static int next_step(faxtester_state_t *s) { faxtest_set_rx_silence(s); } + else if (strcasecmp((const char *) type, "DROPCALL") == 0) + { + span_log(&s->logging, SPAN_LOG_FLOW, "Far end should drop the call\n"); + test_for_call_drop = true; + } else { span_log(&s->logging, SPAN_LOG_FLOW, "Unrecognised type '%s'\n", (const char *) type); @@ -1109,6 +1117,11 @@ static int next_step(faxtester_state_t *s) span_log(&s->logging, SPAN_LOG_FLOW, "ECM image is %d bytes (min row bits %d)\n", len, min_row_bits); faxtester_set_ecm_image_buffer(s, image, len, ecm_block, ecm_frame_size, i); } + else if (strcasecmp((const char *) type, "DROPCALL") == 0) + { + span_log(&s->logging, SPAN_LOG_FLOW, "Time to drop the call\n"); + return 0; + } else { span_log(&s->logging, SPAN_LOG_FLOW, "Unrecognised type '%s'\n", (const char *) type); @@ -1198,6 +1211,16 @@ static void exchange(faxtester_state_t *s) /*endif*/ } /*endif*/ + if (test_for_call_drop) + { + if (!t30_call_active(fax_get_t30_state(fax))) + { + printf("Call dropped\n"); + //break; + } + /*endif*/ + } + /*endif*/ } /*endfor*/ if (log_audio) @@ -1391,6 +1414,7 @@ int main(int argc, char *argv[]) span_log_set_level(&state.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_SHOW_TAG | SPAN_LOG_SHOW_SAMPLE_TIME | SPAN_LOG_FLOW); span_log_set_tag(&state.logging, "B"); get_test_set(&state, xml_file_name, test_name); + faxtester_release(&state); printf("Done\n"); return 0; } diff --git a/libs/spandsp/tests/v17_tests.c b/libs/spandsp/tests/v17_tests.c index 8ceb12060e..4ef9f7306f 100644 --- a/libs/spandsp/tests/v17_tests.c +++ b/libs/spandsp/tests/v17_tests.c @@ -535,7 +535,7 @@ int main(int argc, char *argv[]) //rx.eq_put_step = rand()%(192*10/3); bert_init(&bert, bits_per_test, BERT_PATTERN_ITU_O152_11, test_bps, 20); bert_set_report(&bert, 10000, reporter, NULL); - one_way_line_model_release(line_model); + one_way_line_model_free(line_model); if ((line_model = one_way_line_model_init(line_model_no, (float) noise_level, channel_codec, 0)) == NULL) { fprintf(stderr, " Failed to create line model\n"); @@ -565,7 +565,7 @@ int main(int argc, char *argv[]) fprintf(stderr, "At completion:\n"); fprintf(stderr, "Final result %ddBm0/%ddBm0, %d bits, %d bad bits, %d resyncs\n", signal_level, noise_level, bert_results.total_bits, bert_results.bad_bits, bert_results.resyncs); fprintf(stderr, "Last report %ddBm0/%ddBm0, %d bits, %d bad bits, %d resyncs\n", signal_level, noise_level, latest_results.total_bits, latest_results.bad_bits, latest_results.resyncs); - one_way_line_model_release(line_model); + one_way_line_model_free(line_model); if (signal_level > -43) { @@ -575,6 +575,9 @@ int main(int argc, char *argv[]) printf("Tests passed.\n"); } + v17_rx_free(rx); + if (tx) + v17_tx_free(tx); #if defined(ENABLE_GUI) if (use_gui) qam_wait_to_end(qam_monitor); diff --git a/libs/spandsp/tests/v22bis_tests.c b/libs/spandsp/tests/v22bis_tests.c index 3729687c35..d42b2f4f4d 100644 --- a/libs/spandsp/tests/v22bis_tests.c +++ b/libs/spandsp/tests/v22bis_tests.c @@ -455,6 +455,7 @@ int main(int argc, char *argv[]) } } } + both_ways_line_model_free(model); #if defined(ENABLE_GUI) if (use_gui) qam_wait_to_end(endpoint[0].qam_monitor); diff --git a/libs/spandsp/tests/v27ter_tests.c b/libs/spandsp/tests/v27ter_tests.c index 671fd935af..edac945aa3 100644 --- a/libs/spandsp/tests/v27ter_tests.c +++ b/libs/spandsp/tests/v27ter_tests.c @@ -540,7 +540,7 @@ int main(int argc, char *argv[]) v27ter_rx_restart(rx, test_bps, false); bert_init(&bert, bits_per_test, BERT_PATTERN_ITU_O152_11, test_bps, 20); bert_set_report(&bert, 10000, reporter, NULL); - one_way_line_model_release(line_model); + one_way_line_model_free(line_model); if ((line_model = one_way_line_model_init(line_model_no, (float) noise_level, channel_codec, 0)) == NULL) { fprintf(stderr, " Failed to create line model\n"); @@ -571,7 +571,8 @@ int main(int argc, char *argv[]) fprintf(stderr, "At completion:\n"); fprintf(stderr, "Final result %ddBm0/%ddBm0, %d bits, %d bad bits, %d resyncs\n", signal_level, noise_level, bert_results.total_bits, bert_results.bad_bits, bert_results.resyncs); fprintf(stderr, "Last report %ddBm0/%ddBm0, %d bits, %d bad bits, %d resyncs\n", signal_level, noise_level, latest_results.total_bits, latest_results.bad_bits, latest_results.resyncs); - one_way_line_model_release(line_model); + one_way_line_model_free(line_model); + if (signal_level > -43) { printf("Tests failed.\n"); @@ -580,6 +581,10 @@ int main(int argc, char *argv[]) printf("Tests passed.\n"); } + v27ter_rx_free(rx); + if (tx) + v27ter_tx_free(tx); + bert_release(&bert); #if defined(ENABLE_GUI) if (use_gui) qam_wait_to_end(qam_monitor); diff --git a/libs/spandsp/tests/v29_tests.c b/libs/spandsp/tests/v29_tests.c index ec678c148a..946170cb5d 100644 --- a/libs/spandsp/tests/v29_tests.c +++ b/libs/spandsp/tests/v29_tests.c @@ -520,7 +520,7 @@ int main(int argc, char *argv[]) #endif bert_init(&bert, bits_per_test, BERT_PATTERN_ITU_O152_11, test_bps, 20); bert_set_report(&bert, 10000, reporter, NULL); - one_way_line_model_release(line_model); + one_way_line_model_free(line_model); if ((line_model = one_way_line_model_init(line_model_no, (float) noise_level, channel_codec, 0)) == NULL) { fprintf(stderr, " Failed to create line model\n"); @@ -550,7 +550,7 @@ int main(int argc, char *argv[]) fprintf(stderr, "At completion:\n"); fprintf(stderr, "Final result %ddBm0/%ddBm0, %d bits, %d bad bits, %d resyncs\n", signal_level, noise_level, bert_results.total_bits, bert_results.bad_bits, bert_results.resyncs); fprintf(stderr, "Last report %ddBm0/%ddBm0, %d bits, %d bad bits, %d resyncs\n", signal_level, noise_level, latest_results.total_bits, latest_results.bad_bits, latest_results.resyncs); - one_way_line_model_release(line_model); + one_way_line_model_free(line_model); if (signal_level > -43) { @@ -560,6 +560,10 @@ int main(int argc, char *argv[]) printf("Tests passed.\n"); } + v29_rx_free(rx); + if (tx) + v29_tx_free(tx); + bert_release(&bert); #if defined(ENABLE_GUI) if (use_gui) qam_wait_to_end(qam_monitor); From e7ee4050b2557f69c23728face93bb8b6bf5e986 Mon Sep 17 00:00:00 2001 From: Peter Olsson Date: Sun, 15 Jun 2014 13:51:56 +0200 Subject: [PATCH 056/231] Add ldns to .gitignore --- libs/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/.gitignore b/libs/.gitignore index c6af42feb0..4fca482c49 100644 --- a/libs/.gitignore +++ b/libs/.gitignore @@ -835,3 +835,4 @@ unimrcp/build/compile /curl-*/ /sqlite-*.zip /sqlite-*/ +/ldns/ From 13e02278a1016d0c8d9676d22273203261af84c1 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Mon, 16 Jun 2014 13:45:39 +0000 Subject: [PATCH 057/231] Use portable version of strerror_r() FS-6596 --resolve --- src/switch.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/switch.c b/src/switch.c index 4523bd0589..633524eb56 100644 --- a/src/switch.c +++ b/src/switch.c @@ -402,13 +402,13 @@ static void reincarnate_protect(char **argv) { if (execv(argv[0], argv) == -1) { char buf[256]; fprintf(stderr, "Reincarnate execv() failed: %d %s\n", errno, - strerror_r(errno, buf, sizeof(buf))); + switch_strerror_r(errno, buf, sizeof(buf))); } fprintf(stderr, "Trying reincarnate-reexec plan B...\n"); if (execvp(argv[0], argv) == -1) { char buf[256]; fprintf(stderr, "Reincarnate execvp() failed: %d %s\n", errno, - strerror_r(errno, buf, sizeof(buf))); + switch_strerror_r(errno, buf, sizeof(buf))); } fprintf(stderr, "Falling back to normal reincarnate behavior...\n"); goto refork; From 23259812acb040eea1de0c25e73d3d9606d3ca64 Mon Sep 17 00:00:00 2001 From: Brian West Date: Mon, 16 Jun 2014 10:42:58 -0500 Subject: [PATCH 058/231] FS-6593 --resolve this isn't used, I've tested. --- src/mod/endpoints/mod_verto/mod_verto.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/mod/endpoints/mod_verto/mod_verto.h b/src/mod/endpoints/mod_verto/mod_verto.h index 1b4591d898..d7df38bf15 100644 --- a/src/mod/endpoints/mod_verto/mod_verto.h +++ b/src/mod/endpoints/mod_verto/mod_verto.h @@ -89,7 +89,6 @@ struct jsock_s { struct sockaddr_in local_addr; struct sockaddr_in remote_addr; struct sockaddr_in send_addr; - struct ucred credentials; struct passwd pw; int drop; From 10719e58c8db353a52f7d440095a7c84300df18b Mon Sep 17 00:00:00 2001 From: Brian West Date: Mon, 16 Jun 2014 11:14:42 -0500 Subject: [PATCH 059/231] work around macro definition of fileno breaking our c++ code --- src/mod/endpoints/mod_verto/mcast/MCAST.pm | 2 +- src/mod/endpoints/mod_verto/mcast/mcast_cpp.cpp | 2 +- src/mod/endpoints/mod_verto/mcast/mcast_cpp.h | 2 +- src/mod/endpoints/mod_verto/mcast/mcast_wrap.cpp | 10 +++++----- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/mod/endpoints/mod_verto/mcast/MCAST.pm b/src/mod/endpoints/mod_verto/mcast/MCAST.pm index 531665035b..dc2d01f1f7 100644 --- a/src/mod/endpoints/mod_verto/mcast/MCAST.pm +++ b/src/mod/endpoints/mod_verto/mcast/MCAST.pm @@ -76,7 +76,7 @@ sub DESTROY { *send = *MCASTc::McastHandle_send; *recv = *MCASTc::McastHandle_recv; -*fileno = *MCASTc::McastHandle_fileno; +*filenum = *MCASTc::McastHandle_filenum; sub DISOWN { my $self = shift; my $ptr = tied(%$self); diff --git a/src/mod/endpoints/mod_verto/mcast/mcast_cpp.cpp b/src/mod/endpoints/mod_verto/mcast/mcast_cpp.cpp index 2e3eca6c6d..879d6e0550 100644 --- a/src/mod/endpoints/mod_verto/mcast/mcast_cpp.cpp +++ b/src/mod/endpoints/mod_verto/mcast/mcast_cpp.cpp @@ -63,7 +63,7 @@ char *McastHandle::recv(int ms) return NULL; } -int McastHandle::fileno(void) +int McastHandle::filenum(void) { return handle.sock; } diff --git a/src/mod/endpoints/mod_verto/mcast/mcast_cpp.h b/src/mod/endpoints/mod_verto/mcast/mcast_cpp.h index 5990871a0f..bc9e85822d 100644 --- a/src/mod/endpoints/mod_verto/mcast/mcast_cpp.h +++ b/src/mod/endpoints/mod_verto/mcast/mcast_cpp.h @@ -49,7 +49,7 @@ class McastHandle { virtual ~McastHandle(); int send(const char *data); char *recv(int ms = 0); - int fileno(void); + int filenum(void); }; #ifdef __cplusplus diff --git a/src/mod/endpoints/mod_verto/mcast/mcast_wrap.cpp b/src/mod/endpoints/mod_verto/mcast/mcast_wrap.cpp index 77725cf4bd..4a92825535 100644 --- a/src/mod/endpoints/mod_verto/mcast/mcast_wrap.cpp +++ b/src/mod/endpoints/mod_verto/mcast/mcast_wrap.cpp @@ -1888,7 +1888,7 @@ XS(_wrap_McastHandle_recv) { } -XS(_wrap_McastHandle_fileno) { +XS(_wrap_McastHandle_filenum) { { McastHandle *arg1 = (McastHandle *) 0 ; int result; @@ -1898,14 +1898,14 @@ XS(_wrap_McastHandle_fileno) { dXSARGS; if ((items < 1) || (items > 1)) { - SWIG_croak("Usage: McastHandle_fileno(self);"); + SWIG_croak("Usage: McastHandle_filenum(self);"); } res1 = SWIG_ConvertPtr(ST(0), &argp1,SWIGTYPE_p_McastHandle, 0 | 0 ); if (!SWIG_IsOK(res1)) { - SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "McastHandle_fileno" "', argument " "1"" of type '" "McastHandle *""'"); + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "McastHandle_filenum" "', argument " "1"" of type '" "McastHandle *""'"); } arg1 = reinterpret_cast< McastHandle * >(argp1); - result = (int)(arg1)->fileno(); + result = (int)(arg1)->filenum(); ST(argvi) = SWIG_From_int SWIG_PERL_CALL_ARGS_1(static_cast< int >(result)); argvi++ ; XSRETURN(argvi); @@ -1952,7 +1952,7 @@ static swig_command_info swig_commands[] = { {"MCASTc::delete_McastHandle", _wrap_delete_McastHandle}, {"MCASTc::McastHandle_send", _wrap_McastHandle_send}, {"MCASTc::McastHandle_recv", _wrap_McastHandle_recv}, -{"MCASTc::McastHandle_fileno", _wrap_McastHandle_fileno}, +{"MCASTc::McastHandle_filenum", _wrap_McastHandle_filenum}, {0,0} }; /* ----------------------------------------------------------------------------- From 3c7c167581c1a984ac7a52a7239b948636031fe9 Mon Sep 17 00:00:00 2001 From: Chris Rienzo Date: Mon, 16 Jun 2014 14:39:17 -0400 Subject: [PATCH 060/231] mod_rayo: improved idle detection- call is idle only if no active components and not joined --- src/mod/event_handlers/mod_rayo/mod_rayo.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/mod/event_handlers/mod_rayo/mod_rayo.c b/src/mod/event_handlers/mod_rayo/mod_rayo.c index 1506113808..609e666a58 100644 --- a/src/mod/event_handlers/mod_rayo/mod_rayo.c +++ b/src/mod/event_handlers/mod_rayo/mod_rayo.c @@ -1812,7 +1812,6 @@ void rayo_call_send(struct rayo_actor *call, struct rayo_message *msg) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, executing command\n", RAYO_JID(call)); response = handler(call, msg, session); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s, done executing command\n", RAYO_JID(call)); - RAYO_CALL(call)->idle_start_time = switch_micro_time_now(); } switch_core_session_rwunlock(session); @@ -3719,7 +3718,7 @@ static switch_status_t rayo_call_on_read_frame(switch_core_session_t *session, s switch_time_t idle_start = call->idle_start_time; int idle_duration_ms = (now - idle_start) / 1000; /* detect idle session (rayo-client has stopped controlling call) and terminate call */ - if (rayo_call_is_joined(call) || rayo_call_is_faxing(call)) { + if (rayo_call_is_joined(call) || rayo_call_is_faxing(call) || RAYO_ACTOR(call)->ref_count > 1) { call->idle_start_time = now; } else if (idle_duration_ms > globals.max_idle_ms) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Ending abandoned call. idle_duration_ms = %i ms\n", idle_duration_ms); From 4d5153cdd238d455e74a9239dce3c388f21431ce Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Mon, 16 Jun 2014 20:36:02 +0000 Subject: [PATCH 061/231] Fix ordering in control-modules --- debian/control-modules | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/debian/control-modules b/debian/control-modules index 0b778cfed5..02271b7edf 100644 --- a/debian/control-modules +++ b/debian/control-modules @@ -584,14 +584,14 @@ Module: loggers/mod_console Description: mod_console Adds mod_console. -Module: loggers/mod_logfile -Description: mod_logfile - Adds mod_logfile. - Module: loggers/mod_graylog2 Description: mod_graylog2 Adds mod_greylog2. +Module: loggers/mod_logfile +Description: mod_logfile + Adds mod_logfile. + Module: loggers/mod_syslog Description: mod_syslog Adds mod_syslog. From 062b7f16c22cc4eea16bf3d78ec4f9aeabcbe7b3 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Mon, 16 Jun 2014 20:38:24 +0000 Subject: [PATCH 062/231] Add mod_rtc and mod_verto --- debian/control-modules | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/debian/control-modules b/debian/control-modules index 02271b7edf..e61ae93c46 100644 --- a/debian/control-modules +++ b/debian/control-modules @@ -411,6 +411,10 @@ Module: endpoints/mod_reference Description: mod_reference Adds mod_reference. +Module: endpoints/mod_rtc +Description: Adds mod_rtc. + Adds mod_rtc. + Module: endpoints/mod_rtmp Description: mod_rtmp Adds mod_rtmp. @@ -432,6 +436,10 @@ Module: endpoints/mod_unicall Description: mod_unicall Adds mod_unicall. +Module: endpoints/mod_verto +Description: Adds mod_verto. + Adds mod_verto. + ## mod/event_handlers Module: event_handlers/mod_cdr_csv From 7b974def214f7ee61c4f21e2f97be8aed6491269 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Mon, 16 Jun 2014 20:43:02 +0000 Subject: [PATCH 063/231] Add back mod_perl to debian build The build issues blocking its return appear to have been resolved. --- debian/bootstrap.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/debian/bootstrap.sh b/debian/bootstrap.sh index 4457eb7dd9..809126218a 100755 --- a/debian/bootstrap.sh +++ b/debian/bootstrap.sh @@ -28,7 +28,6 @@ avoid_mods=( endpoints/mod_reference endpoints/mod_unicall languages/mod_managed - languages/mod_perl sdk/autotools xml_int/mod_xml_ldap xml_int/mod_xml_radius From 1893c7ba330e955e2b8eedcc11576737813d5fbf Mon Sep 17 00:00:00 2001 From: Brian West Date: Mon, 16 Jun 2014 18:10:42 -0500 Subject: [PATCH 064/231] External ipv6 --- conf/vanilla/sip_profiles/external-ipv6.xml | 96 +++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 conf/vanilla/sip_profiles/external-ipv6.xml diff --git a/conf/vanilla/sip_profiles/external-ipv6.xml b/conf/vanilla/sip_profiles/external-ipv6.xml new file mode 100644 index 0000000000..6182246763 --- /dev/null +++ b/conf/vanilla/sip_profiles/external-ipv6.xml @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 990847638c9e252b3cd19bc2f8316674b2579499 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Tue, 17 Jun 2014 02:58:29 +0000 Subject: [PATCH 065/231] Pull mod_verto from debian packaging temporarily `make install` on mod_verto needs to be reworked a bit for packaging builds. --- debian/bootstrap.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/debian/bootstrap.sh b/debian/bootstrap.sh index 809126218a..c56ff71220 100755 --- a/debian/bootstrap.sh +++ b/debian/bootstrap.sh @@ -27,6 +27,7 @@ avoid_mods=( endpoints/mod_opal endpoints/mod_reference endpoints/mod_unicall + endpoints/mod_verto languages/mod_managed sdk/autotools xml_int/mod_xml_ldap From 779a2f4ad5a4cfb262017b0f1838506f42dc554c Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Tue, 17 Jun 2014 14:42:15 +0000 Subject: [PATCH 066/231] Add dependency on libperl-dev for mod_verto --- debian/control-modules | 1 + 1 file changed, 1 insertion(+) diff --git a/debian/control-modules b/debian/control-modules index e61ae93c46..dd694d842b 100644 --- a/debian/control-modules +++ b/debian/control-modules @@ -439,6 +439,7 @@ Description: mod_unicall Module: endpoints/mod_verto Description: Adds mod_verto. Adds mod_verto. +Build-Depends: libperl-dev ## mod/event_handlers From b8629901a25a1e11025add0f20dc650de3756746 Mon Sep 17 00:00:00 2001 From: Michael Jerris Date: Tue, 17 Jun 2014 09:44:17 -0500 Subject: [PATCH 067/231] fix dep check for building perl mods --- configure.ac | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index c6ff69b3ae..f41339adee 100644 --- a/configure.ac +++ b/configure.ac @@ -1230,9 +1230,10 @@ AM_CONDITIONAL([HAVE_MYSQL],[test "$found_mysql" = "yes"]) # AC_CHECK_PROG(PERL,perl,[ac_cv_have_perl=yes],[ac_cv_have_perl=no]) -AM_CONDITIONAL([HAVE_PERL],[test "x$ac_cv_have_perl" != "xno"]) +AC_CHECK_HEADER([EXTERN.h], [ac_cv_have_EXTERN_h=yes], [ac_cv_have_EXTERN_h=no]) +AM_CONDITIONAL([HAVE_PERL],[test "x$ac_cv_have_perl" != "xno" -a "x$ac_cv_have_EXTERN_h" != "xno"]) -if test "x$ac_cv_have_perl" != "xno" ; then +if test "x$ac_cv_have_perl" != "xno" -a "x$ac_cv_have_EXTERN_h" != "xno"; then PERL=perl PERL_SITEDIR="`$PERL -MConfig -e 'print $Config{sitelibexp}'`" PERL_LIBDIR="-L`$PERL -MConfig -e 'print $Config{archlib}'`/CORE" From 82dbc5d2b9bf5971aa8c9b0069cecda5630c96ef Mon Sep 17 00:00:00 2001 From: Michael Jerris Date: Tue, 17 Jun 2014 10:35:17 -0500 Subject: [PATCH 068/231] FS-6604: install to archlib not sitelibexp --- configure.ac | 16 ++++++++++++---- src/mod/endpoints/mod_verto/Makefile.am | 1 + 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index f41339adee..635b3d1950 100644 --- a/configure.ac +++ b/configure.ac @@ -1230,17 +1230,23 @@ AM_CONDITIONAL([HAVE_MYSQL],[test "$found_mysql" = "yes"]) # AC_CHECK_PROG(PERL,perl,[ac_cv_have_perl=yes],[ac_cv_have_perl=no]) -AC_CHECK_HEADER([EXTERN.h], [ac_cv_have_EXTERN_h=yes], [ac_cv_have_EXTERN_h=no]) -AM_CONDITIONAL([HAVE_PERL],[test "x$ac_cv_have_perl" != "xno" -a "x$ac_cv_have_EXTERN_h" != "xno"]) -if test "x$ac_cv_have_perl" != "xno" -a "x$ac_cv_have_EXTERN_h" != "xno"; then +# -a "x$ac_cv_have_EXTERN_h" != "xno" + +if test "x$ac_cv_have_perl" != "xno"; then PERL=perl - PERL_SITEDIR="`$PERL -MConfig -e 'print $Config{sitelibexp}'`" + PERL_SITEDIR="`$PERL -MConfig -e 'print $Config{archlib}'`" PERL_LIBDIR="-L`$PERL -MConfig -e 'print $Config{archlib}'`/CORE" PERL_LIBS="`$PERL -MConfig -e 'print $Config{libs}'`" PERL_CFLAGS="-w -DMULTIPLICITY `$PERL -MExtUtils::Embed -e ccopts` -DEMBED_PERL" PERL_LDFLAGS="`$PERL -MExtUtils::Embed -e ldopts`" PERL_INC="`$PERL -MExtUtils::Embed -e perl_inc`" + + save_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$PERL_CFLAGS $CPPFLAGS" + AC_CHECK_HEADER([EXTERN.h], [ac_cv_have_EXTERN_h=yes], [ac_cv_have_EXTERN_h=no]) + CPPFLAGS="$save_CPPFLAGS" + AC_SUBST(PERL_SITEDIR) AC_SUBST(PERL_LIBDIR) AC_SUBST(PERL_LIBS) @@ -1249,6 +1255,8 @@ if test "x$ac_cv_have_perl" != "xno" -a "x$ac_cv_have_EXTERN_h" != "xno"; then AC_SUBST(PERL_INC) fi +AM_CONDITIONAL([HAVE_PERL],[test "x$ac_cv_have_perl" != "xno" -a "x$ac_cv_have_EXTERN_h" != "xno"]) + # # php checks # diff --git a/src/mod/endpoints/mod_verto/Makefile.am b/src/mod/endpoints/mod_verto/Makefile.am index 00744270bc..56d0bd4048 100644 --- a/src/mod/endpoints/mod_verto/Makefile.am +++ b/src/mod/endpoints/mod_verto/Makefile.am @@ -20,6 +20,7 @@ MCAST_la_LDFLAGS = -avoid-version -module -no-undefined -shared $(PERL_LDFLAGS install-data-local: perlmod-install perlmod-install: install-perlLTLIBRARIES + install -m 755 $(PERL_SITEDIR) install -m 755 mcast/MCAST.pm $(PERL_SITEDIR) endif From 5dd779130722b1396b40dfd22125a251b0ff9eaf Mon Sep 17 00:00:00 2001 From: Michael Jerris Date: Tue, 17 Jun 2014 11:17:55 -0500 Subject: [PATCH 069/231] FS-6602: fixed check for EXTERN.h --- configure.ac | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index 635b3d1950..a3b8b75a95 100644 --- a/configure.ac +++ b/configure.ac @@ -1242,10 +1242,11 @@ if test "x$ac_cv_have_perl" != "xno"; then PERL_LDFLAGS="`$PERL -MExtUtils::Embed -e ldopts`" PERL_INC="`$PERL -MExtUtils::Embed -e perl_inc`" - save_CPPFLAGS="$CPPFLAGS" - CPPFLAGS="$PERL_CFLAGS $CPPFLAGS" - AC_CHECK_HEADER([EXTERN.h], [ac_cv_have_EXTERN_h=yes], [ac_cv_have_EXTERN_h=no]) - CPPFLAGS="$save_CPPFLAGS" + save_CFLAGS="$CFLAGS" + CFLAGS="$PERL_CFLAGS" + AC_CHECK_HEADER([EXTERN.h], [ac_cv_have_EXTERN_h=yes], [ac_cv_have_EXTERN_h=no], [[#include +# include ]]) + CFLAGS="$save_CFLAGS" AC_SUBST(PERL_SITEDIR) AC_SUBST(PERL_LIBDIR) From 6e05bfba1382cc88d08875b6b42ea1b48c128a05 Mon Sep 17 00:00:00 2001 From: Michael Jerris Date: Tue, 17 Jun 2014 11:19:02 -0500 Subject: [PATCH 070/231] FS-6604: install to archlib not sitelibexp --- src/mod/endpoints/mod_verto/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mod/endpoints/mod_verto/Makefile.am b/src/mod/endpoints/mod_verto/Makefile.am index 56d0bd4048..06d6e9dffc 100644 --- a/src/mod/endpoints/mod_verto/Makefile.am +++ b/src/mod/endpoints/mod_verto/Makefile.am @@ -20,7 +20,7 @@ MCAST_la_LDFLAGS = -avoid-version -module -no-undefined -shared $(PERL_LDFLAGS install-data-local: perlmod-install perlmod-install: install-perlLTLIBRARIES - install -m 755 $(PERL_SITEDIR) + install -d -m 755 $(PERL_SITEDIR) install -m 755 mcast/MCAST.pm $(PERL_SITEDIR) endif From 548be28694f1afa0cc8f6f79cfec33f81872b339 Mon Sep 17 00:00:00 2001 From: Michael Jerris Date: Tue, 17 Jun 2014 11:44:18 -0500 Subject: [PATCH 071/231] FS-6602: check for libperl libstalled and linkable too --- configure.ac | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index a3b8b75a95..b257069443 100644 --- a/configure.ac +++ b/configure.ac @@ -1248,6 +1248,11 @@ if test "x$ac_cv_have_perl" != "xno"; then # include ]]) CFLAGS="$save_CFLAGS" + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$PERL_LDFLAGS" + AC_CHECK_LIB([perl], [perl_alloc], ac_cv_use_libperl=yes, ac_cv_use_libperl=no) + LDFLAGS="$save_LDFLAGS" + AC_SUBST(PERL_SITEDIR) AC_SUBST(PERL_LIBDIR) AC_SUBST(PERL_LIBS) @@ -1256,7 +1261,7 @@ if test "x$ac_cv_have_perl" != "xno"; then AC_SUBST(PERL_INC) fi -AM_CONDITIONAL([HAVE_PERL],[test "x$ac_cv_have_perl" != "xno" -a "x$ac_cv_have_EXTERN_h" != "xno"]) +AM_CONDITIONAL([HAVE_PERL],[test "x$ac_cv_have_perl" != "xno" -a "x$ac_cv_have_EXTERN_h" != "xno" -a "x$ac_cv_use_libperl" != "xno"]) # # php checks From c76c1326922f09e619e78ba563bb29bb3bc6ffdd Mon Sep 17 00:00:00 2001 From: Michael Jerris Date: Tue, 17 Jun 2014 11:53:10 -0500 Subject: [PATCH 072/231] FS-6604: needs DESTDIR --- src/mod/endpoints/mod_verto/Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mod/endpoints/mod_verto/Makefile.am b/src/mod/endpoints/mod_verto/Makefile.am index 06d6e9dffc..4e85399e7e 100644 --- a/src/mod/endpoints/mod_verto/Makefile.am +++ b/src/mod/endpoints/mod_verto/Makefile.am @@ -20,8 +20,8 @@ MCAST_la_LDFLAGS = -avoid-version -module -no-undefined -shared $(PERL_LDFLAGS install-data-local: perlmod-install perlmod-install: install-perlLTLIBRARIES - install -d -m 755 $(PERL_SITEDIR) - install -m 755 mcast/MCAST.pm $(PERL_SITEDIR) + install -d -m 755 $(DESTDIR)$(PERL_SITEDIR) + install -m 755 mcast/MCAST.pm $(DESTDIR)$(PERL_SITEDIR) endif mcast/esl_wrap.cpp: From 0a6a10f584591cb407372d166f421e2e55b4c76d Mon Sep 17 00:00:00 2001 From: Michael Jerris Date: Tue, 17 Jun 2014 12:10:47 -0500 Subject: [PATCH 073/231] FS-6604: fix this same issue in esl too --- libs/esl/perl/Makefile.am | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/esl/perl/Makefile.am b/libs/esl/perl/Makefile.am index 3c54583eed..8a3fb39517 100644 --- a/libs/esl/perl/Makefile.am +++ b/libs/esl/perl/Makefile.am @@ -12,9 +12,9 @@ perlmod: ESL.la install-data-local: perlmod-install perlmod-install: install-perlLTLIBRARIES - install -m 755 ESL.pm $(PERL_SITEDIR) - install -d -m 755 ESL $(PERL_SITEDIR)/ESL - install -m 755 ESL/* $(PERL_SITEDIR)/ESL + install -d -m 755 ESL $(DESTDIR)$(PERL_SITEDIR)/ESL + install -m 755 ESL.pm $(DESTDIR)$(PERL_SITEDIR) + install -m 755 ESL/* $(DESTDIR)$(PERL_SITEDIR)/ESL endif esl_wrap.cpp: From 50625e36eed8a4393857eab97e265e801e1a7f88 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Tue, 17 Jun 2014 16:24:07 +0000 Subject: [PATCH 074/231] Build mod_verto for debian packaging We still need to add special handling for the perl bits. --- debian/bootstrap.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/debian/bootstrap.sh b/debian/bootstrap.sh index c56ff71220..809126218a 100755 --- a/debian/bootstrap.sh +++ b/debian/bootstrap.sh @@ -27,7 +27,6 @@ avoid_mods=( endpoints/mod_opal endpoints/mod_reference endpoints/mod_unicall - endpoints/mod_verto languages/mod_managed sdk/autotools xml_int/mod_xml_ldap From 94f359904d4fbe16062679526f5846c2b5bcace6 Mon Sep 17 00:00:00 2001 From: Michael Jerris Date: Tue, 17 Jun 2014 19:22:34 +0000 Subject: [PATCH 075/231] remove dual-arch cflags and ldflags that we get on osx, we don't support fat binary stuff yet --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index b257069443..61d4ca1645 100644 --- a/configure.ac +++ b/configure.ac @@ -1238,8 +1238,8 @@ if test "x$ac_cv_have_perl" != "xno"; then PERL_SITEDIR="`$PERL -MConfig -e 'print $Config{archlib}'`" PERL_LIBDIR="-L`$PERL -MConfig -e 'print $Config{archlib}'`/CORE" PERL_LIBS="`$PERL -MConfig -e 'print $Config{libs}'`" - PERL_CFLAGS="-w -DMULTIPLICITY `$PERL -MExtUtils::Embed -e ccopts` -DEMBED_PERL" - PERL_LDFLAGS="`$PERL -MExtUtils::Embed -e ldopts`" + PERL_CFLAGS="-w -DMULTIPLICITY `$PERL -MExtUtils::Embed -e ccopts | sed -e 's|-arch x86_64 -arch i386||'` -DEMBED_PERL" + PERL_LDFLAGS="`$PERL -MExtUtils::Embed -e ldopts| sed -e 's|-arch x86_64 -arch i386||'`" PERL_INC="`$PERL -MExtUtils::Embed -e perl_inc`" save_CFLAGS="$CFLAGS" From c4119dbe54a2f488149cb90dfcdd03a5f5a146a2 Mon Sep 17 00:00:00 2001 From: Brian West Date: Tue, 17 Jun 2014 14:34:17 -0500 Subject: [PATCH 076/231] Updated just build it for Solaris 11 --- build/Makefile.solaris11 | 108 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 build/Makefile.solaris11 diff --git a/build/Makefile.solaris11 b/build/Makefile.solaris11 new file mode 100644 index 0000000000..2a2da59e7f --- /dev/null +++ b/build/Makefile.solaris11 @@ -0,0 +1,108 @@ +# +# FreeSWITCH auto-build Makefile (Solaris 11.1 64bit Tonka Truck Edition) +# http://www.freeswitch.org +# put this file anywhere and type gmake to +# create a fully-built freeswitch.git from scratch +# in that same directory. +# +# +FSPREFIX=/usr/local/freeswitch +PREFIX=/usr/local/ +JP=v8d +SSL=1.0.1h +SQLITE=autoconf-3080403 +PCRE=8.35 +CURL=7.36.0 +SPEEX=1.2rc1 +LIBEDIT=20140213-3.1 +LDNS=1.6.17 +PKGCFG=0.28 +PERL=5.18.2 + +freeswitch: deps has-git freeswitch.git/Makefile + cd freeswitch.git && gmake + +freeswitch.git/Makefile: freeswitch.git/configure + export PATH=$PATH:$(PREFIX)/bin + cd freeswitch.git && PKG_CONFIG_PATH=$(PREFIX)/lib/pkgconfig ./configure --enable-64 LDFLAGS='-L$(PREFIX)/lib -Wl,-rpath=$(PREFIX)/lib' CFLAGS='-I$(PREFIX)/include' --prefix=$(FSPREFIX) + +freeswitch.git/configure: freeswitch.git/bootstrap.sh + cd freeswitch.git && sh bootstrap.sh + +freeswitch.git/bootstrap.sh: has-git + test -d freeswitch.git || git clone git://git.freeswitch.org/freeswitch.git freeswitch.git + +install: freeswitch + cd freeswitch.git && gmake install + +install-git: + pkg install git autoconf automake libtool libjpeg gcc-45 wget + +has-git: + @git --version || (echo "please install git by running 'gmake install-git'" && false) + +clean: + @rm -rf openssl* ldns* jpeg* pcre* perl* pkg-config* speex* sqlite* libedit* curl* *~ + (cd freeswitch.git && git clean -fdx && git reset --hard HEAD && git pull) + +libjpeg: jpeg-8d/Makefile + +jpeg-8d/Makefile: + (test -d jpeg-8d) || (wget -4 -O jpegsrc.$(JP).tar.gz http://www.ijg.org/files/jpegsrc.$(JP).tar.gz && tar zxfv jpegsrc.$(JP).tar.gz) + (cd jpeg-8d && CFLAGS=-m64 LDFLAGS=-m64 ./configure --prefix=$(PREFIX) && gmake && sudo gmake install) + +openssl: openssl-$(SSL)/Makefile +openssl-$(SSL)/Makefile: openssl-$(SSL) +openssl-$(SSL): + (test -d $@) || (wget -4 -O $@.tar.gz http://www.openssl.org/source/$@.tar.gz && tar zxfv $@.tar.gz) + (cd $@ && CFLAGS=-m64 LDFLAGS=-m64 ./Configure --prefix=$(PREFIX) solaris64-x86_64-gcc shared && gmake && sudo gmake install) + +sqlite: sqlite-$(SQLITE)/Makefile +sqlite-$(SQLITE)/Makefile: sqlite-$(SQLITE) +sqlite-$(SQLITE): + (test -d $@) || (wget -4 -O $@.tar.gz http://www.sqlite.org/2014/$@.tar.gz && tar zxfv $@.tar.gz) + (cd $@ && CFLAGS=-m64 LDFLAGS=-m64 ./configure --prefix=$(PREFIX) && gmake && sudo gmake install) + +pcre: pcre-$(PCRE)/Makefile +pcre-$(PCRE)/Makefile: pcre-$(PCRE) +pcre-$(PCRE): + (test -d $@) || (wget -4 -O $@.tar.gz http://downloads.sourceforge.net/project/pcre/pcre/$(PCRE)/$@.tar.gz && tar zxfv $@.tar.gz) + (cd $@ && CXXFLAGS=-m64 CFLAGS=-m64 LDFLAGS=-m64 ./configure --prefix=$(PREFIX) && gmake && sudo gmake install) + +curl: curl-$(CURL)/Makefile +curl-$(CURL)/Makefile: curl-$(CURL) +curl-$(CURL): + (test -d $@) || (wget -4 -O $@.tar.gz http://www.execve.net/curl/$@.tar.gz && tar zxfv $@.tar.gz) + (cd $@ && CFLAGS=-m64 LDFLAGS=-m64 ./configure --prefix=$(PREFIX) && gmake && sudo gmake install) + +speex: speex-$(SPEEX)/Makefile +speex-$(SPEEX)/Makefile: speex-$(SPEEX) +speex-$(SPEEX): + (test -d $@) || (wget -4 -O $@.tar.gz http://downloads.xiph.org/releases/speex/$@.tar.gz && tar zxfv $@.tar.gz) + (cd $@ && CFLAGS=-m64 LDFLAGS=-m64 ./configure --prefix=$(PREFIX) && gmake && sudo gmake install) + +libedit: libedit-$(LIBEDIT)/Makefile +libedit-$(LIBEDIT)/Makefile: libedit-$(LIBEDIT) +libedit-$(LIBEDIT): + (test -d $@) || (wget -4 -O $@.tar.gz http://thrysoee.dk/editline/$@.tar.gz && tar zxfv $@.tar.gz) + (cd $@ && CFLAGS=-m64 LDFLAGS=-m64 ./configure --prefix=$(PREFIX) && gmake && sudo gmake install) + +ldns: openssl ldns-$(LDNS)/Makefile +ldns-$(LDNS)/Makefile: ldns-$(LDNS) +ldns-$(LDNS): + (test -d $@) || (wget -4 -O $@.tar.gz http://www.nlnetlabs.nl/downloads/ldns/$@.tar.gz && tar zxfv $@.tar.gz) + (cd $@ && CFLAGS=-m64 LDFLAGS=-m64 ./configure --with-ssl=$(PREFIX) --prefix=$(PREFIX) && gmake && sudo gmake install) + +pkg-config: openssl pkg-config-$(PKGCFG)/Makefile +pkg-config-$(PKGCFG)/Makefile: pkg-config-$(PKGCFG) +pkg-config-$(PKGCFG): + (test -d $@) || (wget -4 -O $@.tar.gz http://pkgconfig.freedesktop.org/releases/$@.tar.gz && tar zxfv $@.tar.gz) + (cd $@ && CFLAGS=-m64 LDFLAGS=-m64 ./configure --with-internal-glib --prefix=$(PREFIX) && sudo gmake uninstall && gmake && sudo gmake install) + +perl: openssl perl-$(PERL)/Makefile +perl-$(PERL)/Makefile: perl-$(PERL) +perl-$(PERL): + (test -d $@) || (wget -4 -O $@.tar.gz http://www.cpan.org/src/5.0/$@.tar.gz && tar zxfv $@.tar.gz) + (cd $@ && CFLAGS=-m64 LDFLAGS=-m64 ./configure.gnu -Dcc=gcc --prefix=$(PREFIX) && gmake && sudo gmake install) + +deps: libjpeg openssl sqlite pcre curl speex libedit ldns pkg-config perl From fe36c8cc306db570ec28be8857ce5e1f35a5623e Mon Sep 17 00:00:00 2001 From: Brian West Date: Tue, 17 Jun 2014 14:35:12 -0500 Subject: [PATCH 077/231] swish and flick --- build/Makefile.centos5 | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/build/Makefile.centos5 b/build/Makefile.centos5 index a3e7d7d73b..17986156a2 100644 --- a/build/Makefile.centos5 +++ b/build/Makefile.centos5 @@ -10,7 +10,7 @@ FSPREFIX=/usr/local/freeswitch PREFIX=/opt/fs-libs JPEG=v8d -OPENSSL=1.0.1h +OPENSSL=1.0.1g SQLITE=autoconf-3080403 PCRE=8.35 CURL=7.36.0 @@ -34,58 +34,62 @@ install: freeswitch cd freeswitch.git && make install install-git: - rpm -i http://apt.sw.be/redhat/el5/en/x86_64/rpmforge/RPMS//rpmforge-release-0.3.6-1.el5.rf.x86_64.rpm + rpm -i http://apt.sw.be/redhat/el5/en/x86_64/rpmforge/RPMS/rpmforge-release-0.3.6-1.el5.rf.x86_64.rpm yum update -y yum install -y git gcc-c++ wget ncurses-devel zlib-devel e2fsprogs-devel libtool automake autoconf has-git: @git --version || (echo "please install git by running 'make install-git'" && false) +clean: + @rm -rf openssl* ldns* jpeg* pcre* perl* pkg-config* speex* sqlite* libedit* curl* *~ + (cd freeswitch.git && git clean -fdx && git reset --hard HEAD && git pull) + libjpeg: jpeg-8d/Makefile jpeg-8d/Makefile: (test -d jpeg-8d) || (wget -4 -O jpegsrc.$(JPEG).tar.gz http://www.ijg.org/files/jpegsrc.$(JPEG).tar.gz && tar zxfv jpegsrc.$(JPEG).tar.gz) (cd jpeg-8d && ./configure --prefix=$(PREFIX) && make && sudo make install) -openssl: openssl-$(OPENSSL) - +openssl: openssl-$(OPENSSL)/Makefile +openssl-$(OPENSSL)/Makefile: openssl-$(OPENSSL) openssl-$(OPENSSL): (test -d $@) || (wget -4 -O $@.tar.gz http://www.openssl.org/source/$@.tar.gz && tar zxfv $@.tar.gz) (cd $@ && ./Configure --prefix=$(PREFIX) linux-x86_64 shared && make && sudo make install) -sqlite: sqlite-$(SQLITE) - +sqlite: sqlite-$(SQLITE)/Makefile +sqlite-$(SQLITE)/Makefile: sqlite-$(SQLITE) sqlite-$(SQLITE): (test -d $@) || (wget -4 -O $@.tar.gz http://www.sqlite.org/2014/$@.tar.gz && tar zxfv $@.tar.gz) (cd $@ && ./configure --prefix=$(PREFIX) && make && sudo make install) -pcre: pcre-$(PCRE) - +pcre: pcre-$(PCRE)/Makefile +pcre-$(PCRE)/Makefile: pcre-$(PCRE) pcre-$(PCRE): (test -d $@) || (wget -4 -O $@.tar.gz http://downloads.sourceforge.net/project/pcre/pcre/$(PCRE)/$@.tar.gz && tar zxfv $@.tar.gz) (cd $@ && ./configure --prefix=$(PREFIX) && make && sudo make install) -curl: curl-$(CURL) - +curl: curl-$(CURL)/Makefile +curl-$(CURL)/Makefile: curl-$(CURL) curl-$(CURL): - (test -d $@) || (wget -4 -O $@.tar.gz http://curl.haxx.se/download/$@.tar.gz && tar zxfv $@.tar.gz) + (test -d $@) || (wget -4 -O $@.tar.gz http://www.execve.net/curl/$@.tar.gz && tar zxfv $@.tar.gz) (cd $@ && ./configure --prefix=$(PREFIX) && make && sudo make install) -speex: speex-$(SPEEX) - +speex: speex-$(SPEEX)/Makefile +speex-$(SPEEX)/Makefile: speex-$(SPEEX) speex-$(SPEEX): (test -d $@) || (wget -4 -O $@.tar.gz http://downloads.xiph.org/releases/speex/$@.tar.gz && tar zxfv $@.tar.gz) (cd $@ && ./configure --prefix=$(PREFIX) && make && sudo make install) -libedit: libedit-$(LIBEDIT) - +libedit: libedit-$(LIBEDIT)/Makefile +libedit-$(LIBEDIT)/Makefile: libedit-$(LIBEDIT) libedit-$(LIBEDIT): (test -d $@) || (wget -4 -O $@.tar.gz http://thrysoee.dk/editline/$@.tar.gz && tar zxfv $@.tar.gz) (cd $@ && ./configure --prefix=$(PREFIX) && make && sudo make install) -ldns: ldns-$(LDNS) - -ldns-$(LDNS): openssl +ldns: ldns-$(LDNS)/Makefile +ldns-$(LDNS)/Makefile: openssl ldns-$(LDNS) +ldns-$(LDNS): (test -d $@) || (wget -4 -O $@.tar.gz http://www.nlnetlabs.nl/downloads/ldns/$@.tar.gz && tar zxfv $@.tar.gz) (cd $@ && ./configure --with-ssl=$(PREFIX) --prefix=$(PREFIX) && make && sudo make install) From d5856a4197ff653d524ae0a177801508779df4f6 Mon Sep 17 00:00:00 2001 From: Nathan Neulinger Date: Tue, 17 Jun 2014 14:56:21 -0500 Subject: [PATCH 078/231] FS-477 fix inappropriate firing of timeout after call proceeds --resolve --- src/mod/endpoints/mod_skinny/mod_skinny.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/mod/endpoints/mod_skinny/mod_skinny.c b/src/mod/endpoints/mod_skinny/mod_skinny.c index 10c1fede9a..6cd46fc49a 100644 --- a/src/mod/endpoints/mod_skinny/mod_skinny.c +++ b/src/mod/endpoints/mod_skinny/mod_skinny.c @@ -773,6 +773,9 @@ switch_status_t channel_on_routing(switch_core_session_t *session) switch_channel_get_variable(channel, "skinny_device_name"), switch_channel_get_variable(channel, "skinny_device_instance"), switch_channel_get_name(channel)); } + /* clear digit timeout time */ + listener->digit_timeout_time = 0; + /* Future bridge should go straight */ switch_set_flag_locked(tech_pvt, TFLAG_FORCE_ROUTE); break; From 3c081048749248f939177729a33a82b90a1380df Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Wed, 18 Jun 2014 01:17:29 +0500 Subject: [PATCH 079/231] remove unused code --- src/switch_rtp.c | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/src/switch_rtp.c b/src/switch_rtp.c index 0eb3c03516..c1bd07270a 100644 --- a/src/switch_rtp.c +++ b/src/switch_rtp.c @@ -274,10 +274,6 @@ typedef struct ts_normalize_s { uint32_t delta; uint32_t delta_ct; uint32_t delta_ttl; - uint32_t delta_avg; - uint32_t delta_delta; - double delta_percent; - uint8_t m; } ts_normalize_t; struct switch_rtp { @@ -6196,7 +6192,6 @@ static int rtp_common_write(switch_rtp_t *rtp_session, if (!rtp_session->ts_norm.last_ssrc || send_msg->header.ssrc != rtp_session->ts_norm.last_ssrc) { if (rtp_session->ts_norm.last_ssrc) { - rtp_session->ts_norm.m = 1; rtp_session->ts_norm.delta_ct = 1; rtp_session->ts_norm.delta_ttl = 0; if (rtp_session->ts_norm.delta) { @@ -6210,40 +6205,12 @@ static int rtp_common_write(switch_rtp_t *rtp_session, if (ntohl(send_msg->header.ts) != rtp_session->ts_norm.last_frame) { rtp_session->ts_norm.delta = ntohl(send_msg->header.ts) - rtp_session->ts_norm.last_frame; - - if (rtp_session->ts_norm.delta > 0) { - rtp_session->ts_norm.delta_ct++; - if (rtp_session->ts_norm.delta_ct == 1000) { - rtp_session->ts_norm.delta_ct = 1; - rtp_session->ts_norm.delta_ttl = 0; - } - - rtp_session->ts_norm.delta_ttl += rtp_session->ts_norm.delta; - rtp_session->ts_norm.delta_avg = rtp_session->ts_norm.delta_ttl / rtp_session->ts_norm.delta_ct; - rtp_session->ts_norm.delta_delta = abs(rtp_session->ts_norm.delta_avg - rtp_session->ts_norm.delta); - rtp_session->ts_norm.delta_percent = (double)((double)rtp_session->ts_norm.delta / (double)rtp_session->ts_norm.delta_avg) * 100.0f; - - - //if (rtp_session->ts_norm.delta_ct > 50 && rtp_session->ts_norm.delta_percent > 150.0) { - //printf("%s diff %d %d (%.2f)\n",rtp_session_name(rtp_session), - //rtp_session->ts_norm.delta, rtp_session->ts_norm.delta_avg, rtp_session->ts_norm.delta_percent); - //switch_rtp_video_refresh(rtp_session); - //} - } rtp_session->ts_norm.ts += rtp_session->ts_norm.delta; } rtp_session->ts_norm.last_frame = ntohl(send_msg->header.ts); send_msg->header.ts = htonl(rtp_session->ts_norm.ts); - /* wait for a marked frame since we just switched streams */ - if (rtp_session->ts_norm.m) { - if (send_msg->header.m) { - rtp_session->ts_norm.m = 0; - } else { - send = 0; - } - } } send_msg->header.ssrc = htonl(rtp_session->ssrc); From b077217d4420478499b116cf7970f2911efd4246 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Wed, 18 Jun 2014 01:19:14 +0500 Subject: [PATCH 080/231] FS-6337 --- src/switch_stfu.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/src/switch_stfu.c b/src/switch_stfu.c index e50f0f3dfc..7a81e19194 100644 --- a/src/switch_stfu.c +++ b/src/switch_stfu.c @@ -471,11 +471,8 @@ stfu_status_t stfu_n_add_data(stfu_instance_t *i, uint32_t ts, uint16_t seq, uin if (stfu_log != null_logger && i->debug) { stfu_log(STFU_LOG_EMERG, "%s TOO LATE !!! %u \n\n\n", i->name, ts); } - if (i->in_queue->array_len < i->in_queue->array_size) { - i->in_queue->array_len++; - } stfu_n_sync(i, 1); - //return STFU_ITS_TOO_LATE; + return STFU_ITS_TOO_LATE; } } } @@ -615,7 +612,7 @@ static int stfu_n_find_frame(stfu_instance_t *in, stfu_queue_t *queue, uint32_t *r_frame = NULL; } - for(i = 0; i < queue->array_size; i++) { + for(i = 0; i < queue->array_len; i++) { frame = &queue->array[i]; if (frame->ts == max_ts || (frame->ts > min_ts && frame->ts < max_ts)) { @@ -672,11 +669,7 @@ stfu_frame_t *stfu_n_read_a_frame(stfu_instance_t *i) found = stfu_n_find_frame(i, i->out_queue, i->last_wr_ts, i->cur_ts, &rframe); - if (found) { - if (i->out_queue->array_len) { - i->out_queue->array_len--; - } - } else { + if (!found) { found = stfu_n_find_frame(i, i->in_queue, i->last_wr_ts, i->cur_ts, &rframe); if (!found) { @@ -735,7 +728,7 @@ stfu_frame_t *stfu_n_read_a_frame(stfu_instance_t *i) if (stfu_log != null_logger && i->debug) { stfu_log(STFU_LOG_EMERG, "%s ------------\n", i->name); - for(y = 0; y < i->out_queue->array_size; y++) { + for(y = 0; y < i->out_queue->array_len; y++) { frame = &i->out_queue->array[y]; stfu_log(STFU_LOG_EMERG, "%s\t%u:%u\n", i->name, frame->ts, frame->ts / i->samples_per_packet); } @@ -743,7 +736,7 @@ stfu_frame_t *stfu_n_read_a_frame(stfu_instance_t *i) stfu_log(STFU_LOG_EMERG, "%s ------------\n", i->name); - for(y = 0; y < i->in_queue->array_size; y++) { + for(y = 0; y < i->in_queue->array_len; y++) { frame = &i->in_queue->array[y]; stfu_log(STFU_LOG_EMERG, "%s\t%u:%u\n", i->name, frame->ts, frame->ts / i->samples_per_packet); } From 24a8f3da4d67c462bccd8b65dee3891df3b6cf8f Mon Sep 17 00:00:00 2001 From: Brian West Date: Tue, 17 Jun 2014 15:24:55 -0500 Subject: [PATCH 081/231] tweaks --- build/Makefile.centos5 | 60 ++++++++++++++++++----------------- build/Makefile.solaris11 | 67 ++++++++++++++++++++-------------------- 2 files changed, 65 insertions(+), 62 deletions(-) diff --git a/build/Makefile.centos5 b/build/Makefile.centos5 index 17986156a2..66ab2e79a5 100644 --- a/build/Makefile.centos5 +++ b/build/Makefile.centos5 @@ -13,7 +13,7 @@ JPEG=v8d OPENSSL=1.0.1g SQLITE=autoconf-3080403 PCRE=8.35 -CURL=7.36.0 +CURL=7.35.0 SPEEX=1.2rc1 LIBEDIT=20140213-3.1 LDNS=1.6.17 @@ -33,64 +33,66 @@ freeswitch.git/bootstrap.sh: has-git install: freeswitch cd freeswitch.git && make install -install-git: - rpm -i http://apt.sw.be/redhat/el5/en/x86_64/rpmforge/RPMS/rpmforge-release-0.3.6-1.el5.rf.x86_64.rpm +install-git: .done +.done: + rpm -i http://apt.sw.be/redhat/el5/en/x86_64/rpmforge/RPMS/rpmforge-release-0.3.6-1.el5.rf.x86_64.rpm || true yum update -y yum install -y git gcc-c++ wget ncurses-devel zlib-devel e2fsprogs-devel libtool automake autoconf + touch .done -has-git: +has-git: @git --version || (echo "please install git by running 'make install-git'" && false) clean: @rm -rf openssl* ldns* jpeg* pcre* perl* pkg-config* speex* sqlite* libedit* curl* *~ (cd freeswitch.git && git clean -fdx && git reset --hard HEAD && git pull) -libjpeg: jpeg-8d/Makefile +libjpeg: jpeg-8d/.done -jpeg-8d/Makefile: +jpeg-8d/.done: (test -d jpeg-8d) || (wget -4 -O jpegsrc.$(JPEG).tar.gz http://www.ijg.org/files/jpegsrc.$(JPEG).tar.gz && tar zxfv jpegsrc.$(JPEG).tar.gz) - (cd jpeg-8d && ./configure --prefix=$(PREFIX) && make && sudo make install) + (cd jpeg-8d && ./configure --prefix=$(PREFIX) && make && sudo make install && touch .done) -openssl: openssl-$(OPENSSL)/Makefile -openssl-$(OPENSSL)/Makefile: openssl-$(OPENSSL) +openssl: openssl-$(OPENSSL)/.done +openssl-$(OPENSSL)/.done: openssl-$(OPENSSL) openssl-$(OPENSSL): (test -d $@) || (wget -4 -O $@.tar.gz http://www.openssl.org/source/$@.tar.gz && tar zxfv $@.tar.gz) - (cd $@ && ./Configure --prefix=$(PREFIX) linux-x86_64 shared && make && sudo make install) + (cd $@ && ./Configure --prefix=$(PREFIX) linux-x86_64 shared && make && sudo make install && touch .done) -sqlite: sqlite-$(SQLITE)/Makefile -sqlite-$(SQLITE)/Makefile: sqlite-$(SQLITE) +sqlite: sqlite-$(SQLITE)/.done +sqlite-$(SQLITE)/.done: sqlite-$(SQLITE) sqlite-$(SQLITE): (test -d $@) || (wget -4 -O $@.tar.gz http://www.sqlite.org/2014/$@.tar.gz && tar zxfv $@.tar.gz) - (cd $@ && ./configure --prefix=$(PREFIX) && make && sudo make install) + (cd $@ && ./configure --prefix=$(PREFIX) && make && sudo make install && touch .done_sqlite && touch .done) -pcre: pcre-$(PCRE)/Makefile -pcre-$(PCRE)/Makefile: pcre-$(PCRE) +pcre: pcre-$(PCRE)/.done +pcre-$(PCRE)/.done: pcre-$(PCRE) pcre-$(PCRE): (test -d $@) || (wget -4 -O $@.tar.gz http://downloads.sourceforge.net/project/pcre/pcre/$(PCRE)/$@.tar.gz && tar zxfv $@.tar.gz) - (cd $@ && ./configure --prefix=$(PREFIX) && make && sudo make install) + (cd $@ && ./configure --prefix=$(PREFIX) && make && sudo make install && touch .done) -curl: curl-$(CURL)/Makefile -curl-$(CURL)/Makefile: curl-$(CURL) +curl: curl-$(CURL)/.done +curl-$(CURL)/.done: curl-$(CURL) curl-$(CURL): - (test -d $@) || (wget -4 -O $@.tar.gz http://www.execve.net/curl/$@.tar.gz && tar zxfv $@.tar.gz) - (cd $@ && ./configure --prefix=$(PREFIX) && make && sudo make install) + (test -d $@) || (wget -4 -O $@.tar.gz http://files.freeswitch.org/downloads/libs/$@.tar.gz && tar zxfv $@.tar.gz) + (cd $@ && ./configure --prefix=$(PREFIX) && make && sudo make install && touch .done) -speex: speex-$(SPEEX)/Makefile -speex-$(SPEEX)/Makefile: speex-$(SPEEX) +speex: speex-$(SPEEX)/.done +speex-$(SPEEX)/.done: speex-$(SPEEX) speex-$(SPEEX): (test -d $@) || (wget -4 -O $@.tar.gz http://downloads.xiph.org/releases/speex/$@.tar.gz && tar zxfv $@.tar.gz) - (cd $@ && ./configure --prefix=$(PREFIX) && make && sudo make install) + (cd $@ && ./configure --prefix=$(PREFIX) && make && sudo make install && touch .done) -libedit: libedit-$(LIBEDIT)/Makefile -libedit-$(LIBEDIT)/Makefile: libedit-$(LIBEDIT) +libedit: libedit-$(LIBEDIT)/.done +libedit-$(LIBEDIT)/.done: libedit-$(LIBEDIT) libedit-$(LIBEDIT): (test -d $@) || (wget -4 -O $@.tar.gz http://thrysoee.dk/editline/$@.tar.gz && tar zxfv $@.tar.gz) - (cd $@ && ./configure --prefix=$(PREFIX) && make && sudo make install) + (cd $@ && ./configure --prefix=$(PREFIX) && make && sudo make install && touch .done) -ldns: ldns-$(LDNS)/Makefile -ldns-$(LDNS)/Makefile: openssl ldns-$(LDNS) +ldns: ldns-$(LDNS)/.done +ldns-$(LDNS)/.done: ldns-$(LDNS) ldns-$(LDNS): (test -d $@) || (wget -4 -O $@.tar.gz http://www.nlnetlabs.nl/downloads/ldns/$@.tar.gz && tar zxfv $@.tar.gz) - (cd $@ && ./configure --with-ssl=$(PREFIX) --prefix=$(PREFIX) && make && sudo make install) + (cd $@ && ./configure --with-ssl=$(PREFIX) --prefix=$(PREFIX) && make && sudo make install && touch .done) deps: libjpeg openssl sqlite pcre curl speex libedit ldns diff --git a/build/Makefile.solaris11 b/build/Makefile.solaris11 index 2a2da59e7f..eaaf686b68 100644 --- a/build/Makefile.solaris11 +++ b/build/Makefile.solaris11 @@ -12,7 +12,7 @@ JP=v8d SSL=1.0.1h SQLITE=autoconf-3080403 PCRE=8.35 -CURL=7.36.0 +CURL=7.35.0 SPEEX=1.2rc1 LIBEDIT=20140213-3.1 LDNS=1.6.17 @@ -45,64 +45,65 @@ clean: @rm -rf openssl* ldns* jpeg* pcre* perl* pkg-config* speex* sqlite* libedit* curl* *~ (cd freeswitch.git && git clean -fdx && git reset --hard HEAD && git pull) -libjpeg: jpeg-8d/Makefile +libjpeg: jpeg-8d/.done -jpeg-8d/Makefile: +jpeg-8d/.done: (test -d jpeg-8d) || (wget -4 -O jpegsrc.$(JP).tar.gz http://www.ijg.org/files/jpegsrc.$(JP).tar.gz && tar zxfv jpegsrc.$(JP).tar.gz) - (cd jpeg-8d && CFLAGS=-m64 LDFLAGS=-m64 ./configure --prefix=$(PREFIX) && gmake && sudo gmake install) + (cd jpeg-8d && CFLAGS=-m64 LDFLAGS=-m64 ./configure --prefix=$(PREFIX) && gmake && sudo gmake install && touch .done) -openssl: openssl-$(SSL)/Makefile -openssl-$(SSL)/Makefile: openssl-$(SSL) +openssl: openssl-$(SSL)/.done +openssl-$(SSL)/.done: openssl-$(SSL) openssl-$(SSL): (test -d $@) || (wget -4 -O $@.tar.gz http://www.openssl.org/source/$@.tar.gz && tar zxfv $@.tar.gz) - (cd $@ && CFLAGS=-m64 LDFLAGS=-m64 ./Configure --prefix=$(PREFIX) solaris64-x86_64-gcc shared && gmake && sudo gmake install) + (cd $@ && CFLAGS=-m64 LDFLAGS=-m64 ./Configure --prefix=$(PREFIX) solaris64-x86_64-gcc shared && gmake && sudo gmake install && touch .done) -sqlite: sqlite-$(SQLITE)/Makefile -sqlite-$(SQLITE)/Makefile: sqlite-$(SQLITE) +sqlite: sqlite-$(SQLITE)/.done +sqlite-$(SQLITE)/.done: sqlite-$(SQLITE) sqlite-$(SQLITE): (test -d $@) || (wget -4 -O $@.tar.gz http://www.sqlite.org/2014/$@.tar.gz && tar zxfv $@.tar.gz) - (cd $@ && CFLAGS=-m64 LDFLAGS=-m64 ./configure --prefix=$(PREFIX) && gmake && sudo gmake install) + (cd $@ && CFLAGS=-m64 LDFLAGS=-m64 ./configure --prefix=$(PREFIX) && gmake && sudo gmake install && touch .done) -pcre: pcre-$(PCRE)/Makefile -pcre-$(PCRE)/Makefile: pcre-$(PCRE) +pcre: pcre-$(PCRE)/.done +pcre-$(PCRE)/.done: pcre-$(PCRE) pcre-$(PCRE): (test -d $@) || (wget -4 -O $@.tar.gz http://downloads.sourceforge.net/project/pcre/pcre/$(PCRE)/$@.tar.gz && tar zxfv $@.tar.gz) - (cd $@ && CXXFLAGS=-m64 CFLAGS=-m64 LDFLAGS=-m64 ./configure --prefix=$(PREFIX) && gmake && sudo gmake install) + (cd $@ && CXXFLAGS=-m64 CFLAGS=-m64 LDFLAGS=-m64 ./configure --prefix=$(PREFIX) && gmake && sudo gmake install && touch .done) -curl: curl-$(CURL)/Makefile -curl-$(CURL)/Makefile: curl-$(CURL) +curl: curl-$(CURL)/.done +curl-$(CURL)/.done: curl-$(CURL) curl-$(CURL): - (test -d $@) || (wget -4 -O $@.tar.gz http://www.execve.net/curl/$@.tar.gz && tar zxfv $@.tar.gz) - (cd $@ && CFLAGS=-m64 LDFLAGS=-m64 ./configure --prefix=$(PREFIX) && gmake && sudo gmake install) + (test -d $@) || (wget -4 -O $@.tar.gz http://files.freeswitch.org/downloads/libs/$@.tar.gz && tar zxfv $@.tar.gz) + (cd $@ && CFLAGS=-m64 LDFLAGS=-m64 ./configure --prefix=$(PREFIX) && gmake && sudo gmake install && touch .done) -speex: speex-$(SPEEX)/Makefile -speex-$(SPEEX)/Makefile: speex-$(SPEEX) +speex: speex-$(SPEEX)/.done +speex-$(SPEEX)/.done: speex-$(SPEEX) speex-$(SPEEX): (test -d $@) || (wget -4 -O $@.tar.gz http://downloads.xiph.org/releases/speex/$@.tar.gz && tar zxfv $@.tar.gz) - (cd $@ && CFLAGS=-m64 LDFLAGS=-m64 ./configure --prefix=$(PREFIX) && gmake && sudo gmake install) + (cd $@ && CFLAGS=-m64 LDFLAGS=-m64 ./configure --prefix=$(PREFIX) && gmake && sudo gmake install && touch .done) -libedit: libedit-$(LIBEDIT)/Makefile -libedit-$(LIBEDIT)/Makefile: libedit-$(LIBEDIT) +libedit: libedit-$(LIBEDIT)/.done +libedit-$(LIBEDIT)/.done: libedit-$(LIBEDIT) libedit-$(LIBEDIT): (test -d $@) || (wget -4 -O $@.tar.gz http://thrysoee.dk/editline/$@.tar.gz && tar zxfv $@.tar.gz) - (cd $@ && CFLAGS=-m64 LDFLAGS=-m64 ./configure --prefix=$(PREFIX) && gmake && sudo gmake install) + (cd $@ && CFLAGS=-m64 LDFLAGS=-m64 ./configure --prefix=$(PREFIX) && gmake && sudo gmake install && touch .done) -ldns: openssl ldns-$(LDNS)/Makefile -ldns-$(LDNS)/Makefile: ldns-$(LDNS) +ldns: openssl ldns-$(LDNS)/.done +ldns-$(LDNS)/.done: ldns-$(LDNS) ldns-$(LDNS): (test -d $@) || (wget -4 -O $@.tar.gz http://www.nlnetlabs.nl/downloads/ldns/$@.tar.gz && tar zxfv $@.tar.gz) - (cd $@ && CFLAGS=-m64 LDFLAGS=-m64 ./configure --with-ssl=$(PREFIX) --prefix=$(PREFIX) && gmake && sudo gmake install) + (cd $@ && CFLAGS=-m64 LDFLAGS=-m64 ./configure --with-ssl=$(PREFIX) --prefix=$(PREFIX) && gmake && sudo gmake install && touch .done) -pkg-config: openssl pkg-config-$(PKGCFG)/Makefile -pkg-config-$(PKGCFG)/Makefile: pkg-config-$(PKGCFG) +pkg-config: openssl pkg-config-$(PKGCFG)/.done +pkg-config-$(PKGCFG)/.done: pkg-config-$(PKGCFG) pkg-config-$(PKGCFG): (test -d $@) || (wget -4 -O $@.tar.gz http://pkgconfig.freedesktop.org/releases/$@.tar.gz && tar zxfv $@.tar.gz) - (cd $@ && CFLAGS=-m64 LDFLAGS=-m64 ./configure --with-internal-glib --prefix=$(PREFIX) && sudo gmake uninstall && gmake && sudo gmake install) + (cd $@ && CFLAGS=-m64 LDFLAGS=-m64 ./configure --with-internal-glib --prefix=$(PREFIX) && sudo gmake uninstall && gmake && sudo gmake install && \ + touch .done) -perl: openssl perl-$(PERL)/Makefile -perl-$(PERL)/Makefile: perl-$(PERL) +perl: openssl perl-$(PERL)/.done +perl-$(PERL)/.done: perl-$(PERL) perl-$(PERL): (test -d $@) || (wget -4 -O $@.tar.gz http://www.cpan.org/src/5.0/$@.tar.gz && tar zxfv $@.tar.gz) - (cd $@ && CFLAGS=-m64 LDFLAGS=-m64 ./configure.gnu -Dcc=gcc --prefix=$(PREFIX) && gmake && sudo gmake install) + (cd $@ && CFLAGS=-m64 LDFLAGS=-m64 ./configure.gnu -Dcc=gcc --prefix=$(PREFIX) && gmake && sudo gmake install && touch .done) -deps: libjpeg openssl sqlite pcre curl speex libedit ldns pkg-config perl +deps: has-git libjpeg openssl sqlite pcre curl speex libedit ldns pkg-config perl From 0361bd70a43ec93a76b52708e5d642627c236beb Mon Sep 17 00:00:00 2001 From: Brian West Date: Tue, 17 Jun 2014 15:44:32 -0500 Subject: [PATCH 082/231] more tweaks --- build/Makefile.centos5 | 19 ++++++++++--------- build/Makefile.solaris11 | 21 +++++++++++---------- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/build/Makefile.centos5 b/build/Makefile.centos5 index 66ab2e79a5..ec5c231c99 100644 --- a/build/Makefile.centos5 +++ b/build/Makefile.centos5 @@ -9,8 +9,9 @@ # FSPREFIX=/usr/local/freeswitch PREFIX=/opt/fs-libs +DOWNLOAD=http://files.freeswitch.org/downloads/libs JPEG=v8d -OPENSSL=1.0.1g +OPENSSL=1.0.1h SQLITE=autoconf-3080403 PCRE=8.35 CURL=7.35.0 @@ -50,49 +51,49 @@ clean: libjpeg: jpeg-8d/.done jpeg-8d/.done: - (test -d jpeg-8d) || (wget -4 -O jpegsrc.$(JPEG).tar.gz http://www.ijg.org/files/jpegsrc.$(JPEG).tar.gz && tar zxfv jpegsrc.$(JPEG).tar.gz) + (test -d jpeg-8d) || (wget -4 -O jpegsrc.$(JPEG).tar.gz $(DOWNLOAD)/jpegsrc.$(JPEG).tar.gz && tar zxfv jpegsrc.$(JPEG).tar.gz) (cd jpeg-8d && ./configure --prefix=$(PREFIX) && make && sudo make install && touch .done) openssl: openssl-$(OPENSSL)/.done openssl-$(OPENSSL)/.done: openssl-$(OPENSSL) openssl-$(OPENSSL): - (test -d $@) || (wget -4 -O $@.tar.gz http://www.openssl.org/source/$@.tar.gz && tar zxfv $@.tar.gz) + (test -d $@) || (wget -4 -O $@.tar.gz $(DOWNLOAD)/$@.tar.gz && tar zxfv $@.tar.gz) (cd $@ && ./Configure --prefix=$(PREFIX) linux-x86_64 shared && make && sudo make install && touch .done) sqlite: sqlite-$(SQLITE)/.done sqlite-$(SQLITE)/.done: sqlite-$(SQLITE) sqlite-$(SQLITE): - (test -d $@) || (wget -4 -O $@.tar.gz http://www.sqlite.org/2014/$@.tar.gz && tar zxfv $@.tar.gz) + (test -d $@) || (wget -4 -O $@.tar.gz $(DOWNLOAD)/$@.tar.gz && tar zxfv $@.tar.gz) (cd $@ && ./configure --prefix=$(PREFIX) && make && sudo make install && touch .done_sqlite && touch .done) pcre: pcre-$(PCRE)/.done pcre-$(PCRE)/.done: pcre-$(PCRE) pcre-$(PCRE): - (test -d $@) || (wget -4 -O $@.tar.gz http://downloads.sourceforge.net/project/pcre/pcre/$(PCRE)/$@.tar.gz && tar zxfv $@.tar.gz) + (test -d $@) || (wget -4 -O $@.tar.gz $(DOWNLOAD)/$@.tar.gz && tar zxfv $@.tar.gz) (cd $@ && ./configure --prefix=$(PREFIX) && make && sudo make install && touch .done) curl: curl-$(CURL)/.done curl-$(CURL)/.done: curl-$(CURL) curl-$(CURL): - (test -d $@) || (wget -4 -O $@.tar.gz http://files.freeswitch.org/downloads/libs/$@.tar.gz && tar zxfv $@.tar.gz) + (test -d $@) || (wget -4 -O $@.tar.gz $(DOWNLOAD)/$@.tar.gz && tar zxfv $@.tar.gz) (cd $@ && ./configure --prefix=$(PREFIX) && make && sudo make install && touch .done) speex: speex-$(SPEEX)/.done speex-$(SPEEX)/.done: speex-$(SPEEX) speex-$(SPEEX): - (test -d $@) || (wget -4 -O $@.tar.gz http://downloads.xiph.org/releases/speex/$@.tar.gz && tar zxfv $@.tar.gz) + (test -d $@) || (wget -4 -O $@.tar.gz $(DOWNLOAD)/$@.tar.gz && tar zxfv $@.tar.gz) (cd $@ && ./configure --prefix=$(PREFIX) && make && sudo make install && touch .done) libedit: libedit-$(LIBEDIT)/.done libedit-$(LIBEDIT)/.done: libedit-$(LIBEDIT) libedit-$(LIBEDIT): - (test -d $@) || (wget -4 -O $@.tar.gz http://thrysoee.dk/editline/$@.tar.gz && tar zxfv $@.tar.gz) + (test -d $@) || (wget -4 -O $@.tar.gz $(DOWNLOAD)/$@.tar.gz && tar zxfv $@.tar.gz) (cd $@ && ./configure --prefix=$(PREFIX) && make && sudo make install && touch .done) ldns: ldns-$(LDNS)/.done ldns-$(LDNS)/.done: ldns-$(LDNS) ldns-$(LDNS): - (test -d $@) || (wget -4 -O $@.tar.gz http://www.nlnetlabs.nl/downloads/ldns/$@.tar.gz && tar zxfv $@.tar.gz) + (test -d $@) || (wget -4 -O $@.tar.gz $(DOWNLOAD)/$@.tar.gz && tar zxfv $@.tar.gz) (cd $@ && ./configure --with-ssl=$(PREFIX) --prefix=$(PREFIX) && make && sudo make install && touch .done) deps: libjpeg openssl sqlite pcre curl speex libedit ldns diff --git a/build/Makefile.solaris11 b/build/Makefile.solaris11 index eaaf686b68..dbff06e74f 100644 --- a/build/Makefile.solaris11 +++ b/build/Makefile.solaris11 @@ -8,6 +8,7 @@ # FSPREFIX=/usr/local/freeswitch PREFIX=/usr/local/ +DOWNLOAD=http://files.freeswitch.org/downloads/libs JP=v8d SSL=1.0.1h SQLITE=autoconf-3080403 @@ -48,62 +49,62 @@ clean: libjpeg: jpeg-8d/.done jpeg-8d/.done: - (test -d jpeg-8d) || (wget -4 -O jpegsrc.$(JP).tar.gz http://www.ijg.org/files/jpegsrc.$(JP).tar.gz && tar zxfv jpegsrc.$(JP).tar.gz) + (test -d jpeg-8d) || (wget -4 -O jpegsrc.$(JP).tar.gz $(DOWNLOAD)/jpegsrc.$(JP).tar.gz && tar zxfv jpegsrc.$(JP).tar.gz) (cd jpeg-8d && CFLAGS=-m64 LDFLAGS=-m64 ./configure --prefix=$(PREFIX) && gmake && sudo gmake install && touch .done) openssl: openssl-$(SSL)/.done openssl-$(SSL)/.done: openssl-$(SSL) openssl-$(SSL): - (test -d $@) || (wget -4 -O $@.tar.gz http://www.openssl.org/source/$@.tar.gz && tar zxfv $@.tar.gz) + (test -d $@) || (wget -4 -O $@.tar.gz $(DOWNLOAD)/$@.tar.gz && tar zxfv $@.tar.gz) (cd $@ && CFLAGS=-m64 LDFLAGS=-m64 ./Configure --prefix=$(PREFIX) solaris64-x86_64-gcc shared && gmake && sudo gmake install && touch .done) sqlite: sqlite-$(SQLITE)/.done sqlite-$(SQLITE)/.done: sqlite-$(SQLITE) sqlite-$(SQLITE): - (test -d $@) || (wget -4 -O $@.tar.gz http://www.sqlite.org/2014/$@.tar.gz && tar zxfv $@.tar.gz) + (test -d $@) || (wget -4 -O $@.tar.gz $(DOWNLOAD)/$@.tar.gz && tar zxfv $@.tar.gz) (cd $@ && CFLAGS=-m64 LDFLAGS=-m64 ./configure --prefix=$(PREFIX) && gmake && sudo gmake install && touch .done) pcre: pcre-$(PCRE)/.done pcre-$(PCRE)/.done: pcre-$(PCRE) pcre-$(PCRE): - (test -d $@) || (wget -4 -O $@.tar.gz http://downloads.sourceforge.net/project/pcre/pcre/$(PCRE)/$@.tar.gz && tar zxfv $@.tar.gz) + (test -d $@) || (wget -4 -O $@.tar.gz $(DOWNLOAD)/$@.tar.gz && tar zxfv $@.tar.gz) (cd $@ && CXXFLAGS=-m64 CFLAGS=-m64 LDFLAGS=-m64 ./configure --prefix=$(PREFIX) && gmake && sudo gmake install && touch .done) curl: curl-$(CURL)/.done curl-$(CURL)/.done: curl-$(CURL) curl-$(CURL): - (test -d $@) || (wget -4 -O $@.tar.gz http://files.freeswitch.org/downloads/libs/$@.tar.gz && tar zxfv $@.tar.gz) + (test -d $@) || (wget -4 -O $@.tar.gz $(DOWNLOAD)/$@.tar.gz && tar zxfv $@.tar.gz) (cd $@ && CFLAGS=-m64 LDFLAGS=-m64 ./configure --prefix=$(PREFIX) && gmake && sudo gmake install && touch .done) speex: speex-$(SPEEX)/.done speex-$(SPEEX)/.done: speex-$(SPEEX) speex-$(SPEEX): - (test -d $@) || (wget -4 -O $@.tar.gz http://downloads.xiph.org/releases/speex/$@.tar.gz && tar zxfv $@.tar.gz) + (test -d $@) || (wget -4 -O $@.tar.gz $(DOWNLOAD)/$@.tar.gz && tar zxfv $@.tar.gz) (cd $@ && CFLAGS=-m64 LDFLAGS=-m64 ./configure --prefix=$(PREFIX) && gmake && sudo gmake install && touch .done) libedit: libedit-$(LIBEDIT)/.done libedit-$(LIBEDIT)/.done: libedit-$(LIBEDIT) libedit-$(LIBEDIT): - (test -d $@) || (wget -4 -O $@.tar.gz http://thrysoee.dk/editline/$@.tar.gz && tar zxfv $@.tar.gz) + (test -d $@) || (wget -4 -O $@.tar.gz $(DOWNLOAD)/$@.tar.gz && tar zxfv $@.tar.gz) (cd $@ && CFLAGS=-m64 LDFLAGS=-m64 ./configure --prefix=$(PREFIX) && gmake && sudo gmake install && touch .done) ldns: openssl ldns-$(LDNS)/.done ldns-$(LDNS)/.done: ldns-$(LDNS) ldns-$(LDNS): - (test -d $@) || (wget -4 -O $@.tar.gz http://www.nlnetlabs.nl/downloads/ldns/$@.tar.gz && tar zxfv $@.tar.gz) + (test -d $@) || (wget -4 -O $@.tar.gz $(DOWNLOAD)/$@.tar.gz && tar zxfv $@.tar.gz) (cd $@ && CFLAGS=-m64 LDFLAGS=-m64 ./configure --with-ssl=$(PREFIX) --prefix=$(PREFIX) && gmake && sudo gmake install && touch .done) pkg-config: openssl pkg-config-$(PKGCFG)/.done pkg-config-$(PKGCFG)/.done: pkg-config-$(PKGCFG) pkg-config-$(PKGCFG): - (test -d $@) || (wget -4 -O $@.tar.gz http://pkgconfig.freedesktop.org/releases/$@.tar.gz && tar zxfv $@.tar.gz) + (test -d $@) || (wget -4 -O $@.tar.gz $(DOWNLOAD)/$@.tar.gz && tar zxfv $@.tar.gz) (cd $@ && CFLAGS=-m64 LDFLAGS=-m64 ./configure --with-internal-glib --prefix=$(PREFIX) && sudo gmake uninstall && gmake && sudo gmake install && \ touch .done) perl: openssl perl-$(PERL)/.done perl-$(PERL)/.done: perl-$(PERL) perl-$(PERL): - (test -d $@) || (wget -4 -O $@.tar.gz http://www.cpan.org/src/5.0/$@.tar.gz && tar zxfv $@.tar.gz) + (test -d $@) || (wget -4 -O $@.tar.gz $(DOWNLOAD)/$@.tar.gz && tar zxfv $@.tar.gz) (cd $@ && CFLAGS=-m64 LDFLAGS=-m64 ./configure.gnu -Dcc=gcc --prefix=$(PREFIX) && gmake && sudo gmake install && touch .done) deps: has-git libjpeg openssl sqlite pcre curl speex libedit ldns pkg-config perl From 24495304c82a2cbdcde612d7d1ad5731e7545c12 Mon Sep 17 00:00:00 2001 From: Brian West Date: Tue, 17 Jun 2014 16:46:58 -0500 Subject: [PATCH 083/231] Since the FTC won't allow you to register more than 6 or so numbers online without having to call... I wrote this in 10 minutes to solve the problem --- scripts/perl/ftc_dnc_register.pl | 44 ++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 scripts/perl/ftc_dnc_register.pl diff --git a/scripts/perl/ftc_dnc_register.pl b/scripts/perl/ftc_dnc_register.pl new file mode 100644 index 0000000000..011569164e --- /dev/null +++ b/scripts/perl/ftc_dnc_register.pl @@ -0,0 +1,44 @@ +#!/usr/bin/perl +# +# Since the FTC only allows a limited set of numbers to be submitted online +# I've decided to use the power of FreeSWITCH to show how easy this is to solve. +# +# numbers.txt is a file with 1 did per line, 10 digits, If it starts with a 1 thats +# it will be stripped. +# +# Remember, Only use this for numbers YOU personally own. I have many different DID +# +# + +require ESL; +use Data::Dumper; +my $con = new ESL::ESLconnection("localhost", "8021", "ClueCon"); +# one 10 digit number PER LINE. +open(NUMS, "; + +foreach my $num (@nums) { + chomp $num; + $num =~ s/^1//; + print "Dialing from $num\n"; + my @digits = split(//, $num); + my $dial = join('w', @digits); + my $command = "originate {ignore_early_media=true,execute_on_answer_01=\'playback silence_strem://1000\',execute_on_answer_02=\'send_dtmf WWWWW1WWWWWWW1WWWWWWW${dial}w#\',execute_on_answer_03='record_session /tmp/$num.wav',origination_caller_id_number=$num}sofia/gateway/59/18883821222 &park"; + my $e = $con->api('bgapi', "$command"); + print $e->getBody(); + sleep 40; +} +close(NUMS); +print "Done..."; + + + + + + + + + + + From c066fedffed6a069286b3c4bf28862200a35ff00 Mon Sep 17 00:00:00 2001 From: Brian West Date: Tue, 17 Jun 2014 17:11:04 -0500 Subject: [PATCH 084/231] tweak --- scripts/perl/ftc_dnc_register.pl | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/perl/ftc_dnc_register.pl b/scripts/perl/ftc_dnc_register.pl index 011569164e..0471719183 100644 --- a/scripts/perl/ftc_dnc_register.pl +++ b/scripts/perl/ftc_dnc_register.pl @@ -21,6 +21,7 @@ my @nums = ; foreach my $num (@nums) { chomp $num; $num =~ s/^1//; + next if lenght($num) != 10; print "Dialing from $num\n"; my @digits = split(//, $num); my $dial = join('w', @digits); From b0369d321f339a83153c7d1e50207509ab2c9044 Mon Sep 17 00:00:00 2001 From: Brian West Date: Tue, 17 Jun 2014 17:12:42 -0500 Subject: [PATCH 085/231] remove white space --- scripts/perl/ftc_dnc_register.pl | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/scripts/perl/ftc_dnc_register.pl b/scripts/perl/ftc_dnc_register.pl index 0471719183..5e6ddf9243 100644 --- a/scripts/perl/ftc_dnc_register.pl +++ b/scripts/perl/ftc_dnc_register.pl @@ -32,14 +32,3 @@ foreach my $num (@nums) { } close(NUMS); print "Done..."; - - - - - - - - - - - From 315add5637a2ed85651e3502a0c8054c1ef7d813 Mon Sep 17 00:00:00 2001 From: Brian West Date: Tue, 17 Jun 2014 17:20:00 -0500 Subject: [PATCH 086/231] woops typo --- scripts/perl/ftc_dnc_register.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/perl/ftc_dnc_register.pl b/scripts/perl/ftc_dnc_register.pl index 5e6ddf9243..a53b7a6a4d 100644 --- a/scripts/perl/ftc_dnc_register.pl +++ b/scripts/perl/ftc_dnc_register.pl @@ -21,7 +21,7 @@ my @nums = ; foreach my $num (@nums) { chomp $num; $num =~ s/^1//; - next if lenght($num) != 10; + next if length($num) != 10; print "Dialing from $num\n"; my @digits = split(//, $num); my $dial = join('w', @digits); From 412abaddde52343eb8a2aed966a1387bdb85c167 Mon Sep 17 00:00:00 2001 From: Michael Jerris Date: Tue, 17 Jun 2014 20:19:22 -0400 Subject: [PATCH 087/231] no one seems to be okay with actually installing perl modules because it might require the permissions to acutally do so, instead, let the users figure out how to install them themselves so they can figure out how to have permissions and where they acutally go by themselves with no direction from us --- src/mod/endpoints/mod_verto/Makefile.am | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/mod/endpoints/mod_verto/Makefile.am b/src/mod/endpoints/mod_verto/Makefile.am index 4e85399e7e..123976d139 100644 --- a/src/mod/endpoints/mod_verto/Makefile.am +++ b/src/mod/endpoints/mod_verto/Makefile.am @@ -9,19 +9,19 @@ mod_verto_la_LIBADD = $(switch_builddir)/libfreeswitch.la mod_verto_la_LDFLAGS = -avoid-version -module -no-undefined -shared if HAVE_PERL -perldir = $(PERL_SITEDIR) -perl_LTLIBRARIES = MCAST.la +#perldir = $(PERL_SITEDIR) +noinst_LTLIBRARIES = MCAST.la MCAST_la_SOURCES = mcast/mcast_wrap.cpp mcast/perlxsi.c mcast/mcast.c mcast/mcast_cpp.cpp MCAST_la_CFLAGS = $(CC_CFLAGS) $(CFLAGS) $(SWITCH_AM_CFLAGS) $(PERL_CFLAGS) MCAST_la_CXXFLAGS = $(SWITCH_AM_CXXFLAGS) $(CXXFLAGS) -w $(PERL_INC) MCAST_la_CPPFLAGS = -I$(switch_srcdir)/src/mod/endpoints/mod_verto/mcast MCAST_la_LDFLAGS = -avoid-version -module -no-undefined -shared $(PERL_LDFLAGS) -install-data-local: perlmod-install +#install-data-local: perlmod-install -perlmod-install: install-perlLTLIBRARIES - install -d -m 755 $(DESTDIR)$(PERL_SITEDIR) - install -m 755 mcast/MCAST.pm $(DESTDIR)$(PERL_SITEDIR) +#perlmod-install: install-perlLTLIBRARIES +# install -d -m 755 $(DESTDIR)$(PERL_SITEDIR) +# install -m 755 mcast/MCAST.pm $(DESTDIR)$(PERL_SITEDIR) endif mcast/esl_wrap.cpp: From 1e249d61c3eafda96355ab9a2940c15d0a54752f Mon Sep 17 00:00:00 2001 From: Nathan Neulinger Date: Tue, 17 Jun 2014 19:36:55 -0500 Subject: [PATCH 088/231] FS-6607 add notice of IPv6 support for mod_skinny --- src/mod/endpoints/mod_skinny/README.IPv6 | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/mod/endpoints/mod_skinny/README.IPv6 diff --git a/src/mod/endpoints/mod_skinny/README.IPv6 b/src/mod/endpoints/mod_skinny/README.IPv6 new file mode 100644 index 0000000000..9f65d1dec9 --- /dev/null +++ b/src/mod/endpoints/mod_skinny/README.IPv6 @@ -0,0 +1,18 @@ +mod_skinny currently does not support IPv6 (as of 2014-06-17) + +According to Cisco documentation, the underlying protocol does support IPv6 for the "G" series +phones. (Basically a subset of the models running the java based image.) + +http://www.cisco.com/c/en/us/support/docs/voice-unified-communications/unified-communications-manager-version-70/112997-cucmipv6-00.html + + 7906G, 7911G, 7931G, 7942G, 7945G, 7962G, 7965G, and the 7975G + +It is possible that others would be supported, and are just not listed in the Cisco documentation +due to them being past end-of-life. + +Additional changes will be required to mod_skinny to actually support IPv6, at a bare minimum, the +current code has at least one data structure for the server response that contains a fixed +layout structure with uint32_t's for IP addresses. + +If someone has an existing CCM deployment that is using IPv6, sample network captures would be +appreciated. \ No newline at end of file From 723ea008558d0d987c98715559551a0ca22a8c80 Mon Sep 17 00:00:00 2001 From: Nathan Neulinger Date: Tue, 17 Jun 2014 19:53:45 -0500 Subject: [PATCH 089/231] FS-6607 add further not from wiki page about IPv6 support --- src/mod/endpoints/mod_skinny/README.IPv6 | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/mod/endpoints/mod_skinny/README.IPv6 b/src/mod/endpoints/mod_skinny/README.IPv6 index 9f65d1dec9..c685920897 100644 --- a/src/mod/endpoints/mod_skinny/README.IPv6 +++ b/src/mod/endpoints/mod_skinny/README.IPv6 @@ -1,4 +1,8 @@ -mod_skinny currently does not support IPv6 (as of 2014-06-17) +mod_skinny currently is not believed to support IPv6 (as of 2014-06-17) + + There is a notation in the wiki that you can force IPv6 usage + by setting: ip="::" in the profile, but unclear if that is sufficient + for the rest of the protocol. According to Cisco documentation, the underlying protocol does support IPv6 for the "G" series phones. (Basically a subset of the models running the java based image.) From 5dbfc573089b29272eb1041aaa6a444d176037d6 Mon Sep 17 00:00:00 2001 From: Brian West Date: Tue, 17 Jun 2014 21:14:14 -0500 Subject: [PATCH 090/231] ignore fs_ivrd --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 406715b3cf..ad40d3cd3d 100644 --- a/.gitignore +++ b/.gitignore @@ -111,7 +111,7 @@ Release/ /libs/curl/lib/ca-bundle.h /libs/esl/fs_cli -/libs/esl/ivrd +/libs/esl/fs_ivrd /libs/esl/testclient /libs/esl/testserver /libs/freetdm/detect_dtmf From 311889634b6d780369a17c18609e4039ccd29436 Mon Sep 17 00:00:00 2001 From: Brian West Date: Tue, 17 Jun 2014 21:15:02 -0500 Subject: [PATCH 091/231] FS-5223 FS-6603 on platforms that have SO_REUSEPORT it also implies SO_REUSEADDR, On platforms that only have SO_REUSEADDR it seems to imply both in the absence of SO_REUSEPORT. --- libs/sofia-sip/.update | 2 +- libs/sofia-sip/libsofia-sip-ua/su/su.c | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/libs/sofia-sip/.update b/libs/sofia-sip/.update index cb4397f41e..4d1fcfb511 100644 --- a/libs/sofia-sip/.update +++ b/libs/sofia-sip/.update @@ -1 +1 @@ -Mon Jun 9 14:22:59 EDT 2014 +Tue Jun 17 21:14:36 CDT 2014 diff --git a/libs/sofia-sip/libsofia-sip-ua/su/su.c b/libs/sofia-sip/libsofia-sip-ua/su/su.c index c99d32f24d..41b08afc8d 100644 --- a/libs/sofia-sip/libsofia-sip-ua/su/su.c +++ b/libs/sofia-sip/libsofia-sip-ua/su/su.c @@ -350,8 +350,13 @@ int su_getsocktype(su_socket_t s) int su_setreuseaddr(su_socket_t s, int reuse) { +#ifdef SO_REUSEPORT + return setsockopt(s, SOL_SOCKET, SO_REUSEPORT, + (void *)&reuse, (socklen_t)sizeof(reuse)); +#else return setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void *)&reuse, (socklen_t)sizeof(reuse)); +#endif } From d237d0f343c43ee6c6bba893f80ff4ff75f3d43a Mon Sep 17 00:00:00 2001 From: Brian West Date: Tue, 17 Jun 2014 21:28:16 -0500 Subject: [PATCH 092/231] util for quick restarts during debugging --- support-d/rbfs | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 support-d/rbfs diff --git a/support-d/rbfs b/support-d/rbfs new file mode 100644 index 0000000000..dde81020ce --- /dev/null +++ b/support-d/rbfs @@ -0,0 +1,5 @@ +#!/usr/bin/env bash +fs_cli -x "fsctl shutdown now" +pkill -9 freeswitch +sleep 1 +/usr/local/freeswitch/bin/freeswitch -ncwait -nocal From fb92ebc8f24b61b5e7e6f568c624349f0813c2c9 Mon Sep 17 00:00:00 2001 From: Brian West Date: Wed, 18 Jun 2014 08:33:57 -0500 Subject: [PATCH 093/231] FS-5223 and FS-6603, don't trust docs... sheesh --- libs/sofia-sip/.update | 2 +- libs/sofia-sip/libsofia-sip-ua/su/su.c | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/libs/sofia-sip/.update b/libs/sofia-sip/.update index 4d1fcfb511..60fffd18f9 100644 --- a/libs/sofia-sip/.update +++ b/libs/sofia-sip/.update @@ -1 +1 @@ -Tue Jun 17 21:14:36 CDT 2014 +date diff --git a/libs/sofia-sip/libsofia-sip-ua/su/su.c b/libs/sofia-sip/libsofia-sip-ua/su/su.c index 41b08afc8d..b2de1b3e8f 100644 --- a/libs/sofia-sip/libsofia-sip-ua/su/su.c +++ b/libs/sofia-sip/libsofia-sip-ua/su/su.c @@ -351,12 +351,14 @@ int su_getsocktype(su_socket_t s) int su_setreuseaddr(su_socket_t s, int reuse) { #ifdef SO_REUSEPORT - return setsockopt(s, SOL_SOCKET, SO_REUSEPORT, - (void *)&reuse, (socklen_t)sizeof(reuse)); -#else - return setsockopt(s, SOL_SOCKET, SO_REUSEADDR, - (void *)&reuse, (socklen_t)sizeof(reuse)); + if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT, + (void *)&reuse, (socklen_t)sizeof(reuse)) < 0) + return -1; #endif + if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, + (void *)&reuse, (socklen_t)sizeof(reuse)) < 0) + return -1; + return 0; } From e279ae82039d8a1655a46521ce87c374d4791ad8 Mon Sep 17 00:00:00 2001 From: Nathan Neulinger Date: Wed, 18 Jun 2014 08:40:20 -0500 Subject: [PATCH 094/231] FS-6605 add support for automatic dialing when off-hook/ringdown --resolve --- .../conf/directory/default/skinny-example.xml | 1 + src/mod/endpoints/mod_skinny/mod_skinny.h | 1 + src/mod/endpoints/mod_skinny/skinny_server.c | 14 +++++++++++++- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/mod/endpoints/mod_skinny/conf/directory/default/skinny-example.xml b/src/mod/endpoints/mod_skinny/conf/directory/default/skinny-example.xml index c51b5ce9cf..9227a7e7f7 100644 --- a/src/mod/endpoints/mod_skinny/conf/directory/default/skinny-example.xml +++ b/src/mod/endpoints/mod_skinny/conf/directory/default/skinny-example.xml @@ -7,6 +7,7 @@ + --> + diff --git a/src/mod/endpoints/mod_skinny/mod_skinny.c b/src/mod/endpoints/mod_skinny/mod_skinny.c index e2a715baa1..88905973d0 100644 --- a/src/mod/endpoints/mod_skinny/mod_skinny.c +++ b/src/mod/endpoints/mod_skinny/mod_skinny.c @@ -166,6 +166,7 @@ switch_status_t skinny_profile_dump(const skinny_profile_t *profile, switch_stre stream->write_function(stream, "DBName \t%s\n", profile->dbname ? profile->dbname : switch_str_nil(profile->odbc_dsn)); stream->write_function(stream, "Debug \t%d\n", profile->debug); stream->write_function(stream, "Auto-Restart \t%d\n", profile->auto_restart); + stream->write_function(stream, "Non-Blocking \t%d\n", profile->non_blocking); /* stats */ stream->write_function(stream, "CALLS-IN \t%d\n", profile->ib_calls); stream->write_function(stream, "FAILED-CALLS-IN \t%d\n", profile->ib_failed_calls); @@ -1720,12 +1721,12 @@ static void *SWITCH_THREAD_FUNC listener_run(switch_thread_t *thread, void *obj) switch_assert(listener != NULL); -#if MOD_SKINNY_NONBLOCK - switch_socket_opt_set(listener->sock, SWITCH_SO_TCP_NODELAY, TRUE); - switch_socket_opt_set(listener->sock, SWITCH_SO_NONBLOCK, TRUE); -#else - switch_socket_opt_set(listener->sock, SWITCH_SO_NONBLOCK, FALSE); -#endif + if ( profile->non_blocking ) { + switch_socket_opt_set(listener->sock, SWITCH_SO_TCP_NODELAY, TRUE); + switch_socket_opt_set(listener->sock, SWITCH_SO_NONBLOCK, TRUE); + } else { + switch_socket_opt_set(listener->sock, SWITCH_SO_NONBLOCK, FALSE); + } /* 200 ms to allow reasonably fast reaction on digit timeout */ switch_socket_timeout_set(listener->sock, 200000); @@ -2033,6 +2034,8 @@ switch_status_t skinny_profile_set(skinny_profile_t *profile, const char *var, c profile->debug = atoi(val); } else if (!strcasecmp(var, "auto-restart")) { profile->auto_restart = switch_true(val); + } else if (!strcasecmp(var, "non-blocking")) { + profile->non_blocking = switch_true(val); } else if (!strcasecmp(var, "ext-voicemail")) { if (!profile->ext_voicemail || strcmp(val, profile->ext_voicemail)) { profile->ext_voicemail = switch_core_strdup(profile->pool, val); @@ -2106,6 +2109,7 @@ static switch_status_t load_skinny_config(void) profile->pool = profile_pool; profile->name = switch_core_strdup(profile->pool, profile_name); profile->auto_restart = SWITCH_TRUE; + profile->non_blocking = SWITCH_FALSE; profile->digit_timeout = 10000; /* 10 seconds */ switch_mutex_init(&profile->sql_mutex, SWITCH_MUTEX_NESTED, profile->pool); switch_mutex_init(&profile->listener_mutex, SWITCH_MUTEX_NESTED, profile->pool); diff --git a/src/mod/endpoints/mod_skinny/mod_skinny.h b/src/mod/endpoints/mod_skinny/mod_skinny.h index 91598f56bb..e3571dfe95 100644 --- a/src/mod/endpoints/mod_skinny/mod_skinny.h +++ b/src/mod/endpoints/mod_skinny/mod_skinny.h @@ -124,6 +124,7 @@ struct skinny_profile { char date_format[6]; int debug; int auto_restart; + int non_blocking; switch_hash_t *soft_key_set_sets_hash; switch_hash_t *device_type_params_hash; /* extensions */ From d886cc12fa88998c3bb416531b63b000763da57b Mon Sep 17 00:00:00 2001 From: Nathan Neulinger Date: Wed, 18 Jun 2014 17:11:19 -0500 Subject: [PATCH 103/231] mod_skinny: profile digit timeout is integer not string --- src/mod/endpoints/mod_skinny/mod_skinny.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mod/endpoints/mod_skinny/mod_skinny.c b/src/mod/endpoints/mod_skinny/mod_skinny.c index 88905973d0..ab319b2d1b 100644 --- a/src/mod/endpoints/mod_skinny/mod_skinny.c +++ b/src/mod/endpoints/mod_skinny/mod_skinny.c @@ -161,7 +161,7 @@ switch_status_t skinny_profile_dump(const skinny_profile_t *profile, switch_stre stream->write_function(stream, "Patterns-Dialplan \t%s\n", profile->patterns_dialplan); stream->write_function(stream, "Patterns-Context \t%s\n", profile->patterns_context); stream->write_function(stream, "Keep-Alive \t%d\n", profile->keep_alive); - stream->write_function(stream, "Digit-Timeout \t%s\n", profile->digit_timeout); + stream->write_function(stream, "Digit-Timeout \t%d\n", profile->digit_timeout); stream->write_function(stream, "Date-Format \t%s\n", profile->date_format); stream->write_function(stream, "DBName \t%s\n", profile->dbname ? profile->dbname : switch_str_nil(profile->odbc_dsn)); stream->write_function(stream, "Debug \t%d\n", profile->debug); From b780371943246f17d1ad1d04e653803f7459bebc Mon Sep 17 00:00:00 2001 From: Steve Underwood Date: Fri, 20 Jun 2014 00:24:10 +0800 Subject: [PATCH 104/231] Improved TSB85 tests, which now check call clearing. FAX now differentiates properly between and when deciding how to retry. --- libs/spandsp/spandsp/fax-tests.dtd | 1 + libs/spandsp/spandsp/fax-tests.xml | 8 + libs/spandsp/spandsp/tsb85.xml | 463 ++++++++++++++++++++++- libs/spandsp/src/spandsp/private/t30.h | 16 +- libs/spandsp/src/t30.c | 217 ++++------- libs/spandsp/tests/super_tone_rx_tests.c | 31 +- libs/spandsp/tests/super_tone_tx_tests.c | 32 +- libs/spandsp/tests/tsb85_tests.c | 180 +++++++-- libs/spandsp/tests/tsb85_tests.sh | 6 +- 9 files changed, 759 insertions(+), 195 deletions(-) diff --git a/libs/spandsp/spandsp/fax-tests.dtd b/libs/spandsp/spandsp/fax-tests.dtd index beb4eae3ef..39f97febaa 100644 --- a/libs/spandsp/spandsp/fax-tests.dtd +++ b/libs/spandsp/spandsp/fax-tests.dtd @@ -33,6 +33,7 @@ modem CDATA #IMPLIED tag CDATA #IMPLIED value CDATA #IMPLIED + timein CDATA #IMPLIED timeout CDATA #IMPLIED crc_error CDATA #IMPLIED pattern CDATA #IMPLIED diff --git a/libs/spandsp/spandsp/fax-tests.xml b/libs/spandsp/spandsp/fax-tests.xml index 495eadec7e..87574175cd 100644 --- a/libs/spandsp/spandsp/fax-tests.xml +++ b/libs/spandsp/spandsp/fax-tests.xml @@ -91,6 +91,9 @@ + + + @@ -140,6 +144,10 @@ + + + + @@ -196,6 +204,10 @@ + + + + @@ -251,6 +263,10 @@ + + + + @@ -299,6 +315,10 @@ + + + + @@ -347,6 +367,10 @@ + + + + @@ -395,6 +419,10 @@ + + + + @@ -442,6 +470,10 @@ + + + + @@ -493,6 +525,10 @@ + + + + @@ -552,6 +588,10 @@ + + + + @@ -591,6 +631,10 @@ + + + + @@ -648,6 +692,10 @@ + + + + @@ -701,6 +749,10 @@ + + + + @@ -754,6 +806,10 @@ + + + + @@ -810,6 +866,10 @@ + + + + @@ -865,6 +925,10 @@ + + + + @@ -979,6 +1043,10 @@ + + + + @@ -1101,6 +1169,10 @@ + + + + @@ -1148,6 +1220,10 @@ + + + + @@ -1193,6 +1269,10 @@ + + + + @@ -1228,6 +1308,10 @@ + + + + @@ -1311,6 +1395,10 @@ + + + + @@ -1419,6 +1507,10 @@ + + + + @@ -1560,6 +1652,10 @@ + + + + @@ -1703,6 +1799,10 @@ + + + + @@ -1846,6 +1946,10 @@ + + + + @@ -1989,6 +2093,10 @@ + + + + @@ -2109,6 +2217,10 @@ + + + + @@ -2178,6 +2290,10 @@ + + + + @@ -2227,6 +2343,10 @@ + + + + @@ -2264,6 +2384,10 @@ + + + + @@ -2276,6 +2400,9 @@ + + + @@ -2289,6 +2416,10 @@ + + + + @@ -2322,6 +2453,10 @@ + + + + @@ -2347,6 +2482,10 @@ + + + + @@ -2416,6 +2555,10 @@ + + + + @@ -2449,6 +2592,10 @@ + + + + @@ -2482,6 +2629,10 @@ + + + + @@ -2521,6 +2672,10 @@ + + + + @@ -2564,6 +2719,10 @@ + + + + @@ -2604,6 +2763,10 @@ + + + + @@ -2650,6 +2813,10 @@ + + + + @@ -2685,6 +2852,10 @@ + + + + @@ -2719,6 +2890,10 @@ + + + + @@ -2757,6 +2932,10 @@ + + + + @@ -2775,6 +2954,9 @@ + + + @@ -2829,6 +3011,10 @@ + + + + @@ -2885,6 +3071,10 @@ + + + + @@ -2927,6 +3117,9 @@ + + + @@ -2990,6 +3186,9 @@ + + + @@ -3020,6 +3219,9 @@ + + + @@ -3050,6 +3252,9 @@ + + + @@ -3095,6 +3303,9 @@ + + + @@ -3133,6 +3344,9 @@ + + + @@ -3171,6 +3385,9 @@ + + + @@ -3217,6 +3434,9 @@ + + + @@ -3251,6 +3471,9 @@ + + + @@ -3297,6 +3520,9 @@ + + + @@ -3335,6 +3561,9 @@ + + + @@ -3389,6 +3618,9 @@ + + + @@ -3456,6 +3688,9 @@ + + + @@ -3523,6 +3758,9 @@ + + + @@ -3563,6 +3801,9 @@ + + + @@ -3615,6 +3856,9 @@ + + + @@ -3667,6 +3911,9 @@ + + + @@ -3699,6 +3946,9 @@ + + + @@ -3743,6 +3993,9 @@ + + + @@ -3787,6 +4040,9 @@ + + + @@ -3840,6 +4096,9 @@ + + + @@ -3886,6 +4145,9 @@ + + + @@ -3916,6 +4178,9 @@ + + + @@ -3969,6 +4234,9 @@ + + + @@ -4024,6 +4292,9 @@ + + + @@ -4054,6 +4325,9 @@ + + + @@ -4094,6 +4368,9 @@ + + + @@ -4132,6 +4409,9 @@ + + + @@ -4170,6 +4450,9 @@ + + + @@ -4216,6 +4499,9 @@ + + + @@ -4254,6 +4540,9 @@ + + + @@ -4292,6 +4581,9 @@ + + + @@ -4346,6 +4638,9 @@ + + + @@ -4408,6 +4703,9 @@ + + + @@ -4446,6 +4744,9 @@ + + + @@ -4484,6 +4785,9 @@ + + + @@ -4522,6 +4826,9 @@ + + + @@ -4560,6 +4867,9 @@ + + + @@ -4598,6 +4908,9 @@ + + + @@ -4636,6 +4949,9 @@ + + + @@ -4674,6 +4990,9 @@ + + + @@ -4712,6 +5031,9 @@ + + + @@ -4750,6 +5072,9 @@ + + + @@ -4788,6 +5113,9 @@ + + + @@ -4826,6 +5154,9 @@ + + + @@ -4864,6 +5195,9 @@ + + + @@ -4929,6 +5263,9 @@ + + + @@ -4959,6 +5296,9 @@ + + + @@ -5007,6 +5347,9 @@ + + + @@ -5081,6 +5424,9 @@ + + + @@ -5272,6 +5618,9 @@ + + + @@ -5383,7 +5732,9 @@ - + + + @@ -5459,6 +5810,9 @@ + + + @@ -5489,6 +5843,9 @@ + + + @@ -5508,6 +5865,8 @@ + + @@ -5547,6 +5910,10 @@ + + + + @@ -5577,6 +5944,10 @@ + + + + @@ -5605,6 +5976,10 @@ + + + + @@ -5633,6 +6008,10 @@ + + + + @@ -5656,6 +6035,9 @@ + + + @@ -5687,6 +6069,9 @@ + + + @@ -5716,6 +6101,9 @@ + + + @@ -5745,6 +6133,9 @@ + + + @@ -5791,6 +6182,9 @@ + + + @@ -5829,6 +6223,9 @@ + + + @@ -5867,6 +6264,9 @@ + + + @@ -5913,6 +6313,9 @@ + + + @@ -5957,6 +6360,9 @@ + + + @@ -6001,6 +6407,9 @@ + + + @@ -6081,6 +6494,9 @@ + + + @@ -6117,6 +6533,9 @@ + + + @@ -6150,6 +6569,9 @@ + + + @@ -6197,6 +6619,9 @@ + + + @@ -6243,6 +6668,9 @@ + + + @@ -6280,6 +6708,9 @@ + + + @@ -6360,6 +6791,9 @@ + + + @@ -6414,6 +6848,9 @@ + + + @@ -6436,6 +6873,9 @@ + + + @@ -6457,6 +6897,9 @@ + + + @@ -6479,6 +6922,9 @@ + + + @@ -6526,6 +6972,9 @@ + + + @@ -6547,6 +6996,9 @@ + + + @@ -6567,6 +7019,9 @@ + + + 0lJ6uX{`&a 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 z z1`dAH_+C`?(mbB?^`|Fgnqxzs&2pkeHzM{VL&M(8B#xA4wv{bJN{DVpga0rf)A4nS zJrtt{l>f_p!(48c!=1L?W5EBuLP168%agyjJr)8d?wc6{xX7lEz-!zU?A~RZ#$M(q zEb}1#c5b3`_o)1>$E2I#;`JTXcwdY}P_ss>rNO5;^#Z=+bC;|R>XeR2lNX+w_w|0S zet(lSbH-WtZ1tg;K9Tw_U!e%a{|caY$&q4WqBlKxYa4R|>J+s=C&i!(f9C`6B!?0f zpiT6P-PEv%3MneZ%f1YGom;8&F1z?(*&W}718n;0A3z>We8I7skbj?G;eHalS+9v6 z+gPAgIHB(9tgn|Mm0W~B`FP&zdU%l7EH-Pxt@o!%z@4_fP3WqNZabkDmq}-|wc!Ix zi7kPpQ2C-!(59v8w&nzQr6Vr2t@?g_v=WxLJ^g(9Q}tEsN2u}A`t<#NAv6&wl$W2d zy-gml*6tJE{^{3~tt6rsz#y$H(Y(2FBke6AGe`Gr!GJ!h{!On;SHE{~I-5-W_fDX_ z-Li@jfmve4t0mWm!U>u0t2T9+yYlG1^ZJnqC{U=OIn-bVtL=MGI9E2pfNHw^Huu9? zF?BgfTuZgM3-4$dP}gK#!!JtlUBGMD5*C;H$A3@uQ$OYiDON& zm~5lf_N{!VH^pQ;?{`SRSV-g{;eecVSwu1JRL6(K)s7c=efqkapr*5#_0I8nS<&GE zO)Y3$UX^H63>7D9;G-Al-|uPShYY(0JjX@5@>>VSrX%RC!Een5aNfPVWE2p399t#t zZSW`nAUW01;iL#Rmw?f{)|q)YHHGjt_qANK%D92Yo-KcuZ{MSU7JDc}4Jha2S~7o` zcdgRn38|Xw#|E=o749T)*lv9)gt^>|A~GnG8ByWwBE9j= z>q2&A+SUfP01FX!;cOR+1CWvzV9?kbK>~0D>$;qpVyo04p*!_$fa4V+}KfwQnssX z5b|u;zD>ym*DC4P{XLD)eb=o082Jw&$VZ%*Kx!$yrqOv@}TOHMW-#IeB?+G)G`ZIZ@C&_xAF# zahnRk*&}@?r>>(uE1dV9nj3x=YEPV*u?l7``d+bqrV#B5KdwMbm!rL{n1$$F|HUg= zPy4^He%TNm`xy_NLrK~tO%uAXRNraG4b#6(0<%1JzOk$(Pd|w@OSI)yZGbXt+7UdP zOUy8S5x7$P6S<+aOjAZe2PP_ZTdsm~=Qo~nPZMa=Xks4Kx?~^M2F!QV>un9#ZVwE_ zWJe{q>d(3-WKi*NliF?#3_U6fqGCr82~Bki2xP{lvHL6|gY~h!anPmzpyrHbj}&%* zrPn1^OZO_(P3Q2%Dw+q&CN0Zw*EU#KnEc}mdv-Rm-8A{psk*6EPf@KIj|p04WI)7} z5}6^PmwqktZ}n(EfoMR667~0?i#pJ4Q}1D;43mJ#n_UdEK>2!3aoL{+b`uQ;yUW-v+q7> ze!8gNUxlu6NhaFZ-@vQFH18t!>6(y4#@Cq6{goYbXhx%ud$PhS`KDWCFh;{|bx6d= z)zDT%DocN<4w&Iix8jA%k7>KTw)c?W`E$wXt727Uf6s~Lfy|$TU81zW1!md zX@G4kJ3q)@B6DS54^&F^!b<*fhWtSC`*>d%p1S2n%gjx0z3}2~ah+Q7+YhUWMYG8cFFRvb?MEk&6&S6>fK4H+izhaWoHra9(l4rXB-CUzRwxh88 z0m$Rl8NITemRi{i-Tq}nu_z+Vn!nhyh29nM$)-XHT-jwq4|A=LJRGHCAt)XyS81(1 zm?`Vg3Q51(;WdRMLKxs9MQjuOjgAhxbxW%#D_#(@lLh05YLn2F*kFIX78QYj2O$X3 z#GRiN_&OzU3_SCngcJw`CDVTmO|p0@F&uE*lgIW&Jl_&VG&a^9hRsa%wA_Zh4G9f9 z*aIH9PJx6wx??EHm}ly|i4sQeo)bR*Y&4^f7effq>?ud&&0l+;z-|4awlD{&C;pqf z6PWnjxZ0oC*Rzb8S)zuth&jAwN$KDA5|1D0J(hx|`tEr8UWbU#nxCB;c>U(l#Im(A zVyKLJFAfp+3pR~gp)<*C!FeWa$(GcruC*ntF>@vq>#%@Pou=YWF3!gkOY+4p{b2s8 zTpuz7pJ!?}*ia^B)oK}6U099}+Box5+-kYb|EXY2D2gU9iugUd?z9ujVI2$7aGkAJ z))Myk@VDkGp0YJj%*EJzK1+|%S^q6|XEB4qj-hk4mf+(VTnb%MuWO}@LR~d4JO4I! z!~%c+SB!+iU3MDHBBj)`kd%8td+mEwENZcXOxbeNj130eC(5keqBHglr)=y8!BGRQ zgOdp4@(*beVJBM!8o~bKLY1ZBcUAbs6y&zC zy7jbu&s@nJ{KuOz`*oBWx1|wr;-GECW_dXFk|;E`E)N9qkH|KR$7kpKrf*CN{CwTD z;^OVlbermBf0Bb0MG=;UxdZdY7O?)FCSCJ}b*6V^R(xso&>%EakHtbdRbO9|X+#(+ zh&4_{%e%OMZNcvL_U<&I9{rUxPK6{S0E71ij|>dt3=9C+=h2MD=%`5yx2CGJ>h5-4 z9=-}gX=&6O5Xi~49Q(vGMC9S=*hW!)j5ic7j1|Fx>u~@8o&zk2m#jfDC*Tj9tXgdT zc>lxq<#SylaPIlSZN6Bue*&sD8ydvn!f%%EW@PIf5L@X~Rr;l*JWtH2#Ewn4oZ>_0R+HsH3C`e!NKY)$!@wr2wzL}H}=0gMx|W=lu$Ugh`0qS$-xj=NTez>$XpGOU4$GPWC0={-}P zlRZTTVI>=K-LQXv`BiINk2~l!^~sy61b8pD41r4x!)O}HWSZN9jY9qG4e<49b@gg# zmChy{w#tl2+pNR!zmSQ)nq7E(vcv4<$fnF}UOX&iIY+jj-P{_nDB^7T)mF}>)WuSm zF0$m*9BKa2vE5&G+Gcf)t(27vbP(EVDlxe7DxKg2<80c z%`W}SA{$z31}GaWA{D%2G&WYeFy+fTdmVpL?&_;g+0l^Xo40aJfC#Yci6+pFlKl4G zOo$r3+qN0dv0+pHf#b6VQEW2$N#KD|>utgjvadbZy+Nxt>q$-)*3P1xS6m{iP!L3? zSyjAHsva7Ye5D%59-B5z`>A}%)F-KO9~Ehq;yUIquuKscl?9^a(rasI-puwDGs*5W zWvde6xDkaX?xSnfxm!s`q)&!~PgPFFgzKi&xtjz6S)j@+n<>i7&7`WVJB#NAItCTW*dKofhy#di=3j5phaU74Bkv!GARLyb6p3P% zCp{=JQPY97zMzZAZlu6N!4$;^L$+{9Q#|_`L|4PV)zU0xo)u<-lj}#k~2`z>7$7hc&xnhSllnW zM&P6|T0cWF=Hl6EcjLuEw*MpesVppqZlm)PZoKbD7f+topN?5#Rw4&M0~u;I-Cg0* z;%-~-&kU_)t${3px5Tz?_*2Ofu49!sgE)#5SPz-6Lxx`xmdOnab;iW?VNZ6xBUvi=`1S&HHb)2jE(s z^_Esx0@r&B&aZ_!`qrEk003?h`L2Y64ffy&xzSV5!jTr3(d#25KYkm_&JfQSB|dAc zOruiu^%K_hEBKXE@g{6=HHD&`CSx$+9{@9cGk5?pU8ZfcLeW&hUUd1AfOBEth(<$cFN1*y?B_%> zr~1-9W{-?s>qB!FXp_Sw={am+S+54}(i)`aJAK%bjUNB8r+KVMFf--O+q4p#_z}~o z7RVY=q{89Fj6-$o*kB6^HLl3U9%e+Z{evnhDrY%PH@GWBY+CXcE~+b4>b( zLSVS=^JKEFIH~kajqV6R3`2VIy*?H&x#wU;6g{ESBP9{rzwLR#?^rmZJ-z9KifD=o z0u7dZ$>d7*>U{^PZ>9IVi@U}>VdID&4+%eX+dR~mf0O>#<2qpjjV1mrX&8`yqf?W1 zQwZ7-^7RpJl8l)8wf8wL`QSCri6h&IE7|f%G$$BtP*YnuJw8uh??*$xjTfFc8WGg8 z@cQ*rkzW|JY)l;Fb6(M(3v6M+KcdxkaY5`ZFBQWUi5pY!t55jTOFHAf9J|xXfO{1- z?EWkML~Em5^?!AfodfIJeb-NBf^#;FAbwF?49mHyO}9pNj<UfJd%d{Xj;mmgWTg{RJ=g{G{5ySrE zYdo!Pr-g0e5&J#mzZBQ1CpuN%w^Y2(u=rsfcq<4@mAT{(3p(E0JZwUeEQWB&F4B*K#|Cu|_J?Gv#_r-a2-sVMSlG*#W ze|vq``m9%mxxXbMs{Fl5xe&u7eGzCqO$ECLmk(xjdFw8Pe^pb_UXH`FIzQ`aTVxQJ0#H+8UQ!A23UDRn7RKO`fK}HfKYc zu9}&)>DeE5Q&mSoJgueyyb>`D+_S?l{Q@^x zl$3bE!u>+-nV@@A5j2K50YB;)BXc;ZVtx3QGC8bXx9v{lCgz&KB5d>~@_6mwxTZkTe5ew}eu-1l(%7m6XHp)%Z0@RG!QoO5DRN;iFz5~wqqrAAZdq@Fqh z<7?^U#qB|#e2#=bDGLgr{njTh=SQg15>&qo&COL!QP&e1zPh)y%=MqsI4g13V3X^& zM{C8wxScMQk$TeLcKwBbw!zln?^4xlu>4D~`V92|iBoHD!qrElQy(Qn5^<=dem6SKdxg;5-?Q zBWxE-dHgz*xKXn`C@^q;orV$AxYi@sZFKw`Rz5hpaUh2Ex`{*6^)_(wk@6`KkaGgd z)7OOjsN9>}`lCsoX;{VU5oqCE-mkmNfLB*~nVq>@j%8HCN<20C>5Sded~(dfHy7f=bg7@q%ptZ{TYqtw_I)`=IF`Mk^Dw0tL8bJ!wv~^V*XOAv8UInw$2B!>y07g|*2z+O1B0*SPT30o_*X=6o>78w z(UYTx-1^298R#H5lqF%sBg!PTWK{f?(SB zUmkPgI?wNwd}x{x)$)q@EQ5QkDtUoKB0^g*I*j=nRz1I%iYGm7U62!k0Gd=sV0^Fk z{RUYn&j&GM>V#6cj-<`!X~fhm;jQ=&EN>;lI>x}RQiH2)W_!yf9iGQs8@XlJ&fTLm zqnn!Ft8LlUPZ?HsJlopak4hDbJ`gMk)-2*#BwDG%oDss#G>}Gn#P=qI6{&JTJY)2u zLd6h((lDNwEpprHRMcKVMM%2o93v+y7h4h$Mx&sTPyjU}J@*ovp4Iu0!6q+wzE8`? zGc_Yae}bah>c9n*Jgj^Z`j94xHt3sYa)4hL{h3Ld%eC!3fCT@Xqz0R4L`C7qRt0sQ zZ(JvT5vh;Ka`G`a0RaPD8qk1Hmd_TE>_r3o+{vwFf?jT;KfhDIP>_-Ir`!5;Qg1-} zSdi)LupLg#oyI*cN-bvmmoxl{wvve^8G!pY<$I&@Jr%|@IdoYecMtG<;pn)6TQ-8LFDc=VT6NUzK~9ZIIs1!MKdXV7N0sg&T1ldYHP>ug3H zzdp5rk(>rI9brG7#)uoOAdDMBeu#z&az834+uyH2*Wgi5;0$ZeKAPMxpO1yDbjZ1= z2zEF-0lT_*K71+5coa6UX_I@eRV6PpJ-0+lX(pO}4k>g>(bFxu$DfnGweE*`B#$=T zWxIOr>UO?l=c-XRY4l=;xV(`wCPbXRNsO(7_hj;tQ!)(1Tv7KhH8f(H%gSk)$^)C&6iFCP5!u6fm9}aCoUK*WO)D%9&RT;~OoiCBBz5_=i zmk9yU)|wwvmn7)nhz_f4W69>vKT!uNdqM)UzfSbtXFFDWbbMKsPWYH(GsTnCsePEI zM5gQWWz34n9@x9)cfV^;`x*`O)3JJ&Ui0#^^#<5O6DM>Wol`lWs^9((z>CThs8jiZ zIYQ5kcxfeXuNeqNhEFbaqFOLuo3T=5yLgu9rI{_a;lAx32{}rB%Mu{K(EVqRZ-#Ua zPtK`~Retk(3HnnLem$9=F_@DxQqiUonUNIwph8sces0UO+`Jmh)2$yE{e5t=TjnMQ zHwek>6r9qI9K!P(ogP=w2dTDsTVF*P z?BUR_+VIIy_{z8E_u^g_Se^>~U%UA|L;pa}PtA|5l39(H<0%s@m!)t7&h2lX@hB9x znX{B;Yy$|5eUg>VnXyg>uBi;nV#E}k?;vESk2=~-o-BKvf6e)aM?8~BpU_lL$*zhatyWolf3ORC~I9{-FER>ZQL`5><fWK z<>pgPUag$H5A@M-0T0he#4E6P3mz-aN<20k#C?J0G#DQeBW4f9B}1h3F%%##&_NjF z9O`%}t?3$I>|f3S%g{fDOe`TP^3sd%X{$fnfcr}*nsfU9jCW`xaP}Z>FvF%_`({@$ zIPF3ra7_B;P|NmEuBd3*CkX&AW`AluuWenm2Zs^*N*6k^w?(C$-6T(2*%1tR{Z=@J zx2{`%=D6H~%?;OFCn-D8Pv#&5G$9$f=) zn)ODH_w71r)GppW7n61e4&`HfVobIs`Ov0su#v#rk-7=sC@r)FsE=!;HG=oLR6&d^ z<%xo9NES+4TU%eRYM_-)_+0;_&b!brAx!KzJ|V!q1h9>)=85OTB(l*lxS%tD+l%yk zpD8#RADae~Qol)AL8`a5lQ`Uj9Y3p_0snLfS48bY+7L9DNArlnA|5(YBO?rj>6XBG zhqQ>W1~-s@UPzs`ntyJPHYwKb*q+A(OAGYLdnFvDfqx+G! z_U&9PNNFg&^$eyad{^oL?#vVnyN#M`x7)v>pR=s=5Zf+Jt({y6urq%ed+u_G4wyl0&V&2^&)& z6f$oDRK3#PXrw;WhLPGDHLw?XzO^bkx_|0lbqN+q&8uX|oUr2u=*$BEdTPuUB*U}H zS(C2 zMYAnIsf~@DsGR~hIsMpw|Na$`o|2MIxxZiTSiWWW9SRL)QT`tKIEj<-bH#T&9F{e& z^E&J7L0Jo(y}q~7=z0poa*>K`q*Sg(?5s;%&elcjeB#G^TUr&I#?@=f=R#+vJab5o zJ~#ZstJ*U6BbH9ABWj8dG~;^HJ50lJ`8V5Zb=43)A@*BHT|k9IS&+7xrfFNZOqPE8t`8nxc68dRZ2rM z?zPl&Si_FCwzh$`q?zd%002k%JfDn>=2gz3MWwpM(`?f9{g92VcEc07#67xgQQ zk4mli%mAsQHkI~PXNv~gT()^N4Hfnx{>(l;5~)Y_K%lEVzJ5#kK3SC$nKmhBMZ!IR z3?A`oya&a&hStoKp%TFtvg){&`so2pe0HXY$4tsNjhI|7;r-7-#>DS<_fRkd(z&Yp z_81AS{lD30{>}eS{u%6gJH{O2%`m)lZD19g9XVz;0U1@gUp61@dMQmC$#F3ydsM#gm<4gb3gDwG8 z4~HW?)3^NUjC$P~B;^Z{)5fUZa-xqoi!5F_l&_FVc=;)s&25L27{!a_uETH?Wg`GN@@+*tktGJ1>u%OSJG)is zBVyr=qN95*N8J6!JEk<-(IzENUxl!e^MTZF2LHDX*dHrrvu6>=7GrdWUP}r21Y5j0 zS6V)I+twPn_s8V+)X{4UtHHf4{ubKg(YjsNCtcibU7x%oe6WGfz>8M zPNIml{1=}RA8A^skz-hRzaYAz0b9e9hbt9u{)L{4rnK@nDErdgJ&-^ng|CFQ_vvys!47R>n zRBR^>L*HpbUr+5DQzww`C+{nAL zb5ju{hf`<1@eWsy&35!aecr;adYj&X=Nd&GdD#1|JtDgiaMN)m{7e0j6v0#jCR80S z)N(P6J5|v78p9Mt=EEHF2s?0m%m!xj9BGl5f`JTt5vZ{~Al)}NWq8rMN-BJe@UOS! zTUvT;<-_!LCP7Q?Z9IJ+epkLAh<){bDg55KB!OhsDvf<58-ld$fP42trO)ELmQ{J3 z*VW&w&Za3j+C;79>yMw5j`2QPh($`uw&RA10uLkMp|-KDf0Q zza~1LY8AMOuMQsp(O$T`KT>2(J28cq zhy{~KXHc9rujaG+2K!=4FRv|I90H1fBQXOYjgG?KAD5h5)h}T0z>PFt5Z-jUcS+0$ z6EJ9gr?kY;^JHPZTM~EhKc63&I=1P)4*G?iIiAR11g=&$8)G5jX2Wz_tC<;el>urmXk%b+&6^M{E$#lunuz3nM{ebZVd@S9fj2#Gqo)8j-`30u z5KSGbvG-tQ!rrD?F$IG2ZK5KilrcmQfC6nZnOf!@HRpj-3K>LjfK*w}sm@c*Vr=YM z?M(@WB{Ecx%t zZB*Ma1stSGFF21>9&kf8F__e@)V6H|y*&cP)q%R)*=R|ae9sKj&IH7Tf^*y`^iIk+ zP3O0X`FVPrTUXOJ3cLVO_XnbBoqvA*OCP6X=lgKwVB~V(Z9uGOQU$WPnUu1^g-%MU z)RjkIdWdPBCrFp_6%*?R76P@LJQ<8p_uli^0J5$l-J5mkuNH&2=m+di$1h$-RQwsz z=r|>q-Hozp$PP7e(bmFZU}0(7=WRE)3Q49PLKr@8{(&|o48*|<&PmTF%<_h_0|d5G z(JV=t^whUVsT11$V~e&t)R726e}#hiNLS261z$HdlGvNuXHBBPbcBRF^a)j{EIo91 zx=8i~8mr!dw72B!$jMT2W7hHsb-;TRO{?;|!3*jIN|;@T#79*Q{c^l)nJv#IQrDMC zWz6E}zm6F-H5vxY?>KQVJG!605{TO0oWF^G?I?B#9QQuPF3&|OPiM_o6C(&@yf zao0vCi6V%eaf<6G;BkBx)BsKs3p%>17zixCYMb+~0Co3T3ICl%o6WRzWH_UdlM5@T zA%kR9yLd;AcrtE{ZaEIFFBX3J5ZuoTnG){oz(sxK4SlkHroD29!TRw(!iaF7*EUJhl^YcTM-z&n; z&5{@2V{|6f@m}?-NPQ-llIijtAx^z&7yFi=1}*1X{>yG&h|{oZI|x$}Qu0`Mm@kBc zsFpWEDd)|yGT9k)(Gk))N~f(?TPLp9ap%&f*ei~e+%R~~SYv&cQHzLIZeQmm=&*97 zYYK52odO3N*zItN^;NaRekv$M%x?0hd7WAxRu+|v3~@#f)nmtaJN9~L_owp4J?%U0 z4qbeFXn?Uuwa1MS4qq1aeGa)BU$?jA^s~weD*u%KFvFj%1(P?aS#fo4?X|S#5~$Pi ze&I0g@W?5~Dl$a$cfZ#X2o#T8q>02;FpFm2Iq z(i70D`cw48Ih$@c}jLCi19f+$UW@Yzf@dV2Q1u5W+SgrwF%#m z9yWslWJYFPxL1N5MIeWJVWHt{^!_4Yrt0{l8B@k>F2*;b3$?v5c~jehChw4KPbV?|pJpvv`%o`O!7#WA6;@_yXF7Eek{pgwZxYeJ zAIT>h?-Fh<_5RFFTX$iMg)(xCUr9D;MDB8DXZA@FpN(@FIqP&!s_SX&)%scGX5y4Z z+B!RC%G(8*f1(7EGO>qhqk+-QjvfmpCe@fB8=uF>3&c`2m}9R9*LPI+GyiC_$bsB{ zWgK4gQr5y>x>HFE3_w3>T3bJ*UuZE!oAwGvch_+2u(PyKS9UOEOiXkwD`;n{c^5^#cM@0?UwTkB@*h} z@?CYht|-Z-4G{RVrbCR!A~?T0)_1qBopF7~D7yZKZ*MiE;1%o;_!a%U^LJ1>JPonl z)S>1vjZ)8QaiFFwt{v6S@J%nRDOGkj$^2$Z%fGOsuctyML`M2*N}yP~17{u(I@1^! zk!b7mv=;z9ajsjInVsO$3kRIy0kT%2-AKsWq z!8^&|2I_ohrhaP*(o>?AOU{w|~3->>|3>y)Io>q${^8*({mojL;P5n954iQzJDZ^8WAk z?1Sor!A+k^GVQ)Kw*06s-Dq=c1L5)W9uYl}N*h|4d0BI94@V>vu~;mc8Qmy3Z*C_$ zIaj)YQ{6R*R46mmlgobqrngQsrn!`7>c2APFUl~_44oCOxk! zFK8&%2-m&fH9q;sz+-F5bTv!1SlT-BCtE*u0A&dP+xW%$jD*D3R(h%aD=hGs_o-%$ z)DKi&Kpy|YyLVQwG5rs328V=^9C;Qb73lT@UGU@px z)yu}glWf!kB3dHLO@Liv3p(aC zHIToXoP=cH`m@|#U;<-k@8}wLgd`c1e)@eqS0S_LgbK)%z2icK7(;{l2i*8EZ^I2r^UHfh{d)RW5&I$|$xh z^QX(>5PgH!pNkR$!UGeoC{8`Mq{ph~{v`T%mu?}E*I}z(t#n<@Vsiw!>twlEnpuU3 zyv>bBU|gRy+XTAG{NSf19e`6#4Wr^4;a6A|;ZXFumId25yn2E{Mz+%gVV?DHs69zh z0hzrvv5GG=L>nzLtCNIQ88y-JH!^X(NE-;BXhs-G*i1gd!^<`QqRU!TRNjmwaYT1z zDD{+`HZ_@e6s8?;I`cP^UR|B2<3|vV1{ODtHl2IS%yTGl|0O1>0;I+F-aN$p<^93$ zYQKtOKn6EB@*Zzg?xTll4BDN(nl=-0B`Ap&ijUq#MA8=CF1j`%_~PjfED0>-tAbbG zY&p_aB~9mNwWUPCFwE{HI9WJnxlP1Z!)kXn?oG@xU$fG$T6eDxgI4$?rO1-BG6E)p zS7G4i#;b3Ob=|2V2)FZN@>#YlTEb8zV)z|2JBh|XZf`xXH52*8Dv-2NP9@gJf|%&0 zSa-W&$Ewsx;ggE0UA93Txq{{EN*rjn`XsgZj_L+`{qzL9wH925(KI-pbae)r`fQ-M z2N4s;9}|Mq!<#+DS3Ce6nvO2t7!aG7bp7s_EUWK|SSK5MJ0EMb_vO<(|DykD#t_fD z{y96j4q4qy*H2hr{;y&Ty)e}=!DIb!Yadp*)qXrYI&x6@^ve3GF`|(&DMY_O=zA^R zBkBaYr)JU}0*JjDpGDMa)AFc9i%(udgRzS|ncn$JU7~m!(ueGaT+RnV>T*OLqWmw* zCqC03&aL*%1b?vTS_#guxM4{x$3ED=-lW{wK%&=gc{&9$IVZ>aFM@S&&SeF8>aH*+0iAr(01CjmXH9I=#IW4RgRydKffx2+y>k z>Q#C24p47dO=4Tz!hz~t3+Qy+31Gb<5(+4pmEUWVY5dwodRJ zSYD6G8s8^y%)YO3zw;jR-1zxZ!E)&H#1!Z0?hmEvTvgvW!;gf>^zCeQ)@4*)2SJ7~ zL0wC{U>xy~H~8wKop@c4lvR)g&KzfvoPU&eUJAY!x8|3drIxw^7WdaWl4uq*B7C;A zlA8*@54FA!%pwYm7Nms7*=dx&$u+JogU0U@OGy60o=!BLg%81`hCJ*q60Rg*P0SF?4@E<9r#d-bYVk>vw3j(m7Jow90%HlQbB*3W#HS7q|_QtM{Fuh3$} zf}3R!ZG`J32PPi31mu+(Q&r}1{)JQVzw1z7q30rto=X~!Dj_fiq%(6Dvn4AB+X=J> zZ@le!-mzZln{OS=ew=qM%_tJ_v%tP=1zgk|Al-i1f|~4m{-F*?iIpqnGf|^j0!Ip| z5Y`BJc#(ab1<30cI{C3UWy{!e-(n%dI~ukKVH~oqskRXa14b7%cQ>SyvKR~s!=?mG z6~Cmig)_d>)idyZ!Wi9VHR)%rUiuHO-}{ui>dEYl8<5vhN8 z2em2wlbeU}sWWC)9@pUq2e*~Yur6LZ8<9m`;HL1MT@mCc9wV!g7)F&inO)(!F{0;G zzIprmrVm+ObK@Y(fjS|4w@B4wx1E)#7x7XPkvbqWIyBCB%7Up z_lK55-!r4Bng{q1=D5=o_jo6)%PHJAVKSH0~^|MSD+WKmyB zic=zRL09ib>%omzB9j`6ROIQ`>7iNB<6@1a0hdk+M<0EX>O+sLw;g@Qw_7pGMzlx> zy{?c&!wEK)Nu{~c<66Rp>p|l14riU)j|-AsIR&EGMlo5!Wa=FX-l;aEi#W^T1*v1_ zh~ra@vZ|;?K_^>1eSa!F(N7hVM+EnL7>m=jV!30fSl!vugRxdPBa!l zN|WmO>m3;)L&QK+HXJeUA6LyP1{KYysZ60Z<~C=gPA@CVHc;M*5w?4MA5xBdyN$S< z7`&q~V#|KaoNO&)w9OtK%J^ALAh|>aKSkz#7l2f}Fdgp|f#$ulLtK7yW_od9KvT%{ zYg3vK-|SqGilkca)6uVg219apvocgaKVkkXiO4_8z6!r-y`#Mh{&ip`H9Q`E_iq^^ILGN|_J) zfFWl1lGyrEDyY`Qdu=pUQX8NiS~`a7dw~q)Rgc=4hnAG@^DV;<(qqz%h@7d(F+||0 z<0aTyKZ+)3e~QB3q4SV8tfeJR&7Cjq!5anp1R=fof;^R%vbM%4GQWpFa5P4gj_0ek zUy1{PUqJpcv23LM<>kb|M{l~I!?G$z4;^)K5sKJS)y`ahsGd_~1c!YIG=UO7ifSia zkYL_?cWsP!G(SNcvB@x;hrF6vzJ`?KtwVS_oi7#l$6Y=~m~b?4HC%0n9N7NY7Fd>S z&a5bS=vGj{&S5)WOgYe%Ao?g*xW`>oB*TBp7S!_t5018Ws%h7*GAc}MAGogKz{+N>q zT2>Lle7-)%6dMG|zzrVnQqPP3Bjo+}`mUpbww_ez;M>+aSsL(lvFq){+Du^Py7s2V z=;4j|?`1)xh(u21Hi41_s=zF)>R`0`SmeeEF4`y%b#@ZX^=f#GqIg3xaZN4{R@*hO zSBF(xXv$M+;@vV8G zj?h$}3()z5!A>JGj8%@(s<@`eAmVWv4_5}k-34U#8j}+A2M3hsVRFGL4B#O3U2mD& zV>WgZOc2ocFLpF#+B)Lyw9S5NapRf}PyCf#+<2Ypp9_RjIG4Oy+v{itSg20UJ@7D>`fetYyovwCPn)lZ( z!ZEpY4+DhF|Cep?|FT>DKR?Df*BAaDrzPz{dx>{c7I!2WaR}9~*x+5wvroyTV`7Od zxG+ZrCT|5=HmW<%+{h9z)F>vv_E1V*R#S?`^VlB9Qe<^AQZM~S{q_vn%{+mE!8W7! zXkl8TAChIE7qw}{_ygx|Zf#G@yeyX9U*A4&mT%S= z+V3rW0r6_~51?*QHc~B*%SQE*s6Lr*oYlGqeraujquz^!Na+PL_3T`n(c^N(Q9BN& z`3$~`=IwwGw#WzTbR-tHJE!SfoceFCO8fe_Il%9&`YzFU3?3MXa7+m%4B@C4>yzjf zLaHC3_H^e@`Hm*uxU7^Ols@f@;%adOwnmg)aFgYEvp*}niKQ!8N2b zc|k>K=A5Q(rd&Zy!b#YLEV||&-q$6~Ba58%N#E}{5>M5ox2x`PZ4wyMD$oT0G+&+^ zX8JrFD_Vo}Bd9xUl@bf!nhoLP>#^kS_v76gW?M_J)=&LDqA+2*l1uR84kZx_#Bm1K zIC+i)xjXWS&EHgazKE$IqgcUi;c}wxw~enYH=XB&yo{PZWOR%ZTG5jz8&(srbIwBv zt-fyTXoS~nPizYlE1<<%`I|?wa4t=sSNZSKyrugQEavC$r8i$LH8tqR;K;)&ITPFb zk<=Fl)LpB-I7S68aV&#W&xR^)&1`^1mc>a5f_TqCKM-y7KjG30K0YG{PLd<^KMx_$ zHeV3i%LKULNBy^vBKb$aTXHrQ^QKvwR}tBE@e76Fn}cg6n8bWYF*X%Qzl+XkUPDcp zRBy++3U3Hv?4;>;4L5xqb5~NtojtkT4_;W*;H5!E~1SOZpLQ6CFnGy$2gW$m1R3}?4S5; z32JA&%%YPe=YA4(M7%3`lPg6Tcmln8y3jKsQjA$+s1TofH0uxgyPD%$b0*mseMBg^ zq}0-om75i}-le%B8QZl4Li6y%RaLGDk~O1VWZxq%%j!i)H>~>;drCrseK5zJcl(Z> ztw7Cy^p_)U>4_jKe$J26W(bqsO(hGmSCjGy?S{>i1g}8i3b~kRg@z)0xArLNN@J@E zm4c1cC;NQy2Y1KoW*MW$9oS&4L1f*YeRMFO`gwqw9`* zLCX8%l3FVQm*Afj-LEa%iLWDplT&c<#z6G7l&MR_R{^CmrmyV)=LxvW; z4YT3gkQXay`>_!fF?pQqhwLmx38kDd+wuBr!-{gz&|jm1jmQfD%Bd@z^}+SH9zrSh ze|X&M30(%$bTmtlktBE)QKHMG;?INb9t2%-XU`0U$;IwqdM(8D=J`xNsCu0hg*0jD z?k-hrZ^6R<3YV9~@4jq*AhjKcnxfysh8#zV9^W9_*F0uTIpHRn-tIh2(gvRH?_ZdV z2n-O1k@5`|kTi%qj-$}x6itD{N0)%G7$muq?~Csw#rIMO)K%C}Q!0ru2&nflatn^g z=W7#rsQHM_M%%L9pSD}ImO}2vnIm-=e`w2z%f6_9RL@I$FofiC3&Qzfl@_9YlCx!? z6#P>kYq4W*jdK9gEu2zxi3IJH9H1B1a*gVIMO=W(FbiMcTHIi7qwj9;(^RC1asJbm zOI!`M5*e8~d-$4D6u>sO1ad|!;RzGGy~U;Xg+Xpeo@;TZmMElgpSOg53T0Jsx3%EQ z_5lum))sZ&dM!gh=&xjLnI}VLyT0ZJs|>t#SZRtj z&vUS|tG14m1+i?#@T_HpI{kg9o9e>yf#YUTmE%F>M#y;7-_HOmfXsd3)5|OSKSjTK zPVK+r3Rf9}DEe;tI-DU(c87m%EnDl)b5g4V=B!JvkaV^RZ-4#V6TUoI@v9QFCSX+( zYCX*)nqP)jR2XtFe(9f6)jlR}GvC8jV$w3uha=s)^cp*d@(SRx3!dYO<>xelekl-e3%%nmOPDm?kQKbvJQKNo zdUJB+4mZgz+Nf4K-MSuWl!%?9vEMSE9t6=P_c&2dWmfjh?s59)uN+9#*21$mkARZo z0WRGnFY^Y}%+$4G^I2XQ44_rEd4W=w=5yH8x@BmaT&`plt}@5dcD2-D4@R9NDk}){ zRpYD_`0*ysf#vbOn9Lw6ZaM4@K)?Iso#0dJtv{xoG{l>ZpS!=S|+d#T4|EC2du3g*qL3J!@3&_9kM}th1dEEnZS`^pvc7fs}~4Btu=ffb{2E0dpxc+MwzK zy1lxy3;*1))f`wo2V4JCBDBvg!AgwUxV)llkBWy3Q6xgt{8H}Y2^*^XsQ{ftqE~fv z|Bk@QM-cI&_+h(7|Eh3$HsZ+snRy$JESFNnLNSRT5t_uJ1gG|+aBtHQ(s%ud%nk1W z1X1*-pv}#-*)?!w`7D=VaxQY2laZYzD>I2q@4itq9-fNe@67xCoH6yk{jwb#H_~wv zs$Zdx*Btk<7TGN$Sa_KmhIe${Zz-^3CgD*?VaVa{gF5~T;C1t^_y~oRZHCpJgZiEa!5RsqyEb2TK!LJI=b;ak1%YPoM_({IO_k z2I~M!&D|N}uru}@#HursyM}ttDEvGHT1V6i`iRyCN4+HY&9u|O$MqR8J{B_6XK~?v z@tzX@T-n)vGrBOPCamyMQC35>oi#ldQ)>5=ER=$pR`H|<6*3_tKxJ6fC?8`J zyrE13^E$_z+TI!FQ)7HQS<;U{{bSyfe^C;bKBYB~iB4Z%({rzj-2Ci`Z^=&AhcKM{ zv1#kPojyl6@g{2iM`-s>4kVHvveR|82W($pT5;KG4PAWy_ z&yi%%dkVDusOM8HCgLPaFAVdT!_jOgyYhXW6Q6`sku^wtds+ErBt={#M`FM3Tp1|LBcQ0MfMO8u!*%~@t zPxWl?+j%5PqYEk8lPn%=IqzfcDPWLSUcQ=n^ySY|`;o$k{!YV0VxRTS)Hq`-m0WZT z;GLRs`v)Tf8BF!Mf8d|1{F_BzSbt)K1)cQQ#6it4@%%<9ORpd5SGw1V&ZCj?%MP%ys~`FZO0iZbk_fzmB-zIXiG@c03Pfn83MoU!|;B)`-9jM zGF(1Io((zsUwoh}i6`H%e=5A=m&pDiGdWO5x?#~JE|GML?+1hMqK$C%lK%59|1lOZ;n%bj7xKWn37;v*MSD3jyp|pqMroHayan7 zUo+z^jDVt}%3W{?#;^2f-`F^W`Pr+!Eft~uLwDMC=oiKLSCx<3LXTaW+gh9}UFmH# z=2>IziQ4s6JK&KrJ?u6kJB~LIXcUQ9MC#=zdBMyrxz6}%eEsHh)GYEw=VzyblQ-N6 z(+saU7z?obY~^LDnWYO7vc#_*=u7|kE*-Uw@3}r^zoB#{dj&l?bPUv6{fGBPgja9V z1L9a$N2#9H(tuTK4siCnBx89iX9uLL$Fin+9JM3k>T8rJWk_nJvu7%WdxjA$wn2d3l{lbUy(=>xrF} z3*L5q05k5P_@LH%QwBfvlPJ#Y#-O9wH5=esa_M@*#&zwfeY1s@Ech~k8y?rDF9+h5 z=S+idsZ`FJyRp)z0+BI+$bgMfqebpJIKs$*%hyaUJab`j8aQ+LM>8qCHtXBSI3iSEYk;8B&jf#iV`hyyHZG>=;KZ0}z*=q6eGrA$> zwe)BIyHB>=)7{OCM&l@7T*YEgPw(Qq>>PsMp%Mmw;3qO*@(Q2C^it)ju4Px$kSD|| zLFGLF0a;d$O?o!?q+bh5-Q8KP+_fGv#F_}~Fo17jkQWdH#aQ>+FzR+`nSs7hQnm@p zTX#w`wKXLxR; z%4w+-Hzdcz%s;31M%_v9kZolf*OoMu|7)=Ky8cwN9LsjieWP*h*z?yncuy>}W1GTx z7l#mR!+_*!gV&p1kItg=V`vc4no2N!FP&)~5_>0n_u1bGdiaj9lF8UoY-I=5azvuH z0kYc`meCSFI>Aff+N9PLL)Ln$(MNuWZ!=uQ%=?Q+O|SgStj)EBZ*6seb%L~kiEI(> zX-p;DR1`Cl1m%K)b7G-zebXL}%3VktH9cwUI zLBN@hb{|94{CO8QHzJ@8)%4q@nySNxPZgiHd)+N2^^WO|c??)4)jPQ}7C1<`5IjnE zo(+aMpJBsxg4X*{Vyb~Pp3d68PFfv2UVU6XF#SS#kUK=L$-?Mwm!3#0rKLA-d@A-s zi%uUibZ!1iI(6@?d0#ViovLN&wDyo8%KcoC#AT=ntK@3%OC%Vi7P;=+T_#+5Rf&cJ ziyE;)ups2fr{ePRe!B*6B#mAnb9P|``?zxtq~`9V$NSEH+uW}kgT`j&_@wLdRK+q2 zhy40OZAg%u?dNdJ`0T`xWxim*b_%!>$*HCIVdl3IRPseWGZunc-%85?li zQUPu(5I|^pFI--l1myN<>pAn0@y%;n$}evvrZm!LKB}%6Aml8oxX=AZL7kH(O^jEHnqNfBPB_ole)02s+u#QobFN+c>Q{peP?GcvxdqzVMPnT5r;>n|^vR^@y zpV^`hhP7iE>vh7@42z5pl<~`96uLtlukH*O#-;gg>ZP=1Z@wXrTy^3d0-B8iSVkh& z>*2k3&F=|$rT{Ub-_T=I8^w7N4-d=xw)O@I+p~$ja>*u@C;s@D{YB)sr!jr)`jq)w zy#F``Y}RNxB-t32~)hIXclDEX0X#)lCqe#J<0j+um&R=S4Yrd6DKDx^ZBwXcYi zPk*^-%4UGPztPn<%&qKMUkBWg4B1QajSsY~ksu^6~@ePguOOUwBixCthGBXuw@eLSaKJ?z&sU`ToFz z?4IMIzxKWIs^ohqDyLMc4O3g{9%_QwdVH_JtGaij!QJl|$Z^J}pVB*+m5#rW^>^x; zawq@r=)RTB854*+(~BlAKog= zsbg=dGrwKx_y{a#P#tg3RK;yDXz}W2?e<^Vl{ZA7o4FB4`uaIKjuWHqxFiBFjQ`JmK@;0dJ!=iV7>z9rODOpT7gCopWSE4G#C zV*(pcZzO48cD|sjG{J~-X9&ekWz%WQcXhy)5%#Jn<%3*@9$>Uy(1tXNwup<1Oi~$hf68H1l;T?z z2J5%8!VE`$Irv4&=l9mU`TYL(6a4#+U(<)^S2LO-n&hJ&RC64fC+?n<3@!qBCe$(` zsN+nRX&bf~%e1DOUl-(-F4BA^yZ8E5FE&A`YZ#|Mt}}UBJotx~1O1VoEh*a^u;t~e z_~UA))h6=E3T0PsI-E+`dbJDMEPN5PGk`LiYxML^vD#es7cDD}eDiU$B87oTjmVs2 zqPC5f)fiik@x?eJq^x_o!qP#QvV+SB>W|RA=5&SlofsSHxR;Nf(L8%QPdHIo5X`qK zlz_7IC*;VoelG+izu)xwI@`Wb^2FLjb{WFE+(9B@^tHIx2Bz@NDb93$dhzFA#!Dkz zI_`z9-qWu$w+f9OC~nC$f3~h%DZ$;l&VmIJ^Q9-mcU_0ouTORBPY&lGOtW0%51@ai zoTrZx8v2g!mXC;RGKp$r-(ezn)c$I(ZwO?f}D zjw4u2=A+tMTcn8Uh`%S7rpM)FI%<=1o?H7-x}Uk`efH)Tqzi%-6+5?+|M0vzTT^y5 zXXJl|C{)r0PTng~*=IVnDF3@x<|7Or0-BmaMf0cDpdx9Nsc+KrX(9$kIW6PrViMw6 zt7=1buzr?{GLPnLso8F(&>T`90z0qe))GzIC_6lRu)cL=oJA={jtLCjuH$IyCz>DT zRJdc~3;O}G&-lru#QbKI@W2OCErBhf(uf-Q9c}UmL`$ri4?dpv0KUUcxor720lqUU z&3qZ~NOvLnAYjQfF4$4<;HS^q7r^SYrj|c({catuPvepw6RrhFcuSByd#&|-jQRKY z?rJ?7@^3JEPZ%B9iQIR7i^-1bOsh^hhQ;Qm+JE*61W2b@gSUg-WfpW$biFEJBh?M9 zehpVkclR`z?b1t~{Lh3E$(bn48(&GC&>whOw9+CUA!Apb#+<4DDLo1Las~Fz`ku{y z_(xQcLF>l>z_uk$sQ)|)>sTMUxO!}obW3nI5s2)Jm+rkgcjGthfY$jwKUq!o5&@`J zy4h;gT&-$#Py=hjfcIOn4j6F;57AI<4EOUUeZv=mvvBdH{n~FxU1)NzkC%HEjR26 z&9Op?P)!}Elo2bCKK>5*lHau0_Pc8jN5Q!ldQCD@XJN!m?}hvNvC&k<+A8+h zRL9*MU!q?MepARG6+K!HX0Mwq=q{1+=8l>6d4TXTO8?laIY#z>aQ0SFZFbSSFVv_} zK8kx=+}*7dhf<1ba48zx0;Gik#odd$I{|{UXmQsNQd|>ULIU0SpM7)2KIh_$bDNQi zm67*dYt1>I=lL1_<_aDlE8D?M%Mouyz0F1rxDgpcYEw3)#bte)JM#A7f%B%6%N&d# zy4N!^y6PMZefihU;FB60${GZ1mT^Yrh5G@9^@wz_4off{H54P;@AV_oO1r;+MCN=&7j@6 zCa;&cK=_UH$j2Gt_qXpJF%W7hbuI^-t<_{f_LcGz?-;Z4>WMW!-d?;46M`@_4PjL-=T zxjD&}Z2%m?X168%(toi|ppjS%z-Oe%w44Qxsqvn($m5;6H z)ERBlJ9Ec9BD$rDJM$)3b|jf_B-E^>{&ZrMRI=EeaIepMV{uY~6_hc!NCF6og2wqD zo)+-K+?!D2|AO8#BB}QJeSn6@?nPKt>otFEcpAq+V3@Eg_ul%j*4%7_hHlfsv_T*B zmFLvz9ap(zN^@t5@`p=^elJWKE3 z^`pDpuGY1Ol6jN%6C^M4j;X67!y3I`>*@YFiBunaa4vrw2_cNnlRIomP-jhV2( zUF+op3vzddI^q^6nUcgd<4uOF5)X*k^ek3za-Z$%Q*Phb5vztw+PQDv6uDF$CBHZB z48XmE%;h~{uBiBfP9}fCar*h*P0JzcD*JC|R9cCnI#yr4a8x?%SL}Ch1h{l3Iuf%f zSS&Pbk==im4#Ot*WEj|8@t*x%0*}~#u@GTdJ21VvTrp?F1oSxh5d4vu7(hCAkHgx> zcFxyyX>`bzq$NAflXvp#qPW{T4o(wBX8RuLYN@=n6kQXv$4r8x8;;g4PzXQCOo#)7 zay{L(*~sMzqo2x>_?pt#0MZ%xK*(m*xVT!Vsk!>a6Ol*}K(CR=-c>&1Qx%^ApAvkg znMw_(@UrFEWA9DSVU4?3_tc+jW|vP&WrCV=CM_oo^P4^kERKITD=YT**len^X?_-! z8Bz;4me1(p8$~CUYbpPh4e0{nf^EVGEV^I+RN`&9H7^Uc^Q~R|vjLglBx~o(hSuDR zY)eu|@xwNWlEY2uec}b~9T zwT;2IHPP^04->!3_XqNWTD30*N96PITOM#cJ#w~oxpOY3C(R7^c&hdjO;5GgdqrWf z{pMy-t4Cqh^1Qt(7E)Q5%^)<_LTaQjOU{!w8lTHTMtc0H{oScV!X7D22oJ&Wj^zo& z9{UHk`bW0+cv#*;nS#BXIx>5s%jn@Dv>%^6BC9^fsxAv~Nop_E~7f`4Uh^ zQWOf8s6mUKU(+{nh6Z1x|nu!-*DYB77_b(UnXibK2S{0A@ZY#S?VN*RESzH@Loub6y6v z@M#TkdCCdtx-CLFsL=q1RZ^k12*iA)b3$p-tZ?% z0j)4GssBcFv@~%_Tr%I1Av=Dvm+rYFv>p?Vy9tcqkB!u4d(Iv9Ww*)H;j*Nls=s;u zpOLj8XvRnwEMm)C)tRdBsOI|AgR25YSO~E2r9LM;OErF)qR<_?X&ds^S4yB zF0CvpD;*|+A_VU?Y_{{<#I513dJbr)ZIa5>A?&M5KK!{~dF4#Ckz$e%yHEXnGYKb| zeJp%L)X*nUxOzcw<{2JO5wn=TLF_YR?b8b}nhqyvIPbSLG5TKEnVze3jj)Eu(xgqw zMgy#^@7isMw8dSU&P`cIlS*wa^m>0+|4oOWIA&FL?EIc&`y`aGMPg`u=&WklT$asl z1?Gse&k~Jv&_0or7IELJtg0-xszwE8BFFl((;1AC`~+}LAHHnRL*@^U3xtIdwA+3h z-Nj)3f{HxbfZbadwD*WWbff|~NJnM*`y44hxj|awI^XB1o7vS*qzi!8l5y#+yY)to zq9&b;1|A#j8{-5G`ja(y^r@tKVxjtw{yh-fR^U-O=+P zg_1kA%`&u!5A?ztnJJPBw`^eN;GY3fdbEA4C66GzZ)l&kic{y|HA zL3znz)i+sxy(xT-U8j)~N8^{|f8djgH-xP%k><(yXMHKc>V1@5jS z{{4t#cF^h)N<)6--9h1nmA&@?kBIKBE$;P1EP=Okc#ZTmpp8qwxKxlP(Anj(M}*e| z1%THdKuYE70yfLsx>6y`Up16}_S!aRT%D+ENaHSipv3yfv#Tp6sy#jP|G0WnS>hxu ztsqGFkxDIn5*lb!RYzQ$8BbSJvlVj3s^K7w;M-k%?KnEUq$EwH25*`Slv-F1C@oM{3V@l>+S3UUX>Pj;)DRx||@KPcOk!#Q8wx0CS^ zUB5f{GVh>scQ$V&&wZ#Zd6X2Rw8Bd2a`qj_nX|+lHmb_`Rk@P>JS{EL2vGI5mHmhJ zI@lk~h}h9XfMoxYU)*a1NuEL+uhu@eM9k(O8uBbRLGOy(bu2vpb5U3WMbrjt)?yyI z*a;46((;c%<2?st?EExrNa8O5@-H5 z`gh3P(;dj6tldxJq+MU-XRN` zovZ$pG?Cv9u0Es|#xQg^=F4bX;tqRF#uqsVUsD8dCN%MAr7yT2< zg!^B3iL&9_r%FZQMjdWJ;OxOI5&DBa%Btkb?w4z4zc+ndNB?YF7tAWPxAA5E*cYH@ ziegMC%^0Fq(o^yTQK7!eoMHeY-G7-Ye|!6raGkOuh0UD|E;0~;l>rcF_&25do}Zs>vdZ$0V@Hr*WP3zo5hK& zWmT29Xnp_zR@8gIM3d`wGpQ*Ec&j$@-P?tXxTe{7C!n=AdwKLTrD2jdDSasjW@f-~#%_D{oM&~8bmpr&UVT3L<;kBvw$ zeQnrg7n;Wn&*BF=*a=c)^PGYaHa9p-$20uHoEi;MFUjOBRx|Ij-`c0|lWokmdVG4^ zx3()DP$`mQ!q;Cb+o*{FSITX{v{J+kpu_~E;} zO~=|_77flem;OEdXeD6=(kR(Ym#TZo+2Gfh&7E%ThT)`i7n`$y6mri0R@(4GfAE%n zc_>INiT~Sb)${oMKfEBfJ%agI%>RRq^8ZKl_;2C=P&mT=;hhQH{Pz!Uj1e7y5JpWO3U_!pOkbYl!JeXinLLMopU!!GDGD$4jd5g z6VbFb;Yp9NcO%K+dFrlOc@?3Fsv8qIfpzB@7$u--q| zF7$kl6pg=BR1+{MnpT==HDNP*L%v3R@khX)a!cNbE<>c+mU{Fv;g3b?iaWDwwtGvk z0Qi4wdt9LC8-_{xd9x9m+c%!fq^WGbyquq5jDZ+(6{Jt&sW*!n`}DShmmutL3?mc# zE$L$or+(B@#riWnZmG`>J3~#~u%O$n?(Lq+t2~Qa?r49*x)*|Hm|;G@Z;^<@92Dc7 zNO|PN7q0nOKyDFX?|GW*&TJ4*g*EQEES$2JeTug`DSWvX=UqC4wr_F+yD$2AM)jj? z3dft1G#8rY7K$%^%z1tkB~(C5IO(W74eJjU825TmNScN#*UeZC7rU1ei(Lc@=ouWXsuFu{DO62HbjP(NvN()yddm3^%32WH3b@2;J- z&bl1=h}{}_%N-wqDu7#=p%Y%XwacQ*1H+dy#=@-|pp17JbUmT*Kpl;wk*STVMP+17 zI;7DqEhN`?yL<(WL}ret(CE6)C^RNi0^;QEc2PC{Rma&!tgNn{#USo<6q=#`tyZr3 zzFneYKR0vSQ!9GgVbiQvQLTDk#6ezdaz-?Uq-eH>SFbhYd4qIyP(;aH@~uuKakOT< z7>LeiM}SqhYGu=<_a(nmV!y59{@$DKLC-vtS=Rc%H!A7BT_?)X#7hVX$lCY>vbz!{ zt(kWi{By#d?SP;3F0AW1%?TJg`E%u6)qu!4494rYallsPSQxt(=4wYdqo4IG@zp=P zPIWjSR$LSZxprJF%me4S#qFFDhi3b|Rh44ON+li^s;-Sv3Hq;rgDfQttv0CR&U{`# z{OGOfIa5^P0p4$PZjOwD&nsr13Bfw|%ehOVsLpW_9dXT1hl1Ab7ks*RCDIP+QI3_j z!}=;yiL7x?m>g`GA!xBn3LEU|y-UxSG8*Um8(8zYV4#w8Y6dC0TtbZX|61d=(04n? z>O5d>=U(#|s$3A`OSYJa%xR1h==RUg0@GfEggdH*nTF9I{CTXFgX(Y`F3}^I{U#G3 z*bdyuiFtfvc-^IU+WEc^qo5>Czad_FYOQC{VkD)P_$*w*`D7Rbb)_j(nTuThN?LU= zuUJuD@F3!>L@cIjJ!{~IKJ!qfsBZ9cGqjHIN57t}K*JohMt$3t`n>*Y{E*m+O1t6N zMFX_8o~=n0nrtp(b=3yfpjjLvfmVVrZs1-$QQQyUXdvFI+LO^R@FK8l-S0Kfs_~+9 z?!>`s)?<||sRLOEXP&Ka!#>&TCT^x>i9gaBN&w*_hfrJFG@3o*`CC-at6ZYNF6$CG z%u`CDi9myZ#?UV-s-H)2t}J_R=z_hgKCqG@US2oAzORXLmves2+OF_NgDFWE|x zKNdI^7fhBpmh}OCNT{11rYa=@(tqmH;RtmN8s z-(6qVYlQgSaBkm-g&ND?%*!w`dZp%(X5AMt_7!Q&aY}}QC@S!XY2g(waP!^UI<`2zk&wlENMw<^YB`V=3$+JCw z_68)HcT&(*jv$mx<~{4XH#7W+V)=+01}q7gq;(0Vr1<5G8_ebyY0+bcm6QH#vGY&4 zI7fWB%Ar>t|BP@_3wh$8rOO}Jy=xM2yNweHU0la)EXaLH_%vM`GWlO;$CJl1m4+j& zt#x#yj@H$WnWi{*9^FdkIm7x0^~fgaIP*qz42lf~qb83h{jVnNG&K22TZIw?%X6dpsjJ*`ta?eDxJ@gFgAx(%kswC$u? zlh3<~biWyg$yo6H)ugtep0n%X5|q>|lF_jfKy&xxj9B>AGPCbh9w>5od2TxthNY#o z77-*&i>N(Ulz)~;o$J@{m_+x0GZ(Q#wP5~SHcRwO@d&X~{SWWemwT$fFqmH}LX3M} zgyaR}96HJ?*TZLGRhb0!v#bY+(4Q~SCBJeguV4NdCy~{3lg;=(a>MW7UA(>Tq-WO; z%(QdxZz2zx%ytQXsb}wAoiVXZsj_jt=o}o}SjzV=h*Q#hUNAgIMS&tVas_cg%cgHc z@pP&2KE28J9T#$H@B zy7F@~!x|)4%;y6}-S~}FHDX7#o9_=e0@OWef+Km;5SARmSGM{8mNq_u0OWm8wPFpOsofdKefzSd_Uayq@j;mczi{ zYlQsCp;dyA$? z3+j>iA8Oty(hSlzRVC<_cF-OPF0Y_oxCg9T>oHN2z`ye0pD`_NPZ6C-x&m|H3#lL{ zi_M*3TLHAGw~SIQZJH!G;`ci;GCkV^551)udMXZw_1Mi`?Nd9`r=AYpaSw5s?BL7_bw!#!78d^C64$XJ84yQlSr$h~ zdBpvgj^;6(MGmc_6+Y=SfzQz#pyZ7%X+SvVaA!a zOEE|VI|K~S7uX!?)6VEQi%<}$y`D7B5$m^m9%cQw6II}EiE!ieJtNg`91HH0L2Z^kzizaD-m|I-+_~^I> zt=@F_&qP1|A*lnj%Bn3d)*8PmN6{8y{sgPStHrZ1{r=Z(aNdoGYuoR*jPE$o&IXee zBg%p~r3!|Dwv=~ssi#jL>0apkzq|(Fu~mu16WD3^Wy_`41>#o&S;mo+o(_|pV~3P0 z4c zERy%&s(vgRO{)juUC&S7QKtUP#{Fhd)WRNjL1YQL~03pm{4a}10fU=$TeLX7Q_Q3wo6w4=G(Bb~4uM0$vAQJMj`pwe^M zm9MgWX2pT7ee$gmvUZuxy-x1)*>SD*9pR=mfKN*7ILL}(JoPCz?gsT0vz(1S2~0j9 z+Mdb9N+NM{&~w^P5*F z9gpqCxhkXZN|rK`=T%jL!}LUVbK8HtK=}W^hho%wA=hj_zK&6?+tz! zEQfVR)}|lSZCRciZ{nUy7F@5v`MPv8y_8eb-b7zLp`ap97V;NY!4e1HX0TYDBZut} z*0QnBsw5h9M$fex`(Owt15_$+;%C+gbU$ME$IiO5aj7BBI35|E5%4Wt(JwJ-jDzI;nen&Wir&JqJA`eg&)!7I8Vs z`-9w!sx4KEG4thY5@`D*(ZN{k%Vg7W z=2twiOfy!*MY0~UuH5JsOL2hJ;;)2<;Mz?|9cJc%!jSh8kIQ3!{iQd0J}3MMopb_s z^~jekqp-jz58&Lb!W$;f|f2w@}9pF?(sF)55Zck#V|_Yw4oPL7~kXA4?>qx8uIJNy;*+ z8F6F0W1j5{a^9a2-kUHuic6*!TFLYTzLw@pX@#Wh%P3H>#5V1GjY~WGE>~B}EE_Hn zY!iR>a4P8Bm!Fx{4Ea;YHvOjiz&P^<6G7R4wbQe(n&0{rwUKCS{<J@YuxVDuNNT z>3t=$x(bpH#u2)XH1?q)3&(?7e3(4KpKFqJob89@=YFd-(mYD(Z<4lE-Gv-?t|2n# zd5JZxqx2uQrF(3IkDkh+ zAA>n~!*#W5B?WuR1FF1$j$g8bsh+hGX?7nUaWMTD(Bz!zak}avH1woQp!UN?=(N_l z-^~*T{ldWR{z{Lgdc%yR=RT8|O-t{Fy3SWncPCBHq?UQ=;C%*kgQJcl^)mWIlEBP3 zkwYxsUJ^D?t20>1m;5$?%3?@0qd4D#2wAHv!q$*PQt>sxvi^*@4yXmeGhx88o(!LQ zqUmw4aNaC!g|^jhAPw#~a?o#1nwd-*zGPL@ql?ndA1hB0xMJ{7Ri#ZV&$KhDru}XX z!mR1!-e2VT#yf{PwMHUKQr$k(z)wz3HGh~aN4(j{^3%=js>dxYyJh!*+{3%dO*906 zO=v|PqtchYW?Gb`Qy7>~;xDi@nc&QA0bWTqlw*`0M8&mvWvpunYq!x;oJHrTb8xEY z89iDOJHZcJ{k+2m7d%zQ&l$G77IoXUNcVN^`fUUuPb>03PE;P$K$w+w;n}#3MnbN1V?zIpFl5>HfhAelS2BE2N?s(Z1dGKBpfUW84{$eHCB4PD(D zML^@uWG7-xIo0RhBub9Cd%&_2xnf0d0*y|OVtJG5FAM+(G_l4KlCpgrfqis>!{@ zoLHVy35}7IleKrm#w!-m>dAWA?E6xHuEFM(^=_Xy8gl$0q7zHRGmNhobG=3;Rh2mz z$^59I<1Si@BkTzPOwtXZlO7;1tJ4#@Pih7rDk zc>_J_Z%Rg*2dS7{JV_HfRWmxrY6mjHr5^#)u%nx<#3RgLQEg65wQt|FzI}^}+clrN zZ1#))D{Y^&;_Vkh-P<^YG;I~-q{FWk6w+Q4Ce$-6ENtK30&*SMWF|)1y~zWmf_uLP zi(VU?``@r*J7xT^9LtgsU8hicTj0n0lf&SS!gTjz6@I`#=wZidjU8eoC9&4iZM*f= z#i4OEy$MZxNEP$7AWM`-%6X%wIVxhJv*FtN+GI`E;cf!{cEvvTfO5UP&61Y+Xl-53 zCgn;gxzD3%fGH+%|4E&}dnKB?W>`xcBFHBEJ!#StO*dKsk`HX}Clx$5gZF-2)LC5F zn*m2|0bSgBL63#Wby(lcObIPX#Qby{(lOkcos~~47%5Q@7#SuH6Lo3~HI@DI5KR+U zIUG2A2uw5Q>tGDT2JgkkiYG5GjhXu)10&2_@2;0&rn^ee@Fs7vCOWSKAI0u$gt;)}5L)sMi+$!srVtw-j@s z1Iv%*XRjs21O&zK-&-LgY&t{};qYJ6zp3U|+0DGn_rNA82TVirS!P zgSS>CD~Z+xMj;0q!_(Fc!T|>FW)`QVQj+Ejv;}pF`JrM0BZtnTk9e-`J!xPDSrZSUzbU7UXvK1hjR(H!n| z{6G11^=z0IH1lw|whnN^3EfcF_5muQHm}Ou^@zF)`s92>3-xN~s56Z4#jIAl;Ov~h zt${(OItJ!>%?Qf54!Pn?Z(Z|RaYb{C*Q^|zNsc;j{iQHC;OSKD4=3Y?nJ6=T`{~p8 zF!@uw4~)<67Fi;p7}-sg~*+2ZEB6Ak8juKH2A>!+elvk!bpad5k&Jy?CJg zuy2_@GI;!`cKhZOF3I}^_uA#|lvKl;8|H0Ag!HJYn?a0JDb?{b@o`nm286Udz(>_3 zK^IZSt0CgJ?sf+L5NLFP%MkV7Jzzg z#|lTb#X1_kPAVHvHQ4Y8N$EFDW?hTOlfKz;b=;c0?7l)qvq5vS)v7;`0U9-AWMbQ< zpMDGcZ(vb3@c@5ouXoG26>7?7>VvG)V7wGGJMHV)&8xrlqIEGi9*4s+;lEo|M|?`3 zaZ(5-%r-H`#eOM>cGP=1_+Gx1w)l}w-B*4uXvtvN_4#wOx6u?CE|u?IPB&1e?;qa7 zn<+_9@T`|G0sPo_A-JqyRqw)tg6Z5xT2cSbNDvf|`+OmqZ};s(UCN#3d%C{zu(tLN z9{H_{T}&QD4leHTJ#ZzV?gpk*BQdk|RFaA7Yp;~ZY=t9XKn!ZUy`$|`OWnm@lOeoq z^JmPivyUV|>?3$ta<6lEMXtVz!~U7ch1H%- z>azCJgDfS9&zMjd^v}HZ^E~)rPW6=^HK2F$R~K=4g;#5;Spa^LJ`ve3yfijan+yBV z#b-dMiBR~Dd1LI-XRySp5O6ZovB&db;-GZ!!zEeUWc@^ml%vs3D2Wm2n>w^O>rmK1Losu zy?kFNs=mC@9A~)Ip5(V3Zj|{hp!zr6!%X?2293vt8J@3Z17R_Xe6Y@h;SWL~{r};; z`KB%AzWzbtr40YIvYC!|IEBM5M25uK?rM5iXYvW?t!j8#b!qvCp24iXmfoVOrmDE# zVThFFSg#5^YX9vINnG*1F6H5sezt)oJ_n;SuHuk4u^p|Y2R}7frr{>Z?1|37 zR?*Kwjx<{Ij2@1*gIN6ytk~Vfvbee)+leGmw|huP6&-!gjzEz47p=u?d-8o)CyT#!NuYw!g5BMVf9za?>9sOv zBbNaLWk`RJYaRhUNgynVDNS|H9@?QlEeNSCWr=-x>XYtg3vq}dOJcLhY0M#+Kb`sb zH1TWFhuDJ8)p8cmDB0^6SHX^(Y#=v`A8+x=!ob^#;nM8G!b2Q$lS9J*a+AlFPw5|z z^~dEG(wT(@2-6^Tx}2+D&Pl!tS5kPB!%F-$JnBfE&-~T;D1~|cUsKb(FPb;XX#;~U zUDxNhyz1bc$SDp>^4k*UB!>#8}&Fw_a!}{TABq)_UJ)4j1kH@i=%T8Mi1p zu|U|LQN6gs*c_FQsYcb8!HO2-4QX-DodM6>$a2qAvl8_Y(``~9LfLh8m=pgQ4Z0Sa zf!63)x37Zb$gY5{I=nI_*N@CDj*wk19hhbZZF8yWg=xZ%y%KYDldXQ`2H`{%F71*_ zuT-|AyDDg5snyTf)nH32fBYW4R|r8+k=BitqKz~L4?VrGANaA$5opfYx-pJ6k;P9) zK#|gdTJ;(u9d+t#6$Ru}m`g=ZMBg~IbTiQk+y{f4siBEmK%V!c6=ymv5IY_E`JCen zbRvb`sE)K$G_$P|iYD1*!<|e}EtV@KN3X@n;`>moD*O7o1-rMhYoW(N zbwj#T`X?OkY5spV9+F@AO)9jqn(^by>43IvM*eX-2I2|BWmj|HLAgVsAeXF8-htSf zh@$ZK**=7E9_wV^o;I61=?RVGFUeRnP}Nyb^(k7ENVP)sVgt{kN4V1zuvqYnGnF6XSSv!)1y(!@5uYnEBiFkvh<-O znK95eu={VX&LSE$^VQcux2c| zTsfqFVhpzy8bx)UJ~6VfEatcE>IxM4A5(_6+3>xG7{hlkr{rR-j2!Y+&&_-)+5mc` zX*$|*m8LGXbO&z|30^sT^{cEhiaLhiG%I#1bEs@^o3*;?x0YkV470AY`{HU{H_Jb~ zjvyG%-PG1A-LB8VbANbwu*7z`9nsL2E6PM`o# z=M^oZPYFU!lz7Q&6fTe7cLLg zSaIjgt$6|6y4NKixSo}4o>T@rOva^CJ*Pk-5@EjR*GI7xXW=}Jy*MrwD~yhAk*=(z z!$=^7&NpVYB4_eiT50ls`gR(K&NFWzs4-7t(a_?;&l){pGo@VB!Y}(faYAu2yFa1B zzIg%gS+^~v?)1b~jqcl>1rs>8+w_;XKN_qNFF9V8Zg0g(G1kcT`i=#*xP^uhq$R=1o>VH%vzJ`*jHqyV=w|;%@V< z|N0>uCl7($)$fR*ETe`M4j+$AS2{Q?m!#c}NzDvC`qT=1U4R=UGzggL%Xv2&8!r)d z9b3Lh8+b3LofoVv=KSB{YyCJBXjw>gzN@M)EP;0o66$Q6?U=GInK zty0QK2LS}0+8DD&TH8GCqv@P$!jAO(1Wwd6omw-Wvew9^n(3gWv2MtiU=tUVlyi}px=`o_c2F0#NV-qO$_OhaS;a=*>n?GgXcrrFUk?N zigNw;wyp7;@63**f8V>$!|Slq;B3~>n$44;Vi0I6Zua1IykLG>-^;)Nn7f#MV{Ytn zKp2q>_a|;}%RGPe(Cv6k#&Dx5)4H^}z|dGE*bsW{8l8Uk1JjN1ZN;RI)A$UxnO83= zm;>a#2%G+ytybUc^iC3^=Oue=#PHcdj1c$)FzF2iiJ2)F^E#&eWjB2o;v~Pn@F^jl za4tu*anE-F{H&!)V0vMD#Fe&N_EooO&Bsj2@{Rkq(jt{v&R!?zqDPIYhg`s!rH>h$f7iMG8-Hj_Sb*P zoy{SBJo(`}D>g|h3NPb|1sdxs8|%w$E#w}(ekx2y{GV=u;?unWMJ}BI(i3&sDGh4% zm(vo%qzx(sn`!L-r6h^}7gGJ~5ly_E!8*ZbSul3wrff#mu4V47>Wl%0yZQ9&jW8b% ziTg43m8i6i0bUvjH{mPtfXH3y#Vc!9<;5jNIK4G(0kTf^TsgAj>MrZdTex76t}~YM zNqEcznE?TlSLp~td1p&VhCgYr0xl4aCkgrwPef#GaEEPz5wW zzf;~I;)APe!Z66*x&19Cx}gkvE5R=N%)Pb>e6KhyT|1>e?R<*gU+X`*{B702 zQ1<3fx`budB_d>85mIq3A3P^bD%>!19k0wNk2A&DG&5hn*)>ydz4nFoc(k8qx8@XX zpy2)H0DqvfR$t1uCDR`v**_&g8PT}ecr zJRl)cO^)OvQ)*ZO$#InlK}Yb?x!p##EGH<>T#*S=dlfxc#1tNt(_cyO|vk6+E3G&r{{&uMes=SCBC&YS4hN-NB9 ziE}Jzc2*7$)FO@Jr?lzPiYJC4hT6>~l=y0k-zMdVY%f|Dk%8f>HE?mdUiQ|pMh(^Q zA-&D~{spP?S#@0xE!~YOj$KT~{%e+LA)lyquQV>l86(^BG^5=#)v_$*G=~zOBqQ6z z=wYr#abBh*aU8%+Ra9oT zD*Nrg<{Q9CUt{;P%UyG<-`XAb3ipb`&srpR$udUwq3Q$*7n5{vL}*>NH&nQCo>F}+;y$Sm|V za$!kmQPH2}2#Lyn?ARdIyoNeD+G>asTOpqZykBhlJQG83wnw;zU}&|&APj4JhqoZY zPkf27Z)S&n)C~NVSaURm6Mfp`ABsfSwPWz1KIaId8s~ z(erLSIgI-?D&H;$Fki(0-Cc81m7#_C5u_OCgKQnYBaMOY6AK#^4*Qj3RAgnos5s@N*G-KWPckSeh;2X9*@_m7rb=D(8%!u{5SJ;t(%=E4y2Y(7t* zuIHeZ2z8HA5n+yBiRM}#p33IwNa_?^u>v*Xt5+*h3P-Fh9SsGRI4T|0t_uZ(dZUUL zK5wx*vTtTCC+iv~KpiYAYVA++PD*8W0Ge>RhBc#GROVWCc4J3tU0LhGLpK+~L%GHd zPP;7+0{&Fjv|mSS!z&(E5PExlLS_v+6G^SSKl3sok<6I|B~i=|Ca>RIDWdJu(fTvo z6DxxwSTj{7&kwWaAFB#vT2*UG7OCHQtK^&b&8f2My*wIF+0hssO!HwI8!di7ND5YX zAb2h;MxVp9eN!>75z^;!`{le@D5JW=?x2#r>I)NYc0R5A_q%;1XMCKO~6x8J?H2CE~Uf`Wj~t8q({ z>v`a#n)LKun-$rTH}bjz8U!zE z{%k^1+SwSw+LNT3W{B9|$)wX}+m2f`{SXC6p|JJ2bt|KVJc@?E;Y%GYXbGI3mkz83z-iRh0XQFFzK*0Qsi^YVB;mQ$A5sHmuos?Bnbt*Z+uWMiwq z*&EYJDd(VXcz(x!=lyg(EecFiOwY>x}n%oIBb&_cY@JaTZRsdGb!YsTLUhe__ywhf%2WHK zh!6Lzqb_8^I{H;VzL6D$%1{3^keZo!Hw=MQdk@#)qg6D|q#vPUt4?l{$pAVrN8Q82 zTUI5hdkrVn8R}Yk`8SMR!F>Z-xNe<(WyUv?<#Pu_gOnQF#UR!53WG)aiM52N9%f z4AB{4 z5l@qvQ_S&`@wQmYL70zbHSeUNXQyrzzzCRq=yp+OuwdsF3%Mrn@D>H^iXc4f+%JV{ zlv9(q7EA(NxeHo6G9CSCgX-` zd2`<5k~>;V#^9+DI<~ccQ17NvOaGrm1cSPX(Mzt!MHS_lv@cX>O{q7~80;kOii3`^ zk`Z%3?XJKzn|zK3YCEb9W$J%>^UwrZHuU`F-1q4sv{RO*zdWMDrAFEL6h_!>7WnVy zCW*#n$}6cn(x9KlP>jfot$LR1av@L@qS=>w?Hx(Tzdj44`Y#y10bL(imL`N*Y>^AO zM%P_S#`c?VjYKtYlXCl6$Er>cd;ptzi@*-4t`$E$uM-65K^q-XM|JJ&hbDP*MXM6u zl?hR+{~Wnyth2 zFpR+I8YaIn77DK;!0`g66-p9TS|W5IgqFa5*Y#@jd#fAH;kO=rH-<^ZSzm+i{Kpp4 zK;iRU05zMOD|At$eZpK*r_OKB=g{Pe6}C;DO_SGS+iA<^^xL+td#mHAqwxM_5xtiq zpx0x?(!GHo268JAnE^kM8Y1?KKe&M^>D~ZTf<3d2amM_z^8-A=GX0m!cnk zHgy2e`*n?CM*R+K$q~kKwEN)z#yw4`)Su z#dTYjnadLEn1nVc+1c3oL&LvV#KQfol<5a2zadTvdv@5dJsqHDQ$hZK*}L{Rj2dk$ z&%g@&vhkW_Hz-;@=}$~`8ywo^BZI5vr*5*0msy3HQ|DWn=Mv|o+zJ&EnBKM6%J26s1%+=I#x7NVoTm+PVqqE z#NZWPT2T$h|cv&#)N9k-BqLIbbvf)L8*`-y4^js34Q~RTh zUt#p8a*Jx9D-|bN^uP?34!98;7K7sH+S~SojW^sW_M?HX1{07ki&U%-uL-G&+oB0o0_sI zcy-$MK8s@L^FZvx?INTtqVVo}t-aC)#mFu4q-QH#@22oD2vRTRgWVs$HQa$MJslf# z5RzoA<&$~I5mr_{VdJx~1rs05U(X*PF%W}qIc0MGiCSvlV#4nl*fOtOnN;0*`eC&e zh(uS9K7Z97 zE6 zCGN<=bqaMgTb+RHWGm49o^=J#xZV}W3;puv^;t(5*0TbgB2Hx<)7)`rhtinDl1H#4 zQX0E=_g4bo%z)pBj1 zl(3XBPDt-D$Vi~FYIbt)4{t&8xcd71m4#SXVG4l3$l%?)$>L5XYiawO>xoKGx#wl9b9AlG)b*0HZsnF+?50>t; zMOB6V%32h!<~qN*rZIBWR%lAM*Hbf6iHQf2)N4sgB~%CT;M>TCDR95&l1e!=B6<7Z zWB)J>zIL2+CTK_RW};gTB)q!4+yy_Qc(5R;_u18=>F2@G!<7SKnUi0xOLa|>`Ch;_ z!Lv=V((5DQY@k$X@IewM_()i9jt_W|+J#KqiWuz|4hHj5@Q9pnaeJGk9A3$*5N@}aR<~Vr8plJyS#!@$Z z*^nSIo3~#-+j^k7K$#bvK4|^CHHiQNMV*e|0-jHT%^G)Uk9~20aXN=s?h;6>`OfnS zr@#QyTm=HJc+KcXN$p^ErxxHMwN7UBW^CrKnx7gR7O$)Z+pv%1NL{_UVJLR~6nHjQ zo500i4wtghi2FuAO5zHgw@PA5swjySwTDkwL<*<$loO8wVvO>EXy6X2d+`Xhy;`k^ z9c#goe(?b!UB4J8yn|;4qtw$5pd!Qu^ZrCjdy__7d{Op!{_j6Z#Vy(hoS}wn#%Ox# zJr6?(&*_XfekcbZx;{(S@V1S+Mx+b z44w?s<~7 zO6ISwx^SD~?|eh6@j}Hs9y}xkB@taMO56^oYH>te8@?laxPVsuhnE?D?sCO;GcR~6 zl6-Z)som0M#>?=D_a9MS#6C}RmuUBDG|8?31T5s8dSME!>mc%}Nt3RW!w+hjn<{=a z+%2eB>*0&L6TUSn=%;I$pSDScJlm7K(>U0Y&>!s*GCq96ZxTgsDhmz|XnMbIO)?uz}~>bYkQjBxL^l~5E_v_wvrVK6wPrns3%zgj|x z<*5)=A-@Z=O@(=kxEO{F2olpul2p2K1mHzX*&Y;$_Rvq95H9D0z#Z`;{L zQuaBFEJ~*>z474?_RDA|ttg`b^=E&6$4|_ogFhhwIBlnTXcbEuTG??W25Mhw-eG0nC#rzw)3pEh>SOgvS{{kpII0)XWbx^b_~yt zNiGcyW2&lgg$H;tbvx9E_GQ4QXr|Z9^Pw-3Em`khd6{9UH|hG1ZfA`;AP-&qW^HkK z*9w#TmkGan<%ora_qAU1lG(4-mg}yowN#j(`eUBpdG_oHXze)Rwm3q6%I;!#aUC~! zs9X#cXasVLL(`O2X8prED#K;oyBySHtFh_W4N?rQ_vq*K`+s;13iGn(Q$7@TK|X7^ zDx~0j+@UHPrybWO^-OqrUE=VQWX;#UjvBLmBoh#H8dGTt>Jq+W%!pW~u}~6A8k6tB zKB?ydd!&+lFOC!zd3E~ur_Lsik2vL#8{#-g`fJ_JlcyTpD>X(QSsbhZBX1IW!;E#b zd)O4S&>7c_h)cJkCgabt+&4^9h~5 z_9Vks6A0&J*m=GAJO(aKAoh^o`T1pW-6%y!rj^e-WkqeLdGzf87Vv=Kvo&k`M}4F1 z1f?w{ZLCo5{);D8K@#6;%+w-J(+zHY0((n*rT z8@TA$1T=$Z&Fm#guz2U;nPXw}Yo5M} zQRS(odWeTa0;!gz=hN*V$}og3qu{gWmQ6_-(h81&*Vc#s@P6bPEoLeUc?pYiqpjmC zMIOp~F6b?`$mjrY{52h%-?Gpz!#U3A+jeZ5q8_xa@yZq?ahw7gO~#djPyaC2 z(SJtKLfXU(mD*a;ZBR5_(wg&wTkaWI+|r6e$l#9BP^v^bFtcqQRr=YmYI}%&e!w=y zdP^3BAqjQgIXJw8nZ1}-z^l-aOYpl`fOnY#R5(qCD4)tn ze3OzHq?JVX$Rp|2tNIpDuBAH#fh-~hJTxCU$IXSgQC^e=#tH_oU^LL1OF;XT zw#F2(pq*XM_Bt0uieyven3rS3`Ga?f@J!;cq3|YndUr6i!p*M zC#KO=`cME+5%Q(G;c}*_)SC)LJutcX>e+Z=mHWxe&FP?`r7MVxRmQ*6&OXu6 z<6~#lE9a`GDW%W)Md-C==7-L)SKyoZJG<=ACrMXw%ct8uHFH%Jwad~vjRLQ*vX!Di z0DWCKQ6=gY$Kt#qzHH(1F`{i;_qkM+*I5&xZXG>+TM>-!Q&&A&adL<5!_tp{u-{>M zC2& zQl@Gztg5OM;(CP4g^cVDi{4XOr`5cxd>~UoZ1s)tdmXW!k<0>!2b3K#LYk3JDkBg` zy9Q?~_Ayev(J5ML>I&?#X~C>Ac{yw!c0b=akt&vQ;A=AXY-)=+r|$wvzQ9<2hlJJg;O&8h$K}; z&Qr1jOhEI*c5ZV@WDJ3RX@aw(aP(Y0UjkIy$3Yzsl-Px_|A#kZw0n4t9XKOR5_hih zx=86`OEK%x|F~Bn;3XtSSP_d~Il`MUt+a7>bt82L%x4ZJz0tT5JAG8@qooXOlrh}I zuxxm4j63|}==)R* zJ?ePGVm}~scy;5PcfXwkN6I9JK%&*Wn>NDv-qdM zMe6BqfDd-aggA=}*nS8riwC>GKmVq82qv8kDo2g;oLL+c#ji45Z_`1yu4AY20j#%7kje2Vo=5tHWMvC)HXzy^oBZ_N3pYIU|+? ztiNJnwKVNsHknlEbFU3fvc?DNdexrFzvkbgmeTPXk#*Z@{J{-EVX!?iH@@Dte>*@? zm3s;sw>%sgRO1gZ8lE`ggXNIA7bDGL`(F$CeV4LTOTvDKzh7Z64HpW{EZ2L@-_sO+wRx49@BTVK8ZUr}dSH=>7=s z2wXye)V}T zaMT+$G46U^SNU0(&6$TrU)$PBoJI(LdhMluoB6KCH+o$d0`URxZH`jzBM)-N+r(*_d9tSY#iNS7 z9Sdg!OXQ%Gu<+kh&DtGh`UHATF9NG>S}!ykcc%EFrvqc0p0Howq)Fl_=WiWu=hMx4 zzXMog;cVH5#^Jcmw*gp!Q~Gg-CQvrH(iLup&10FFSyOTlA1iGDGv`@Ml^$y15X+-( zY<&I0Vxiyww0RrT>5H*-gNhhn*x=d+Bh4_QF#&5d?BWPm^s#PV7 zf6bC+DLUFbep)HkwQy(ScKlbHeh3IHI_%kAK2_SV9I1`|OIy%zA|22k5Yqs8YTC^K z`Uc=;mHn&&?}%v(*10IdgvutZoGy%L87R=HjlHjH#%WL$a3sB#jK@;(YS0$u zeuj@sP}YtUFJog%EH`PCP!mXnwq-G3eX!n1TrO{~I7`;jyl zxSoQt4RO-z>NlS%i%A`27Ot4iYN>C^gFS%I-LYBFi!U;bc~h%W`3MhkT@S!ogGO)$En%)>&5#qBFaE>S}~r9DOhcOP&o4gWdl83 z4SpF`vT6?bxVI%=KKCI3`F!r)w-iHxJLk|YI@RPiS(El0X?et6&*p#68$2K8|7$!; z*LuvU&!fSwqV{-hWNY?#_weN9Rl&{Jok@0wWLq$gkF6h#=m}P?M`G5;svP5M?3NsF z{7|Auyv2ixrC{7|6(RGke9puMhj2 zmVE7BAHz7`!qLr}Vt>QD8m=gYwAJ!bV=LB)B5gx*mb1;fSNk{6JCjSGTiJmS4!4JK z0*;#pKk=Un^jtQrbOGkhe;rYLQ~i4$cze4fo!;tmORFyyXVg1q4Ym(krDXB5O%e^i z?Zn0gkRegGF5^xvZEn=DoiWTz?pYkx(F!6)&){&l(wj#NnhoGOV(@ExV&1EC&yJ{q zxx|83688w=Rg;u&DyHlj?$|Cx$H!)O7V^c~TpYLK3d4M*gJ{iZY1NhVJxjsk3+3+K57T`t!izxG3172RRF{7)(E0JgV3wrr>vR^En&^^Kaa9F$> zV^6on#&iuYDvR}p=`zyeb&}JrVN@on#x6wC<-v>cM+YpnUa{BRBY{}+=F4S+6IgU} zwef)C!{BFxJn?e<7i(*`zVS%J>|(Z{#CVmlRKQlFu@eV#shRytC;cvFk!7O4B{+2Z z*|O^B<9+vXmUq-pCN4&?E`Up=^O-?&CQX<+&J9fjj)uY7Bb=N$!3QP&2hI+OQBJIR zPL!GPEKxG&ChSEa?CW9p{n2Fae&G?};kX(1f9^9UsX!Hz-p;Vkuutp0owkX6g;ySl zU&v1Lz<~Vza>U=TGf+Sv-xbRoE{@Z_1~}3{bYFYQ8nm^v+;2F|9G@Ji9D{xzwQ@QT z`iN+56OHpI`|EHjZ=iv`qOwd{^L38;^SX z?qG{ag=Sd9aSB%CT*Uv1`B~x2_7TduJyyS+>Z^<9tBJ?5(BjEUm_GHPi@i^pZY7gK z{3I@kZm!8`;>R^ZRvzy2kp)~*U1rG_A@3Z8`l0l&|Fu?1{`hRyo#o9oOjaf!z~SO1 zx1dp|OCCqLBI$wndOy;__4ybqRmDAW+p6=Y#iXyMe&oKj7s%%^# zUGeRFIMuKC`AEy{p6WsbRJO5rb^0K;tKrKXq~>#TTYXeb*@T>^YAHBc9oFI@URYic zUC8YvOsJ!t^oCa;9xMm$HGXV7y?EK<@eeOh z?(Xa#-UaRYo85XhCF&}i3}T3Ogko49C+@bc2HRihyvl8n%9C=fEf zf#%N&aunW;@$R@~PFr_lZBAk_RweiT$cu7e@Ui#_>6zSsa#FoXl~mN;#{7RS4M3LY%>A3f60VAe5|BITYQk_#Oi=fv;* z`SOi9?`o2(0$IRlcjPsH@c#)P@jpWr|4scDzuJFidPDad0vD0ISu1n!#d1k5(52>C z;b~AF@({4u+9JABd}5%tD34x7)+Y{Ze>z#1Q4riuaY_?*KhTy_#EfA{1(&*)#{*bO z*ISxh$i@Yr&&xSoXu!kH#i2UC5`X38#2H(CIvF0m`A$*sqna+%O!moE!_gM7~@EbZwtG zwEHUJ*Z%>0ZnmHo>#D4uCwX#KvdN;wv?L2a`@(qAP||%4=*Dy&zL|F02-k*ag<2|! zcU4@w@-q=Dd|SFnmg-}B=8<;}#RyX4%R#{sE`cskgTTD|ijskRGrw@EKsfoQdN#OG(dnhH{kxsfRN)1~1^64?G2Kjn-niHdFaU>( zHtPy%lO5n0L^udn>zWFxJP}7(d-x^!CC{`T9~WvTT8vig(SE)Cdhuh#8)~rwUhNU6 zL))9Qn_h8wm|7B=8?hj^Bn~*s?J|#<8a;xG^PzP%O&yhOl4CNymfq+^d(6W<`%Jip zPudMa`dhw3xrtY~O$H*=rH(zf)`m$?ua zo^CW9MLl=dQ@1XgyBKfOkaWp1^trTFxeJoD=6@^Qqk+clR@ewt_UT(;10jc`lskz8ZgodLWR816XS>4sr%<~TUKG;laS8j%)Q7pif zHmuz@&}-j7hLnOwgGVatyPo0b>C9B|fOPPEW9=-YO(B};@Hl`TC)-cNtW(^u#RnYq zeD5KXO`mwWyP}T(G~;T>My$m&B}+MQds%z430Cr2Ss2-^_j1Q>DJ>h6WXMu zyC}cAo*#&y&g>wy26UBla{Blm9X%u^kj($&_QPyZ^S10PV+;`WpF1|o>=tI~eQ?89mZxI%GDtWMr|Y`kADop9W#a1pDV)T?S!LcF zcZEY0(rc`*D41Q%;W?GxE2o-eici>AXygbW-Q4vD@HR-6Kopk{@$Y*+#md4!#KZH3 z(=5IxSy|EXe~h^U=c9IUSP(f>l ztdEZ`R^a*NfQ3gRUnCq0dKn4my88w>n$kudiLQjd{WdZ}t;Ri5<=#~DR5NHJcsG5` z?F6$IP)bq)y*&K$pxB>Kw)pWq{WKy8R+#@cpGtcOxye$! zHEiGFet7aPQj3V-{lBwDE2a(k9vVIHM_NjeCH>PIpbj?nlzrlP5uCRK)cJASiPHgW z4RU;jAEJDJbt-?1^zPLgME>|D#FJXh78e!BaWlN=G1)Zoy!m$ZrZd?5>KZpP^6?94 zsXgXO0>!?jGP~O!nb~wUrHv%J0DVq5*V55Zk=HUXen^Pj#mH>O+xYvy-4W6|0eAM@ zpeJr{D;S5nzlgq$Q=76)lp1@I8_7kQK5nNFC-xGMeFM)KcnN$$6y1@@Uv&FN|C;Eo zS8rMknIG#%SN6Nt)N*-d`@GFqgB1?DkmS=;6E_75Pg9!DYhTQ{OMzLk2d~vQ!JR)M zVK_IwFm#t`wucpzL$7etxtyyf_W8!=uW{P)Yq}noc+eQ@SWFkZDuC48huX~~t22Cd zWd)8`KF3HN(r#wb%g?s9S`YI(uJj)!6z8`Qb0Pnu%PJDKsgG)z=P{x}j|eWu); zZad(OpFnCRtx$7z@V9C}yVr;HZ7Z!x$aaDM@W=;sHy_|L8>AFA6voAobMFg2$TOVk z=WI0Pk-gy&#f49ZRJFFVMGOq|r}bv_^ltk7!JM3|-f^!P!eyfY%#CVHxYA7HjIR%F zH*u32A6>;*=DfcTV&#}~^SR`KxEJL?!NC)xrL}kPu^CQN0ww} z+deQbps=@>{Pn;9e=EPNgYwR~XHv^6FzC)Ob^lCh6G1F-@@aU4`Fvrvmf!JtoD4u{b|J%G+G?Bj{7gO23Zgfz7#Ydm*GtIZN$hh2mi_MC95 z<}+XyZeiHd(%OL_`Pm%4vqAWw(!q&-ZiO<<@W*|bW*zdj_xmoM;&J<(BHatYrE7hi zxyt(UlR{rq!EN*$tS9q;mQ^!k07B$}p( zHrHjkD1euHU%C&nfooq{UZw7+p0r_z~bfDDeEzc{3JH8GG&}c_mL1yfbBv!>hO(S~^e#rBv|7ue5 zL9~ebU}B+)k)<)Wa7vUvb=VM!?PzaCz9E$DQb-8-d)c~O{DY__sfT@_6E%68s?LL zsm8M1FNASdVtm+`W`L^?ILQNTyDiF+HT=V)k#W2EGccraM!$tV4yrhLw7F`L#Nn$b zOC=g?>W2!x83&BE+2jhoMs*A>+Ho-Fv4py9kaM;;jBK4I%zls!)Cv}>35M)yxpYl;Q^H_A8Bz0CMoChJLTL~3U0Cj11?G$(t~(ZfiMF67=nyw@o+%;)R6 zb6Cz`c`48X3KbQ>4=Znz#b9|Z7SHQGvCXKA%t#Ozt*9I`ud5N0WipuPk`-N$Mk_kuRaQV|x|@rUs|>~;KirtK%Tl@sC1a8cCAS%hrGEMk?+>92%BC9a(3}5P-S;eDwj-`$|9}FG8Gj~jT^mO z;>h;-EK{U?8UKJ>tm(oos%$M8LFcdy)ZB?!zD-%)nwlYfHo!>kx0&@Zar3$(yPEe@ zjyZ9F7%x`!I?E<(=myuL|$fw~>h9l5jY;L`B4 zFc{MVbpzo`E-t0O{n75j+rF#aWQc{uZp+G*lDjX6m zGhGv7k4#azJas!Ar}AyCiNXV0V=5}{@Atlw&85sIM3B3a>2pX~4NPP(#o%E69dGWm z=*McAZYJ*BTWXTzTJ8r`2a)h(jeN)CN4{Xs;ysSUB1J7#l| zqNhSLq9*e}ze%^4l=^*-AC4Ysg%*P$;W;+Z;=aqYfGX=Rdr1e{18QI81O}*7gvuEj zhJFgB6TC)J`>)j6K$s)H&h`7V|HI=DzK^Vx^Y!&{HP@;0kW6I?FX9odw{E#*#_-SC zbCD}Xl^NLjmKBwSt88iOw+|FQ`}iC}?+^MNCYug9OF|JHhk%IgNUSl7A1`*SByfw` zH{IeG&^F%+mY)AQOhqy;|1DZ0rn`|A(Td(mC9B)=FkZ=HRPCJe9KgI7M4I?-j`n!2 z`30Y>v{AIL?qDleYOrlem*k&UNBKtjHx?U{Y#?E?%Tk%OfdfWChj*2EFFkw#q-m)Xfq3B!JaK6Wy zkMuCCYjT&g1KNtMf`@*5Qt)JqOB0PD*Lz$R#_HUeHiJL@E$Xq2B{6$qgo=3d-~_Hq z%0-y4Qsdn#0{(L0GbZRl+xiT2{s8d{$aq$6pOY!y-H67v=0e3E`{9%SCQ4!k^#XXbef6v(>E*A=52r zQRf|h8$_Nw4sG)JJU&cx_?WfbgR_|17GLBA)poS0d^=FH`Qzr#t5a*PD?a4@`SwV* zkAp-E*wL9-#5CW7sy#|oxPH27R`1gum+e=nVB0X4gOym-_xx=vC}XT z4z+U}&j9=FA2bO38hINz!mAIE>HuJ*u}z-O8oJC^afq7movrbyZ12{#)@*gEjThrO zFU_7yvsjN&e%3R1m87D@@5X;%Nn*>{RPFfFL740ELO zZH#J}J)4?bk0-h2)aGVR#n|HFAKF$|)x;?$j1(PP z_}P`k;CI#GlH^600T@Qs3-|t7eHb!QYZuMpmvs^K?2S7uc*RuC;W6ol4-8pGzaNht zv2`I_+k$3B7u_nI2zE7vRGVMd59K5G3XWv5*Vb50FX0$JAN`aRXi8O4QS=va&ze;J z$8=t${X@z9n;Lz_zFRjMH`Y$$LU1tBdx zK{3_@9^eVj;mwgaB@PXH6)vZAMVy{@wxk==&cKUYfkOqBb&B~&*>GFuO2;JJgRh~W zbi$n`<7}9D^Fl(3^PVpOcnWgHa=5lF{&g7hXpD5nawW(vscNqZ5Uf{m$Lbasr1{Q= z#gP8VjYp5KAz*xfK+>|=r8J>N=w7pKX}RH+)Qpjy-%Lig@$I2+d?(q8R2vfKETn-1 zCIV|JeLLRu2Iolbef$tPXlg*2wy_7^i&yQ(VK`%K;+^$G7PbYGLR*A(qZe|hr}#2A z-g;RFzu)ReD&=OKJgA~GVO|j&B6sk&*;bAdV9iHv7OIvrJ9kPs^NDC!>7Nc1D=zW@ zzITh^=E{XKEH{-`4;Da=#Kg|fVAvWBwlVlq8(%!f zLKC$bSxZl6^OT6H_HG069g~VxNI`gN->Nq@Dj;l_rl32Z%;uPA#WQcwN#y7tQR}`_ zI9t-6zSbZ$^|QaKy=uLrQMy&bf*;6NCY-$8$zlK(5Fa8z(ieDO-IUq_;j0T1h*p2@ zb|ZS#sE$LDgG)^25v_S%Z8Vj7oP;GA39W*r!k(|d=!mI^C2X*lIOQaYS6(nqvkSKg zEdgy~r)BYjy#b?^aem{$l(-6A zs`vBZ?P6bR`W>~$+!;GP1jTjPG`d9H@}7y^)`BJfpi0hu(Fl25%UyyrZ3J1 z_d11?S2z7=-+8~d@-tpqcdj$Bhjg=Y0d16zy~J_AcyQ<~WqvRQ)wS65->K>UZzaJ0 zr+*3P-^|rNJSR^c%gHAYHRY+D<-Weq@>h zuy1kK8*2A|9v2B7D|$!Ar1|l&V-;b-;18!pn1#8;z{Lmda&KoT^1SZmbuHP3E&|%M zPP8a=N!;@I=%uZ@_?~_5(D$P08+kqveL;cngr>UN9(bWY)z5}V;SfTPX!yWQ&z;>r zykXLAO!xBNikm)+!w1Zs%uY&+*gAqX?o)XZ$wi z^Ukb{8TANU)+L_Wgg73(ap8CcuulDeM|@(f)K7TlB`%JyG!WYtI^v`0lO4P%cxm3t zK0Kz;CdOi?V4%yx_}b&+M}c{r4}V?5co={|uAh`*)s=;167uOKxawszF%bqgfd^(v zr;~#ylH+en*_z*022|U)k*;24OetWZL%HvLdX!vT2N{0*jz7~J8VY2tV7yVkp{Y;UAu=EN=&S;+sJf;xuH~kXHg8T|~*@SJ@Hc`N>(soH;oWa~t}CB32Y{{yZ~BYl(hGtabx=8L zTH1Ey`<&&TrfW4PdO+#@ zxPnP$o{60PX_n15Z<3xw5qyRnScV>GmbJ0{Y1S!!m6O1|J@z=&ewFXhp1f|4-~+W_ z3(J|SxG1+#&Eat^`^0d&G+i`c#Qvh1}T6@JhpLKN= z9^r~MC~+{nhQQMiG>eaDr8^orjGBVeI?PHtJ+w}uBI%HC6C>lDI^Zpaw-FWL_w0Mo2OFE--Ga}JZ9jpfIUT`V@o3NKm}RUDz-!HX;76Q(Ngp6k z!NN!~)seOsoRpS%=xLl)zQ38~Z|fbl!WrQmYbZj%8E=2?g?o>C^yGAp!X@MVfuIPr z7ae@F zFo@(KPs`9s{0sDkezeH#T6?S(6M;hI$FH3IL`it(3|`f3zJ3Z0E)wiy()+(aE&F6D zXP_cnV~eAcSX&mjp^!?|F?@OTv0Zt2qE$Hm8Q>yTZTOFQB>qjlSKGHHOqAd#lYGv^9Z1G>27B zTpsO{X?Vf=ga}FNYv|xq3fsP^TS1(C@eK{2^X>_OUOBO58M$yO(Ks7N{keDS7oX93gPRPQUP&QIV}f*&i;C|)<;zy=#CLRvJ=ake zBVYWzc_O^oXbU$Uw+(4YCtREYI{K6@rYMJ)RFx_TX->~oCD!r;L9&jIQ!()?{^uDC z_UOgxm<$H4^?hL;YsIl`vvOMU4 zS1nA7F7oMcTG7^;uOaHFpZ6B9Nc{9ZnS>Z@9?GKzA|&%VC#9aV%}T7~9EeSN{nMo+ zzWwO#UH+)28^(~rA0#B3LL1PI)!U>P{1FbUtqqpF+!>hgskIJFLLyUDa+x8j4Ia|2-;LMJSf%bg04P1PviAjv$>-1gVgQjo<1`JQoJmw z?uI)E*zzt43RdY3gNHs!6hxB$pvNg^*#=F(%<(KXapqRwZK`1zguotCuY7Y4PAz+a6?))=U^M%OjkGCVL^c{ z>1hxO3ZB;inY^sZ%&AEPNskM|2xp%O)RcJ~?Z6$5sgWmZ7O)W-$Jk=QI{YR){C5+C zY>P5x_cUR^n!~mDgv)<;mZ;nMwzIbCzVN%#`E}2XA8~3NEd1r8`dfz;r}GB7eK)33%t_8W8H!fwH z);bq1!)=%v8nKXjQG-BLs;=y>KdZj$sPU_cZ@5kA=Nw?GfH!H~<5>Suv$ly2gS%6! zMpG5v2i5bPXYjGl#4}aX158b>tVtgLR?Y`~v0sRBt%t#<9eIwlHcpRqN8d4g(oW2| zH{JLb=i7oEE=URit;ERJ#AB9;6HnPT=8<7Qxkg3ni45!WuGPykQ z)s^WU?HS^W`-g`+BWAi;yLLzJS7`wQ!^T~!oHy&{u8?DS<3|=5%U5RM?ckf1jg>3P zmL8*{{mQA1gS0e>_SENnH1phvb=X|-F<6hS4*;5Vm9`07M%Lu(Wo*QOyZb%02cciWgMYLFeFfCnLHv>LO2XjKL-s=BbA(?{Y}D9yd}; zMeCuwq$#nX@_K1;l=IpA7-e0ZM>KFi|AiPY+;nY2_J$>9UDmwRYSV?8%-9 z`ri)Kjiwb`a#|dvA0rGNo?rR*xQm1STxPpew5;IfQws}bQgahJPqxXk6j(VYdQ)HR zQ%8!(DMl77XUe4;K;uCpdRLW!8wWWQqngowmyKav4zOj7wS+z&GGDKoV3;>`5l84M zC9<}ovbfLfZV?7A6o0e&TJ`-EqQIZEjj$Abc~- z0^tfF{GfU=#LZQ+I`gsd$>1-pEc|-~<$HW?jllGJo;h;ZhKHj!Lp9-}nEUX3d7SlqOn?{q3~IBtQyG^% z%oM}G$uv_kuVNa1rImf#hG|TBdO0=&KQ_yks(pTnw0+(&6k!;0_Il}?iT+UW&iCEo zWH`0p^7>AOdVt?Y7fRWUwYkplU_-O~6?P&WpKTm(>`I>sCrYB)=I#X+nE@b$CrZ z=e@roxamcgU#AtSb|G*xvd^zX^L*0U3m+CHJ;LlBTMn;|n?Tq+Qgqztwx;CVAaGwL z=PiOrb3e<6$;B+ipv@OPKR+h+gPod>d?jOoK5Pv+^tWyFK{ar)Z0TEi8Cn7yQJUK6 zGE5Rs-9{_3wML~!8w-D1uvOAOCm8AUk_R2A7nxD6%HA_-dr|(plJMRjE`v!55_O9W zTAR=1yJ_quFt9ndq?CEP08m=V4QpBMX`{|+toHfQL0|I)TMf?OZo5saKNV>vHA+{2Ksq}tMf6CA%wo}cEIVl?mbWkn}KIu=i+EhZxth+jTX21McPoy{TSbv}E)}uOel7 zR}gJEN0a-1zd;-VK@L87yXg%les`Tq^RJNu ziwW6f%?B7btQObract9aES23fVb$0RVQEe~W|#-KJZtf3#nsoqB)?}JtOImHRDt-o z^SmY5D`Yy{yr%zjMVadTc9y`YK>1JTv-h!P3Y?^6D!j16)jzBBjO-o(4zzlagELl6 zr#RERexaErV}do9Wn_!oL{GSBne)q0m+B1D;~nROxHN+^o?@I)0JMWR@w_@#=#jba zyVhIXyue1WFprI~_YMw_{E7?s;VRp^SScPQN-}v)yVBK)OF~V#_evfHFk4E=D)t_{F77*1_AYrdE}$g~QGMSp>`Yi#_jz5vGUs z)6D9%7O|p8oZNNF%~tAi(2hy@i0y(7H`LMNd|nlu4{&`FS9Lx&I(aA)8CuJ*+lXPh(kAF#$) zYmMjPncw-DpUM1`-|>WUY|f9ou`rYpb%pr)pq8FhYDsBX_v%tV@anbz>5tAM1t*{M zKb_YqOF*xrWz%9J(d}SGexfnCYtCkbP}dr)w-swR7sNS2l@-Jrc zxT97l-FgD4ZI+jwt;8)XoXBr^)lA48W@fkuI4u`ilsg~yWvNhj$`x-?mD@Mc9&&CR z|7{3)AwBc-0?|7p+NbR0VlP#o!`d$*rp(UJnW@gzWX%LWlq(l^vyQulk@`)?a32%@ zq%?Qd8aA@L$D0KH^$M{#^U}~*y~8WFYh%8N^cH6*D&#w1KCu#0*M&JS#fU`4jF2ee*LoGY5vo&Nr}!bXRT?ZY=an ztKp1n;m1uyKi_!g5uE|9HU2j4>R`q1w5cwEYe@+__OIyfQkGL0MD3||T-szyH(jzo z<;?KaYsRo7+Z6(H-{rfxK$S)mU|UZACCC7cZ^K>82Z_NX-P~Y(&2LKYJuUj=%l^`T zLPQsC(^i}ow%Rs56w=p99!DwWbCFFZg;e%V_ar;m^$XIIi?~r?<>!jeN}anvv^jzH3?kAS>#dqEx!G zb%Qhex_)o_upO+`4e4m;*nnQnY||&&^8BkWnmk_Hdb6}*`p8Nh5+Vab!-5kOVihA0 zU5Q`K0EMPTFY6*K66u1kJTMvL7;{b9RIHgpl|?1Ob+yCR;fg^yncwQ}=Hv@HM6w(y zdzYp@xxG6`OQaxVTS{blKc*78ako^AE7M#i`;rTb)%+i|Jzg?oQ`tt7Hu2QXWEa|6j`^`qRcjbw&(ymotkhN%j<*p?y47n; zd~~vV_ZP0!!U4DA9y9?EDcVWG>Y6M(ALk7iQ*J2_X42YmSY0rx%Uo=6lh*^#!@Mix zUezbR$Y+DED@c^lO9v-eF$}jznqb@x&yB8vylAEA6BWJap|%XmaIigcZz)_OJvw>z;&#RzjtBlg-z(J2(d zWw^w|Byxo&XJq72b3TfnH02QfMdQ4DmE#sX!t8P*Hd^tH%Kz2q@&C2lm4aSQ{6`jw z_ol3R1YN#Hb9CGdh#R<(N|b6jBbY%hP2BftN@lRA){27fcpih59gFr0c7whJQk@OE z?07Nm)n%7UrsXGl4L(IcjA0}wH8|?E7ybSro?e**8(c{FxsZSw4wvng8Os@GfAr#T zA=>AD)IC$FPl%HSr|Nqke?W@Xrs*KzY$|D?+h^%{zEdA{LDT)g#+7b<$LGgu1hB_2 z9(9Hca2dm_t;AM8Cd}?cfYp2weqtZGL$f0ugxwU$CcAixhSCKJU+z861iT zT)xHWpySrPAZ~lH@@)e(t6sB@8`hFj6!?;nx(D`}h-cTSb5*c6`T11pYNyP2vG-WC z53IE|Rs4H&m>PpT1*0!x9?7OX3718w@QMY-ph4=u7QyF5sZPhhbWGaa{&H?vx);1w zmYzaItPJHexIrzx@BACh$LJ-=zTCCNDYXH|-_v&8SWK3pds6i7#c?$D9DDJ3j@uJ~ zVhfq{;=DNiTynYRA@LL29>)gEU{qGp(1{=^Y}r$i;>S)Bq%xB6-e-BzK*!tlcFb(- zv~Yhm;24+cUn+!TFiW)aA67x)(G9!h8WnwbFmlRt3x?;il zy;j+|J5t`S@ceW-i{J}&0JpbZ;h3SXvLM#V6U&PG^ufU7;>UC)S^P>DlM*7)w{@Q% zZwJF%mU1zxjFc8)Sg2dkuID$a*&{8PuNLHhA026yva?mGwDw(RY5}X;$UQkhL!)V_ zNi|D6Y(f*LF$b7xrUHEm$H|P0yLC+YpoPJfPFW!fr-ON9=oCQ6UT|XDzA?O!PK9HQ z+g5mYT1<)yvI^$^%|r?|BF|tYqj$(Rrrtw%S}PPCD`KShLanKV%2P#*PoE}N6eezL zLil$d$`JiHXm$WfPg@10Q4>Z{!UMt^)T#A)!429)iB=Vn49rW4mzoB z7BQppN$50$SlacumzQ0`q*vjp6|Q;3)+0ojHUb_*f`__=e3pqy8AyQWz{}6}==iiJ z&t?Fr4BB@CBdEA<i3a0&rsTXSCWeN3kT|LZ`eUgZ*lY7; z)E(OySza(?>-!46$>QPycP_}eYHY>%>dJnVQY;p=cXlVs3=d(Nn)PPY5|b97$h?~X zlo{ekEiDsZN`x8BdxlNA*u%OuH(+Pk-CrNJnG?4AM4ifxUZ%*CVZt(RY28@Hr;N=y z*@41Vk2fKiIVG8XiJZSPWdZ%$z=+!0XYR-0KdXr_4>t)L_dUbhMOisI+yX}nStR62 z77>VRwv_O^mQs}Z;o+B|6c%^+<8-hW|LRBLVb}=7r%Le93o6w1EAT#gWZZ|M zg2}XPY&zH{WZ2Hfe|To*W4#n+i@%r6JPvH@dEUj7;IJopcfs z>)k^AXL)VMNd~lun1x$J5L?9?Z&j6zm-vRdcT%tB1q4;no)^co*psPzGNi>v4CBBJMsu>G`ZTx-2l>yht<4;b7I^I#DCY z%BGdy=P#9;%E|_8BDc9Py*ZK>hrg#8I~Vde;xjf(v^Id%)FlDF+hcUI0IA#? zf|?huyx9XW@liJyX)gSS+>$U8e&>we!J{qmV00aoBCB_g{rV$QyE+bSsROO28nkSB zhV0h3sxqT3I@F}7wWghz7~OLCfGe>lG@Xb)lwMC8Vou?{QveN{IG+$U!8^5hdU_5Q z>m_rmA$;E^%?SEVd3Fr%7Rt>-?0Xm;OD$wdK@QH!bH6l(DZ+wjYChC1x>DA(9(=q#g{ipONH<;f>5Bf1{IKEHg+)sD(n^3PE;3$=N(b?Z z+#>WAKdxk2g-Y$2omaotw~3U$U#xlduPkan9Wfx7RGY3`N9T@<4(@Q z-8#PTypP<_Vd$TB)VDdA?-JUyT^-fG0a~7B1?M`}XQ!H;wCa*yk0}`ly2Tfz=%a-s$<-Op zfNgM{PLV1<*^pn;MHQc9y>T()IF*li{QA>G`9BzH!b0`Q6hSW0LnG>;TZzs|RecX} zqcCWCQ8LYM4_01#m<^&6xc7YMRPWCcJF!n;FCF6!fb< z_M2nU3$z7g*!}$;VO~HYg*7lg2J>!E5n9rYs4mUhm5x6Yc&q&+Y#4xR!)!v+u=9O^ z?jtSLM3uIHJ6>+$tufm_quhBBO-J*-UiN7+vp|f3o0TP9mP$%RZ?_(e_xSjP;Z3;m z00~RN|IC>>w(6@5n*`7LYzTqp)rGt8@qLcUFu#t+wM7Xf(e`iNxEnoBOm%pqz4=2m z5`1HpY4?h6hq%mu5Yw9)E-$7V6hGM}J>QqO{>!-$H>PemQ~wkB;grS)Wlk=233x>= zOA$@DWt%3lE|m-J^n#;oHS(pq-$BvOUA@){C&KISpI3;2yzZKPh4)BDp`zR5(+gA;tJ+aHN(D-<|^0Ej)jOwFR^TKNvsU&ZF7IcC+QOwU~^i-NS zz4ps<>Vh!cZg;!%+W2C44j^pB*8w$XzFrh?J0&jzY1bX6qobIbEr?;RL`~yT&?C`A z6+5+L)vZnOEarj5GrM~1w#lW4oHvP|X9{T<0W`yhjV%hXG*LuT6rVIdmBNI4iapnM<(CyU0*<5JHX?W9w+XG zbYK6$U@J;{6f?0bk}N|ri5V~WO#hR`#YQgnazE_LuJWa;8l7IvACjbKBh94#V|lp6 z6>}APv43B#P^2UCL77iqo*V@^4`MXmee~0gaa>#`bTO|{_{po8-=Q`Gi-|U3>6AW2ci3uh@*b`HpiTow%jZ0s-CWX**3?_3zPvg zx3?F~kGz*gyNZ?gSeA16Z@Ugf_#^l8yRaBQE+?d&$!mT zv0-nL)b80NzOj;26q-ddW=P{&71Z1HeKdeaphOdtXLsW?G5TzlaJRJ;E#Z=YAl z4+am0yE)V;1xafkdVWFH71=wUomej!)a+P>^_5nP-Up4F8?RE7qMSQNR}-Uog*9C= zBlKimCQPqja~P&{s4>`=aJhP>mhdG$G_RcXN@Ss+GIHU3%?b!?k!ot$E1GNn z0EEr_!eGp%y6K@~0Td#cy`hQxMxSfV{(GA@LrlF8(sq~ke_A|`N3L-PK*Ycix5;5Q zy)Uzj__G!DjmdKhCw{fdk1p()%r;>xiJ-z^Gl+@h2Z18D8P0$G{k_`~<6j6Av4%Y4 z384zl*%+ZzoRpEAwD4Ddsf2SsSVc1jn7C~r4J7LcBa#6t0cZS9?j6Vl<9*X9pTCd~B-lanEJ&td5ej-~Oq zm1%2F?C@-c$Jy?6$ZNi4*Y%#2^@22B8Fw?2DA|Jy#{WmBdY=ppN9`L;|&WVmSx z{rA6AUu*{M6Fb8tJ*v)+8$R2F0*J@cUic{YowRN<$Rd)EO764UJgYK=u6SQWG>Z%p z)J)HS`p9IpNUedP!=F0VOXUXd&Z2q1_k#r6z zb`Gc*;S_8QElo8iXvw5UCxN}vUDj&RGYb2-JFEerDiCOXzuB#gz%l<#!EDsi_G zxsJFLMk{WJOnN@0*?Q1zv{Ia@+wWAI#;sfPyI#K7Sh~gvD5)JMi6;(0(rv63-w!eYsAHmdfYDrBkm*msH{>?LDQH0aD^T#hgMZIS z!>q+Or@>+-pyqOA`h?l_Pdq+mF&=spK5Q8NL4LB`|IX+y;FC09O?UgJNwIK} zceV0xhPc2~A{wI7{89`wM0Rd5AMOg)2UIl&`83jQZkcf;t2*j@-qA33lu8Ip3X5nH5`G>dt z6Yu}viu|v*U^#b)1+#-*NCX`0q%9 zxIBfA`%|1e3h$x<0QB-I@-lkfKYyEI7^WZ|gJuJcXo7KNQirspdpgNmyyU)D8`-cs zI6yvSq}XJvF{|8#P+Ge^>dHbtj!!mo@hjy^@Plv6) z)Ji}X2E>T0emcDuIs9ZOqwCY$@cr)RWOK!8m?8zG(le6!SoDE7Vw;y1f0FHX$cJ4Q zHi7e93s`!LLi8ThH3)M#HDt0%eVhxwpj*SBwQ-e~hy1jMQg4xEKqEr7Js?b3U2`Fd z(00FN5`2m;l;V#O&*YczX9X7ksiMDZKKNeu#!eSSaA_4_mV11)7ow}04E{*x9Is{@ za8I`k=O}W?+Bc3x9wvbnM4v8*Vim{t;+ zYyUYyB@MXg@tLvyEa$yJ1>!fy*z>^L+Bp5@(m$h--sq^Y?AgZd6oWjywo7AvK9!)L zWQ;xs(~Z?_X`$>ds&*_^8DQJJn4|&)dNsp$;UedyFZW3tvz9mP8}4C%TO5QGu>M(y zbTB3o*W=yrz&8v6+M8L5x|rFqKNby*lnkgxqf2Os@mk-pUX&$csP8E^Tncygz@WStvnOc=R&@zOwjn*l3|g|do2=z8148d#_;rjPR>OHL*%iG zfBdmS_J^T^Y5fxyF#l*D3AA3=pJmJBk+(abnIXMM&8&4hfA(~DTB}=}Q=DvU9GoR!Fej1FN6X#kn#hj0h9oeGXn+~=8)nvBVbm5GZrayF*x1x1c9WF<;(DXZ#Hxo+NjSgS2%>Wul)%2Q7a_6>MMfQGji%oc(^>Xy?NJe6Y}s| zOLFdYzG9IVM5UNjJO5nlAvo;jCT(TWEs1{cVn#>ctJ#8Pvi8H5X^vx_Jv7NsJ?5Me$~6gp)%2VRD-Qn{+pA0 zGxS5}d*UDsd63BmWVwu_OM^;HyL!rD4s`m;sh=5ZwHKgVF*1C~A7^*(Tnzg*1RTj~ zKQ;ci7twmu^#xWL45JVw0vvTKrY+rb+saZ$mf}|_@=y>sY_BIV`Upw*D9p!0gVtdN z?`uzfPx9&w$-UtNUh%P~I#fCx_1x}>iWJj``M7g77uHr~C>AMXUfnLGKj-xjQb`n) zt)v)K9R6I+it2TyOcUO$n$5(uy(i3daZKNm?n`VzQNrDuETl_g#q)2xPL|n2e z5{`u-s{Y(IgV0Za_EvrH#|jSR5~&uyY_?1HHyS!AXza=pxVMSWw0(KNM_Kp-HV>)c zjItRC7uEHQf2r!C`l=ut-!jCx{3g)lv*|`{4gmT?U;mF;ZtgDa%XD*SCW%2DTEo(+ zgJ9deQMF>(LbJ1rk;->a5zWs6_zVacuoc2WKBohou?q_T9*^@4Vo877@$mf8Qw{gb z8Uu;Odyb)Lnax4#YBST{VcEt)AGC z&yreMEz#PBSk_x0rZF;d3SM*R0HgA9^F{8{e_-^Yk)x4l*6 z$(`>~dI-ZrGb(PmXU66LjyJO8xa-d(6`0^Nc z9_xDcnj>1O=!qx)eaMTcn6&YZ!964kB>X{96wE>$4MLK>9S5t$=jAeGOtMHOFQ9Jz z%-6?BJk=*er^v6rzO&^MgiSjf#NnL?)xAbT^1qPOT%q>&<7m~hzat-JPF`MHu+yPA}Sf5l> zi-0)vV-)F>`SYfsF5@Bebajy;9k3BSQP?NKk$FM9l%ZkLq7Wmj)7n>Y#X3p;`I(U_ z)(Y}THgC;Mord>~H5O7cbLrMyzX4!h`jtY1JrG_tmzF!+4txy=u9^=-WOXI!uD z($urk;Ki>)F>Xri-#VGx!Ef_M4(m=!ArhHrMg%o}SXeUqGmj074_l)T`Ltn!3`pIB zgwzwHV+T^rWGx1@URoukVvJJ0B>v}DkyzNR9d!zB$CENBH?BL=^?lcS7-W69}9;av*1tZ3M_H-?UFbr7?N)rGJQ|)|k-}K~-<^bDs`f|Of z4%}xb<;cX)CgbY9pLw%9ubbH$gg^2@+#~LT?szTxD+IOCi?o>=yoZX?G2K{O;kVzq ziHKe@CoQ$&kSk?(d%u+*CZmhk3V4`jWbLUq*vPw_Ei(#Fig<(Wu(BY%Js>J=#OD;f z^n+C?doxI@I8!605EaQN?K}PU79ogmX3+a^2UuKl&-4YA5-xJ~d< z?XW_&0>#RDjK|MA0se^@2=o351eHpnd?fp~;sm5!ET_gX=@$oj&hXx)PFl53qqlnJ zhb@~oa_uaX8Z>tw#{#w<=D~E*XK#?ucXMt!_+CV8YN$m|I5!eyJ*S(pk)N zjE$4MAx%{kza$;W8Cm~mGdj2jiG*T#_+1K9RtaZfUfz-M!5Gd+Ki6yVw_DA<1w}KI zafdG|rP_k9?*)o@)2gtDwWE`)jv@!u?`wK<+s~(^*(F2))#&C4bO&+!1c%ox=PGO2 z2g*{TxYJKL6VXyG*UB%KTrZyxI@|AC)#Im`0`2&-zq*k*!5l@}#)w! zC_P5cWqWzps0cBrU2B-}`RHtMo-{aGJ{>U{LMMfiG*3!o7Q61#;~aOk00V1WVJ!RT z;w*qfHFHM)xOlEpl%i=eT*VAfn>u`6wmL0Rl0h5KYsb90Ba%T>C`8Mx1pOIZu&lqL z%{2yq#CcBwzm@abM&xz7(TTGNHzOsRYw7f?#8RFt$A=&xd71eIQ>3s7^m+|EApcHy z6KfmSQMAz79iO2_C=VElQ;Z`#M?wj%|4mr?J@i*?M*)hmN;6 zkg+YOSO@<`j_d6uCglXDF{sv?3rd=(SpEI&SNXni%VX>!5TN0Ss;?+jMn`g znbY!c>2!?@N*65j8mtNjd})oeN=FDiC6v^jpeO{Y#QG=36<^+EV0QE0fQxJrEJa}uI?)1Dbp~K3$VmnKg0^}j-X8i%R0}{ z{*-u^Bu~oafGvYH%~;0H%U%-UIlM<3Lmt=75_@&Zkk4+`{6afcHs^yi-c4e^z&Siq z-5<;|i16R{eRV$>kW@BZOjbLn2BHmMym$^`EwVE626yvsJ`EnF&{_yl z$xi6SetYq13H9m5naaj=2LF2Pz}F5OlVwX{BJ5Nk?ZYSn6D}h+0GvIH*?Nv`W}ZedL5g3-}%rNPj%y=_3-5@ zXBkW0A$peLomSm)o!GMv#@aii15LqS$u+ZisqT!{Eik3ttcb;3P&Z&lM=f$PO-ISo zr!zCPdhfblg-56L=1{-L3kyS~Jz8!WUKV-{+L68^36hFc%aI?MU3)Wk@B+k|Q`wLH@g>O)Yz#xQ9^y@9)Sd=d&S z3&HztUUmU<&@;V4LgH@1*emlCEgCNWvYQb!0XfDwLFJiE!_St1@GP zvbA9$pkPHY;hE&emzkaLEovR2NS71g=w+9kP10JO@@HSD+1`rhOCsw(%Ux(#_+qsk zN>KW;)$OsTk9o79-kdx4%G>CI(W81g$rD&*ct08jZAk$N+7--$$ zW+~pSp0?E6tXQ)l=tvsTfrR&zIcj+Rev2$A-E_MMyVps7fXD5AYJV%CCSgC!K*+xS z7P{rrB~jO$JKGl77u-GhAwM|sbis3(g+}T??R8h)$W)&Mzr)24O@iYLx2VtFIitC* z1*izQ@$@tD9nDBx(49#2X3RWPqdL-L5>fiLNNGlt2LRq(w8bm0ig{1EwKE|dl#*`l zkKvnWnCjZ%ZTb0RuQj0qzPg@BAbA~gOwe}w$xaU5B7E9@Av$vO$!`^INxvg7(cqDUvpXhO~9B=4Hi^R{ETg_rNGI_2{S!ikI$N^j=^ojH`J0Zr0{Z7 zQi!e6*`%(L!zg~Pl>%btYGTth)FSX9rusO&hBcL%PP=^I6xTh|{MFt0Y3UV+JF_dAH;bv_bCGVgKe#iecJ}F zqtnpMqFW_F*ONt_swFyc$ZjV{-#8J`5e|%~vz>lerg1bzBa+O2XopCvosE zaHO8oD%lnbDLkY}4VF{NuQT%&_WVk?n|Qc&IN$`DL zOY&dm-AgAlb&guu={4>xu(DqVI&w=LAGLhw6qpvbf+rA%q55Z_Yd{;+<6Z;A?LzjV}ojsO({!^Plb5a(|}Z7gcmqd!ZeCd*a0IF~PQr!5ytPUOs+=bScwMG3L9@k-xMh2m{(e8uOf zL_?tj>|N09Rw>Y~al4FHoQIRKl9fR(-*Da749B)yg$Q&UDgi-Zo=0CGi#wBQ9UbDs z;$uJP8AZlMM+LbAFWv&LvEPO5(Zvyenoa$|xFg|BDtWoi0?>*eoW6ABghb_vLCHxB zD=^~8BXH9@oZgIX=?}xYUGJmpHfT{qLB9@jK8T7y`uvIvGl@Xgq8FnChhGFu+d;`s z3ANGBCOOb;meb^+n|?BSWBEmxaMMVhXV}>ArMDp35Q(2pu*0vB`=~sjKLAJL1EYt^ zSw*f+|IIz=aM=@N+|WLy_yE}MDZ)ac&)11&u6rf*lX@nj;Z1<5Lxq=yr$%JCmKG8F z#;MbOh`tKw!~59BRs+%F>^)mR);Rpf=lp5xm&bdQJCg!gB~J^Y#Zwt)v1lx_+LOgt zKzaYlmw0HKp=5azO$aSXxhd4_U2}*14^^tpU4F3G6iN!)gMJn&Gkq4ZYqKErbwJhe z(pznWD1M0!Q*3NB6{?kH(5scNmb{jHS-*o;nuCM@MyOhNwaDLLZIO9zvXhc@nN?14 zjdL_^R(twBF8Tc#o!Pzc>>#R%3k{c~5_a$|qOQnS=bvCF4{6C7ByI?3c79)U%UtNr zF;w0y4!zJEe;#ERY{x3ilPIs_hPW&tly z|2VPv**X9{oi5{J`rO53j+p7M$CLc57kvO5R%DvcFc+^fjQq9!Ul+W;pK)2~ z751Tb zrT22@wa4%GFZWQ;0oV=?Q#h&l+&wbR>{nChD5<-W_1PZFw|Y;?^*`8s`_MlzR#m}8 z+$rHJSnIQoQ&q8(r$bA_p-t9{T)Tj_bbG)Pu~D8p>1u0RnkfMt=y+2&^Mx90x5}QN zoQ!kC{eF)cCY_wJiywm7jUzMvb>+|99_euV1vZYvsk{HU6n?jCiMUg|VFm_fE54TC z%dqx85_-%$>?%6&BTR7k0cn?*r>PH%Q-^m&{KIMuCTbg!YND*U?$hp|5}2Rs!$STV zG8ZJCDi_Pw?_4vn9BTV2^7FI<>Xw)=n8J$ZqJ(B~U*6XCx(9p+lEA4qpYF{EeRA`b zy%K2cJtDajd)g-GlfJ0b!ZJTwY9Y(?P-Ey>_IS^fr5#%Aqn?$MtT>Vv069Ckq-a2!c4-HWFY;M!8AKODs=^^nt zI>u5#4~uNF{xyPKiL)7HxQ(tB_NsGJe32z$0GCZv|gx_1;GPHb$t2fE#A2*T%2Fx3XB_3L6)+r&fwXqR;YWi#@rR5!cn%dof zlcCK0vOhTZ?Y_8ZqT3shUT&MBh^p06M{B#g{a5e`WTmgwfY|wan2J6&|9;NN({y&g{Gz(tdjekai>o zXPVs|_sb@{h0!xC|Do}2L&F|}r_{d2KJw3z*Txx_EiW;u1!~@_4hYdH;3etv{U-tSnJp)m@wDYpE(^f zl5_bxPU|3=8~+sPBXNS*^ne1E_!=c!0Z0;JdX0fbj426}-%48a(q6?wfD>$!?dx5& z3{yW54UN!jdYe&jYIZhJFZpq+8Wspw2^AtznSa)UKwN~pWY(RXo)f*$eA>)H3XGuf z6BTxcU{Mn_$QuWLKTv&157Ad3x`?VxW9!ZgB${Ik$xf~qSd^h)Ai~Ff#F{B8V?g{w z2stfxfUdPwKgiO(E6Hhf!tfrpG{RFBD)y*MRdV2CYMLX(96uPpb07k-2L$I##Uueq z)h$9pBwO$K_2{qD0&yI190DKSGNq&vp%NQbiajR}jdDVqqw`ZEwZm)Fs zRPv0#SP9rwjAf zK?!^=>^mKmNh9UJ*6S42I$;`QzAXSL%!Jk*b-)!+w|5YVDTQ_f$|;Z=j*B)G&v?93Fcun}IDB=Qb$}&b;CaASEtZ_VJXNNBv&K zG*Z}>Dd9B`vs1;4XBOSfvs&>qLi|gulkvk!a`g^FL6#PoiG+={fByE)p87azd}b^6 zMlV#lM7iir0;Q+l&Ye~=Kp@QrJ|rAUn6TC`d?~!N@)N9 literal 0 HcmV?d00001 diff --git a/html5/verto/demo/img/logo_big.png b/html5/verto/demo/img/logo_big.png new file mode 100644 index 0000000000000000000000000000000000000000..99184e956571c3d01e32a4cc254535e3ec761d68 GIT binary patch literal 70654 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

;Wz`JaB1}znN?U1!1yw#E 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 U+bh*4nE!M^$56ZUoWtG!0%-Er@c;k- literal 0 HcmV?d00001 diff --git a/html5/verto/demo/img/logo_med.png b/html5/verto/demo/img/logo_med.png new file mode 100644 index 0000000000000000000000000000000000000000..1b47ebfaccbd6e36ebf7d750ef0f56c1d544466b GIT binary patch literal 22847 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 literal 0 HcmV?d00001 diff --git a/html5/verto/demo/index.html b/html5/verto/demo/index.html new file mode 100644 index 0000000000..667920a763 --- /dev/null +++ b/html5/verto/demo/index.html @@ -0,0 +1,5 @@ + + + diff --git a/html5/verto/demo/js/jquery-2.0.3.min.js b/html5/verto/demo/js/jquery-2.0.3.min.js new file mode 100644 index 0000000000..e1e3d3a87b --- /dev/null +++ b/html5/verto/demo/js/jquery-2.0.3.min.js @@ -0,0 +1,6 @@ +/*! jQuery v2.0.3 | (c) 2005, 2013 jQuery Foundation, Inc. | jquery.org/license +//# sourceMappingURL=jquery-2.0.3.min.map +*/ +(function(e,undefined){var t,n,r=typeof undefined,i=e.location,o=e.document,s=o.documentElement,a=e.jQuery,u=e.$,l={},c=[],p="2.0.3",f=c.concat,h=c.push,d=c.slice,g=c.indexOf,m=l.toString,y=l.hasOwnProperty,v=p.trim,x=function(e,n){return new x.fn.init(e,n,t)},b=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,w=/\S+/g,T=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,k=/^-ms-/,N=/-([\da-z])/gi,E=function(e,t){return t.toUpperCase()},S=function(){o.removeEventListener("DOMContentLoaded",S,!1),e.removeEventListener("load",S,!1),x.ready()};x.fn=x.prototype={jquery:p,constructor:x,init:function(e,t,n){var r,i;if(!e)return this;if("string"==typeof e){if(r="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:T.exec(e),!r||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof x?t[0]:t,x.merge(this,x.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:o,!0)),C.test(r[1])&&x.isPlainObject(t))for(r in t)x.isFunction(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return i=o.getElementById(r[2]),i&&i.parentNode&&(this.length=1,this[0]=i),this.context=o,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):x.isFunction(e)?n.ready(e):(e.selector!==undefined&&(this.selector=e.selector,this.context=e.context),x.makeArray(e,this))},selector:"",length:0,toArray:function(){return d.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=x.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return x.each(this,e,t)},ready:function(e){return x.ready.promise().done(e),this},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(x.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:h,sort:[].sort,splice:[].splice},x.fn.init.prototype=x.fn,x.extend=x.fn.extend=function(){var e,t,n,r,i,o,s=arguments[0]||{},a=1,u=arguments.length,l=!1;for("boolean"==typeof s&&(l=s,s=arguments[1]||{},a=2),"object"==typeof s||x.isFunction(s)||(s={}),u===a&&(s=this,--a);u>a;a++)if(null!=(e=arguments[a]))for(t in e)n=s[t],r=e[t],s!==r&&(l&&r&&(x.isPlainObject(r)||(i=x.isArray(r)))?(i?(i=!1,o=n&&x.isArray(n)?n:[]):o=n&&x.isPlainObject(n)?n:{},s[t]=x.extend(l,o,r)):r!==undefined&&(s[t]=r));return s},x.extend({expando:"jQuery"+(p+Math.random()).replace(/\D/g,""),noConflict:function(t){return e.$===x&&(e.$=u),t&&e.jQuery===x&&(e.jQuery=a),x},isReady:!1,readyWait:1,holdReady:function(e){e?x.readyWait++:x.ready(!0)},ready:function(e){(e===!0?--x.readyWait:x.isReady)||(x.isReady=!0,e!==!0&&--x.readyWait>0||(n.resolveWith(o,[x]),x.fn.trigger&&x(o).trigger("ready").off("ready")))},isFunction:function(e){return"function"===x.type(e)},isArray:Array.isArray,isWindow:function(e){return null!=e&&e===e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[m.call(e)]||"object":typeof e},isPlainObject:function(e){if("object"!==x.type(e)||e.nodeType||x.isWindow(e))return!1;try{if(e.constructor&&!y.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(t){return!1}return!0},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||o;var r=C.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=x.buildFragment([e],t,i),i&&x(i).remove(),x.merge([],r.childNodes))},parseJSON:JSON.parse,parseXML:function(e){var t,n;if(!e||"string"!=typeof e)return null;try{n=new DOMParser,t=n.parseFromString(e,"text/xml")}catch(r){t=undefined}return(!t||t.getElementsByTagName("parsererror").length)&&x.error("Invalid XML: "+e),t},noop:function(){},globalEval:function(e){var t,n=eval;e=x.trim(e),e&&(1===e.indexOf("use strict")?(t=o.createElement("script"),t.text=e,o.head.appendChild(t).parentNode.removeChild(t)):n(e))},camelCase:function(e){return e.replace(k,"ms-").replace(N,E)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,o=e.length,s=j(e);if(n){if(s){for(;o>i;i++)if(r=t.apply(e[i],n),r===!1)break}else for(i in e)if(r=t.apply(e[i],n),r===!1)break}else if(s){for(;o>i;i++)if(r=t.call(e[i],i,e[i]),r===!1)break}else for(i in e)if(r=t.call(e[i],i,e[i]),r===!1)break;return e},trim:function(e){return null==e?"":v.call(e)},makeArray:function(e,t){var n=t||[];return null!=e&&(j(Object(e))?x.merge(n,"string"==typeof e?[e]:e):h.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:g.call(t,e,n)},merge:function(e,t){var n=t.length,r=e.length,i=0;if("number"==typeof n)for(;n>i;i++)e[r++]=t[i];else while(t[i]!==undefined)e[r++]=t[i++];return e.length=r,e},grep:function(e,t,n){var r,i=[],o=0,s=e.length;for(n=!!n;s>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,n){var r,i=0,o=e.length,s=j(e),a=[];if(s)for(;o>i;i++)r=t(e[i],i,n),null!=r&&(a[a.length]=r);else for(i in e)r=t(e[i],i,n),null!=r&&(a[a.length]=r);return f.apply([],a)},guid:1,proxy:function(e,t){var n,r,i;return"string"==typeof t&&(n=e[t],t=e,e=n),x.isFunction(e)?(r=d.call(arguments,2),i=function(){return e.apply(t||this,r.concat(d.call(arguments)))},i.guid=e.guid=e.guid||x.guid++,i):undefined},access:function(e,t,n,r,i,o,s){var a=0,u=e.length,l=null==n;if("object"===x.type(n)){i=!0;for(a in n)x.access(e,t,a,n[a],!0,o,s)}else if(r!==undefined&&(i=!0,x.isFunction(r)||(s=!0),l&&(s?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(x(e),n)})),t))for(;u>a;a++)t(e[a],n,s?r:r.call(e[a],a,t(e[a],n)));return i?e:l?t.call(e):u?t(e[0],n):o},now:Date.now,swap:function(e,t,n,r){var i,o,s={};for(o in t)s[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=s[o];return i}}),x.ready.promise=function(t){return n||(n=x.Deferred(),"complete"===o.readyState?setTimeout(x.ready):(o.addEventListener("DOMContentLoaded",S,!1),e.addEventListener("load",S,!1))),n.promise(t)},x.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){l["[object "+t+"]"]=t.toLowerCase()});function j(e){var t=e.length,n=x.type(e);return x.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}t=x(o),function(e,undefined){var t,n,r,i,o,s,a,u,l,c,p,f,h,d,g,m,y,v="sizzle"+-new Date,b=e.document,w=0,T=0,C=st(),k=st(),N=st(),E=!1,S=function(e,t){return e===t?(E=!0,0):0},j=typeof undefined,D=1<<31,A={}.hasOwnProperty,L=[],q=L.pop,H=L.push,O=L.push,F=L.slice,P=L.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},R="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",W="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",$=W.replace("w","w#"),B="\\["+M+"*("+W+")"+M+"*(?:([*^$|!~]?=)"+M+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+$+")|)|)"+M+"*\\]",I=":("+W+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+B.replace(3,8)+")*)|.*)\\)|)",z=RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),_=RegExp("^"+M+"*,"+M+"*"),X=RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=RegExp(M+"*[+~]"),Y=RegExp("="+M+"*([^\\]'\"]*)"+M+"*\\]","g"),V=RegExp(I),G=RegExp("^"+$+"$"),J={ID:RegExp("^#("+W+")"),CLASS:RegExp("^\\.("+W+")"),TAG:RegExp("^("+W.replace("w","w*")+")"),ATTR:RegExp("^"+B),PSEUDO:RegExp("^"+I),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:RegExp("^(?:"+R+")$","i"),needsContext:RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Q=/^[^{]+\{\s*\[native \w/,K=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,Z=/^(?:input|select|textarea|button)$/i,et=/^h\d$/i,tt=/'|\\/g,nt=RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),rt=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:0>r?String.fromCharCode(r+65536):String.fromCharCode(55296|r>>10,56320|1023&r)};try{O.apply(L=F.call(b.childNodes),b.childNodes),L[b.childNodes.length].nodeType}catch(it){O={apply:L.length?function(e,t){H.apply(e,F.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function ot(e,t,r,i){var o,s,a,u,l,f,g,m,x,w;if((t?t.ownerDocument||t:b)!==p&&c(t),t=t||p,r=r||[],!e||"string"!=typeof e)return r;if(1!==(u=t.nodeType)&&9!==u)return[];if(h&&!i){if(o=K.exec(e))if(a=o[1]){if(9===u){if(s=t.getElementById(a),!s||!s.parentNode)return r;if(s.id===a)return r.push(s),r}else if(t.ownerDocument&&(s=t.ownerDocument.getElementById(a))&&y(t,s)&&s.id===a)return r.push(s),r}else{if(o[2])return O.apply(r,t.getElementsByTagName(e)),r;if((a=o[3])&&n.getElementsByClassName&&t.getElementsByClassName)return O.apply(r,t.getElementsByClassName(a)),r}if(n.qsa&&(!d||!d.test(e))){if(m=g=v,x=t,w=9===u&&e,1===u&&"object"!==t.nodeName.toLowerCase()){f=gt(e),(g=t.getAttribute("id"))?m=g.replace(tt,"\\$&"):t.setAttribute("id",m),m="[id='"+m+"'] ",l=f.length;while(l--)f[l]=m+mt(f[l]);x=U.test(e)&&t.parentNode||t,w=f.join(",")}if(w)try{return O.apply(r,x.querySelectorAll(w)),r}catch(T){}finally{g||t.removeAttribute("id")}}}return kt(e.replace(z,"$1"),t,r,i)}function st(){var e=[];function t(n,r){return e.push(n+=" ")>i.cacheLength&&delete t[e.shift()],t[n]=r}return t}function at(e){return e[v]=!0,e}function ut(e){var t=p.createElement("div");try{return!!e(t)}catch(n){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function lt(e,t){var n=e.split("|"),r=e.length;while(r--)i.attrHandle[n[r]]=t}function ct(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&(~t.sourceIndex||D)-(~e.sourceIndex||D);if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function pt(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function ft(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function ht(e){return at(function(t){return t=+t,at(function(n,r){var i,o=e([],n.length,t),s=o.length;while(s--)n[i=o[s]]&&(n[i]=!(r[i]=n[i]))})})}s=ot.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},n=ot.support={},c=ot.setDocument=function(e){var t=e?e.ownerDocument||e:b,r=t.defaultView;return t!==p&&9===t.nodeType&&t.documentElement?(p=t,f=t.documentElement,h=!s(t),r&&r.attachEvent&&r!==r.top&&r.attachEvent("onbeforeunload",function(){c()}),n.attributes=ut(function(e){return e.className="i",!e.getAttribute("className")}),n.getElementsByTagName=ut(function(e){return e.appendChild(t.createComment("")),!e.getElementsByTagName("*").length}),n.getElementsByClassName=ut(function(e){return e.innerHTML="
",e.firstChild.className="i",2===e.getElementsByClassName("i").length}),n.getById=ut(function(e){return f.appendChild(e).id=v,!t.getElementsByName||!t.getElementsByName(v).length}),n.getById?(i.find.ID=function(e,t){if(typeof t.getElementById!==j&&h){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},i.filter.ID=function(e){var t=e.replace(nt,rt);return function(e){return e.getAttribute("id")===t}}):(delete i.find.ID,i.filter.ID=function(e){var t=e.replace(nt,rt);return function(e){var n=typeof e.getAttributeNode!==j&&e.getAttributeNode("id");return n&&n.value===t}}),i.find.TAG=n.getElementsByTagName?function(e,t){return typeof t.getElementsByTagName!==j?t.getElementsByTagName(e):undefined}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},i.find.CLASS=n.getElementsByClassName&&function(e,t){return typeof t.getElementsByClassName!==j&&h?t.getElementsByClassName(e):undefined},g=[],d=[],(n.qsa=Q.test(t.querySelectorAll))&&(ut(function(e){e.innerHTML="",e.querySelectorAll("[selected]").length||d.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll(":checked").length||d.push(":checked")}),ut(function(e){var n=t.createElement("input");n.setAttribute("type","hidden"),e.appendChild(n).setAttribute("t",""),e.querySelectorAll("[t^='']").length&&d.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll(":enabled").length||d.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),d.push(",.*:")})),(n.matchesSelector=Q.test(m=f.webkitMatchesSelector||f.mozMatchesSelector||f.oMatchesSelector||f.msMatchesSelector))&&ut(function(e){n.disconnectedMatch=m.call(e,"div"),m.call(e,"[s!='']:x"),g.push("!=",I)}),d=d.length&&RegExp(d.join("|")),g=g.length&&RegExp(g.join("|")),y=Q.test(f.contains)||f.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},S=f.compareDocumentPosition?function(e,r){if(e===r)return E=!0,0;var i=r.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(r);return i?1&i||!n.sortDetached&&r.compareDocumentPosition(e)===i?e===t||y(b,e)?-1:r===t||y(b,r)?1:l?P.call(l,e)-P.call(l,r):0:4&i?-1:1:e.compareDocumentPosition?-1:1}:function(e,n){var r,i=0,o=e.parentNode,s=n.parentNode,a=[e],u=[n];if(e===n)return E=!0,0;if(!o||!s)return e===t?-1:n===t?1:o?-1:s?1:l?P.call(l,e)-P.call(l,n):0;if(o===s)return ct(e,n);r=e;while(r=r.parentNode)a.unshift(r);r=n;while(r=r.parentNode)u.unshift(r);while(a[i]===u[i])i++;return i?ct(a[i],u[i]):a[i]===b?-1:u[i]===b?1:0},t):p},ot.matches=function(e,t){return ot(e,null,null,t)},ot.matchesSelector=function(e,t){if((e.ownerDocument||e)!==p&&c(e),t=t.replace(Y,"='$1']"),!(!n.matchesSelector||!h||g&&g.test(t)||d&&d.test(t)))try{var r=m.call(e,t);if(r||n.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(i){}return ot(t,p,null,[e]).length>0},ot.contains=function(e,t){return(e.ownerDocument||e)!==p&&c(e),y(e,t)},ot.attr=function(e,t){(e.ownerDocument||e)!==p&&c(e);var r=i.attrHandle[t.toLowerCase()],o=r&&A.call(i.attrHandle,t.toLowerCase())?r(e,t,!h):undefined;return o===undefined?n.attributes||!h?e.getAttribute(t):(o=e.getAttributeNode(t))&&o.specified?o.value:null:o},ot.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},ot.uniqueSort=function(e){var t,r=[],i=0,o=0;if(E=!n.detectDuplicates,l=!n.sortStable&&e.slice(0),e.sort(S),E){while(t=e[o++])t===e[o]&&(i=r.push(o));while(i--)e.splice(r[i],1)}return e},o=ot.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r];r++)n+=o(t);return n},i=ot.selectors={cacheLength:50,createPseudo:at,match:J,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(nt,rt),e[3]=(e[4]||e[5]||"").replace(nt,rt),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||ot.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&ot.error(e[0]),e},PSEUDO:function(e){var t,n=!e[5]&&e[2];return J.CHILD.test(e[0])?null:(e[3]&&e[4]!==undefined?e[2]=e[4]:n&&V.test(n)&&(t=gt(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(nt,rt).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=C[e+" "];return t||(t=RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&C(e,function(e){return t.test("string"==typeof e.className&&e.className||typeof e.getAttribute!==j&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=ot.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.slice(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),s="last"!==e.slice(-4),a="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,p,f,h,d,g=o!==s?"nextSibling":"previousSibling",m=t.parentNode,y=a&&t.nodeName.toLowerCase(),x=!u&&!a;if(m){if(o){while(g){p=t;while(p=p[g])if(a?p.nodeName.toLowerCase()===y:1===p.nodeType)return!1;d=g="only"===e&&!d&&"nextSibling"}return!0}if(d=[s?m.firstChild:m.lastChild],s&&x){c=m[v]||(m[v]={}),l=c[e]||[],h=l[0]===w&&l[1],f=l[0]===w&&l[2],p=h&&m.childNodes[h];while(p=++h&&p&&p[g]||(f=h=0)||d.pop())if(1===p.nodeType&&++f&&p===t){c[e]=[w,h,f];break}}else if(x&&(l=(t[v]||(t[v]={}))[e])&&l[0]===w)f=l[1];else while(p=++h&&p&&p[g]||(f=h=0)||d.pop())if((a?p.nodeName.toLowerCase()===y:1===p.nodeType)&&++f&&(x&&((p[v]||(p[v]={}))[e]=[w,f]),p===t))break;return f-=i,f===r||0===f%r&&f/r>=0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||ot.error("unsupported pseudo: "+e);return r[v]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?at(function(e,n){var i,o=r(e,t),s=o.length;while(s--)i=P.call(e,o[s]),e[i]=!(n[i]=o[s])}):function(e){return r(e,0,n)}):r}},pseudos:{not:at(function(e){var t=[],n=[],r=a(e.replace(z,"$1"));return r[v]?at(function(e,t,n,i){var o,s=r(e,null,i,[]),a=e.length;while(a--)(o=s[a])&&(e[a]=!(t[a]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:at(function(e){return function(t){return ot(e,t).length>0}}),contains:at(function(e){return function(t){return(t.textContent||t.innerText||o(t)).indexOf(e)>-1}}),lang:at(function(e){return G.test(e||"")||ot.error("unsupported lang: "+e),e=e.replace(nt,rt).toLowerCase(),function(t){var n;do if(n=h?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===f},focus:function(e){return e===p.activeElement&&(!p.hasFocus||p.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!i.pseudos.empty(e)},header:function(e){return et.test(e.nodeName)},input:function(e){return Z.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:ht(function(){return[0]}),last:ht(function(e,t){return[t-1]}),eq:ht(function(e,t,n){return[0>n?n+t:n]}),even:ht(function(e,t){var n=0;for(;t>n;n+=2)e.push(n);return e}),odd:ht(function(e,t){var n=1;for(;t>n;n+=2)e.push(n);return e}),lt:ht(function(e,t,n){var r=0>n?n+t:n;for(;--r>=0;)e.push(r);return e}),gt:ht(function(e,t,n){var r=0>n?n+t:n;for(;t>++r;)e.push(r);return e})}},i.pseudos.nth=i.pseudos.eq;for(t in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})i.pseudos[t]=pt(t);for(t in{submit:!0,reset:!0})i.pseudos[t]=ft(t);function dt(){}dt.prototype=i.filters=i.pseudos,i.setFilters=new dt;function gt(e,t){var n,r,o,s,a,u,l,c=k[e+" "];if(c)return t?0:c.slice(0);a=e,u=[],l=i.preFilter;while(a){(!n||(r=_.exec(a)))&&(r&&(a=a.slice(r[0].length)||a),u.push(o=[])),n=!1,(r=X.exec(a))&&(n=r.shift(),o.push({value:n,type:r[0].replace(z," ")}),a=a.slice(n.length));for(s in i.filter)!(r=J[s].exec(a))||l[s]&&!(r=l[s](r))||(n=r.shift(),o.push({value:n,type:s,matches:r}),a=a.slice(n.length));if(!n)break}return t?a.length:a?ot.error(e):k(e,u).slice(0)}function mt(e){var t=0,n=e.length,r="";for(;n>t;t++)r+=e[t].value;return r}function yt(e,t,n){var i=t.dir,o=n&&"parentNode"===i,s=T++;return t.first?function(t,n,r){while(t=t[i])if(1===t.nodeType||o)return e(t,n,r)}:function(t,n,a){var u,l,c,p=w+" "+s;if(a){while(t=t[i])if((1===t.nodeType||o)&&e(t,n,a))return!0}else while(t=t[i])if(1===t.nodeType||o)if(c=t[v]||(t[v]={}),(l=c[i])&&l[0]===p){if((u=l[1])===!0||u===r)return u===!0}else if(l=c[i]=[p],l[1]=e(t,n,a)||r,l[1]===!0)return!0}}function vt(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function xt(e,t,n,r,i){var o,s=[],a=0,u=e.length,l=null!=t;for(;u>a;a++)(o=e[a])&&(!n||n(o,r,i))&&(s.push(o),l&&t.push(a));return s}function bt(e,t,n,r,i,o){return r&&!r[v]&&(r=bt(r)),i&&!i[v]&&(i=bt(i,o)),at(function(o,s,a,u){var l,c,p,f=[],h=[],d=s.length,g=o||Ct(t||"*",a.nodeType?[a]:a,[]),m=!e||!o&&t?g:xt(g,f,e,a,u),y=n?i||(o?e:d||r)?[]:s:m;if(n&&n(m,y,a,u),r){l=xt(y,h),r(l,[],a,u),c=l.length;while(c--)(p=l[c])&&(y[h[c]]=!(m[h[c]]=p))}if(o){if(i||e){if(i){l=[],c=y.length;while(c--)(p=y[c])&&l.push(m[c]=p);i(null,y=[],l,u)}c=y.length;while(c--)(p=y[c])&&(l=i?P.call(o,p):f[c])>-1&&(o[l]=!(s[l]=p))}}else y=xt(y===s?y.splice(d,y.length):y),i?i(null,s,y,u):O.apply(s,y)})}function wt(e){var t,n,r,o=e.length,s=i.relative[e[0].type],a=s||i.relative[" "],l=s?1:0,c=yt(function(e){return e===t},a,!0),p=yt(function(e){return P.call(t,e)>-1},a,!0),f=[function(e,n,r){return!s&&(r||n!==u)||((t=n).nodeType?c(e,n,r):p(e,n,r))}];for(;o>l;l++)if(n=i.relative[e[l].type])f=[yt(vt(f),n)];else{if(n=i.filter[e[l].type].apply(null,e[l].matches),n[v]){for(r=++l;o>r;r++)if(i.relative[e[r].type])break;return bt(l>1&&vt(f),l>1&&mt(e.slice(0,l-1).concat({value:" "===e[l-2].type?"*":""})).replace(z,"$1"),n,r>l&&wt(e.slice(l,r)),o>r&&wt(e=e.slice(r)),o>r&&mt(e))}f.push(n)}return vt(f)}function Tt(e,t){var n=0,o=t.length>0,s=e.length>0,a=function(a,l,c,f,h){var d,g,m,y=[],v=0,x="0",b=a&&[],T=null!=h,C=u,k=a||s&&i.find.TAG("*",h&&l.parentNode||l),N=w+=null==C?1:Math.random()||.1;for(T&&(u=l!==p&&l,r=n);null!=(d=k[x]);x++){if(s&&d){g=0;while(m=e[g++])if(m(d,l,c)){f.push(d);break}T&&(w=N,r=++n)}o&&((d=!m&&d)&&v--,a&&b.push(d))}if(v+=x,o&&x!==v){g=0;while(m=t[g++])m(b,y,l,c);if(a){if(v>0)while(x--)b[x]||y[x]||(y[x]=q.call(f));y=xt(y)}O.apply(f,y),T&&!a&&y.length>0&&v+t.length>1&&ot.uniqueSort(f)}return T&&(w=N,u=C),b};return o?at(a):a}a=ot.compile=function(e,t){var n,r=[],i=[],o=N[e+" "];if(!o){t||(t=gt(e)),n=t.length;while(n--)o=wt(t[n]),o[v]?r.push(o):i.push(o);o=N(e,Tt(i,r))}return o};function Ct(e,t,n){var r=0,i=t.length;for(;i>r;r++)ot(e,t[r],n);return n}function kt(e,t,r,o){var s,u,l,c,p,f=gt(e);if(!o&&1===f.length){if(u=f[0]=f[0].slice(0),u.length>2&&"ID"===(l=u[0]).type&&n.getById&&9===t.nodeType&&h&&i.relative[u[1].type]){if(t=(i.find.ID(l.matches[0].replace(nt,rt),t)||[])[0],!t)return r;e=e.slice(u.shift().value.length)}s=J.needsContext.test(e)?0:u.length;while(s--){if(l=u[s],i.relative[c=l.type])break;if((p=i.find[c])&&(o=p(l.matches[0].replace(nt,rt),U.test(u[0].type)&&t.parentNode||t))){if(u.splice(s,1),e=o.length&&mt(u),!e)return O.apply(r,o),r;break}}}return a(e,f)(o,t,!h,r,U.test(e)),r}n.sortStable=v.split("").sort(S).join("")===v,n.detectDuplicates=E,c(),n.sortDetached=ut(function(e){return 1&e.compareDocumentPosition(p.createElement("div"))}),ut(function(e){return e.innerHTML="
","#"===e.firstChild.getAttribute("href")})||lt("type|href|height|width",function(e,t,n){return n?undefined:e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),n.attributes&&ut(function(e){return e.innerHTML="",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||lt("value",function(e,t,n){return n||"input"!==e.nodeName.toLowerCase()?undefined:e.defaultValue}),ut(function(e){return null==e.getAttribute("disabled")})||lt(R,function(e,t,n){var r;return n?undefined:(r=e.getAttributeNode(t))&&r.specified?r.value:e[t]===!0?t.toLowerCase():null}),x.find=ot,x.expr=ot.selectors,x.expr[":"]=x.expr.pseudos,x.unique=ot.uniqueSort,x.text=ot.getText,x.isXMLDoc=ot.isXML,x.contains=ot.contains}(e);var D={};function A(e){var t=D[e]={};return x.each(e.match(w)||[],function(e,n){t[n]=!0}),t}x.Callbacks=function(e){e="string"==typeof e?D[e]||A(e):x.extend({},e);var t,n,r,i,o,s,a=[],u=!e.once&&[],l=function(p){for(t=e.memory&&p,n=!0,s=i||0,i=0,o=a.length,r=!0;a&&o>s;s++)if(a[s].apply(p[0],p[1])===!1&&e.stopOnFalse){t=!1;break}r=!1,a&&(u?u.length&&l(u.shift()):t?a=[]:c.disable())},c={add:function(){if(a){var n=a.length;(function s(t){x.each(t,function(t,n){var r=x.type(n);"function"===r?e.unique&&c.has(n)||a.push(n):n&&n.length&&"string"!==r&&s(n)})})(arguments),r?o=a.length:t&&(i=n,l(t))}return this},remove:function(){return a&&x.each(arguments,function(e,t){var n;while((n=x.inArray(t,a,n))>-1)a.splice(n,1),r&&(o>=n&&o--,s>=n&&s--)}),this},has:function(e){return e?x.inArray(e,a)>-1:!(!a||!a.length)},empty:function(){return a=[],o=0,this},disable:function(){return a=u=t=undefined,this},disabled:function(){return!a},lock:function(){return u=undefined,t||c.disable(),this},locked:function(){return!u},fireWith:function(e,t){return!a||n&&!u||(t=t||[],t=[e,t.slice?t.slice():t],r?u.push(t):l(t)),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!n}};return c},x.extend({Deferred:function(e){var t=[["resolve","done",x.Callbacks("once memory"),"resolved"],["reject","fail",x.Callbacks("once memory"),"rejected"],["notify","progress",x.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return x.Deferred(function(n){x.each(t,function(t,o){var s=o[0],a=x.isFunction(e[t])&&e[t];i[o[1]](function(){var e=a&&a.apply(this,arguments);e&&x.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[s+"With"](this===r?n.promise():this,a?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?x.extend(e,r):r}},i={};return r.pipe=r.then,x.each(t,function(e,o){var s=o[2],a=o[3];r[o[1]]=s.add,a&&s.add(function(){n=a},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=s.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=d.call(arguments),r=n.length,i=1!==r||e&&x.isFunction(e.promise)?r:0,o=1===i?e:x.Deferred(),s=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?d.call(arguments):r,n===a?o.notifyWith(t,n):--i||o.resolveWith(t,n)}},a,u,l;if(r>1)for(a=Array(r),u=Array(r),l=Array(r);r>t;t++)n[t]&&x.isFunction(n[t].promise)?n[t].promise().done(s(t,l,n)).fail(o.reject).progress(s(t,u,a)):--i;return i||o.resolveWith(l,n),o.promise()}}),x.support=function(t){var n=o.createElement("input"),r=o.createDocumentFragment(),i=o.createElement("div"),s=o.createElement("select"),a=s.appendChild(o.createElement("option"));return n.type?(n.type="checkbox",t.checkOn=""!==n.value,t.optSelected=a.selected,t.reliableMarginRight=!0,t.boxSizingReliable=!0,t.pixelPosition=!1,n.checked=!0,t.noCloneChecked=n.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!a.disabled,n=o.createElement("input"),n.value="t",n.type="radio",t.radioValue="t"===n.value,n.setAttribute("checked","t"),n.setAttribute("name","t"),r.appendChild(n),t.checkClone=r.cloneNode(!0).cloneNode(!0).lastChild.checked,t.focusinBubbles="onfocusin"in e,i.style.backgroundClip="content-box",i.cloneNode(!0).style.backgroundClip="",t.clearCloneStyle="content-box"===i.style.backgroundClip,x(function(){var n,r,s="padding:0;margin:0;border:0;display:block;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box",a=o.getElementsByTagName("body")[0];a&&(n=o.createElement("div"),n.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",a.appendChild(n).appendChild(i),i.innerHTML="",i.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%",x.swap(a,null!=a.style.zoom?{zoom:1}:{},function(){t.boxSizing=4===i.offsetWidth}),e.getComputedStyle&&(t.pixelPosition="1%"!==(e.getComputedStyle(i,null)||{}).top,t.boxSizingReliable="4px"===(e.getComputedStyle(i,null)||{width:"4px"}).width,r=i.appendChild(o.createElement("div")),r.style.cssText=i.style.cssText=s,r.style.marginRight=r.style.width="0",i.style.width="1px",t.reliableMarginRight=!parseFloat((e.getComputedStyle(r,null)||{}).marginRight)),a.removeChild(n))}),t):t}({});var L,q,H=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,O=/([A-Z])/g;function F(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=x.expando+Math.random()}F.uid=1,F.accepts=function(e){return e.nodeType?1===e.nodeType||9===e.nodeType:!0},F.prototype={key:function(e){if(!F.accepts(e))return 0;var t={},n=e[this.expando];if(!n){n=F.uid++;try{t[this.expando]={value:n},Object.defineProperties(e,t)}catch(r){t[this.expando]=n,x.extend(e,t)}}return this.cache[n]||(this.cache[n]={}),n},set:function(e,t,n){var r,i=this.key(e),o=this.cache[i];if("string"==typeof t)o[t]=n;else if(x.isEmptyObject(o))x.extend(this.cache[i],t);else for(r in t)o[r]=t[r];return o},get:function(e,t){var n=this.cache[this.key(e)];return t===undefined?n:n[t]},access:function(e,t,n){var r;return t===undefined||t&&"string"==typeof t&&n===undefined?(r=this.get(e,t),r!==undefined?r:this.get(e,x.camelCase(t))):(this.set(e,t,n),n!==undefined?n:t)},remove:function(e,t){var n,r,i,o=this.key(e),s=this.cache[o];if(t===undefined)this.cache[o]={};else{x.isArray(t)?r=t.concat(t.map(x.camelCase)):(i=x.camelCase(t),t in s?r=[t,i]:(r=i,r=r in s?[r]:r.match(w)||[])),n=r.length;while(n--)delete s[r[n]]}},hasData:function(e){return!x.isEmptyObject(this.cache[e[this.expando]]||{})},discard:function(e){e[this.expando]&&delete this.cache[e[this.expando]]}},L=new F,q=new F,x.extend({acceptData:F.accepts,hasData:function(e){return L.hasData(e)||q.hasData(e)},data:function(e,t,n){return L.access(e,t,n)},removeData:function(e,t){L.remove(e,t)},_data:function(e,t,n){return q.access(e,t,n)},_removeData:function(e,t){q.remove(e,t)}}),x.fn.extend({data:function(e,t){var n,r,i=this[0],o=0,s=null;if(e===undefined){if(this.length&&(s=L.get(i),1===i.nodeType&&!q.get(i,"hasDataAttrs"))){for(n=i.attributes;n.length>o;o++)r=n[o].name,0===r.indexOf("data-")&&(r=x.camelCase(r.slice(5)),P(i,r,s[r]));q.set(i,"hasDataAttrs",!0)}return s}return"object"==typeof e?this.each(function(){L.set(this,e)}):x.access(this,function(t){var n,r=x.camelCase(e);if(i&&t===undefined){if(n=L.get(i,e),n!==undefined)return n;if(n=L.get(i,r),n!==undefined)return n;if(n=P(i,r,undefined),n!==undefined)return n}else this.each(function(){var n=L.get(this,r);L.set(this,r,t),-1!==e.indexOf("-")&&n!==undefined&&L.set(this,e,t)})},null,t,arguments.length>1,null,!0)},removeData:function(e){return this.each(function(){L.remove(this,e)})}});function P(e,t,n){var r;if(n===undefined&&1===e.nodeType)if(r="data-"+t.replace(O,"-$1").toLowerCase(),n=e.getAttribute(r),"string"==typeof n){try{n="true"===n?!0:"false"===n?!1:"null"===n?null:+n+""===n?+n:H.test(n)?JSON.parse(n):n}catch(i){}L.set(e,t,n)}else n=undefined;return n}x.extend({queue:function(e,t,n){var r;return e?(t=(t||"fx")+"queue",r=q.get(e,t),n&&(!r||x.isArray(n)?r=q.access(e,t,x.makeArray(n)):r.push(n)),r||[]):undefined},dequeue:function(e,t){t=t||"fx";var n=x.queue(e,t),r=n.length,i=n.shift(),o=x._queueHooks(e,t),s=function(){x.dequeue(e,t) +};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,s,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return q.get(e,n)||q.access(e,n,{empty:x.Callbacks("once memory").add(function(){q.remove(e,[t+"queue",n])})})}}),x.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),n>arguments.length?x.queue(this[0],e):t===undefined?this:this.each(function(){var n=x.queue(this,e,t);x._queueHooks(this,e),"fx"===e&&"inprogress"!==n[0]&&x.dequeue(this,e)})},dequeue:function(e){return this.each(function(){x.dequeue(this,e)})},delay:function(e,t){return e=x.fx?x.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,t){var n,r=1,i=x.Deferred(),o=this,s=this.length,a=function(){--r||i.resolveWith(o,[o])};"string"!=typeof e&&(t=e,e=undefined),e=e||"fx";while(s--)n=q.get(o[s],e+"queueHooks"),n&&n.empty&&(r++,n.empty.add(a));return a(),i.promise(t)}});var R,M,W=/[\t\r\n\f]/g,$=/\r/g,B=/^(?:input|select|textarea|button)$/i;x.fn.extend({attr:function(e,t){return x.access(this,x.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){x.removeAttr(this,e)})},prop:function(e,t){return x.access(this,x.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each(function(){delete this[x.propFix[e]||e]})},addClass:function(e){var t,n,r,i,o,s=0,a=this.length,u="string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).addClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];a>s;s++)if(n=this[s],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(W," "):" ")){o=0;while(i=t[o++])0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=x.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,s=0,a=this.length,u=0===arguments.length||"string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).removeClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];a>s;s++)if(n=this[s],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(W," "):"")){o=0;while(i=t[o++])while(r.indexOf(" "+i+" ")>=0)r=r.replace(" "+i+" "," ");n.className=e?x.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e;return"boolean"==typeof t&&"string"===n?t?this.addClass(e):this.removeClass(e):x.isFunction(e)?this.each(function(n){x(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n){var t,i=0,o=x(this),s=e.match(w)||[];while(t=s[i++])o.hasClass(t)?o.removeClass(t):o.addClass(t)}else(n===r||"boolean"===n)&&(this.className&&q.set(this,"__className__",this.className),this.className=this.className||e===!1?"":q.get(this,"__className__")||"")})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(W," ").indexOf(t)>=0)return!0;return!1},val:function(e){var t,n,r,i=this[0];{if(arguments.length)return r=x.isFunction(e),this.each(function(n){var i;1===this.nodeType&&(i=r?e.call(this,n,x(this).val()):e,null==i?i="":"number"==typeof i?i+="":x.isArray(i)&&(i=x.map(i,function(e){return null==e?"":e+""})),t=x.valHooks[this.type]||x.valHooks[this.nodeName.toLowerCase()],t&&"set"in t&&t.set(this,i,"value")!==undefined||(this.value=i))});if(i)return t=x.valHooks[i.type]||x.valHooks[i.nodeName.toLowerCase()],t&&"get"in t&&(n=t.get(i,"value"))!==undefined?n:(n=i.value,"string"==typeof n?n.replace($,""):null==n?"":n)}}}),x.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,s=o?null:[],a=o?i+1:r.length,u=0>i?a:o?i:0;for(;a>u;u++)if(n=r[u],!(!n.selected&&u!==i||(x.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&x.nodeName(n.parentNode,"optgroup"))){if(t=x(n).val(),o)return t;s.push(t)}return s},set:function(e,t){var n,r,i=e.options,o=x.makeArray(t),s=i.length;while(s--)r=i[s],(r.selected=x.inArray(x(r).val(),o)>=0)&&(n=!0);return n||(e.selectedIndex=-1),o}}},attr:function(e,t,n){var i,o,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return typeof e.getAttribute===r?x.prop(e,t,n):(1===s&&x.isXMLDoc(e)||(t=t.toLowerCase(),i=x.attrHooks[t]||(x.expr.match.bool.test(t)?M:R)),n===undefined?i&&"get"in i&&null!==(o=i.get(e,t))?o:(o=x.find.attr(e,t),null==o?undefined:o):null!==n?i&&"set"in i&&(o=i.set(e,n,t))!==undefined?o:(e.setAttribute(t,n+""),n):(x.removeAttr(e,t),undefined))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(w);if(o&&1===e.nodeType)while(n=o[i++])r=x.propFix[n]||n,x.expr.match.bool.test(n)&&(e[r]=!1),e.removeAttribute(n)},attrHooks:{type:{set:function(e,t){if(!x.support.radioValue&&"radio"===t&&x.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},propFix:{"for":"htmlFor","class":"className"},prop:function(e,t,n){var r,i,o,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return o=1!==s||!x.isXMLDoc(e),o&&(t=x.propFix[t]||t,i=x.propHooks[t]),n!==undefined?i&&"set"in i&&(r=i.set(e,n,t))!==undefined?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){return e.hasAttribute("tabindex")||B.test(e.nodeName)||e.href?e.tabIndex:-1}}}}),M={set:function(e,t,n){return t===!1?x.removeAttr(e,n):e.setAttribute(n,n),n}},x.each(x.expr.match.bool.source.match(/\w+/g),function(e,t){var n=x.expr.attrHandle[t]||x.find.attr;x.expr.attrHandle[t]=function(e,t,r){var i=x.expr.attrHandle[t],o=r?undefined:(x.expr.attrHandle[t]=undefined)!=n(e,t,r)?t.toLowerCase():null;return x.expr.attrHandle[t]=i,o}}),x.support.optSelected||(x.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null}}),x.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){x.propFix[this.toLowerCase()]=this}),x.each(["radio","checkbox"],function(){x.valHooks[this]={set:function(e,t){return x.isArray(t)?e.checked=x.inArray(x(e).val(),t)>=0:undefined}},x.support.checkOn||(x.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})});var I=/^key/,z=/^(?:mouse|contextmenu)|click/,_=/^(?:focusinfocus|focusoutblur)$/,X=/^([^.]*)(?:\.(.+)|)$/;function U(){return!0}function Y(){return!1}function V(){try{return o.activeElement}catch(e){}}x.event={global:{},add:function(e,t,n,i,o){var s,a,u,l,c,p,f,h,d,g,m,y=q.get(e);if(y){n.handler&&(s=n,n=s.handler,o=s.selector),n.guid||(n.guid=x.guid++),(l=y.events)||(l=y.events={}),(a=y.handle)||(a=y.handle=function(e){return typeof x===r||e&&x.event.triggered===e.type?undefined:x.event.dispatch.apply(a.elem,arguments)},a.elem=e),t=(t||"").match(w)||[""],c=t.length;while(c--)u=X.exec(t[c])||[],d=m=u[1],g=(u[2]||"").split(".").sort(),d&&(f=x.event.special[d]||{},d=(o?f.delegateType:f.bindType)||d,f=x.event.special[d]||{},p=x.extend({type:d,origType:m,data:i,handler:n,guid:n.guid,selector:o,needsContext:o&&x.expr.match.needsContext.test(o),namespace:g.join(".")},s),(h=l[d])||(h=l[d]=[],h.delegateCount=0,f.setup&&f.setup.call(e,i,g,a)!==!1||e.addEventListener&&e.addEventListener(d,a,!1)),f.add&&(f.add.call(e,p),p.handler.guid||(p.handler.guid=n.guid)),o?h.splice(h.delegateCount++,0,p):h.push(p),x.event.global[d]=!0);e=null}},remove:function(e,t,n,r,i){var o,s,a,u,l,c,p,f,h,d,g,m=q.hasData(e)&&q.get(e);if(m&&(u=m.events)){t=(t||"").match(w)||[""],l=t.length;while(l--)if(a=X.exec(t[l])||[],h=g=a[1],d=(a[2]||"").split(".").sort(),h){p=x.event.special[h]||{},h=(r?p.delegateType:p.bindType)||h,f=u[h]||[],a=a[2]&&RegExp("(^|\\.)"+d.join("\\.(?:.*\\.|)")+"(\\.|$)"),s=o=f.length;while(o--)c=f[o],!i&&g!==c.origType||n&&n.guid!==c.guid||a&&!a.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(f.splice(o,1),c.selector&&f.delegateCount--,p.remove&&p.remove.call(e,c));s&&!f.length&&(p.teardown&&p.teardown.call(e,d,m.handle)!==!1||x.removeEvent(e,h,m.handle),delete u[h])}else for(h in u)x.event.remove(e,h+t[l],n,r,!0);x.isEmptyObject(u)&&(delete m.handle,q.remove(e,"events"))}},trigger:function(t,n,r,i){var s,a,u,l,c,p,f,h=[r||o],d=y.call(t,"type")?t.type:t,g=y.call(t,"namespace")?t.namespace.split("."):[];if(a=u=r=r||o,3!==r.nodeType&&8!==r.nodeType&&!_.test(d+x.event.triggered)&&(d.indexOf(".")>=0&&(g=d.split("."),d=g.shift(),g.sort()),c=0>d.indexOf(":")&&"on"+d,t=t[x.expando]?t:new x.Event(d,"object"==typeof t&&t),t.isTrigger=i?2:3,t.namespace=g.join("."),t.namespace_re=t.namespace?RegExp("(^|\\.)"+g.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,t.result=undefined,t.target||(t.target=r),n=null==n?[t]:x.makeArray(n,[t]),f=x.event.special[d]||{},i||!f.trigger||f.trigger.apply(r,n)!==!1)){if(!i&&!f.noBubble&&!x.isWindow(r)){for(l=f.delegateType||d,_.test(l+d)||(a=a.parentNode);a;a=a.parentNode)h.push(a),u=a;u===(r.ownerDocument||o)&&h.push(u.defaultView||u.parentWindow||e)}s=0;while((a=h[s++])&&!t.isPropagationStopped())t.type=s>1?l:f.bindType||d,p=(q.get(a,"events")||{})[t.type]&&q.get(a,"handle"),p&&p.apply(a,n),p=c&&a[c],p&&x.acceptData(a)&&p.apply&&p.apply(a,n)===!1&&t.preventDefault();return t.type=d,i||t.isDefaultPrevented()||f._default&&f._default.apply(h.pop(),n)!==!1||!x.acceptData(r)||c&&x.isFunction(r[d])&&!x.isWindow(r)&&(u=r[c],u&&(r[c]=null),x.event.triggered=d,r[d](),x.event.triggered=undefined,u&&(r[c]=u)),t.result}},dispatch:function(e){e=x.event.fix(e);var t,n,r,i,o,s=[],a=d.call(arguments),u=(q.get(this,"events")||{})[e.type]||[],l=x.event.special[e.type]||{};if(a[0]=e,e.delegateTarget=this,!l.preDispatch||l.preDispatch.call(this,e)!==!1){s=x.event.handlers.call(this,e,u),t=0;while((i=s[t++])&&!e.isPropagationStopped()){e.currentTarget=i.elem,n=0;while((o=i.handlers[n++])&&!e.isImmediatePropagationStopped())(!e.namespace_re||e.namespace_re.test(o.namespace))&&(e.handleObj=o,e.data=o.data,r=((x.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,a),r!==undefined&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()))}return l.postDispatch&&l.postDispatch.call(this,e),e.result}},handlers:function(e,t){var n,r,i,o,s=[],a=t.delegateCount,u=e.target;if(a&&u.nodeType&&(!e.button||"click"!==e.type))for(;u!==this;u=u.parentNode||this)if(u.disabled!==!0||"click"!==e.type){for(r=[],n=0;a>n;n++)o=t[n],i=o.selector+" ",r[i]===undefined&&(r[i]=o.needsContext?x(i,this).index(u)>=0:x.find(i,this,null,[u]).length),r[i]&&r.push(o);r.length&&s.push({elem:u,handlers:r})}return t.length>a&&s.push({elem:this,handlers:t.slice(a)}),s},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,t){var n,r,i,s=t.button;return null==e.pageX&&null!=t.clientX&&(n=e.target.ownerDocument||o,r=n.documentElement,i=n.body,e.pageX=t.clientX+(r&&r.scrollLeft||i&&i.scrollLeft||0)-(r&&r.clientLeft||i&&i.clientLeft||0),e.pageY=t.clientY+(r&&r.scrollTop||i&&i.scrollTop||0)-(r&&r.clientTop||i&&i.clientTop||0)),e.which||s===undefined||(e.which=1&s?1:2&s?3:4&s?2:0),e}},fix:function(e){if(e[x.expando])return e;var t,n,r,i=e.type,s=e,a=this.fixHooks[i];a||(this.fixHooks[i]=a=z.test(i)?this.mouseHooks:I.test(i)?this.keyHooks:{}),r=a.props?this.props.concat(a.props):this.props,e=new x.Event(s),t=r.length;while(t--)n=r[t],e[n]=s[n];return e.target||(e.target=o),3===e.target.nodeType&&(e.target=e.target.parentNode),a.filter?a.filter(e,s):e},special:{load:{noBubble:!0},focus:{trigger:function(){return this!==V()&&this.focus?(this.focus(),!1):undefined},delegateType:"focusin"},blur:{trigger:function(){return this===V()&&this.blur?(this.blur(),!1):undefined},delegateType:"focusout"},click:{trigger:function(){return"checkbox"===this.type&&this.click&&x.nodeName(this,"input")?(this.click(),!1):undefined},_default:function(e){return x.nodeName(e.target,"a")}},beforeunload:{postDispatch:function(e){e.result!==undefined&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=x.extend(new x.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?x.event.trigger(i,null,t):x.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},x.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)},x.Event=function(e,t){return this instanceof x.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.getPreventDefault&&e.getPreventDefault()?U:Y):this.type=e,t&&x.extend(this,t),this.timeStamp=e&&e.timeStamp||x.now(),this[x.expando]=!0,undefined):new x.Event(e,t)},x.Event.prototype={isDefaultPrevented:Y,isPropagationStopped:Y,isImmediatePropagationStopped:Y,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=U,e&&e.preventDefault&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=U,e&&e.stopPropagation&&e.stopPropagation()},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=U,this.stopPropagation()}},x.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){x.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj;return(!i||i!==r&&!x.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),x.support.focusinBubbles||x.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){x.event.simulate(t,e.target,x.event.fix(e),!0)};x.event.special[t]={setup:function(){0===n++&&o.addEventListener(e,r,!0)},teardown:function(){0===--n&&o.removeEventListener(e,r,!0)}}}),x.fn.extend({on:function(e,t,n,r,i){var o,s;if("object"==typeof e){"string"!=typeof t&&(n=n||t,t=undefined);for(s in e)this.on(s,t,n,e[s],i);return this}if(null==n&&null==r?(r=t,n=t=undefined):null==r&&("string"==typeof t?(r=n,n=undefined):(r=n,n=t,t=undefined)),r===!1)r=Y;else if(!r)return this;return 1===i&&(o=r,r=function(e){return x().off(e),o.apply(this,arguments)},r.guid=o.guid||(o.guid=x.guid++)),this.each(function(){x.event.add(this,e,r,n,t)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,x(e.delegateTarget).off(r.namespace?r.origType+"."+r.namespace:r.origType,r.selector,r.handler),this;if("object"==typeof e){for(i in e)this.off(i,t,e[i]);return this}return(t===!1||"function"==typeof t)&&(n=t,t=undefined),n===!1&&(n=Y),this.each(function(){x.event.remove(this,e,n,t)})},trigger:function(e,t){return this.each(function(){x.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];return n?x.event.trigger(e,t,n,!0):undefined}});var G=/^.[^:#\[\.,]*$/,J=/^(?:parents|prev(?:Until|All))/,Q=x.expr.match.needsContext,K={children:!0,contents:!0,next:!0,prev:!0};x.fn.extend({find:function(e){var t,n=[],r=this,i=r.length;if("string"!=typeof e)return this.pushStack(x(e).filter(function(){for(t=0;i>t;t++)if(x.contains(r[t],this))return!0}));for(t=0;i>t;t++)x.find(e,r[t],n);return n=this.pushStack(i>1?x.unique(n):n),n.selector=this.selector?this.selector+" "+e:e,n},has:function(e){var t=x(e,this),n=t.length;return this.filter(function(){var e=0;for(;n>e;e++)if(x.contains(this,t[e]))return!0})},not:function(e){return this.pushStack(et(this,e||[],!0))},filter:function(e){return this.pushStack(et(this,e||[],!1))},is:function(e){return!!et(this,"string"==typeof e&&Q.test(e)?x(e):e||[],!1).length},closest:function(e,t){var n,r=0,i=this.length,o=[],s=Q.test(e)||"string"!=typeof e?x(e,t||this.context):0;for(;i>r;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(11>n.nodeType&&(s?s.index(n)>-1:1===n.nodeType&&x.find.matchesSelector(n,e))){n=o.push(n);break}return this.pushStack(o.length>1?x.unique(o):o)},index:function(e){return e?"string"==typeof e?g.call(x(e),this[0]):g.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?x(e,t):x.makeArray(e&&e.nodeType?[e]:e),r=x.merge(this.get(),n);return this.pushStack(x.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function Z(e,t){while((e=e[t])&&1!==e.nodeType);return e}x.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return x.dir(e,"parentNode")},parentsUntil:function(e,t,n){return x.dir(e,"parentNode",n)},next:function(e){return Z(e,"nextSibling")},prev:function(e){return Z(e,"previousSibling")},nextAll:function(e){return x.dir(e,"nextSibling")},prevAll:function(e){return x.dir(e,"previousSibling")},nextUntil:function(e,t,n){return x.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return x.dir(e,"previousSibling",n)},siblings:function(e){return x.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return x.sibling(e.firstChild)},contents:function(e){return e.contentDocument||x.merge([],e.childNodes)}},function(e,t){x.fn[e]=function(n,r){var i=x.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=x.filter(r,i)),this.length>1&&(K[e]||x.unique(i),J.test(e)&&i.reverse()),this.pushStack(i)}}),x.extend({filter:function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?x.find.matchesSelector(r,e)?[r]:[]:x.find.matches(e,x.grep(t,function(e){return 1===e.nodeType}))},dir:function(e,t,n){var r=[],i=n!==undefined;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&x(e).is(n))break;r.push(e)}return r},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});function et(e,t,n){if(x.isFunction(t))return x.grep(e,function(e,r){return!!t.call(e,r,e)!==n});if(t.nodeType)return x.grep(e,function(e){return e===t!==n});if("string"==typeof t){if(G.test(t))return x.filter(t,e,n);t=x.filter(t,e)}return x.grep(e,function(e){return g.call(t,e)>=0!==n})}var tt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,nt=/<([\w:]+)/,rt=/<|&#?\w+;/,it=/<(?:script|style|link)/i,ot=/^(?:checkbox|radio)$/i,st=/checked\s*(?:[^=]|=\s*.checked.)/i,at=/^$|\/(?:java|ecma)script/i,ut=/^true\/(.*)/,lt=/^\s*\s*$/g,ct={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};ct.optgroup=ct.option,ct.tbody=ct.tfoot=ct.colgroup=ct.caption=ct.thead,ct.th=ct.td,x.fn.extend({text:function(e){return x.access(this,function(e){return e===undefined?x.text(this):this.empty().append((this[0]&&this[0].ownerDocument||o).createTextNode(e))},null,e,arguments.length)},append:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=pt(this,e);t.appendChild(e)}})},prepend:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=pt(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){var n,r=e?x.filter(e,this):this,i=0;for(;null!=(n=r[i]);i++)t||1!==n.nodeType||x.cleanData(mt(n)),n.parentNode&&(t&&x.contains(n.ownerDocument,n)&&dt(mt(n,"script")),n.parentNode.removeChild(n));return this},empty:function(){var e,t=0;for(;null!=(e=this[t]);t++)1===e.nodeType&&(x.cleanData(mt(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return x.clone(this,e,t)})},html:function(e){return x.access(this,function(e){var t=this[0]||{},n=0,r=this.length;if(e===undefined&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!it.test(e)&&!ct[(nt.exec(e)||["",""])[1].toLowerCase()]){e=e.replace(tt,"<$1>");try{for(;r>n;n++)t=this[n]||{},1===t.nodeType&&(x.cleanData(mt(t,!1)),t.innerHTML=e);t=0}catch(i){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var e=x.map(this,function(e){return[e.nextSibling,e.parentNode]}),t=0;return this.domManip(arguments,function(n){var r=e[t++],i=e[t++];i&&(r&&r.parentNode!==i&&(r=this.nextSibling),x(this).remove(),i.insertBefore(n,r))},!0),t?this:this.remove()},detach:function(e){return this.remove(e,!0)},domManip:function(e,t,n){e=f.apply([],e);var r,i,o,s,a,u,l=0,c=this.length,p=this,h=c-1,d=e[0],g=x.isFunction(d);if(g||!(1>=c||"string"!=typeof d||x.support.checkClone)&&st.test(d))return this.each(function(r){var i=p.eq(r);g&&(e[0]=d.call(this,r,i.html())),i.domManip(e,t,n)});if(c&&(r=x.buildFragment(e,this[0].ownerDocument,!1,!n&&this),i=r.firstChild,1===r.childNodes.length&&(r=i),i)){for(o=x.map(mt(r,"script"),ft),s=o.length;c>l;l++)a=r,l!==h&&(a=x.clone(a,!0,!0),s&&x.merge(o,mt(a,"script"))),t.call(this[l],a,l);if(s)for(u=o[o.length-1].ownerDocument,x.map(o,ht),l=0;s>l;l++)a=o[l],at.test(a.type||"")&&!q.access(a,"globalEval")&&x.contains(u,a)&&(a.src?x._evalUrl(a.src):x.globalEval(a.textContent.replace(lt,"")))}return this}}),x.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){x.fn[e]=function(e){var n,r=[],i=x(e),o=i.length-1,s=0;for(;o>=s;s++)n=s===o?this:this.clone(!0),x(i[s])[t](n),h.apply(r,n.get());return this.pushStack(r)}}),x.extend({clone:function(e,t,n){var r,i,o,s,a=e.cloneNode(!0),u=x.contains(e.ownerDocument,e);if(!(x.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||x.isXMLDoc(e)))for(s=mt(a),o=mt(e),r=0,i=o.length;i>r;r++)yt(o[r],s[r]);if(t)if(n)for(o=o||mt(e),s=s||mt(a),r=0,i=o.length;i>r;r++)gt(o[r],s[r]);else gt(e,a);return s=mt(a,"script"),s.length>0&&dt(s,!u&&mt(e,"script")),a},buildFragment:function(e,t,n,r){var i,o,s,a,u,l,c=0,p=e.length,f=t.createDocumentFragment(),h=[];for(;p>c;c++)if(i=e[c],i||0===i)if("object"===x.type(i))x.merge(h,i.nodeType?[i]:i);else if(rt.test(i)){o=o||f.appendChild(t.createElement("div")),s=(nt.exec(i)||["",""])[1].toLowerCase(),a=ct[s]||ct._default,o.innerHTML=a[1]+i.replace(tt,"<$1>")+a[2],l=a[0];while(l--)o=o.lastChild;x.merge(h,o.childNodes),o=f.firstChild,o.textContent=""}else h.push(t.createTextNode(i));f.textContent="",c=0;while(i=h[c++])if((!r||-1===x.inArray(i,r))&&(u=x.contains(i.ownerDocument,i),o=mt(f.appendChild(i),"script"),u&&dt(o),n)){l=0;while(i=o[l++])at.test(i.type||"")&&n.push(i)}return f},cleanData:function(e){var t,n,r,i,o,s,a=x.event.special,u=0;for(;(n=e[u])!==undefined;u++){if(F.accepts(n)&&(o=n[q.expando],o&&(t=q.cache[o]))){if(r=Object.keys(t.events||{}),r.length)for(s=0;(i=r[s])!==undefined;s++)a[i]?x.event.remove(n,i):x.removeEvent(n,i,t.handle);q.cache[o]&&delete q.cache[o]}delete L.cache[n[L.expando]]}},_evalUrl:function(e){return x.ajax({url:e,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})}});function pt(e,t){return x.nodeName(e,"table")&&x.nodeName(1===t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function ft(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function ht(e){var t=ut.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function dt(e,t){var n=e.length,r=0;for(;n>r;r++)q.set(e[r],"globalEval",!t||q.get(t[r],"globalEval"))}function gt(e,t){var n,r,i,o,s,a,u,l;if(1===t.nodeType){if(q.hasData(e)&&(o=q.access(e),s=q.set(t,o),l=o.events)){delete s.handle,s.events={};for(i in l)for(n=0,r=l[i].length;r>n;n++)x.event.add(t,i,l[i][n])}L.hasData(e)&&(a=L.access(e),u=x.extend({},a),L.set(t,u))}}function mt(e,t){var n=e.getElementsByTagName?e.getElementsByTagName(t||"*"):e.querySelectorAll?e.querySelectorAll(t||"*"):[];return t===undefined||t&&x.nodeName(e,t)?x.merge([e],n):n}function yt(e,t){var n=t.nodeName.toLowerCase();"input"===n&&ot.test(e.type)?t.checked=e.checked:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}x.fn.extend({wrapAll:function(e){var t;return x.isFunction(e)?this.each(function(t){x(this).wrapAll(e.call(this,t))}):(this[0]&&(t=x(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this)},wrapInner:function(e){return x.isFunction(e)?this.each(function(t){x(this).wrapInner(e.call(this,t))}):this.each(function(){var t=x(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=x.isFunction(e);return this.each(function(n){x(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){x.nodeName(this,"body")||x(this).replaceWith(this.childNodes)}).end()}});var vt,xt,bt=/^(none|table(?!-c[ea]).+)/,wt=/^margin/,Tt=RegExp("^("+b+")(.*)$","i"),Ct=RegExp("^("+b+")(?!px)[a-z%]+$","i"),kt=RegExp("^([+-])=("+b+")","i"),Nt={BODY:"block"},Et={position:"absolute",visibility:"hidden",display:"block"},St={letterSpacing:0,fontWeight:400},jt=["Top","Right","Bottom","Left"],Dt=["Webkit","O","Moz","ms"];function At(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=Dt.length;while(i--)if(t=Dt[i]+n,t in e)return t;return r}function Lt(e,t){return e=t||e,"none"===x.css(e,"display")||!x.contains(e.ownerDocument,e)}function qt(t){return e.getComputedStyle(t,null)}function Ht(e,t){var n,r,i,o=[],s=0,a=e.length;for(;a>s;s++)r=e[s],r.style&&(o[s]=q.get(r,"olddisplay"),n=r.style.display,t?(o[s]||"none"!==n||(r.style.display=""),""===r.style.display&&Lt(r)&&(o[s]=q.access(r,"olddisplay",Rt(r.nodeName)))):o[s]||(i=Lt(r),(n&&"none"!==n||!i)&&q.set(r,"olddisplay",i?n:x.css(r,"display"))));for(s=0;a>s;s++)r=e[s],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[s]||"":"none"));return e}x.fn.extend({css:function(e,t){return x.access(this,function(e,t,n){var r,i,o={},s=0;if(x.isArray(t)){for(r=qt(e),i=t.length;i>s;s++)o[t[s]]=x.css(e,t[s],!1,r);return o}return n!==undefined?x.style(e,t,n):x.css(e,t)},e,t,arguments.length>1)},show:function(){return Ht(this,!0)},hide:function(){return Ht(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){Lt(this)?x(this).show():x(this).hide()})}}),x.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=vt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":"cssFloat"},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,s,a=x.camelCase(t),u=e.style;return t=x.cssProps[a]||(x.cssProps[a]=At(u,a)),s=x.cssHooks[t]||x.cssHooks[a],n===undefined?s&&"get"in s&&(i=s.get(e,!1,r))!==undefined?i:u[t]:(o=typeof n,"string"===o&&(i=kt.exec(n))&&(n=(i[1]+1)*i[2]+parseFloat(x.css(e,t)),o="number"),null==n||"number"===o&&isNaN(n)||("number"!==o||x.cssNumber[a]||(n+="px"),x.support.clearCloneStyle||""!==n||0!==t.indexOf("background")||(u[t]="inherit"),s&&"set"in s&&(n=s.set(e,n,r))===undefined||(u[t]=n)),undefined)}},css:function(e,t,n,r){var i,o,s,a=x.camelCase(t);return t=x.cssProps[a]||(x.cssProps[a]=At(e.style,a)),s=x.cssHooks[t]||x.cssHooks[a],s&&"get"in s&&(i=s.get(e,!0,n)),i===undefined&&(i=vt(e,t,r)),"normal"===i&&t in St&&(i=St[t]),""===n||n?(o=parseFloat(i),n===!0||x.isNumeric(o)?o||0:i):i}}),vt=function(e,t,n){var r,i,o,s=n||qt(e),a=s?s.getPropertyValue(t)||s[t]:undefined,u=e.style;return s&&(""!==a||x.contains(e.ownerDocument,e)||(a=x.style(e,t)),Ct.test(a)&&wt.test(t)&&(r=u.width,i=u.minWidth,o=u.maxWidth,u.minWidth=u.maxWidth=u.width=a,a=s.width,u.width=r,u.minWidth=i,u.maxWidth=o)),a};function Ot(e,t,n){var r=Tt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function Ft(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,s=0;for(;4>o;o+=2)"margin"===n&&(s+=x.css(e,n+jt[o],!0,i)),r?("content"===n&&(s-=x.css(e,"padding"+jt[o],!0,i)),"margin"!==n&&(s-=x.css(e,"border"+jt[o]+"Width",!0,i))):(s+=x.css(e,"padding"+jt[o],!0,i),"padding"!==n&&(s+=x.css(e,"border"+jt[o]+"Width",!0,i)));return s}function Pt(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=qt(e),s=x.support.boxSizing&&"border-box"===x.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=vt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Ct.test(i))return i;r=s&&(x.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+Ft(e,t,n||(s?"border":"content"),r,o)+"px"}function Rt(e){var t=o,n=Nt[e];return n||(n=Mt(e,t),"none"!==n&&n||(xt=(xt||x("