From 118f53ec459b4e025025fc810dfa2d8e6739ed5f Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Mon, 7 Feb 2011 17:29:26 -0500 Subject: [PATCH 001/126] freetdm: allow reception of FACILITY msg in any channel state when transparent facility is enabled --- .../ftmod_sangoma_isdn_stack_hndl.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c index 0b52011d42..fff34fcae6 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c @@ -797,6 +797,23 @@ void sngisdn_process_fac_ind (sngisdn_event_data_t *sngisdn_event) ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Processing FACILITY IND (suId:%u suInstId:%u spInstId:%u)\n", suId, suInstId, spInstId); + if (signal_data->facility_ie_decode == SNGISDN_OPT_FALSE) { + /* If Facility decoding is disabled, we do not care about current call state, just pass event up to user */ + ftdm_sigmsg_t sigev; + if (facEvnt->facElmt.facStr.pres) { + get_facility_ie_str(ftdmchan, &facEvnt->facElmt.facStr.val[2], facEvnt->facElmt.facStr.len-2); + } + memset(&sigev, 0, sizeof(sigev)); + sigev.chan_id = ftdmchan->chan_id; + sigev.span_id = ftdmchan->span_id; + sigev.channel = ftdmchan; + + sigev.event_id = FTDM_SIGEVENT_FACILITY; + ftdm_span_send_signal(ftdmchan->span, &sigev); + ISDN_FUNC_TRACE_EXIT(__FUNCTION__); + return; + } + switch (ftdmchan->state) { case FTDM_CHANNEL_STATE_GET_CALLERID: /* Update the caller ID Name */ From 3a0d5b6297d37f45bc1a8e26a89dc7751514d3de Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Mon, 28 Feb 2011 12:42:43 -0500 Subject: [PATCH 002/126] freetdm: remove unused prototype for ftdm_call_clear_data --- libs/freetdm/src/include/freetdm.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/libs/freetdm/src/include/freetdm.h b/libs/freetdm/src/include/freetdm.h index 6556164aac..d2c0a7e267 100755 --- a/libs/freetdm/src/include/freetdm.h +++ b/libs/freetdm/src/include/freetdm.h @@ -1463,11 +1463,6 @@ FT_DECLARE(ftdm_iterator_t *) ftdm_iterator_next(ftdm_iterator_t *iter); */ FT_DECLARE(ftdm_status_t) ftdm_iterator_free(ftdm_iterator_t *iter); -/*! \brief Clears all the temporary data attached to this call - * \note Clears caller_data->variables and caller_data->raw_data. - * */ -FT_DECLARE(void) ftdm_call_clear_data(ftdm_caller_data_t *caller_data); - /*! \brief Get the span pointer associated to the channel */ FT_DECLARE(ftdm_span_t *) ftdm_channel_get_span(const ftdm_channel_t *ftdmchan); From f9540b7258e9a39e9f79599d1427f8f1e4bb6ae2 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Mon, 28 Feb 2011 18:53:02 -0500 Subject: [PATCH 003/126] freetdm: Do not call sng_isdn_retrieve_facility_caller_name when transparent facility is enabled --- .../ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c index cfc5017a8d..9cac9d05b1 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c @@ -162,7 +162,10 @@ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event) #if 1 /* this section will not be needed once asn decoding function with key-value pairs is implemented */ - if (signal_data->facility == SNGISDN_OPT_TRUE && conEvnt->facilityStr.eh.pres) { + if (signal_data->facility == SNGISDN_OPT_TRUE && + signal_data->facility_ie_decode != SNGISDN_OPT_FALSE && + conEvnt->facilityStr.eh.pres) { + /* Verify whether the Caller Name will come in a subsequent FACILITY message */ uint16_t ret_val; char retrieved_str[255]; @@ -832,7 +835,7 @@ void sngisdn_process_fac_ind (sngisdn_event_data_t *sngisdn_event) If there will be no information following, but current FACILITY IE contains a caller name, returns 0 If there will be information following, returns 1 */ - + if (sng_isdn_retrieve_facility_caller_name(&facEvnt->facElmt.facStr.val[2], facEvnt->facElmt.facStr.len, retrieved_str) == 0) { strcpy(ftdmchan->caller_data.cid_name, retrieved_str); } else { From 1fbb321f3d665d1ee73658bdeb134e42f0b01187 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Thu, 3 Mar 2011 09:48:48 -0500 Subject: [PATCH 004/126] freetdm: Allow user to indicate FACILITY on outbound calls --- libs/freetdm/src/ftdm_io.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index 765a3b3431..6b225fe8f0 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -2312,7 +2312,9 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_indicate(const char *file, const ch ftdm_set_flag(ftdmchan, FTDM_CHANNEL_IND_ACK_PENDING); } - if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { + if (indication != FTDM_CHANNEL_INDICATE_FACILITY && + ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) { + ftdm_log_chan_ex(ftdmchan, file, func, line, FTDM_LOG_LEVEL_WARNING, "Cannot indicate %s in outgoing channel in state %s\n", ftdm_channel_indication2str(indication), ftdm_channel_state2str(ftdmchan->state)); status = FTDM_EINVAL; From c5dd481fbd7713e996f1d25d04f03758887d7bfd Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Wed, 2 Mar 2011 10:59:43 -0500 Subject: [PATCH 005/126] freetdm: ISDN - ftdm_complete_state is not called in state_advance if a new state is set --- .../ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c index 1437b45883..d119ff4fd2 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c @@ -603,6 +603,7 @@ static ftdm_status_t ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdm ftdm_sigmsg_t sigev; ftdm_channel_state_t initial_state; sngisdn_chan_data_t *sngisdn_info = ftdmchan->call_data; + uint8_t state_change = 0; memset(&sigev, 0, sizeof(sigev)); @@ -673,6 +674,7 @@ static ftdm_status_t ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdm sngisdn_send_signal(sngisdn_info, FTDM_SIGEVENT_PROCEED); if (sngisdn_test_flag(sngisdn_info, FLAG_MEDIA_READY)) { + state_change++; ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA); } } else { @@ -693,6 +695,7 @@ static ftdm_status_t ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdm sngisdn_send_signal(sngisdn_info, FTDM_SIGEVENT_RINGING); if (sngisdn_test_flag(sngisdn_info, FLAG_MEDIA_READY)) { + state_change++; ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA); } } else { @@ -752,6 +755,7 @@ static ftdm_status_t ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdm /* Send a release complete */ sngisdn_snd_release(ftdmchan, 0); /*now go to the HANGUP complete state*/ + state_change++; ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE); } break; @@ -811,6 +815,7 @@ static ftdm_status_t ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdm } } /* now go to the HANGUP complete state */ + state_change++; ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE); } break; @@ -819,6 +824,7 @@ static ftdm_status_t ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdm if (sngisdn_test_flag(sngisdn_info, FLAG_REMOTE_ABORT) || sngisdn_test_flag(sngisdn_info, FLAG_LOCAL_ABORT)) { /* If the remote side aborted, we will not get anymore message for this call */ + state_change++; ftdm_set_state(ftdmchan, FTDM_CHANNEL_STATE_DOWN); } else { /* waiting on remote confirmation before moving to down */ @@ -873,8 +879,10 @@ static ftdm_status_t ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdm break; } - /* Acknowledge the state change */ - ftdm_channel_complete_state(ftdmchan); + if (!state_change) { + /* Acknowledge the state change */ + ftdm_channel_complete_state(ftdmchan); + } /* If sngisdn_info->variables is not NULL, it means did not send any * sigevent to the user, therefore we have to free that hashtable */ From 00dc8577e826ab06cc41d79d4485a219fa7075e0 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Tue, 1 Mar 2011 09:54:52 -0500 Subject: [PATCH 006/126] freetdm: Typo in function define --- libs/freetdm/src/ftdm_io.c | 2 +- libs/freetdm/src/include/private/ftdm_core.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index 6b225fe8f0..4c75b6bd8a 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -4051,7 +4051,7 @@ done: return status; } -FT_DECLARE(ftdm_iterator_t) *ftdm_get_iterator(ftdm_iterator_type_t type, ftdm_iterator_t *iter) +FT_DECLARE(ftdm_iterator_t *) ftdm_get_iterator(ftdm_iterator_type_t type, ftdm_iterator_t *iter) { int allocated = 0; if (iter) { diff --git a/libs/freetdm/src/include/private/ftdm_core.h b/libs/freetdm/src/include/private/ftdm_core.h index 464b1c0209..3c21be392f 100644 --- a/libs/freetdm/src/include/private/ftdm_core.h +++ b/libs/freetdm/src/include/private/ftdm_core.h @@ -590,7 +590,7 @@ FT_DECLARE(ftdm_status_t) ftdm_channel_open_chan(ftdm_channel_t *ftdmchan); FT_DECLARE(void) ftdm_ack_indication(ftdm_channel_t *ftdmchan, ftdm_channel_indication_t indication, ftdm_status_t status); -FT_DECLARE(ftdm_iterator_t) *ftdm_get_iterator(ftdm_iterator_type_t type, ftdm_iterator_t *iter); +FT_DECLARE(ftdm_iterator_t *) ftdm_get_iterator(ftdm_iterator_type_t type, ftdm_iterator_t *iter); /*! From d36933df10cb788e2791018eac4a35de40344c62 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Mon, 7 Mar 2011 10:57:37 -0500 Subject: [PATCH 007/126] Fix for Raw Facility IE, introduced with ftdm_variables3 patch --- .../src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c index bd3db2942a..d0856bdce9 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c @@ -370,7 +370,7 @@ ftdm_status_t get_facility_ie_str(ftdm_channel_t *ftdmchan, uint8_t *data, uint8 my_data[1] = data_len; memcpy(&my_data[2], data, data_len); - sngisdn_add_raw_data((sngisdn_chan_data_t*)ftdmchan->call_data, data, data_len+2); + sngisdn_add_raw_data((sngisdn_chan_data_t*)ftdmchan->call_data, my_data, data_len+2); ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Raw Facility IE copied available\n"); } else { From 30813ca58a3da5f31f1947d6c611ecce25eff0c0 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Mon, 7 Mar 2011 10:35:32 -0600 Subject: [PATCH 008/126] FS-3130 --- .../mod_event_socket/mod_event_socket.c | 82 ++++++++++--------- 1 file changed, 43 insertions(+), 39 deletions(-) diff --git a/src/mod/event_handlers/mod_event_socket/mod_event_socket.c b/src/mod/event_handlers/mod_event_socket/mod_event_socket.c index 2bb1d453a0..5ec7ca9b79 100644 --- a/src/mod/event_handlers/mod_event_socket/mod_event_socket.c +++ b/src/mod/event_handlers/mod_event_socket/mod_event_socket.c @@ -305,56 +305,60 @@ static void event_handler(switch_event_t *event) } } - if (send && l->filters && l->filters->headers) { - switch_event_header_t *hp; - const char *hval; - - send = 0; + if (send) { switch_mutex_lock(l->filter_mutex); - for (hp = l->filters->headers; hp; hp = hp->next) { - if ((hval = switch_event_get_header(event, hp->name))) { - const char *comp_to = hp->value; - int pos = 1, cmp = 0; - while (comp_to && *comp_to) { - if (*comp_to == '+') { - pos = 1; - } else if (*comp_to == '-') { - pos = 0; - } else if (*comp_to != ' ') { - break; + if (l->filters && l->filters->headers) { + switch_event_header_t *hp; + const char *hval; + + send = 0; + + for (hp = l->filters->headers; hp; hp = hp->next) { + if ((hval = switch_event_get_header(event, hp->name))) { + const char *comp_to = hp->value; + int pos = 1, cmp = 0; + + while (comp_to && *comp_to) { + if (*comp_to == '+') { + pos = 1; + } else if (*comp_to == '-') { + pos = 0; + } else if (*comp_to != ' ') { + break; + } + comp_to++; } - comp_to++; - } - if (send && pos) { - continue; - } + if (send && pos) { + continue; + } - if (!comp_to) { - continue; - } + if (!comp_to) { + continue; + } - if (*hp->value == '/') { - switch_regex_t *re = NULL; - int ovector[30]; - cmp = !!switch_regex_perform(hval, comp_to, &re, ovector, sizeof(ovector) / sizeof(ovector[0])); - switch_regex_safe_free(re); - } else { - cmp = !strcasecmp(hval, comp_to); - } - - if (cmp) { - if (pos) { - send = 1; + if (*hp->value == '/') { + switch_regex_t *re = NULL; + int ovector[30]; + cmp = !!switch_regex_perform(hval, comp_to, &re, ovector, sizeof(ovector) / sizeof(ovector[0])); + switch_regex_safe_free(re); } else { - send = 0; - break; + cmp = !strcasecmp(hval, comp_to); + } + + if (cmp) { + if (pos) { + send = 1; + } else { + send = 0; + break; + } } } } + switch_mutex_unlock(l->filter_mutex); } - switch_mutex_unlock(l->filter_mutex); } if (send && switch_test_flag(l, LFLAG_MYEVENTS)) { From 89592a86e57ce8962d3968564fe97f2baedfd8d3 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Mon, 7 Mar 2011 12:15:46 -0600 Subject: [PATCH 009/126] fix issue with polycom changing to 1 way audio on hold --- src/mod/endpoints/mod_sofia/sofia_glue.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index a76467f5d8..0c23472406 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -2996,6 +2996,16 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f if (switch_rtp_ready(tech_pvt->rtp_session)) { switch_rtp_set_default_payload(tech_pvt->rtp_session, tech_pvt->agreed_pt); + + if (tech_pvt->audio_recv_pt != tech_pvt->agreed_pt) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, + "%s Set audio receive payload to %u\n", switch_channel_get_name(tech_pvt->channel), tech_pvt->audio_recv_pt); + + switch_rtp_set_recv_pt(tech_pvt->rtp_session, tech_pvt->audio_recv_pt); + } else { + switch_rtp_set_recv_pt(tech_pvt->rtp_session, tech_pvt->agreed_pt); + } + } } @@ -4654,7 +4664,7 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_s switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE, tmp); tech_pvt->audio_recv_pt = map->rm_pt; - if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND && !sofia_test_flag(tech_pvt, TFLAG_REINVITE)) { sofia_glue_get_offered_pt(tech_pvt, mimp, &tech_pvt->audio_recv_pt); } From 0db261ac28002a55fd057d2a6f5fc433ece56a9c Mon Sep 17 00:00:00 2001 From: Michael S Collins Date: Mon, 7 Mar 2011 10:57:25 -0800 Subject: [PATCH 010/126] Add missing newline on fs_cli usage --- libs/esl/fs_cli.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/esl/fs_cli.c b/libs/esl/fs_cli.c index f5975342cc..2985bca2af 100644 --- a/libs/esl/fs_cli.c +++ b/libs/esl/fs_cli.c @@ -577,7 +577,7 @@ static int usage(char *name){ printf(" -P, --port=port Port to connect (1 - 65535)\n"); printf(" -u, --user=user@domain user@domain\n"); printf(" -p, --password=password Password\n"); - printf(" -i, --interrupt Allow Control-c to interrupt"); + printf(" -i, --interrupt Allow Control-c to interrupt\n"); printf(" -x, --execute=command Execute Command and Exit\n"); printf(" -l, --loglevel=command Log Level\n"); printf(" -q, --quiet Disable logging\n"); From bfd0ba97984599d18f58253ca404927fd88ed8e5 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Mon, 7 Mar 2011 13:02:21 -0600 Subject: [PATCH 011/126] do not renegotiate codecs on hold re-invites --- conf/sip_profiles/internal.xml | 7 +++++++ src/mod/endpoints/mod_sofia/mod_sofia.h | 3 ++- src/mod/endpoints/mod_sofia/sofia.c | 12 ++++++++++++ src/mod/endpoints/mod_sofia/sofia_glue.c | 23 +++++++++++++++++++++-- 4 files changed, 42 insertions(+), 3 deletions(-) diff --git a/conf/sip_profiles/internal.xml b/conf/sip_profiles/internal.xml index 426264a1c5..b78ea20070 100644 --- a/conf/sip_profiles/internal.xml +++ b/conf/sip_profiles/internal.xml @@ -342,6 +342,13 @@ + + + + diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index 31cd058dfa..373601683d 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -230,6 +230,7 @@ typedef enum { PFLAG_PRESENCE_ON_REGISTER, PFLAG_PRESENCE_ON_FIRST_REGISTER, PFLAG_NO_CONNECTION_REUSE, + PFLAG_RENEG_ON_HOLD, /* No new flags below this line */ PFLAG_MAX } PFLAGS; @@ -984,7 +985,7 @@ void sofia_glue_del_every_gateway(sofia_profile_t *profile); void sofia_reg_send_reboot(sofia_profile_t *profile, const char *user, const char *host, const char *contact, const char *user_agent, const char *network_ip); void sofia_glue_restart_all_profiles(void); -void sofia_glue_toggle_hold(private_object_t *tech_pvt, int sendonly); +int sofia_glue_toggle_hold(private_object_t *tech_pvt, int sendonly); const char *sofia_state_string(int state); switch_status_t sofia_glue_tech_set_codec(private_object_t *tech_pvt, int force); void sofia_wait_for_reply(struct private_object *tech_pvt, nua_event_t event, uint32_t timeout); diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index fac089d12c..b6d6b74aa6 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -2436,6 +2436,12 @@ switch_status_t reconfig_sofia(sofia_profile_t *profile) } else { sofia_clear_pflag(profile, PFLAG_IGNORE_183NOSDP); } + } else if (!strcasecmp(var, "renegotiate-codec-on-hold")) { + if (switch_true(val)) { + sofia_set_pflag(profile, PFLAG_RENEG_ON_HOLD); + } else { + sofia_clear_pflag(profile, PFLAG_RENEG_ON_HOLD); + } } else if (!strcasecmp(var, "presence-probe-on-register")) { if (switch_true(val)) { sofia_set_pflag(profile, PFLAG_PRESENCE_PROBE_ON_REGISTER); @@ -3119,6 +3125,12 @@ switch_status_t config_sofia(int reload, char *profile_name) } else { sofia_clear_pflag(profile, PFLAG_IGNORE_183NOSDP); } + } else if (!strcasecmp(var, "renegotiate-codec-on-hold")) { + if (switch_true(val)) { + sofia_set_pflag(profile, PFLAG_RENEG_ON_HOLD); + } else { + sofia_clear_pflag(profile, PFLAG_RENEG_ON_HOLD); + } } else if (!strcasecmp(var, "presence-probe-on-register")) { if (switch_true(val)) { sofia_set_pflag(profile, PFLAG_PRESENCE_PROBE_ON_REGISTER); diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index 0c23472406..f66993ef6f 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -3759,8 +3759,10 @@ switch_status_t sofia_glue_tech_media(private_object_t *tech_pvt, const char *r_ return SWITCH_STATUS_FALSE; } -void sofia_glue_toggle_hold(private_object_t *tech_pvt, int sendonly) +int sofia_glue_toggle_hold(private_object_t *tech_pvt, int sendonly) { + int changed = 0; + if (sendonly && switch_channel_test_flag(tech_pvt->channel, CF_ANSWERED)) { if (!sofia_test_flag(tech_pvt, TFLAG_SIP_HOLD)) { const char *stream; @@ -3779,6 +3781,7 @@ void sofia_glue_toggle_hold(private_object_t *tech_pvt, int sendonly) switch_channel_set_flag(tech_pvt->channel, CF_LEG_HOLDING); switch_channel_mark_hold(tech_pvt->channel, SWITCH_TRUE); switch_channel_presence(tech_pvt->channel, "unknown", msg, NULL); + changed = 1; if (tech_pvt->max_missed_hold_packets) { switch_rtp_set_max_missed_packets(tech_pvt->rtp_session, tech_pvt->max_missed_hold_packets); @@ -3805,6 +3808,7 @@ void sofia_glue_toggle_hold(private_object_t *tech_pvt, int sendonly) sofia_set_flag(tech_pvt, TFLAG_SIP_HOLD); switch_channel_set_flag(tech_pvt->channel, CF_LEG_HOLDING); switch_channel_mark_hold(tech_pvt->channel, SWITCH_TRUE); + changed = 1; } sofia_clear_flag_locked(tech_pvt, TFLAG_HOLD_LOCK); @@ -3838,8 +3842,11 @@ void sofia_glue_toggle_hold(private_object_t *tech_pvt, int sendonly) switch_channel_clear_flag(tech_pvt->channel, CF_LEG_HOLDING); switch_channel_mark_hold(tech_pvt->channel, SWITCH_FALSE); switch_channel_presence(tech_pvt->channel, "unknown", "unhold", NULL); + changed = 1; } } + + return changed; } void sofia_glue_copy_t38_options(switch_t38_options_t *t38_options, switch_core_session_t *session) @@ -4264,7 +4271,19 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_s if (!tech_pvt->hold_laps) { tech_pvt->hold_laps++; - sofia_glue_toggle_hold(tech_pvt, sendonly); + if (sofia_glue_toggle_hold(tech_pvt, sendonly)) { + int reneg = sofia_test_pflag(tech_pvt->profile, PFLAG_RENEG_ON_HOLD); + + if ((val = switch_channel_get_variable(tech_pvt->channel, "sip_renegotiate_codec_on_hold"))) { + reneg = switch_true(val); + } + + if (!reneg) { + match = 1; + goto done; + } + } + } } From 8da371c74a5fa3391cfb727250adb01c920f7def Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Mon, 7 Mar 2011 15:18:46 -0600 Subject: [PATCH 012/126] FS-3127 --comment-only can you try this patch first to see if it fixes it without any changes to mod_cc --- src/switch_core_sqldb.c | 114 ++++++++++++++++++++++++++-------------- 1 file changed, 76 insertions(+), 38 deletions(-) diff --git a/src/switch_core_sqldb.c b/src/switch_core_sqldb.c index a4ed5ca83c..58eb90485a 100644 --- a/src/switch_core_sqldb.c +++ b/src/switch_core_sqldb.c @@ -46,8 +46,10 @@ struct switch_cache_db_handle { switch_memory_pool_t *pool; int32_t flags; unsigned long hash; + unsigned long thread_hash; char creator[CACHE_DB_LEN]; char last_user[CACHE_DB_LEN]; + uint32_t use_count; struct switch_cache_db_handle *next; }; @@ -71,12 +73,36 @@ static struct { } sql_manager; -static void add_handle(switch_cache_db_handle_t *dbh) +static switch_cache_db_handle_t *create_handle(switch_cache_db_handle_type_t type) { + switch_cache_db_handle_t *new_dbh = NULL; + switch_memory_pool_t *pool = NULL; + + switch_core_new_memory_pool(&pool); + new_dbh = switch_core_alloc(pool, sizeof(*new_dbh)); + new_dbh->pool = pool; + new_dbh->type = type; + switch_mutex_init(&new_dbh->mutex, SWITCH_MUTEX_NESTED, new_dbh->pool); + + return new_dbh; +} + +static void add_handle(switch_cache_db_handle_t *dbh, const char *db_str, const char *db_callsite_str, const char *thread_str) +{ + switch_ssize_t hlen = -1; + switch_mutex_lock(sql_manager.dbh_mutex); - switch_set_flag(dbh, CDF_INUSE); + + switch_set_string(dbh->creator, db_callsite_str); + + switch_set_string(dbh->name, db_str); + dbh->hash = switch_ci_hashfunc_default(db_str, &hlen); + dbh->thread_hash = switch_ci_hashfunc_default(thread_str, &hlen); + + dbh->use_count++; sql_manager.total_used_handles++; dbh->next = sql_manager.handle_pool; + sql_manager.handle_pool = dbh; sql_manager.total_handles++; switch_mutex_lock(dbh->mutex); @@ -85,48 +111,61 @@ static void add_handle(switch_cache_db_handle_t *dbh) static void del_handle(switch_cache_db_handle_t *dbh) { - switch_cache_db_handle_t *dbhp, *last = NULL; + switch_cache_db_handle_t *dbh_ptr, *last = NULL; switch_mutex_lock(sql_manager.dbh_mutex); - for (dbhp = sql_manager.handle_pool; dbhp; dbhp = dbhp->next) { - if (dbhp == dbh) { + for (dbh_ptr = sql_manager.handle_pool; dbh_ptr; dbh_ptr = dbh_ptr->next) { + if (dbh_ptr == dbh) { if (last) { - last->next = dbhp->next; + last->next = dbh_ptr->next; } else { - sql_manager.handle_pool = dbhp->next; + sql_manager.handle_pool = dbh_ptr->next; } sql_manager.total_handles--; break; } - last = dbhp; + last = dbh_ptr; } switch_mutex_unlock(sql_manager.dbh_mutex); } -static switch_cache_db_handle_t *get_handle(const char *db_str, const char *user_str) +static switch_cache_db_handle_t *get_handle(const char *db_str, const char *user_str, const char *thread_str) { switch_ssize_t hlen = -1; - unsigned long hash = 0; - switch_cache_db_handle_t *dbhp, *r = NULL; - + unsigned long hash = 0, thread_hash = 0; + switch_cache_db_handle_t *dbh_ptr, *r = NULL; hash = switch_ci_hashfunc_default(db_str, &hlen); + thread_hash = switch_ci_hashfunc_default(thread_str, &hlen); switch_mutex_lock(sql_manager.dbh_mutex); - for (dbhp = sql_manager.handle_pool; dbhp; dbhp = dbhp->next) { - if (dbhp->hash == hash && !switch_test_flag(dbhp, CDF_INUSE) && - !switch_test_flag(dbhp, CDF_PRUNE) && switch_mutex_trylock(dbhp->mutex) == SWITCH_STATUS_SUCCESS) { - r = dbhp; - switch_set_flag(dbhp, CDF_INUSE); - sql_manager.total_used_handles++; - dbhp->hash = switch_ci_hashfunc_default(db_str, &hlen); - switch_set_string(dbhp->last_user, user_str); + for (dbh_ptr = sql_manager.handle_pool; dbh_ptr; dbh_ptr = dbh_ptr->next) { + if (dbh_ptr->thread_hash == thread_hash && dbh_ptr->hash == hash && + !switch_test_flag(dbh_ptr, CDF_PRUNE) && switch_mutex_trylock(dbh_ptr->mutex) == SWITCH_STATUS_SUCCESS) { + r = dbh_ptr; + } + } + if (!r) { + for (dbh_ptr = sql_manager.handle_pool; dbh_ptr; dbh_ptr = dbh_ptr->next) { + if (dbh_ptr->hash == hash && !dbh_ptr->use_count && !switch_test_flag(dbh_ptr, CDF_PRUNE) && + switch_mutex_trylock(dbh_ptr->mutex) == SWITCH_STATUS_SUCCESS) { + r = dbh_ptr; break; } } + } + + if (r) { + r->use_count++; + sql_manager.total_used_handles++; + r->hash = switch_ci_hashfunc_default(db_str, &hlen); + r->thread_hash = thread_hash; + switch_set_string(r->last_user, user_str); + } + switch_mutex_unlock(sql_manager.dbh_mutex); return r; @@ -190,7 +229,7 @@ static void sql_close(time_t prune) diff = (time_t) prune - dbh->last_used; } - if (prune > 0 && (switch_test_flag(dbh, CDF_INUSE) || (diff < SQL_CACHE_TIMEOUT && !switch_test_flag(dbh, CDF_PRUNE)))) { + if (prune > 0 && (dbh->use_count || (diff < SQL_CACHE_TIMEOUT && !switch_test_flag(dbh, CDF_PRUNE)))) { continue; } @@ -249,7 +288,12 @@ SWITCH_DECLARE(void) switch_cache_db_release_db_handle(switch_cache_db_handle_t if (dbh && *dbh) { switch_mutex_lock(sql_manager.dbh_mutex); (*dbh)->last_used = switch_epoch_time_now(NULL); - switch_clear_flag((*dbh), CDF_INUSE); + + if ((*dbh)->use_count) { + if (--(*dbh)->use_count == 0) { + (*dbh)->thread_hash = 1; + } + } switch_mutex_unlock((*dbh)->mutex); sql_manager.total_used_handles--; *dbh = NULL; @@ -269,10 +313,11 @@ SWITCH_DECLARE(switch_status_t) _switch_cache_db_get_db_handle(switch_cache_db_h switch_cache_db_connection_options_t *connection_options, const char *file, const char *func, int line) { + switch_thread_id_t self = switch_thread_self(); + char thread_str[CACHE_DB_LEN] = ""; char db_str[CACHE_DB_LEN] = ""; char db_callsite_str[CACHE_DB_LEN] = ""; switch_cache_db_handle_t *new_dbh = NULL; - switch_ssize_t hlen = -1; int waiting = 0; uint32_t yield_len = 100000, total_yield = 0; @@ -317,15 +362,15 @@ SWITCH_DECLARE(switch_status_t) _switch_cache_db_get_db_handle(switch_cache_db_h return SWITCH_STATUS_FALSE; } + snprintf(db_str, sizeof(db_str) - 1, "db=\"%s\";user=\"%s\";pass=\"%s\"", db_name, db_user, db_pass); snprintf(db_callsite_str, sizeof(db_callsite_str) - 1, "%s:%d", file, line); + snprintf(thread_str, sizeof(thread_str) - 1, "thread=\"%lu\"", (unsigned long) (intptr_t) self); - - if ((new_dbh = get_handle(db_str, db_callsite_str))) { + if ((new_dbh = get_handle(db_str, db_callsite_str, thread_str))) { switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_DEBUG10, "Reuse Unused Cached DB handle %s [%s]\n", new_dbh->name, switch_cache_db_type_name(new_dbh->type)); } else { - switch_memory_pool_t *pool = NULL; switch_core_db_t *db = NULL; switch_odbc_handle_t *odbc_dbh = NULL; @@ -366,12 +411,7 @@ SWITCH_DECLARE(switch_status_t) _switch_cache_db_get_db_handle(switch_cache_db_h switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_DEBUG10, "Create Cached DB handle %s [%s] %s:%d\n", new_dbh->name, switch_cache_db_type_name(type), file, line); - switch_core_new_memory_pool(&pool); - new_dbh = switch_core_alloc(pool, sizeof(*new_dbh)); - new_dbh->pool = pool; - new_dbh->type = type; - switch_set_string(new_dbh->name, db_str); - new_dbh->hash = switch_ci_hashfunc_default(db_str, &hlen); + new_dbh = create_handle(type); if (db) { new_dbh->native_handle.core_db_dbh = db; @@ -379,9 +419,7 @@ SWITCH_DECLARE(switch_status_t) _switch_cache_db_get_db_handle(switch_cache_db_h new_dbh->native_handle.odbc_dbh = odbc_dbh; } - switch_mutex_init(&new_dbh->mutex, SWITCH_MUTEX_UNNESTED, new_dbh->pool); - switch_set_string(new_dbh->creator, db_callsite_str); - add_handle(new_dbh); + add_handle(new_dbh, db_str, db_callsite_str, thread_str); } end: @@ -1937,17 +1975,17 @@ SWITCH_DECLARE(void) switch_cache_db_status(switch_stream_handle_t *stream) count++; - if (switch_test_flag(dbh, CDF_INUSE)) { + if (dbh->use_count) { used++; } - stream->write_function(stream, "%s\n\tType: %s\n\tLast used: %d\n\tFlags: %s, %s\n" + stream->write_function(stream, "%s\n\tType: %s\n\tLast used: %d\n\tFlags: %s, %s(%d)\n" "\tCreator: %s\n\tLast User: %s\n", cleankey_str, switch_cache_db_type_name(dbh->type), diff, locked ? "Locked" : "Unlocked", - switch_test_flag(dbh, CDF_INUSE) ? "Attached" : "Detached", dbh->creator, dbh->last_user); + dbh->use_count ? "Attached" : "Detached", dbh->use_count, dbh->creator, dbh->last_user); } stream->write_function(stream, "%d total. %d in use.\n", count, used); From 8727e568e8f0891a914bd7203e7c07a24a2c6d1e Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Tue, 8 Mar 2011 10:37:16 -0600 Subject: [PATCH 013/126] alter implementation of renegotiate codec on hold feature to still take other sdp elements into consideration --- src/mod/endpoints/mod_sofia/mod_sofia.h | 2 ++ src/mod/endpoints/mod_sofia/sofia_glue.c | 36 ++++++++++++++++-------- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index 373601683d..c46e6395a0 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -599,6 +599,8 @@ struct private_object { int codec_order_last; const switch_codec_implementation_t *codecs[SWITCH_MAX_CODECS]; int num_codecs; + const switch_codec_implementation_t *negotiated_codecs[SWITCH_MAX_CODECS]; + int num_negotiated_codecs; switch_codec_t read_codec; switch_codec_t write_codec; uint32_t codec_ms; diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index f66993ef6f..8d7fb6bc57 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -4171,6 +4171,14 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_s int scrooge = 0; sdp_parser_t *parser = NULL; sdp_session_t *sdp; + int reneg = 1; + const switch_codec_implementation_t **codec_array; + int total_codecs; + + + codec_array = tech_pvt->codecs; + total_codecs = tech_pvt->num_codecs; + if (!(parser = sdp_parse(NULL, r_sdp, (int) strlen(r_sdp), 0))) { return 0; @@ -4272,21 +4280,21 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_s if (!tech_pvt->hold_laps) { tech_pvt->hold_laps++; if (sofia_glue_toggle_hold(tech_pvt, sendonly)) { - int reneg = sofia_test_pflag(tech_pvt->profile, PFLAG_RENEG_ON_HOLD); + reneg = sofia_test_pflag(tech_pvt->profile, PFLAG_RENEG_ON_HOLD); if ((val = switch_channel_get_variable(tech_pvt->channel, "sip_renegotiate_codec_on_hold"))) { reneg = switch_true(val); } - - if (!reneg) { - match = 1; - goto done; - } } } } + if (!reneg) { + codec_array = tech_pvt->negotiated_codecs; + total_codecs = tech_pvt->num_negotiated_codecs; + } + for (m = sdp->sdp_media; m; m = m->m_next) { sdp_connection_t *connection; switch_core_session_t *other_session; @@ -4380,6 +4388,7 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_s goto done; } else if (m->m_type == sdp_media_audio && m->m_port && !got_audio) { sdp_rtpmap_t *map; + for (attr = m->m_attributes; attr; attr = attr->a_next) { if (!strcasecmp(attr->a_name, "rtcp") && attr->a_value) { @@ -4590,8 +4599,9 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_s } } - for (i = first; i < last && i < tech_pvt->num_codecs; i++) { - const switch_codec_implementation_t *imp = tech_pvt->codecs[i]; + + for (i = first; i < last && i < total_codecs; i++) { + const switch_codec_implementation_t *imp = codec_array[i]; uint32_t bit_rate = imp->bits_per_second; uint32_t codec_rate = imp->samples_per_second; if (imp->codec_type != SWITCH_CODEC_TYPE_AUDIO) { @@ -4678,6 +4688,7 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_s tech_pvt->rm_fmtp = switch_core_session_strdup(session, (char *) map->rm_fmtp); tech_pvt->remote_sdp_audio_port = (switch_port_t) m->m_port; tech_pvt->agreed_pt = (switch_payload_t) map->rm_pt; + tech_pvt->negotiated_codecs[tech_pvt->num_negotiated_codecs++] = mimp; switch_snprintf(tmp, sizeof(tmp), "%d", tech_pvt->remote_sdp_audio_port); switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE, tech_pvt->remote_sdp_audio_ip); switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE, tmp); @@ -4719,7 +4730,7 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_s } - if (!match && greedy && mine < tech_pvt->num_codecs) { + if (!match && greedy && mine < total_codecs) { mine++; skip = 0; goto greed; @@ -4758,8 +4769,8 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_s rm_encoding = ""; } - for (i = 0; i < tech_pvt->num_codecs; i++) { - const switch_codec_implementation_t *imp = tech_pvt->codecs[i]; + for (i = 0; i < total_codecs; i++) { + const switch_codec_implementation_t *imp = codec_array[i]; if (imp->codec_type != SWITCH_CODEC_TYPE_VIDEO) { continue; @@ -4821,8 +4832,9 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_s done: - if (parser) + if (parser) { sdp_parser_free(parser); + } tech_pvt->cng_pt = cng_pt; sofia_set_flag_locked(tech_pvt, TFLAG_SDP); From 0be456565be0a8708cc1e32abe5f1427373dc5e7 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Tue, 8 Mar 2011 12:39:07 -0600 Subject: [PATCH 014/126] FS-3133 --comment-only this looks like a bad assert, can you update and try again --- libs/sofia-sip/libsofia-sip-ua/nta/nta.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/sofia-sip/libsofia-sip-ua/nta/nta.c b/libs/sofia-sip/libsofia-sip-ua/nta/nta.c index 13454c1a8e..543f0e135a 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nta/nta.c +++ b/libs/sofia-sip/libsofia-sip-ua/nta/nta.c @@ -7781,7 +7781,7 @@ nta_outgoing_t *outgoing_create(nta_agent_t *agent, if (tpn) { /* CANCEL or ACK to [3456]XX */ invalid = tport_name_dup(home, orq->orq_tpn, tpn); -#if HAVE_SOFIA_SRESOLV +#if 0 //HAVE_SOFIA_SRESOLV /* We send ACK or CANCEL only if original request was really sent */ assert(tport_name_is_resolved(orq->orq_tpn)); #endif From 564046412d3b537b246f6c96058af5edb2742024 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Tue, 8 Mar 2011 12:40:58 -0600 Subject: [PATCH 015/126] FS-3133 --comment-only this looks like a bad assert, can you update and try again, part 2 --- libs/sofia-sip/.update | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/sofia-sip/.update b/libs/sofia-sip/.update index aacfc996d3..a21313983b 100644 --- a/libs/sofia-sip/.update +++ b/libs/sofia-sip/.update @@ -1 +1 @@ -Wed Nov 3 13:53:34 EDT 2010 +Tue Mar 8 12:40:45 CST 2011 From 189d81a1b2913c9ce3a83dbe07a5c05de6a7be7c Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Tue, 8 Mar 2011 16:50:35 -0600 Subject: [PATCH 016/126] Bugfix: FreeSWITCH::Client::sendmsg was returning the first FSES packet it received, which caused a race condition when an event was in transit; now it waits for Content-Type: command/reply --- scripts/perl/FreeSWITCH/Client.pm | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/scripts/perl/FreeSWITCH/Client.pm b/scripts/perl/FreeSWITCH/Client.pm index 9e97218580..01748a8180 100644 --- a/scripts/perl/FreeSWITCH/Client.pm +++ b/scripts/perl/FreeSWITCH/Client.pm @@ -143,7 +143,13 @@ sub sendmsg($$$) { } $self->output("\n"); - return $self->readhash($to); + for(;;) { + $e = $self->readhash(undef); + last if $e->{socketerror} or $e->{'content-type'} eq 'command/reply'; + push @{$self->{events}}, $e; + } + + return $e; } sub command($$) { From 419d7e2335042e2d86c678c0daf86c2d9c867036 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Wed, 9 Mar 2011 14:38:22 -0500 Subject: [PATCH 017/126] FreeTDM: ISDN - Fix for q921 frames not printing span name properly --- .../src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.c index c2e9b5c3a1..8c8c8d5159 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_trace.c @@ -114,7 +114,7 @@ void sngisdn_trace_interpreted_q921(sngisdn_span_data_t *signal_data, ftdm_trace { char *data_str = ftdm_calloc(1,200); /* TODO Find a proper size */ sngisdn_decode_q921(data_str, data, data_len); - ftdm_log(FTDM_LOG_INFO, "[SNGISDN Q921] s%d FRAME %s:%s\n", signal_data->ftdm_span->name, ftdm_trace_dir2str(dir), data_str); + ftdm_log(FTDM_LOG_INFO, "[SNGISDN Q921] %s FRAME %s:%s\n", signal_data->ftdm_span->name, ftdm_trace_dir2str(dir), data_str); ftdm_safe_free(data_str); } From 8533c32fe1d5abe5267eb52148d1b0385fb685bf Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Wed, 9 Mar 2011 15:16:15 -0600 Subject: [PATCH 018/126] FS-3095 regression from 547d53932c4849dff81001b0d6b2a787f7fdb8da --- src/mod/applications/mod_conference/mod_conference.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/mod/applications/mod_conference/mod_conference.c b/src/mod/applications/mod_conference/mod_conference.c index d0f5fac081..762bc1aa40 100644 --- a/src/mod/applications/mod_conference/mod_conference.c +++ b/src/mod/applications/mod_conference/mod_conference.c @@ -4625,6 +4625,7 @@ static switch_status_t conf_api_sub_transfer(conference_obj_t *conference, switc /* move the member from the old conference to the new one */ lock_member(member); + switch_thread_rwlock_unlock(member->rwlock); if (conference != new_conference) { conference_del_member(conference, member); @@ -4660,10 +4661,6 @@ static switch_status_t conf_api_sub_transfer(conference_obj_t *conference, switc switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "transfer"); switch_event_fire(&event); } - - if (member) { - switch_thread_rwlock_unlock(member->rwlock); - } } if (new_conference) { From 2a35dfb51e2fce46c3989eb8ff417b2a07139d55 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Wed, 9 Mar 2011 15:17:09 -0600 Subject: [PATCH 019/126] add rtp-notimer-during-bridge (alternative to rtp-autoflush-during-bridge --- src/mod/endpoints/mod_sofia/mod_sofia.c | 72 ++++++++++++++++-------- src/mod/endpoints/mod_sofia/mod_sofia.h | 4 ++ src/mod/endpoints/mod_sofia/sofia.c | 12 ++++ src/mod/endpoints/mod_sofia/sofia_glue.c | 2 +- src/switch_rtp.c | 41 +++++++++----- 5 files changed, 94 insertions(+), 37 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index 0921f1f313..ebf51b9c39 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -1444,69 +1444,97 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi case SWITCH_MESSAGE_INDICATE_BRIDGE: { - const char *var = switch_channel_get_variable(tech_pvt->channel, "sip_jitter_buffer_during_bridge"); - sofia_glue_tech_track(tech_pvt->profile, session); sofia_glue_tech_simplify(tech_pvt); - if (switch_false(var) && switch_rtp_ready(tech_pvt->rtp_session)) { + if (switch_rtp_ready(tech_pvt->rtp_session)) { const char *val; int ok = 0; - if (switch_channel_test_flag(tech_pvt->channel, CF_JITTERBUFFER) && switch_channel_test_cap_partner(tech_pvt->channel, CC_FS_RTP)) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, - "%s PAUSE Jitterbuffer\n", switch_channel_get_name(channel)); - switch_rtp_pause_jitter_buffer(tech_pvt->rtp_session, SWITCH_TRUE); + if (!(val = switch_channel_get_variable(tech_pvt->channel, "sip_jitter_buffer_during_bridge")) || switch_false(val)) { + if (switch_channel_test_flag(tech_pvt->channel, CF_JITTERBUFFER) && switch_channel_test_cap_partner(tech_pvt->channel, CC_FS_RTP)) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, + "%s PAUSE Jitterbuffer\n", switch_channel_get_name(channel)); + switch_rtp_pause_jitter_buffer(tech_pvt->rtp_session, SWITCH_TRUE); + sofia_set_flag(tech_pvt, TFLAG_JB_PAUSED); + } } - + if (sofia_test_flag(tech_pvt, TFLAG_PASS_RFC2833) && switch_channel_test_flag_partner(channel, CF_FS_RTP)) { switch_rtp_set_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_PASS_RFC2833); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s activate passthru 2833 mode.\n", switch_channel_get_name(channel)); } - if ((val = switch_channel_get_variable(channel, "rtp_autoflush_during_bridge"))) { + + if ((val = switch_channel_get_variable(channel, "rtp_notimer_during_bridge"))) { ok = switch_true(val); } else { - ok = sofia_test_pflag(tech_pvt->profile, PFLAG_RTP_AUTOFLUSH_DURING_BRIDGE); + ok = sofia_test_pflag(tech_pvt->profile, PFLAG_RTP_NOTIMER_DURING_BRIDGE); + } + + if (ok && !switch_rtp_test_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_USE_TIMER)) { + ok = 0; + } + + if (ok) { + switch_rtp_clear_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_USE_TIMER); + switch_rtp_set_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_NOBLOCK); + sofia_set_flag(tech_pvt, TFLAG_NOTIMER_DURING_BRIDGE); + } + + if (ok && sofia_test_flag(tech_pvt, TFLAG_NOTIMER_DURING_BRIDGE)) { + /* these are not compat */ + ok = 0; + } else { + if ((val = switch_channel_get_variable(channel, "rtp_autoflush_during_bridge"))) { + ok = switch_true(val); + } else { + ok = sofia_test_pflag(tech_pvt->profile, PFLAG_RTP_AUTOFLUSH_DURING_BRIDGE); + } } if (ok) { rtp_flush_read_buffer(tech_pvt->rtp_session, SWITCH_RTP_FLUSH_STICK); + sofia_set_flag(tech_pvt, TFLAG_AUTOFLUSH_DURING_BRIDGE); } else { rtp_flush_read_buffer(tech_pvt->rtp_session, SWITCH_RTP_FLUSH_ONCE); } + } } goto end; case SWITCH_MESSAGE_INDICATE_UNBRIDGE: if (switch_rtp_ready(tech_pvt->rtp_session)) { - const char *val; - int ok = 0; sofia_glue_tech_track(tech_pvt->profile, session); - if (switch_channel_test_flag(tech_pvt->channel, CF_JITTERBUFFER)) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, - "%s RESUME Jitterbuffer\n", switch_channel_get_name(channel)); - switch_rtp_pause_jitter_buffer(tech_pvt->rtp_session, SWITCH_FALSE); + if (sofia_test_flag(tech_pvt, TFLAG_JB_PAUSED)) { + sofia_clear_flag(tech_pvt, TFLAG_JB_PAUSED); + if (switch_channel_test_flag(tech_pvt->channel, CF_JITTERBUFFER)) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, + "%s RESUME Jitterbuffer\n", switch_channel_get_name(channel)); + switch_rtp_pause_jitter_buffer(tech_pvt->rtp_session, SWITCH_FALSE); + } } + if (switch_rtp_test_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_PASS_RFC2833)) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s deactivate passthru 2833 mode.\n", switch_channel_get_name(channel)); switch_rtp_clear_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_PASS_RFC2833); } - - if ((val = switch_channel_get_variable(channel, "rtp_autoflush_during_bridge"))) { - ok = switch_true(val); - } else { - ok = sofia_test_pflag(tech_pvt->profile, PFLAG_RTP_AUTOFLUSH_DURING_BRIDGE); + + if (sofia_test_flag(tech_pvt, TFLAG_NOTIMER_DURING_BRIDGE)) { + switch_rtp_set_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_USE_TIMER); + switch_rtp_clear_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_NOBLOCK); + sofia_clear_flag(tech_pvt, TFLAG_NOTIMER_DURING_BRIDGE); } - if (ok) { + if (sofia_test_flag(tech_pvt, TFLAG_AUTOFLUSH_DURING_BRIDGE)) { rtp_flush_read_buffer(tech_pvt->rtp_session, SWITCH_RTP_FLUSH_UNSTICK); + sofia_clear_flag(tech_pvt, TFLAG_AUTOFLUSH_DURING_BRIDGE); } else { rtp_flush_read_buffer(tech_pvt->rtp_session, SWITCH_RTP_FLUSH_ONCE); } diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index c46e6395a0..c3b60da317 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -231,6 +231,7 @@ typedef enum { PFLAG_PRESENCE_ON_FIRST_REGISTER, PFLAG_NO_CONNECTION_REUSE, PFLAG_RENEG_ON_HOLD, + PFLAG_RTP_NOTIMER_DURING_BRIDGE, /* No new flags below this line */ PFLAG_MAX } PFLAGS; @@ -289,6 +290,9 @@ typedef enum { TFLAG_RECOVERING_BRIDGE, TFLAG_T38_PASSTHRU, TFLAG_RECOVERED, + TFLAG_AUTOFLUSH_DURING_BRIDGE, + TFLAG_NOTIMER_DURING_BRIDGE, + TFLAG_JB_PAUSED, /* No new flags below this line */ TFLAG_MAX } TFLAGS; diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index b6d6b74aa6..8e38393efb 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -2525,6 +2525,12 @@ switch_status_t reconfig_sofia(sofia_profile_t *profile) } else { sofia_clear_pflag(profile, PFLAG_RTP_AUTOFLUSH_DURING_BRIDGE); } + } else if (!strcasecmp(var, "rtp-notimer-during-bridge")) { + if (switch_true(val)) { + sofia_set_pflag(profile, PFLAG_RTP_NOTIMER_DURING_BRIDGE); + } else { + sofia_clear_pflag(profile, PFLAG_RTP_NOTIMER_DURING_BRIDGE); + } } else if (!strcasecmp(var, "manual-redirect")) { if (switch_true(val)) { sofia_set_pflag(profile, PFLAG_MANUAL_REDIRECT); @@ -3202,6 +3208,12 @@ switch_status_t config_sofia(int reload, char *profile_name) } else { sofia_clear_pflag(profile, PFLAG_RTP_AUTOFLUSH_DURING_BRIDGE); } + } else if (!strcasecmp(var, "rtp-notimer-during-bridge")) { + if (switch_true(val)) { + sofia_set_pflag(profile, PFLAG_RTP_NOTIMER_DURING_BRIDGE); + } else { + sofia_clear_pflag(profile, PFLAG_RTP_NOTIMER_DURING_BRIDGE); + } } else if (!strcasecmp(var, "manual-redirect")) { if (switch_true(val)) { sofia_set_pflag(profile, PFLAG_MANUAL_REDIRECT); diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index 8d7fb6bc57..91cf5b6fba 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -3176,7 +3176,7 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f if ((val = switch_channel_get_variable(tech_pvt->channel, "jitterbuffer_msec")) || (val = tech_pvt->profile->jb_msec)) { int jb_msec = atoi(val); - int maxlen = 0, max_drift = 0; + int maxlen = 0, max_drift = 1000; char *p, *q; if ((p = strchr(val, ':'))) { diff --git a/src/switch_rtp.c b/src/switch_rtp.c index f5a7022928..6b8c6b0dc6 100644 --- a/src/switch_rtp.c +++ b/src/switch_rtp.c @@ -2182,7 +2182,10 @@ SWITCH_DECLARE(void) switch_rtp_set_flag(switch_rtp_t *rtp_session, switch_rtp_f rtp_session->autoadj_window = 20; rtp_session->autoadj_tally = 0; rtp_flush_read_buffer(rtp_session, SWITCH_RTP_FLUSH_ONCE); + } else if (flags & SWITCH_RTP_FLAG_NOBLOCK) { + switch_socket_opt_set(rtp_session->sock_input, SWITCH_SO_NONBLOCK, TRUE); } + } SWITCH_DECLARE(uint32_t) switch_rtp_test_flag(switch_rtp_t *rtp_session, switch_rtp_flag_t flags) @@ -2193,6 +2196,10 @@ SWITCH_DECLARE(uint32_t) switch_rtp_test_flag(switch_rtp_t *rtp_session, switch_ SWITCH_DECLARE(void) switch_rtp_clear_flag(switch_rtp_t *rtp_session, switch_rtp_flag_t flags) { switch_clear_flag_locked(rtp_session, flags); + + if (flags & SWITCH_RTP_FLAG_NOBLOCK) { + switch_socket_opt_set(rtp_session->sock_input, SWITCH_SO_NONBLOCK, FALSE); + } } static void do_2833(switch_rtp_t *rtp_session, switch_core_session_t *session) @@ -2240,7 +2247,7 @@ static void do_2833(switch_rtp_t *rtp_session, switch_core_session_t *session) if (loops != 1) { rtp_session->last_write_ts = rtp_session->dtmf_data.timestamp_dtmf + rtp_session->dtmf_data.out_digit_sub_sofar; rtp_session->sending_dtmf = 0; - if (rtp_session->timer.interval) { + if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_USE_TIMER)) { rtp_session->last_write_samplecount = rtp_session->timer.samplecount; rtp_session->next_write_samplecount = rtp_session->timer.samplecount + samples * 5; } @@ -2251,7 +2258,7 @@ static void do_2833(switch_rtp_t *rtp_session, switch_core_session_t *session) if (!rtp_session->dtmf_data.out_digit_dur && rtp_session->dtmf_data.dtmf_queue && switch_queue_size(rtp_session->dtmf_data.dtmf_queue)) { void *pop; - if (rtp_session->timer.interval) { + if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_USE_TIMER)) { if (rtp_session->timer.samplecount < rtp_session->next_write_samplecount) { return; } @@ -2275,7 +2282,7 @@ static void do_2833(switch_rtp_t *rtp_session, switch_core_session_t *session) rtp_session->dtmf_data.timestamp_dtmf = rtp_session->last_write_ts + samples; - if (rtp_session->timer.interval) { + if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_USE_TIMER)) { offset = rtp_session->timer.samplecount - rtp_session->last_write_samplecount; if (offset > 0) { rtp_session->dtmf_data.timestamp_dtmf = (uint32_t) (rtp_session->dtmf_data.timestamp_dtmf + offset); @@ -2491,10 +2498,14 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t stfu_n_reset(rtp_session->jb); } + if (!switch_test_flag(rtp_session, SWITCH_RTP_FLAG_USE_TIMER) && rtp_session->timer.interval) { + switch_core_timer_sync(&rtp_session->timer); + } + if (stfu_n_eat(rtp_session->jb, rtp_session->last_read_ts, rtp_session->recv_msg.header.pt, rtp_session->recv_msg.body, *bytes - rtp_header_len, rtp_session->timer.samplecount) == STFU_ITS_TOO_LATE) { - printf("doh\n"); + goto more; } @@ -2657,7 +2668,7 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ return -1; } - if (rtp_session->timer.interval) { + if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_USE_TIMER)) { sleep_mss = rtp_session->timer.interval * 1000; } @@ -2668,7 +2679,7 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ int read_pretriggered = 0; bytes = 0; - if (rtp_session->timer.interval) { + if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_USE_TIMER)) { if ((switch_test_flag(rtp_session, SWITCH_RTP_FLAG_AUTOFLUSH) || switch_test_flag(rtp_session, SWITCH_RTP_FLAG_STICKY_FLUSH)) && rtp_session->read_pollfd) { if (switch_poll(rtp_session->read_pollfd, 1, &fdr, 0) == SWITCH_STATUS_SUCCESS) { @@ -2722,8 +2733,8 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ if (!switch_rtp_ready(rtp_session)) { break; } - - if (!rtp_session->timer.interval && rtp_session->read_pollfd) { + + if (!switch_test_flag(rtp_session, SWITCH_RTP_FLAG_USE_TIMER) && rtp_session->read_pollfd) { int pt = poll_sec * 1000000; if (rtp_session->dtmf_data.out_digit_dur > 0 || rtp_session->dtmf_data.in_digit_sanity) { @@ -3160,7 +3171,8 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ goto end; } - if (check || (bytes && !rtp_session->timer.interval)) { + + if (check || (bytes && !switch_test_flag(rtp_session, SWITCH_RTP_FLAG_USE_TIMER))) { if (!bytes && switch_test_flag(rtp_session, SWITCH_RTP_FLAG_USE_TIMER)) { /* We're late! We're Late! */ if (!switch_test_flag(rtp_session, SWITCH_RTP_FLAG_NOBLOCK) && status == SWITCH_STATUS_BREAK) { switch_cond_next(); @@ -3186,7 +3198,7 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ do_continue: - if (!bytes && !rtp_session->timer.interval) { + if (!bytes && !switch_test_flag(rtp_session, SWITCH_RTP_FLAG_USE_TIMER)) { switch_yield(sleep_mss); } @@ -3522,7 +3534,7 @@ static int rtp_common_write(switch_rtp_t *rtp_session, if (rtp_session->ts <= rtp_session->last_write_ts && !(rtp_session->rtp_bugs & RTP_BUG_NEVER_SEND_MARKER)) { m++; } - } else if (rtp_session->timer.timer_interface) { + } else if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_USE_TIMER)) { rtp_session->ts = rtp_session->timer.samplecount; if (rtp_session->ts <= rtp_session->last_write_ts && rtp_session->ts > 0) { @@ -3540,11 +3552,12 @@ static int rtp_common_write(switch_rtp_t *rtp_session, m++; } - if (rtp_session->timer.interval && (rtp_session->timer.samplecount - rtp_session->last_write_samplecount) > rtp_session->samples_per_interval * 10) { + if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_USE_TIMER) && + (rtp_session->timer.samplecount - rtp_session->last_write_samplecount) > rtp_session->samples_per_interval * 10) { m++; } - if (!rtp_session->timer.interval && + if (!switch_test_flag(rtp_session, SWITCH_RTP_FLAG_USE_TIMER) && ((unsigned) ((switch_micro_time_now() - rtp_session->last_write_timestamp))) > (rtp_session->ms_per_packet * 10)) { m++; } @@ -3785,7 +3798,7 @@ static int rtp_common_write(switch_rtp_t *rtp_session, rtp_session->stats.outbound.media_bytes += bytes; } - if (rtp_session->timer.interval) { + if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_USE_TIMER)) { rtp_session->last_write_samplecount = rtp_session->timer.samplecount; } else { rtp_session->last_write_timestamp = (uint32_t) switch_micro_time_now(); From 0c5222a4608f998d41adfd5c9515fcbbe4711ab5 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Wed, 9 Mar 2011 15:17:23 -0600 Subject: [PATCH 020/126] add rtp-notimer-during-bridge (alternative to rtp-autoflush-during-bridge --- libs/stfu/stfu.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/libs/stfu/stfu.c b/libs/stfu/stfu.c index f00dfafa39..d8797f7cd0 100644 --- a/libs/stfu/stfu.c +++ b/libs/stfu/stfu.c @@ -428,6 +428,12 @@ stfu_status_t stfu_n_add_data(stfu_instance_t *i, uint32_t ts, uint32_t pt, void i->ts_drift = ts + (i->ts_offset - timer_ts); + if (i->ts_offset && i->ts_drift > 0) { + i->ts_offset = timer_ts - ts; + i->ts_drift = ts + (i->ts_offset - timer_ts); + } + + if (i->max_drift) { if (i->ts_drift < i->max_drift) { if (++i->drift_dropped_packets < i->drift_max_dropped) { @@ -518,8 +524,8 @@ stfu_status_t stfu_n_add_data(stfu_instance_t *i, uint32_t ts, uint32_t pt, void if (stfu_log != null_logger && i->debug) { - stfu_log(STFU_LOG_EMERG, "I: %s %u i=%u/%u - g:%u/%u c:%u/%u b:%u - %u:%u - %u %d %u %u %d %d %d/%d\n", i->name, - i->qlen, i->period_packet_in_count, i->period_time, i->consecutive_good_count, + stfu_log(STFU_LOG_EMERG, "I: %s %u/%u i=%u/%u - g:%u/%u c:%u/%u b:%u - %u:%u - %u %d %u %u %d %d %d/%d\n", i->name, + i->qlen, i->max_qlen, i->period_packet_in_count, i->period_time, i->consecutive_good_count, i->decrement_time, i->period_clean_count, i->decrement_time, i->consecutive_bad_count, ts, ts / i->samples_per_packet, i->period_missing_count, i->period_need_range_avg, From dbfa7fa817e52a1a4b92be27cf29e1a0f1d2260f Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Wed, 9 Mar 2011 16:55:33 -0500 Subject: [PATCH 021/126] freetdm:Fix ftdm_sigmsg_get_raw_data_detached ISDN: Fix for Facility IE in Facility message not passed to user in raw mode --- libs/freetdm/src/ftdm_io.c | 7 +++++-- .../ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c | 9 +-------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c index 4c75b6bd8a..12397c0666 100644 --- a/libs/freetdm/src/ftdm_io.c +++ b/libs/freetdm/src/ftdm_io.c @@ -6053,9 +6053,12 @@ FT_DECLARE(ftdm_status_t) ftdm_sigmsg_get_raw_data_detached(ftdm_sigmsg_t *sigms if (!sigmsg || !sigmsg->raw.len) { return FTDM_FAIL; } - + *data = sigmsg->raw.data; - *datalen = sigmsg->raw.len; + *datalen = sigmsg->raw.len; + + sigmsg->raw.data = NULL; + sigmsg->raw.len = 0; return FTDM_SUCCESS; } diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c index 9cac9d05b1..33f3d9870b 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c @@ -808,17 +808,10 @@ void sngisdn_process_fac_ind (sngisdn_event_data_t *sngisdn_event) if (signal_data->facility_ie_decode == SNGISDN_OPT_FALSE) { /* If Facility decoding is disabled, we do not care about current call state, just pass event up to user */ - ftdm_sigmsg_t sigev; if (facEvnt->facElmt.facStr.pres) { get_facility_ie_str(ftdmchan, &facEvnt->facElmt.facStr.val[2], facEvnt->facElmt.facStr.len-2); + sngisdn_send_signal(sngisdn_info, FTDM_SIGEVENT_FACILITY); } - memset(&sigev, 0, sizeof(sigev)); - sigev.chan_id = ftdmchan->chan_id; - sigev.span_id = ftdmchan->span_id; - sigev.channel = ftdmchan; - - sigev.event_id = FTDM_SIGEVENT_FACILITY; - ftdm_span_send_signal(ftdmchan->span, &sigev); ISDN_FUNC_TRACE_EXIT(__FUNCTION__); return; } From 8cb2bad004efad30b7ce3e285e3067a98e6f8b21 Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Wed, 9 Mar 2011 19:01:50 -0500 Subject: [PATCH 022/126] Fix segv --- src/switch_ivr_originate.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/switch_ivr_originate.c b/src/switch_ivr_originate.c index 78743e6420..92137ea5d8 100644 --- a/src/switch_ivr_originate.c +++ b/src/switch_ivr_originate.c @@ -1423,8 +1423,10 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_enterprise_originate(switch_core_sess } } - switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, "ent_originate_aleg_uuid", switch_core_session_get_uuid(session)); - + if (session) { + switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, "ent_originate_aleg_uuid", switch_core_session_get_uuid(session)); + } + if (channel) { switch_channel_process_export(channel, NULL, var_event, SWITCH_EXPORT_VARS_VARIABLE); } From 59da356d067a1158029ed7c3fe46a052d4245a5e Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Wed, 9 Mar 2011 20:06:27 -0600 Subject: [PATCH 023/126] fix mistake from earlier commit and improve flow of dtmf through a bridge when timer is disabled --- src/mod/endpoints/mod_sofia/mod_sofia.c | 4 ++-- src/switch_ivr_bridge.c | 1 + src/switch_rtp.c | 9 +++++++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index ebf51b9c39..3bc5cc2231 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -1480,7 +1480,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi if (ok) { switch_rtp_clear_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_USE_TIMER); - switch_rtp_set_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_NOBLOCK); + switch_rtp_clear_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_NOBLOCK); sofia_set_flag(tech_pvt, TFLAG_NOTIMER_DURING_BRIDGE); } @@ -1528,7 +1528,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi if (sofia_test_flag(tech_pvt, TFLAG_NOTIMER_DURING_BRIDGE)) { switch_rtp_set_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_USE_TIMER); - switch_rtp_clear_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_NOBLOCK); + switch_rtp_set_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_NOBLOCK); sofia_clear_flag(tech_pvt, TFLAG_NOTIMER_DURING_BRIDGE); } diff --git a/src/switch_ivr_bridge.c b/src/switch_ivr_bridge.c index 88c72bf1b8..dbe3b811fe 100644 --- a/src/switch_ivr_bridge.c +++ b/src/switch_ivr_bridge.c @@ -386,6 +386,7 @@ static void *audio_bridge_thread(switch_thread_t *thread, void *obj) if (send_dtmf) { switch_core_session_send_dtmf(session_b, &dtmf); + switch_core_session_kill_channel(session_b, SWITCH_SIG_BREAK); } } } diff --git a/src/switch_rtp.c b/src/switch_rtp.c index 6b8c6b0dc6..e81812a463 100644 --- a/src/switch_rtp.c +++ b/src/switch_rtp.c @@ -267,6 +267,8 @@ typedef enum { RESULT_GOTO_TIMERCHECK } handle_rfc2833_result_t; +static void do_2833(switch_rtp_t *rtp_session, switch_core_session_t *session); + static handle_rfc2833_result_t handle_rfc2833(switch_rtp_t *rtp_session, switch_size_t bytes, int *do_cng) { #ifdef DEBUG_2833 @@ -2209,6 +2211,7 @@ static void do_2833(switch_rtp_t *rtp_session, switch_core_session_t *session) if (rtp_session->dtmf_data.out_digit_dur > 0) { int x, loops = 1; + rtp_session->dtmf_data.out_digit_sofar += samples; rtp_session->dtmf_data.out_digit_sub_sofar += samples; @@ -2737,7 +2740,10 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ if (!switch_test_flag(rtp_session, SWITCH_RTP_FLAG_USE_TIMER) && rtp_session->read_pollfd) { int pt = poll_sec * 1000000; - if (rtp_session->dtmf_data.out_digit_dur > 0 || rtp_session->dtmf_data.in_digit_sanity) { + do_2833(rtp_session, session); + + if (rtp_session->dtmf_data.out_digit_dur > 0 || rtp_session->dtmf_data.in_digit_sanity || rtp_session->sending_dtmf || + switch_queue_size(rtp_session->dtmf_data.dtmf_queue) || switch_queue_size(rtp_session->dtmf_data.dtmf_inqueue)) { pt = 20000; } @@ -2746,7 +2752,6 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ } poll_status = switch_poll(rtp_session->read_pollfd, 1, &fdr, pt); - do_2833(rtp_session, session); if (rtp_session->dtmf_data.out_digit_dur > 0) { return_cng_frame(); From 9e89f607c8a92ee6af26b7af4c6c9cfc2bcd9f41 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Thu, 10 Mar 2011 00:18:06 -0600 Subject: [PATCH 024/126] FS-3140 --comment-only please try this patch --- src/mod/endpoints/mod_sofia/mod_sofia.h | 1 + src/mod/endpoints/mod_sofia/sofia.c | 12 ++++++++++++ src/mod/endpoints/mod_sofia/sofia_glue.c | 11 ++++++++++- 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index c3b60da317..156a69d5a7 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -231,6 +231,7 @@ typedef enum { PFLAG_PRESENCE_ON_FIRST_REGISTER, PFLAG_NO_CONNECTION_REUSE, PFLAG_RENEG_ON_HOLD, + PFLAG_RENEG_ON_REINVITE, PFLAG_RTP_NOTIMER_DURING_BRIDGE, /* No new flags below this line */ PFLAG_MAX diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 8e38393efb..761a03ce62 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -2442,6 +2442,12 @@ switch_status_t reconfig_sofia(sofia_profile_t *profile) } else { sofia_clear_pflag(profile, PFLAG_RENEG_ON_HOLD); } + } else if (!strcasecmp(var, "renegotiate-codec-on-reinvite")) { + if (switch_true(val)) { + sofia_set_pflag(profile, PFLAG_RENEG_ON_REINVITE); + } else { + sofia_clear_pflag(profile, PFLAG_RENEG_ON_REINVITE); + } } else if (!strcasecmp(var, "presence-probe-on-register")) { if (switch_true(val)) { sofia_set_pflag(profile, PFLAG_PRESENCE_PROBE_ON_REGISTER); @@ -3137,6 +3143,12 @@ switch_status_t config_sofia(int reload, char *profile_name) } else { sofia_clear_pflag(profile, PFLAG_RENEG_ON_HOLD); } + } else if (!strcasecmp(var, "renegotiate-codec-on-reinvite")) { + if (switch_true(val)) { + sofia_set_pflag(profile, PFLAG_RENEG_ON_REINVITE); + } else { + sofia_clear_pflag(profile, PFLAG_RENEG_ON_REINVITE); + } } else if (!strcasecmp(var, "presence-probe-on-register")) { if (switch_true(val)) { sofia_set_pflag(profile, PFLAG_PRESENCE_PROBE_ON_REGISTER); diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index 91cf5b6fba..1e42afc269 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -4290,7 +4290,15 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_s } } - if (!reneg) { + if (reneg) { + reneg = sofia_test_pflag(tech_pvt->profile, PFLAG_RENEG_ON_REINVITE); + + if ((val = switch_channel_get_variable(tech_pvt->channel, "sip_renegotiate_codec_on_reinvite"))) { + reneg = switch_true(val); + } + } + + if (!reneg && tech_pvt->num_negotiated_codecs) { codec_array = tech_pvt->negotiated_codecs; total_codecs = tech_pvt->num_negotiated_codecs; } @@ -4688,6 +4696,7 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_s tech_pvt->rm_fmtp = switch_core_session_strdup(session, (char *) map->rm_fmtp); tech_pvt->remote_sdp_audio_port = (switch_port_t) m->m_port; tech_pvt->agreed_pt = (switch_payload_t) map->rm_pt; + tech_pvt->num_negotiated_codecs = 0; tech_pvt->negotiated_codecs[tech_pvt->num_negotiated_codecs++] = mimp; switch_snprintf(tmp, sizeof(tmp), "%d", tech_pvt->remote_sdp_audio_port); switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE, tech_pvt->remote_sdp_audio_ip); From e8474d602d3830f6132bf6847cefc487f6907917 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Thu, 10 Mar 2011 00:33:43 -0600 Subject: [PATCH 025/126] ESL-57 --- libs/esl/src/esl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/esl/src/esl.c b/libs/esl/src/esl.c index b0bc311ce0..27000f6071 100644 --- a/libs/esl/src/esl.c +++ b/libs/esl/src/esl.c @@ -934,7 +934,6 @@ ESL_DECLARE(esl_status_t) esl_recv_event(esl_handle_t *handle, int check_q, esl_ goto fail; } - esl_event_safe_destroy(&handle->last_event); esl_event_safe_destroy(&handle->last_ievent); if (check_q && handle->race_event) { @@ -1053,6 +1052,7 @@ ESL_DECLARE(esl_status_t) esl_recv_event(esl_handle_t *handle, int check_q, esl_ *save_event = revent; revent = NULL; } else { + esl_event_safe_destroy(&handle->last_event); handle->last_event = revent; } From 3bbab5cbeae67dae6181cd435af40b575040ae85 Mon Sep 17 00:00:00 2001 From: Moises Silva Date: Thu, 10 Mar 2011 09:25:49 -0500 Subject: [PATCH 026/126] freetdm: ftmod_zt - print more specific errors for overrun and bad checksum --- libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.c b/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.c index 1b55b739fc..9c01b41299 100644 --- a/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.c +++ b/libs/freetdm/src/ftmod/ftmod_zt/ftmod_zt.c @@ -1064,6 +1064,20 @@ static __inline__ ftdm_status_t zt_channel_process_event(ftdm_channel_t *fchan, fchan->rx_cas_bits = bits; } break; + case ZT_EVENT_BADFCS: + { + ftdm_log_chan_msg(fchan, FTDM_LOG_ERROR, "Bad frame checksum (ZT_EVENT_BADFCS)!\n"); + /* What else could we do? */ + *event_id = FTDM_OOB_NOOP; + } + break; + case ZT_EVENT_OVERRUN: + { + ftdm_log_chan_msg(fchan, FTDM_LOG_ERROR, "Driver overrun! (ZT_EVENT_OVERRUN)\n"); + /* What else could we do? */ + *event_id = FTDM_OOB_NOOP; + } + break; case ZT_EVENT_NONE: { ftdm_log_chan_msg(fchan, FTDM_LOG_DEBUG, "No event\n"); From 687140b5888e51615c78f60f08b1d1c84cb3388a Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Wed, 9 Mar 2011 20:26:17 -0600 Subject: [PATCH 027/126] FS-3139 --- libs/libdingaling/src/libdingaling.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/libs/libdingaling/src/libdingaling.c b/libs/libdingaling/src/libdingaling.c index 44c4589429..6793c3df61 100644 --- a/libs/libdingaling/src/libdingaling.c +++ b/libs/libdingaling/src/libdingaling.c @@ -384,9 +384,12 @@ static ldl_status parse_session_code(ldl_handle_t *handle, char *id, char *from, } while(xml) { - char *type = xtype ? xtype : iks_find_attrib(xml, "type"); + char *type = NULL; iks *tag; - + + if (iks_type(xml)!=IKS_CDATA) + type = xtype ? xtype : iks_find_attrib(xml, "type"); + if (type) { if (!strcasecmp(type, "redirect")) { @@ -994,9 +997,9 @@ static int on_commands(void *user_data, ikspak *pak) uint8_t is_result = strcasecmp(type, "result") ? 0 : 1; uint8_t is_error = strcasecmp(type, "error") ? 0 : 1; iks *xml, *xsession, *xerror = NULL, *xredir = NULL; - + struct iks_tag* tmp; xml = iks_child (pak->x); - + tmp = (struct iks_tag*) xml; if (is_error) { if ((xerror = working_find(xml, "error"))) { char *code = iks_find_attrib(xerror, "code"); From 8758d2f71df0e689f65e2330755d2cc3ebb7f3b0 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Thu, 10 Mar 2011 10:47:26 -0600 Subject: [PATCH 028/126] FS-3141 --- src/switch_channel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/switch_channel.c b/src/switch_channel.c index 4341ea9214..bc9b76e90b 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -751,7 +751,7 @@ SWITCH_DECLARE(switch_event_header_t *) switch_channel_variable_first(switch_cha switch_assert(channel != NULL); switch_mutex_lock(channel->profile_mutex); - if ((hi = channel->variables->headers)) { + if (channel->variables && (hi = channel->variables->headers)) { channel->vi = 1; } else { switch_mutex_unlock(channel->profile_mutex); From 1a54968d99505923ec370963bc32466b62650cfc Mon Sep 17 00:00:00 2001 From: Stefan Knoblich Date: Thu, 10 Mar 2011 18:25:43 +0100 Subject: [PATCH 029/126] ftmod_libpri: go to PROGRESS_MEDIA in on_ringing() if there is inband information available and rework channel opening to not skip state changes when the channel is already open. The latter part affects on_ringing(), on_progress() and on_proceeding(). Somewhat experimental and untested (apart from a compile run). Signed-off-by: Stefan Knoblich --- .../src/ftmod/ftmod_libpri/ftmod_libpri.c | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c b/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c index e051477346..6653a923aa 100644 --- a/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c +++ b/libs/freetdm/src/ftmod/ftmod_libpri/ftmod_libpri.c @@ -943,12 +943,12 @@ static int on_proceeding(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_ if (chan) { /* Open channel if inband information is available */ - if ((pevent->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE) && !ftdm_test_flag(chan, FTDM_CHANNEL_OPEN)) { - ftdm_log(FTDM_LOG_DEBUG, "-- In-band information available, opening B-Channel %d:%d\n", + if (pevent->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE) { + ftdm_log(FTDM_LOG_DEBUG, "-- In-band information available, B-Channel %d:%d\n", ftdm_channel_get_span_id(chan), ftdm_channel_get_id(chan)); - if (ftdm_channel_open_chan(chan) != FTDM_SUCCESS) { + if (!ftdm_test_flag(chan, FTDM_CHANNEL_OPEN) && (ftdm_channel_open_chan(chan) != FTDM_SUCCESS)) { ftdm_caller_data_t *caller_data = ftdm_channel_get_caller_data(chan); ftdm_log(FTDM_LOG_ERROR, "-- Error opening channel %d:%d\n", @@ -985,12 +985,12 @@ static int on_progress(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_ev if (chan) { /* Open channel if inband information is available */ - if ((pevent->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE) && !ftdm_test_flag(chan, FTDM_CHANNEL_OPEN)) { - ftdm_log(FTDM_LOG_DEBUG, "-- In-band information available, opening B-Channel %d:%d\n", + if (pevent->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE) { + ftdm_log(FTDM_LOG_DEBUG, "-- In-band information available, B-Channel %d:%d\n", ftdm_channel_get_span_id(chan), ftdm_channel_get_id(chan)); - if (ftdm_channel_open_chan(chan) != FTDM_SUCCESS) { + if (!ftdm_test_flag(chan, FTDM_CHANNEL_OPEN) && (ftdm_channel_open_chan(chan) != FTDM_SUCCESS)) { ftdm_caller_data_t *caller_data = ftdm_channel_get_caller_data(chan); ftdm_log(FTDM_LOG_ERROR, "-- Error opening channel %d:%d\n", @@ -1028,8 +1028,6 @@ static int on_ringing(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_eve ftdm_channel_t *chan = ftdm_span_get_channel(span, pevent->ringing.channel); if (chan) { - ftdm_log(FTDM_LOG_DEBUG, "-- Ringing on channel %d:%d\n", ftdm_span_get_id(span), pevent->ringing.channel); - /* we may get on_ringing even when we're already in FTDM_CHANNEL_STATE_PROGRESS_MEDIA */ // if (ftdm_channel_get_state(chan) == FTDM_CHANNEL_STATE_PROGRESS_MEDIA) { // /* dont try to move to STATE_PROGRESS to avoid annoying veto warning */ @@ -1037,12 +1035,12 @@ static int on_ringing(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_eve // } /* Open channel if inband information is available */ - if ((pevent->ringing.progressmask & PRI_PROG_INBAND_AVAILABLE) && !ftdm_test_flag(chan, FTDM_CHANNEL_OPEN)) { - ftdm_log(FTDM_LOG_DEBUG, "-- In-band information available, opening B-Channel %d:%d\n", + if ((pevent->ringing.progressmask & PRI_PROG_INBAND_AVAILABLE)) { + ftdm_log(FTDM_LOG_DEBUG, "-- In-band information available, B-Channel %d:%d\n", ftdm_channel_get_span_id(chan), ftdm_channel_get_id(chan)); - if (ftdm_channel_open_chan(chan) != FTDM_SUCCESS) { + if (!ftdm_test_flag(chan, FTDM_CHANNEL_OPEN) && (ftdm_channel_open_chan(chan) != FTDM_SUCCESS)) { ftdm_caller_data_t *caller_data = ftdm_channel_get_caller_data(chan); ftdm_log(FTDM_LOG_ERROR, "-- Error opening channel %d:%d\n", @@ -1053,9 +1051,13 @@ static int on_ringing(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_eve ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_TERMINATING); goto out; } + ftdm_log(FTDM_LOG_DEBUG, "-- Ringing on channel %d:%d with media\n", ftdm_span_get_id(span), pevent->proceeding.channel); + ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA); + } else { +// ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_PROGRESS); + ftdm_log(FTDM_LOG_DEBUG, "-- Ringing on channel %d:%d\n", ftdm_span_get_id(span), pevent->proceeding.channel); + ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_RINGING); } -// ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_PROGRESS); - ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_RINGING); } else { ftdm_log(FTDM_LOG_DEBUG, "-- Ringing on channel %d:%d but it's not in the span?\n", ftdm_span_get_id(span), pevent->ringing.channel); From a80fae922ff3cb7411bef8b189b4c905d3da9ed9 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Thu, 10 Mar 2011 11:33:01 -0600 Subject: [PATCH 030/126] FS-3126 --- src/switch_core_sqldb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/switch_core_sqldb.c b/src/switch_core_sqldb.c index 58eb90485a..27bac6d4b4 100644 --- a/src/switch_core_sqldb.c +++ b/src/switch_core_sqldb.c @@ -1714,7 +1714,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_expire_registration(int force) switch_cache_db_handle_t *dbh; char *sql; - switch_time_t now; + time_t now; if (!switch_test_flag((&runtime), SCF_USE_SQL)) { return SWITCH_STATUS_FALSE; From 844f69def072313c849ab098000edf11fd368f3f Mon Sep 17 00:00:00 2001 From: Michael S Collins Date: Thu, 10 Mar 2011 09:56:10 -0800 Subject: [PATCH 031/126] Update to-be-recorded prompts --- docs/phrase/phrase_en.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/phrase/phrase_en.xml b/docs/phrase/phrase_en.xml index 41bc69cde1..36d986bb61 100644 --- a/docs/phrase/phrase_en.xml +++ b/docs/phrase/phrase_en.xml @@ -428,6 +428,7 @@ + From 4832d26a3a4fdf1763d7fa1503d6148e06b6eab0 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Thu, 10 Mar 2011 15:32:09 -0600 Subject: [PATCH 032/126] put this back to 0 --- src/mod/endpoints/mod_sofia/sofia_glue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index 1e42afc269..3ca14e921d 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -3176,7 +3176,7 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f if ((val = switch_channel_get_variable(tech_pvt->channel, "jitterbuffer_msec")) || (val = tech_pvt->profile->jb_msec)) { int jb_msec = atoi(val); - int maxlen = 0, max_drift = 1000; + int maxlen = 0, max_drift = 0; char *p, *q; if ((p = strchr(val, ':'))) { From a8f01d5bc68e4e9ba1f46fa1fd8ac50f170b21b8 Mon Sep 17 00:00:00 2001 From: Jeff Lenk Date: Thu, 10 Mar 2011 16:58:16 -0600 Subject: [PATCH 033/126] Correct gains usage example --- libs/freetdm/mod_freetdm/mod_freetdm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c index 0652a8e128..c230e186ee 100755 --- a/libs/freetdm/mod_freetdm/mod_freetdm.c +++ b/libs/freetdm/mod_freetdm/mod_freetdm.c @@ -4059,7 +4059,7 @@ SWITCH_STANDARD_API(ft_function) ftdm_channel_t *chan; ftdm_span_t *span = NULL; if (argc < 4) { - stream->write_function(stream, "-ERR Usage: ft gains []\n"); + stream->write_function(stream, "-ERR Usage: ft gains []\n"); goto end; } ftdm_span_find_by_name(argv[3], &span); From 59f6654e960656c95ca5ff01fc4871a36a9c3fba Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Thu, 10 Mar 2011 22:02:45 -0600 Subject: [PATCH 034/126] send another presence event on calls that were cancelled from LOSE_RACE to fix winnable race in Broadsoft SCA --- src/mod/endpoints/mod_sofia/sofia_presence.c | 2 +- src/switch_channel.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mod/endpoints/mod_sofia/sofia_presence.c b/src/mod/endpoints/mod_sofia/sofia_presence.c index 91808a7f50..a9a762e00e 100644 --- a/src/mod/endpoints/mod_sofia/sofia_presence.c +++ b/src/mod/endpoints/mod_sofia/sofia_presence.c @@ -2004,7 +2004,7 @@ static void sync_sla(sofia_profile_t *profile, const char *to_user, const char * switch_core_hash_init(&sh->hash, sh->pool); sql = switch_mprintf("select sip_from_user,sip_from_host,call_info,call_info_state,uuid from sip_dialogs " - "where hostname='%q' and ((sip_from_user='%q' and sip_from_host='%q') or presence_id='%q@%q')", + "where call_info_state is not null and hostname='%q' and ((sip_from_user='%q' and sip_from_host='%q') or presence_id='%q@%q')", mod_sofia_globals.hostname, to_user, to_host, to_user, to_host); diff --git a/src/switch_channel.c b/src/switch_channel.c index bc9b76e90b..f737dc53c6 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -2539,6 +2539,7 @@ SWITCH_DECLARE(switch_channel_state_t) switch_channel_perform_hangup(switch_chan if (hangup_cause == SWITCH_CAUSE_LOSE_RACE) { + switch_channel_presence(channel, "unknown", "cancelled", NULL); switch_channel_set_variable(channel, "presence_call_info", NULL); } From 373972c0e6d528e4e5d2c1cd20dc4c4f110d7e2e Mon Sep 17 00:00:00 2001 From: Jeff Lenk Date: Fri, 11 Mar 2011 08:52:32 -0600 Subject: [PATCH 035/126] OPENZAP-147 2008 project also needs x64 additions --- .../ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.2008.vcproj | 2 +- .../ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.2010.vcxproj | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.2008.vcproj b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.2008.vcproj index 2e7fb82041..01395cb1db 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.2008.vcproj +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.2008.vcproj @@ -118,7 +118,7 @@ - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDLL @@ -157,7 +157,7 @@ - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDLL From 9257b749534932dde03940007b2ea276a71d7855 Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Fri, 11 Mar 2011 11:16:52 -0500 Subject: [PATCH 036/126] freetdm: Updated variables.txt documentation --- libs/freetdm/docs/variables.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libs/freetdm/docs/variables.txt b/libs/freetdm/docs/variables.txt index 0beecd016c..cb518e14d8 100644 --- a/libs/freetdm/docs/variables.txt +++ b/libs/freetdm/docs/variables.txt @@ -10,6 +10,7 @@ example #1a - Making an outbound call: To make an outbound call: ftdm_usrmsg_t usrmsg; + memset(&usrmsg, 0, sizeof(usrmsg)); /* Attach variable to usrmsg */ ftdm_usrmsg_add_var(&usrmsg, "isdn.prog_ind.descr", "inband-info-available"); @@ -22,6 +23,7 @@ When using ftmod_sangoma_isdn, user want to specify progress indicator inside PR ftdm_usrmsg_t usrmsg; + memset(&usrmsg, 0, sizeof(usrmsg)); /* Attach variable to usrmsg */ ftdm_usrmsg_add_var(&usrmsg, "isdn.prog_ind.descr", "inband-info-available"); @@ -40,6 +42,8 @@ When using ftmod_sangoma_isdn, user wants to transmit a custom Facility IE, insi uint8_t *my_facility_ie = ftdm_calloc(1, 200); /*memory has to be allocated using ftdm_calloc !! */ unsigned my_facility_ie_len = 0; + memset(&usrmsg, 0, sizeof(usrmsg)); + /* Fill my_facility_ie with custom data here */ my_facility_ie[my_facility_ie_len++] = 0x1C; /* Q.931 Facility IE ID */ my_facility_ie[my_facility_ie_len++] = 0x03; /* Length of facility IE */ @@ -49,7 +53,7 @@ When using ftmod_sangoma_isdn, user wants to transmit a custom Facility IE, insi ftdm_usrmsg_set_raw_data(&usrmsg, my_facility_ie, my_facility_ie_len); - ftdm_channel_call_indicate(ftdmchan, FTDM_CHANNEL_INDICATE_FACILITY, &usrmsg); + ftdm_channel_call_indicate_ex(ftdmchan, FTDM_CHANNEL_INDICATE_FACILITY, &usrmsg); /* FreeTDM will automatically free my_facility_ie */ From 51a531aaefe3c7c7f966da4a4fb035fec51a2875 Mon Sep 17 00:00:00 2001 From: Marc Olivier Chouinard Date: Fri, 11 Mar 2011 12:40:56 -0500 Subject: [PATCH 037/126] mod_callcenter: Fix a bug when an caller leave the queue from a BREAK Call (Transfer...), it doesn't think an agent answered. --- src/mod/applications/mod_callcenter/mod_callcenter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mod/applications/mod_callcenter/mod_callcenter.c b/src/mod/applications/mod_callcenter/mod_callcenter.c index 12e1960841..99e790db50 100644 --- a/src/mod/applications/mod_callcenter/mod_callcenter.c +++ b/src/mod/applications/mod_callcenter/mod_callcenter.c @@ -2302,7 +2302,7 @@ SWITCH_STANDARD_APP(callcenter_function) } /* Hangup any agents been callback */ - if (!switch_channel_up(member_channel)) { /* If channel is still up, it mean that the member didn't hangup, so we should leave the agent alone */ + if (!switch_channel_up(member_channel) || !switch_channel_get_variable(member_channel, "cc_agent_uuid")) { /* If channel is still up, it mean that the member didn't hangup, so we should leave the agent alone */ switch_core_session_hupall_matching_var("cc_member_uuid", member_uuid, SWITCH_CAUSE_ORIGINATOR_CANCEL); sql = switch_mprintf("UPDATE members SET state = '%q', uuid = '', abandoned_epoch = '%ld' WHERE system = 'single_box' AND uuid = '%q'", cc_member_state2str(CC_MEMBER_STATE_ABANDONED), (long) switch_epoch_time_now(NULL), member_uuid); From 6cd5ce7265ce2400dea3715aa0ac9aa3617df3b3 Mon Sep 17 00:00:00 2001 From: Michael S Collins Date: Fri, 11 Mar 2011 10:24:55 -0800 Subject: [PATCH 038/126] Add README_IMPORTANT.txt to default configuration --- conf/README_IMPORTANT.txt | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 conf/README_IMPORTANT.txt diff --git a/conf/README_IMPORTANT.txt b/conf/README_IMPORTANT.txt new file mode 100644 index 0000000000..8d82b404f6 --- /dev/null +++ b/conf/README_IMPORTANT.txt @@ -0,0 +1,35 @@ + -= PLEASE READ THIS BEFORE YOU PUT A FreeSWITCH BOX INTO PRODUCTION =- + +This configuration, generally known as the "default configuration" for FreeSWITCH, is *NOT* designed to be put into a production environment without some important modifications. Please keep in mind that the default configuration is designed to demonstrate what FreeSWITCH *can* do, not what it *should* do in your specific scenario. + +*** SECURING YOUR SERVER *** + +By default, FreeSWITCH starts up and does a NATPMP and UPnP request to your router. If your router supports either of these protocols then FreeSWITCH does two things: +#1 - It gets the external IP address, which it uses for SIP communications +#2 - It causes there to be a "pinhole" opened up in the router allowing inbound communications to your FreeSWITCH server + +Please re-read #2. Now, please re-read #2 again. If you do not want a pinhole coming through your router then DO NOT USE the "auto-nat" tools. The way to disable the auto-nat (that is, UPnP/NATPMP) checking is to start FreeSWITCH with the "-nonat" flag. Easy enough. + +If you are planning on putting a system into production then you had better pay attention to security in other areas as well. If you are behind a firewall then make sure your firewall is actually protecting you. If you have your server on a public-facing Internet connection then we recommend a few things: +#1 - Consider using iptables (Linux/Unix) +#2 - Consider using fail2ban (see http://wiki.freeswitch.org/wiki/Fail2ban) + +*** SECURING YOUR USERS *** + +By default, the static XML files have 20 "directory users" in conf/directory/10xx.xml, numbered 1000-1019. Also, the default dialplan has routing for calls to those same extension numbers. (NOTE: the directory and the dialplan are 100% separate concepts. Check out chapters 3-5 of the awesome FreeSWITCH book for details.) + +The default users all have *very* simple passwords for SIP credentials and voicemail. If you put those into a production system then you are either brave, ignorant, or stupid. Please don't be any of those three things! You have a few choices for handling your users: + +#1 - Delete the static XML files and use mod_xml_curl for dynamic users from a back-end database +#2 - Manually edit the static XML user directory files and modify the passwords +#3 - Run the handy randomize-passwords.pl script found in scripts/perl/ subdirectory under the main FreeSWITCH source directory + +*** GETTING HELP *** + +FreeSWITCH has a thriving on-line community - we welcome you to join us! +IRC: #freeswitch on irc.freenode.net +Mailing List: freeswitch-users on lists.freeswitch.org + +You can also get professional FreeSWITCH assistance by visiting http://www.freeswitchsolutions.com or sending an email to consulting@freeswitch.org. + +Happy FreeSWITCHing! From 24a972925b851c39d4f39db5f536d12ef4118a8b Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Fri, 11 Mar 2011 13:00:16 -0600 Subject: [PATCH 039/126] pass header in X-FS headers on attended transfer CID update to indicate specific situation to flip callee/caller id when targeting a 1 legged call --- src/include/switch_channel.h | 1 + src/include/switch_types.h | 2 ++ src/mod/endpoints/mod_sofia/mod_sofia.c | 11 +++++++ src/mod/endpoints/mod_sofia/sofia.c | 25 +++++++++++++-- src/switch_channel.c | 41 ++++++++++++++++--------- src/switch_ivr_originate.c | 2 ++ 6 files changed, 65 insertions(+), 17 deletions(-) diff --git a/src/include/switch_channel.h b/src/include/switch_channel.h index 25273bafc4..fdbbc9ab91 100644 --- a/src/include/switch_channel.h +++ b/src/include/switch_channel.h @@ -315,6 +315,7 @@ SWITCH_DECLARE(switch_status_t) switch_channel_caller_extension_masquerade(switc */ SWITCH_DECLARE(void) switch_channel_set_caller_extension(switch_channel_t *channel, switch_caller_extension_t *caller_extension); +SWITCH_DECLARE(void) switch_channel_flip_cid(switch_channel_t *channel); SWITCH_DECLARE(void) switch_channel_sort_cid(switch_channel_t *channel, switch_bool_t in); /*! diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 4253d0e542..79494d8979 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -1107,6 +1107,8 @@ typedef enum { CF_DIALPLAN, CF_BLOCK_BROADCAST_UNTIL_MEDIA, CF_CNG_PLC, + CF_ATTENDED_TRANSFER, + CF_LAZY_ATTENDED_TRANSFER, /* WARNING: DO NOT ADD ANY FLAGS BELOW THIS LINE */ CF_FLAG_MAX } switch_channel_flag_t; diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index 3bc5cc2231..f50e057d5f 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -1878,6 +1878,17 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi if (switch_stristr("update_display", tech_pvt->x_freeswitch_support_remote)) { snprintf(message, sizeof(message), "X-FS-Display-Name: %s\nX-FS-Display-Number: %s\n", name, number); + if (switch_channel_test_flag(tech_pvt->channel, CF_LAZY_ATTENDED_TRANSFER)) { + snprintf(message + strlen(message), sizeof(message) - strlen(message), "X-FS-Lazy-Attended-Transfer: true\n"); + switch_channel_clear_flag(tech_pvt->channel, CF_LAZY_ATTENDED_TRANSFER); + switch_channel_clear_flag(tech_pvt->channel, CF_ATTENDED_TRANSFER); + } + + if (switch_channel_test_flag(tech_pvt->channel, CF_ATTENDED_TRANSFER)) { + snprintf(message + strlen(message), sizeof(message) - strlen(message), "X-FS-Attended-Transfer: true\n"); + switch_channel_clear_flag(tech_pvt->channel, CF_ATTENDED_TRANSFER); + } + nua_info(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/update_display"), TAG_IF(!zstr_buf(message), SIPTAG_HEADER_STR(message)), TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)), TAG_END()); diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 761a03ce62..d612e30f0b 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -637,7 +637,7 @@ void sofia_update_callee_id(switch_core_session_t *session, sofia_profile_t *pro char *dup = NULL; switch_event_t *event; const char *val; - int fs = 0; + int fs = 0, lazy = 0, att = 0; if (switch_true(switch_channel_get_variable(channel, SWITCH_IGNORE_DISPLAY_UPDATES_VARIABLE))) { return; @@ -656,6 +656,16 @@ void sofia_update_callee_id(switch_core_session_t *session, sofia_profile_t *pro name = (char *) val; fs++; } + + if ((val = sofia_glue_get_unknown_header(sip, "X-FS-Lazy-Attended-Transfer"))) { + lazy = switch_true(val); + fs++; + } + + if ((val = sofia_glue_get_unknown_header(sip, "X-FS-Attended-Transfer"))) { + att = switch_true(val); + fs++; + } if (!fs) { if ((passerted = sip_p_asserted_identity(sip))) { @@ -727,6 +737,10 @@ void sofia_update_callee_id(switch_core_session_t *session, sofia_profile_t *pro caller_profile->callee_id_name = switch_sanitize_number(switch_core_strdup(caller_profile->pool, name)); caller_profile->callee_id_number = switch_sanitize_number(switch_core_strdup(caller_profile->pool, number)); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s Update Callee ID to \"%s\" <%s>\n", switch_channel_get_name(channel), name, number); + + if (lazy || (att && !switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE))) { + switch_channel_flip_cid(channel); + } } if (send) { @@ -5717,9 +5731,14 @@ void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t 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 ((profile->media_options & MEDIA_OPT_BYPASS_AFTER_ATT_XFER) && (tmp = switch_core_session_locate(br_b))) { + if ((tmp = switch_core_session_locate(br_b))) { switch_channel_t *tchannel = switch_core_session_get_channel(tmp); - switch_channel_set_flag(tchannel, CF_BYPASS_MEDIA_AFTER_BRIDGE); + + if ((profile->media_options & MEDIA_OPT_BYPASS_AFTER_ATT_XFER)) { + switch_channel_set_flag(tchannel, CF_BYPASS_MEDIA_AFTER_BRIDGE); + } + + switch_channel_set_flag(tchannel, CF_ATTENDED_TRANSFER); switch_core_session_rwunlock(tmp); } diff --git a/src/switch_channel.c b/src/switch_channel.c index f737dc53c6..784577c642 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -2434,26 +2434,39 @@ SWITCH_DECLARE(switch_status_t) switch_channel_caller_extension_masquerade(switc return status; } +SWITCH_DECLARE(void) switch_channel_flip_cid(switch_channel_t *channel) +{ + switch_mutex_lock(channel->profile_mutex); + if (channel->caller_profile->callee_id_name) { + switch_channel_set_variable(channel, "pre_transfer_caller_id_name", channel->caller_profile->caller_id_name); + channel->caller_profile->caller_id_name = switch_core_strdup(channel->caller_profile->pool, channel->caller_profile->callee_id_name); + } + channel->caller_profile->callee_id_name = SWITCH_BLANK_STRING; + + if (channel->caller_profile->callee_id_number) { + switch_channel_set_variable(channel, "pre_transfer_caller_id_number", channel->caller_profile->caller_id_number); + channel->caller_profile->caller_id_number = switch_core_strdup(channel->caller_profile->pool, channel->caller_profile->callee_id_number); + } + channel->caller_profile->callee_id_number = SWITCH_BLANK_STRING; + switch_mutex_unlock(channel->profile_mutex); + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(channel->session), SWITCH_LOG_INFO, "%s Flipping CID from \"%s\" <%s> to \"%s\" <%s>\n", + switch_channel_get_name(channel), + switch_channel_get_variable(channel, "pre_transfer_caller_id_name"), + switch_channel_get_variable(channel, "pre_transfer_caller_id_number"), + channel->caller_profile->caller_id_name, + channel->caller_profile->caller_id_number + ); + +} + SWITCH_DECLARE(void) switch_channel_sort_cid(switch_channel_t *channel, switch_bool_t in) { if (in) { if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND && !switch_channel_test_flag(channel, CF_DIALPLAN)) { switch_channel_set_flag(channel, CF_DIALPLAN); - - switch_mutex_lock(channel->profile_mutex); - if (channel->caller_profile->callee_id_name) { - switch_channel_set_variable(channel, "pre_transfer_caller_id_name", channel->caller_profile->caller_id_name); - channel->caller_profile->caller_id_name = switch_core_strdup(channel->caller_profile->pool, channel->caller_profile->callee_id_name); - } - channel->caller_profile->callee_id_name = SWITCH_BLANK_STRING; - - if (channel->caller_profile->callee_id_number) { - switch_channel_set_variable(channel, "pre_transfer_caller_id_number", channel->caller_profile->caller_id_number); - channel->caller_profile->caller_id_number = switch_core_strdup(channel->caller_profile->pool, channel->caller_profile->callee_id_number); - } - channel->caller_profile->callee_id_number = SWITCH_BLANK_STRING; - switch_mutex_unlock(channel->profile_mutex); + switch_channel_flip_cid(channel); } return; diff --git a/src/switch_ivr_originate.c b/src/switch_ivr_originate.c index 92137ea5d8..fe5edac504 100644 --- a/src/switch_ivr_originate.c +++ b/src/switch_ivr_originate.c @@ -3264,6 +3264,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess switch_channel_set_variable(switch_core_session_get_channel(holding_session), SWITCH_HANGUP_AFTER_BRIDGE_VARIABLE, "true"); switch_core_session_rwunlock(holding_session); } + switch_channel_set_flag(peer_channel, CF_LAZY_ATTENDED_TRANSFER); switch_ivr_uuid_bridge(holding, switch_core_session_get_uuid(peer_session)); holding = NULL; oglobals.idx = IDX_NADA; @@ -3335,6 +3336,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess switch_channel_set_variable(switch_core_session_get_channel(holding_session), SWITCH_HANGUP_AFTER_BRIDGE_VARIABLE, "true"); switch_core_session_rwunlock(holding_session); } + switch_channel_set_flag(originate_status[i].peer_channel, CF_LAZY_ATTENDED_TRANSFER); switch_ivr_uuid_bridge(holding, switch_core_session_get_uuid(originate_status[i].peer_session)); holding = NULL; } else { From b0ded7ff3b39ead5049d0474834fc1722190050f Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Fri, 11 Mar 2011 14:48:26 -0500 Subject: [PATCH 040/126] freetdm: ISDN-Q921 Unsollicited protocol errors printed in DEBUG instead of INFO --- .../ftmod_sangoma_isdn_stack_rcv.c | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_rcv.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_rcv.c index 791b65f0f6..9df1fe5557 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_rcv.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_rcv.c @@ -662,6 +662,7 @@ void sngisdn_rcv_phy_ind(SuId suId, Reason reason) void sngisdn_rcv_q921_ind(BdMngmt *status) { ftdm_span_t *ftdmspan; + unsigned loglevel = FTDM_LOG_LEVEL_INFO; sngisdn_span_data_t *signal_data = g_sngisdn_data.dchans[status->t.usta.lnkNmb].spans[1]; @@ -677,19 +678,11 @@ void sngisdn_rcv_q921_ind(BdMngmt *status) } switch (status->t.usta.alarm.category) { - case (LCM_CATEGORY_INTERFACE): - ftdm_log(FTDM_LOG_INFO, "[SNGISDN Q921] %s: %s: %s(%d): %s(%d)\n", - ftdmspan->name, - DECODE_LCM_CATEGORY(status->t.usta.alarm.category), - DECODE_LCM_EVENT(status->t.usta.alarm.event), status->t.usta.alarm.event, - DECODE_LCM_CAUSE(status->t.usta.alarm.cause), status->t.usta.alarm.cause); + case (LCM_CATEGORY_PROTOCOL): + loglevel = FTDM_LOG_LEVEL_DEBUG; break; default: - ftdm_log(FTDM_LOG_INFO, "[SNGISDN Q921] %s: %s: %s(%d): %s(%d)\n", - ftdmspan->name, - DECODE_LCM_CATEGORY(status->t.usta.alarm.category), - DECODE_LLD_EVENT(status->t.usta.alarm.event), status->t.usta.alarm.event, - DECODE_LLD_CAUSE(status->t.usta.alarm.cause), status->t.usta.alarm.cause); + loglevel = FTDM_LOG_LEVEL_INFO; switch (status->t.usta.alarm.event) { case ENTR_CONG: /* Entering Congestion */ @@ -703,6 +696,12 @@ void sngisdn_rcv_q921_ind(BdMngmt *status) } break; } + ftdm_log(FTDM_PRE, loglevel, "[SNGISDN Q921] %s: %s: %s(%d): %s(%d)\n", + ftdmspan->name, + DECODE_LCM_CATEGORY(status->t.usta.alarm.category), + DECODE_LCM_EVENT(status->t.usta.alarm.event), status->t.usta.alarm.event, + DECODE_LCM_CAUSE(status->t.usta.alarm.cause), status->t.usta.alarm.cause); + return; } void sngisdn_rcv_q931_ind(InMngmt *status) From 7da95316925292ac4813af0add7b929481fa9d0f Mon Sep 17 00:00:00 2001 From: David Yat Sin Date: Fri, 11 Mar 2011 15:06:22 -0500 Subject: [PATCH 041/126] freetdm:Fix for Q921 indications not decoded properly --- .../ftmod_sangoma_isdn_stack_rcv.c | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_rcv.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_rcv.c index 9df1fe5557..7b9989dd4c 100644 --- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_rcv.c +++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_rcv.c @@ -662,7 +662,6 @@ void sngisdn_rcv_phy_ind(SuId suId, Reason reason) void sngisdn_rcv_q921_ind(BdMngmt *status) { ftdm_span_t *ftdmspan; - unsigned loglevel = FTDM_LOG_LEVEL_INFO; sngisdn_span_data_t *signal_data = g_sngisdn_data.dchans[status->t.usta.lnkNmb].spans[1]; @@ -679,11 +678,19 @@ void sngisdn_rcv_q921_ind(BdMngmt *status) switch (status->t.usta.alarm.category) { case (LCM_CATEGORY_PROTOCOL): - loglevel = FTDM_LOG_LEVEL_DEBUG; + ftdm_log(FTDM_LOG_DEBUG, "[SNGISDN Q921] %s: %s: %s(%d): %s(%d)\n", + ftdmspan->name, + DECODE_LCM_CATEGORY(status->t.usta.alarm.category), + DECODE_LLD_EVENT(status->t.usta.alarm.event), status->t.usta.alarm.event, + DECODE_LLD_CAUSE(status->t.usta.alarm.cause), status->t.usta.alarm.cause); break; default: - loglevel = FTDM_LOG_LEVEL_INFO; - + ftdm_log(FTDM_LOG_INFO, "[SNGISDN Q921] %s: %s: %s(%d): %s(%d)\n", + ftdmspan->name, + DECODE_LCM_CATEGORY(status->t.usta.alarm.category), + DECODE_LLD_EVENT(status->t.usta.alarm.event), status->t.usta.alarm.event, + DECODE_LLD_CAUSE(status->t.usta.alarm.cause), status->t.usta.alarm.cause); + switch (status->t.usta.alarm.event) { case ENTR_CONG: /* Entering Congestion */ ftdm_log(FTDM_LOG_WARNING, "s%d: Entering Congestion\n", ftdmspan->span_id); @@ -696,12 +703,6 @@ void sngisdn_rcv_q921_ind(BdMngmt *status) } break; } - ftdm_log(FTDM_PRE, loglevel, "[SNGISDN Q921] %s: %s: %s(%d): %s(%d)\n", - ftdmspan->name, - DECODE_LCM_CATEGORY(status->t.usta.alarm.category), - DECODE_LCM_EVENT(status->t.usta.alarm.event), status->t.usta.alarm.event, - DECODE_LCM_CAUSE(status->t.usta.alarm.cause), status->t.usta.alarm.cause); - return; } void sngisdn_rcv_q931_ind(InMngmt *status) From 30dd1774ad59ff4db0f10f4d4d4de7660d4bc0c7 Mon Sep 17 00:00:00 2001 From: Marc Olivier Chouinard Date: Sat, 12 Mar 2011 11:03:03 -0500 Subject: [PATCH 042/126] =?UTF-8?q?mod=5Fcallcenter:=20Add=20new=20CLI=20c?= =?UTF-8?q?md=20and=20change=20some=20to=20be=20more=20standard.=20=20Patc?= =?UTF-8?q?h=20from=20Fran=C3=A7ois=20Delawarde,=20thanks.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mod_callcenter/mod_callcenter.c | 121 +++++++++++++----- 1 file changed, 90 insertions(+), 31 deletions(-) diff --git a/src/mod/applications/mod_callcenter/mod_callcenter.c b/src/mod/applications/mod_callcenter/mod_callcenter.c index 99e790db50..468739806d 100644 --- a/src/mod/applications/mod_callcenter/mod_callcenter.c +++ b/src/mod/applications/mod_callcenter/mod_callcenter.c @@ -2395,17 +2395,24 @@ static int list_result_callback(void *pArg, int argc, char **argv, char **column "callcenter_config agent set reject_delay_time [agent_name] [wait second] | "\ "callcenter_config agent set busy_delay_time [agent_name] [wait second] | "\ "callcenter_config agent get status [agent_name] | " \ +"callcenter_config agent list | " \ "callcenter_config tier add [queue_name] [agent_name] [level] [position] | " \ "callcenter_config tier set state [queue_name] [agent_name] [state] | " \ "callcenter_config tier set level [queue_name] [agent_name] [level] | " \ "callcenter_config tier set position [queue_name] [agent_name] [position] | " \ "callcenter_config tier del [queue_name] [agent_name] | " \ +"callcenter_config tier list | " \ "callcenter_config queue load [queue_name] | " \ "callcenter_config queue unload [queue_name] | " \ "callcenter_config queue reload [queue_name] | " \ -"callcenter_config tier list [queue_name] | " \ -"callcenter_config queue list [queue_name] | " \ -"callcenter_config queue count [queue_name]" +"callcenter_config queue list | " \ +"callcenter_config queue list agents [queue_name] [status] | " \ +"callcenter_config queue list members [queue_name] | " \ +"callcenter_config queue list tiers [queue_name] | " \ +"callcenter_config queue count | " \ +"callcenter_config queue count agents [queue_name] [status] | " \ +"callcenter_config queue count members [queue_name] | " \ +"callcenter_config queue count tiers [queue_name]" SWITCH_STANDARD_API(cc_config_api_function) { @@ -2513,6 +2520,7 @@ SWITCH_STANDARD_API(cc_config_api_function) } } + } else if (action && !strcasecmp(action, "get")) { if (argc-initial_argc < 2) { stream->write_function(stream, "%s", "-ERR Invalid!\n"); @@ -2538,6 +2546,7 @@ SWITCH_STANDARD_API(cc_config_api_function) } } + } else if (action && !strcasecmp(action, "list")) { struct list_result cbt; cbt.row_process = 0; @@ -2616,6 +2625,7 @@ SWITCH_STANDARD_API(cc_config_api_function) goto done; } } + } else if (action && !strcasecmp(action, "del")) { if (argc-initial_argc < 2) { stream->write_function(stream, "%s", "-ERR Invalid!\n"); @@ -2635,19 +2645,13 @@ SWITCH_STANDARD_API(cc_config_api_function) } } else if (action && !strcasecmp(action, "list")) { - if (argc-initial_argc < 1) { - stream->write_function(stream, "%s", "-ERR Invalid!\n"); - goto done; - } else { - const char *queue = argv[0 + initial_argc]; - struct list_result cbt; - cbt.row_process = 0; - cbt.stream = stream; - sql = switch_mprintf("SELECT * FROM tiers WHERE queue = '%q' ORDER BY level, position", queue); - cc_execute_sql_callback(NULL /* queue */, NULL /* mutex */, sql, list_result_callback, &cbt /* Call back variables */); - switch_safe_free(sql); - stream->write_function(stream, "%s", "+OK\n"); - } + struct list_result cbt; + cbt.row_process = 0; + cbt.stream = stream; + sql = switch_mprintf("SELECT * FROM tiers ORDER BY level, position"); + cc_execute_sql_callback(NULL /* queue */, NULL /* mutex */, sql, list_result_callback, &cbt /* Call back variables */); + switch_safe_free(sql); + stream->write_function(stream, "%s", "+OK\n"); } } else if (section && !strcasecmp(section, "queue")) { if (action && !strcasecmp(action, "load")) { @@ -2664,6 +2668,7 @@ SWITCH_STANDARD_API(cc_config_api_function) stream->write_function(stream, "%s", "-ERR Invalid Queue not found!\n"); } } + } else if (action && !strcasecmp(action, "unload")) { if (argc-initial_argc < 1) { stream->write_function(stream, "%s", "-ERR Invalid!\n"); @@ -2674,6 +2679,7 @@ SWITCH_STANDARD_API(cc_config_api_function) stream->write_function(stream, "%s", "+OK\n"); } + } else if (action && !strcasecmp(action, "reload")) { if (argc-initial_argc < 1) { stream->write_function(stream, "%s", "-ERR Invalid!\n"); @@ -2689,7 +2695,9 @@ SWITCH_STANDARD_API(cc_config_api_function) stream->write_function(stream, "%s", "-ERR Invalid Queue not found!\n"); } } + } else if (action && !strcasecmp(action, "list")) { + /* queue list */ if (argc-initial_argc < 1) { switch_hash_index_t *hi; stream->write_function(stream, "%s", "name|strategy|moh_sound|time_base_score|tier_rules_apply|tier_rule_wait_second|tier_rule_wait_multiply_level|tier_rule_no_agent_no_wait|discard_abandoned_after|abandoned_resume_allowed|max_wait_time|max_wait_time_with_no_agent|max_wait_time_with_no_agent_time_reached|record_template\n"); @@ -2708,35 +2716,81 @@ SWITCH_STANDARD_API(cc_config_api_function) stream->write_function(stream, "%s", "+OK\n"); goto done; } else { - const char *queue_name = argv[0 + initial_argc]; + const char *sub_action = argv[0 + initial_argc]; + const char *queue_name = argv[1 + initial_argc]; + const char *status = NULL; struct list_result cbt; + + /* queue list agents */ + if (sub_action && !strcasecmp(sub_action, "agents")) { + if (argc-initial_argc > 2) { + status = argv[2 + initial_argc]; + } + if (status) { + sql = switch_mprintf("SELECT agents.* FROM agents,tiers WHERE tiers.agent = agents.name AND tiers.queue = '%q' AND agents.status = '%q'", queue_name, status); + } else { + sql = switch_mprintf("SELECT agents.* FROM agents,tiers WHERE tiers.agent = agents.name AND tiers.queue = '%q'", queue_name); + } + /* queue list members */ + } else if (sub_action && !strcasecmp(sub_action, "members")) { + sql = switch_mprintf("SELECT * FROM members WHERE queue = '%q';", queue_name); + /* queue list tiers */ + } else if (sub_action && !strcasecmp(sub_action, "tiers")) { + sql = switch_mprintf("SELECT * FROM tiers WHERE queue = '%q';", queue_name); + } else { + stream->write_function(stream, "%s", "-ERR Invalid!\n"); + goto done; + } + cbt.row_process = 0; cbt.stream = stream; - sql = switch_mprintf("SELECT * FROM members WHERE queue = '%q'", queue_name); cc_execute_sql_callback(NULL /* queue */, NULL /* mutex */, sql, list_result_callback, &cbt /* Call back variables */); switch_safe_free(sql); stream->write_function(stream, "%s", "+OK\n"); } + } else if (action && !strcasecmp(action, "count")) { + /* queue count */ if (argc-initial_argc < 1) { - stream->write_function(stream, "%s", "-ERR Invalid!\n"); + switch_hash_index_t *hi; + int queue_count = 0; + switch_mutex_lock(globals.mutex); + for (hi = switch_hash_first(NULL, globals.queue_hash); hi; hi = switch_hash_next(hi)) { + queue_count++; + } + switch_mutex_unlock(globals.mutex); + stream->write_function(stream, "%d\n", queue_count); goto done; } else { - const char *queue_name = argv[0 + initial_argc]; + const char *sub_action = argv[0 + initial_argc]; + const char *queue_name = argv[1 + initial_argc]; + const char *status = NULL; char res[256] = ""; - switch_event_t *event; - /* Check to see if agent already exist */ - sql = switch_mprintf("SELECT count(*) FROM members WHERE queue = '%q'", queue_name); + + /* queue count agents */ + if (sub_action && !strcasecmp(sub_action, "agents")) { + if (argc-initial_argc > 2) { + status = argv[2 + initial_argc]; + } + if (status) { + sql = switch_mprintf("SELECT count(*) FROM agents,tiers WHERE tiers.agent = agents.name AND tiers.queue = '%q' AND agents.status = '%q'", queue_name, status); + } else { + sql = switch_mprintf("SELECT count(*) FROM agents,tiers WHERE tiers.agent = agents.name AND tiers.queue = '%q'", queue_name); + } + /* queue count members */ + } else if (sub_action && !strcasecmp(sub_action, "members")) { + sql = switch_mprintf("SELECT count(*) FROM members WHERE queue = '%q';", queue_name); + /* queue count tiers */ + } else if (sub_action && !strcasecmp(sub_action, "tiers")) { + sql = switch_mprintf("SELECT count(*) FROM tiers WHERE queue = '%q';", queue_name); + } else { + stream->write_function(stream, "%s", "-ERR Invalid!\n"); + goto done; + } + cc_execute_sql2str(NULL, NULL, sql, res, sizeof(res)); switch_safe_free(sql); stream->write_function(stream, "%d\n", atoi(res)); - - if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) { - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", queue_name); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "members-count"); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Count", res); - switch_event_fire(&event); - } } } } @@ -2792,7 +2846,6 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_callcenter_load) switch_console_set_complete("add callcenter_config agent get status"); switch_console_set_complete("add callcenter_config agent list"); - switch_console_set_complete("add callcenter_config tier add"); switch_console_set_complete("add callcenter_config tier del"); switch_console_set_complete("add callcenter_config tier set state"); @@ -2804,7 +2857,13 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_callcenter_load) switch_console_set_complete("add callcenter_config queue unload"); switch_console_set_complete("add callcenter_config queue reload"); switch_console_set_complete("add callcenter_config queue list"); + switch_console_set_complete("add callcenter_config queue list agents"); + switch_console_set_complete("add callcenter_config queue list members"); + switch_console_set_complete("add callcenter_config queue list tiers"); switch_console_set_complete("add callcenter_config queue count"); + switch_console_set_complete("add callcenter_config queue count agents"); + switch_console_set_complete("add callcenter_config queue count members"); + switch_console_set_complete("add callcenter_config queue count tiers"); /* indicate that the module should continue to be loaded */ return SWITCH_STATUS_SUCCESS; From 5f2337859b3f468abdd3e07c23dc6b465fbdb830 Mon Sep 17 00:00:00 2001 From: Marc Olivier Chouinard Date: Sat, 12 Mar 2011 11:29:20 -0500 Subject: [PATCH 043/126] mod_callcenter: >WARNING, some event value got removed< Adding new event time value that can then be used to calculate the Wait;Talk;Total duration of a member were on call. CC-Wait-Time CC-Talk-Time and CC-Total-Time are no longer returned. Visit the code or check the wiki for the updated variable. --- .../mod_callcenter/mod_callcenter.c | 34 +++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/src/mod/applications/mod_callcenter/mod_callcenter.c b/src/mod/applications/mod_callcenter/mod_callcenter.c index 468739806d..0e40cbb591 100644 --- a/src/mod/applications/mod_callcenter/mod_callcenter.c +++ b/src/mod/applications/mod_callcenter/mod_callcenter.c @@ -1466,6 +1466,9 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent", h->agent_name); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-System", h->agent_system); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-UUID", agent_uuid); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Agent-Called-Time", "%ld", (long) t_agent_called); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Agent-Answered-Time", "%ld", (long) t_agent_answered); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Caller-Joined-Time", "%ld", (long) t_member_called); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-UUID", h->member_uuid); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Name", h->member_caller_name); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Number", h->member_caller_number); @@ -1514,9 +1517,14 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa switch_channel_event_set_data(agent_channel, event); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", h->queue_name); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "bridge-agent-end"); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Hangup-Cause", switch_channel_cause2str(cause)); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent", h->agent_name); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-System", h->agent_system); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-UUID", agent_uuid); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Agent-Called-Time", "%ld", (long) t_agent_called); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Agent-Answered-Time", "%ld", (long) t_agent_answered); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Caller-Joined-Time", "%ld", (long) t_member_called); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Bridge-Terminated-Time", "%ld", (long) switch_epoch_time_now(NULL)); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-UUID", h->member_uuid); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Name", h->member_caller_name); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Number", h->member_caller_number); @@ -1543,10 +1551,10 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", h->queue_name); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "member-queue-end"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Cause", "Terminated"); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Agent-Answer-Time", "%ld", (long) (t_agent_answered - t_agent_called)); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Wait-Time", "%ld", (long) (t_agent_answered - t_member_called)); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Talk-Time", "%ld", (long) (switch_epoch_time_now(NULL) - t_agent_answered)); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Total-Time", "%ld", (long) (switch_epoch_time_now(NULL) - t_member_called)); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Agent-Called-Time", "%ld", (long) t_agent_called); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Agent-Answered-Time", "%ld", (long) t_agent_answered); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Caller-Leaving-Time", "%ld", (long) switch_epoch_time_now(NULL)); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Caller-Joined-Time", "%ld", (long) t_member_called); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-UUID", h->member_uuid); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Name", switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_name"))); @@ -1566,7 +1574,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa cc_execute_sql(NULL, sql, NULL); switch_safe_free(sql); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Agent %s Origination Canceled : %s\n",h->agent_name, switch_channel_cause2str(cause)); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Agent %s Origination Canceled : %s\n", h->agent_name, switch_channel_cause2str(cause)); switch (cause) { case SWITCH_CAUSE_USER_NOT_REGISTERED: /* When we are calling a unregistred device */ @@ -1609,6 +1617,19 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa } } + /* Fire up event when contact agent fails */ + if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", h->queue_name); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "bridge-agent-fail"); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Hangup-Cause", switch_channel_cause2str(cause)); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent", h->agent_name); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-System", h->agent_system); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-UUID", h->member_uuid); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Name", h->member_caller_name); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Number", h->member_caller_number); + switch_event_fire(&event); + } + } done: @@ -2314,7 +2335,8 @@ SWITCH_STANDARD_APP(callcenter_function) switch_channel_event_set_data(member_channel, event); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", queue_name); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "member-queue-end"); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Wait-Time", "%ld", (long) (switch_epoch_time_now(NULL) - t_member_called)); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Agent-Answered-Time", "%ld", (long) switch_epoch_time_now(NULL)); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Caller-Joined-Time", "%ld", (long) t_member_called); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Member \"%s\" <%s> exit queue %s due to %s\n", switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_name")), switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_number")), From 943e289043fadc8725609ea991c160484de7eb56 Mon Sep 17 00:00:00 2001 From: Marc Olivier Chouinard Date: Sat, 12 Mar 2011 11:44:35 -0500 Subject: [PATCH 044/126] mod_callcenter: Small event value correction from previous commit --- src/mod/applications/mod_callcenter/mod_callcenter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mod/applications/mod_callcenter/mod_callcenter.c b/src/mod/applications/mod_callcenter/mod_callcenter.c index 0e40cbb591..c4a8ea389f 100644 --- a/src/mod/applications/mod_callcenter/mod_callcenter.c +++ b/src/mod/applications/mod_callcenter/mod_callcenter.c @@ -2335,7 +2335,7 @@ SWITCH_STANDARD_APP(callcenter_function) switch_channel_event_set_data(member_channel, event); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", queue_name); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "member-queue-end"); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Agent-Answered-Time", "%ld", (long) switch_epoch_time_now(NULL)); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Caller-Leaving-Time", "%ld", (long) switch_epoch_time_now(NULL)); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Caller-Joined-Time", "%ld", (long) t_member_called); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Member \"%s\" <%s> exit queue %s due to %s\n", switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_name")), From 26303c5c7a53383d89eae2ac1df21bd38953dc64 Mon Sep 17 00:00:00 2001 From: Marc Olivier Chouinard Date: Sat, 12 Mar 2011 11:58:35 -0500 Subject: [PATCH 045/126] =?UTF-8?q?mod=5Fcallcenter:=20Add=20better=20supp?= =?UTF-8?q?ort=20when=20agent=20doesn't=20answer,=20including=20creating?= =?UTF-8?q?=20a=20new=20variable=20for=20the=20delay=20that=20is=20differe?= =?UTF-8?q?nt=20than=20reject=20or=20busy.=20=20Thanks=20to=20Fran=C3=A7oi?= =?UTF-8?q?s=20Delawarde?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mod_callcenter/mod_callcenter.c | 81 +++++++++++-------- 1 file changed, 49 insertions(+), 32 deletions(-) diff --git a/src/mod/applications/mod_callcenter/mod_callcenter.c b/src/mod/applications/mod_callcenter/mod_callcenter.c index c4a8ea389f..6d09479714 100644 --- a/src/mod/applications/mod_callcenter/mod_callcenter.c +++ b/src/mod/applications/mod_callcenter/mod_callcenter.c @@ -216,6 +216,7 @@ static char agents_sql[] = " wrap_up_time INTEGER NOT NULL DEFAULT 0,\n" " reject_delay_time INTEGER NOT NULL DEFAULT 0,\n" " busy_delay_time INTEGER NOT NULL DEFAULT 0,\n" +" no_answer_delay_time INTEGER NOT NULL DEFAULT 0,\n" " last_bridge_start INTEGER NOT NULL DEFAULT 0,\n" " last_bridge_end INTEGER NOT NULL DEFAULT 0,\n" " last_offered_call INTEGER NOT NULL DEFAULT 0,\n" @@ -705,6 +706,7 @@ static cc_queue_t *load_queue(const char *queue_name) switch_cache_db_test_reactive(dbh, "select count(ready_time) from agents", NULL, "alter table agents add ready_time integer not null default 0;" "alter table agents add reject_delay_time integer not null default 0;" "alter table agents add busy_delay_time integer not null default 0;"); + switch_cache_db_test_reactive(dbh, "select count(no_answer_delay_time) from agents", NULL, "alter table agents add no_answer_delay_time integer not null default 0;"); switch_cache_db_test_reactive(dbh, "select count(ready_time) from agents", "drop table agents", agents_sql); switch_cache_db_test_reactive(dbh, "select count(queue) from tiers", "drop table tiers" , tiers_sql); switch_mutex_init(&queue->mutex, SWITCH_MUTEX_NESTED, queue->pool); @@ -768,6 +770,7 @@ struct call_helper { int max_no_answer; int reject_delay_time; int busy_delay_time; + int no_answer_delay_time; switch_memory_pool_t *pool; }; @@ -1007,6 +1010,12 @@ cc_status_t cc_agent_update(const char *key, const char *value, const char *agen cc_execute_sql(NULL, sql, NULL); switch_safe_free(sql); + result = CC_STATUS_SUCCESS; + } else if (!strcasecmp(key, "no_answer_delay_time")) { + sql = switch_mprintf("UPDATE agents SET no_answer_delay_time = '%ld', system = 'single_box' WHERE name = '%q'", atol(value), agent); + cc_execute_sql(NULL, sql, NULL); + switch_safe_free(sql); + result = CC_STATUS_SUCCESS; } else if (!strcasecmp(key, "type")) { if (strcasecmp(value, CC_AGENT_TYPE_CALLBACK) && strcasecmp(value, CC_AGENT_TYPE_UUID_STANDBY)) { @@ -1203,6 +1212,7 @@ static switch_status_t load_agent(const char *agent_name) const char *wrap_up_time = switch_xml_attr(x_agent, "wrap-up-time"); const char *reject_delay_time = switch_xml_attr(x_agent, "reject-delay-time"); const char *busy_delay_time = switch_xml_attr(x_agent, "busy-delay-time"); + const char *no_answer_delay_time = switch_xml_attr(x_agent, "no-answer-delay-time"); if (type) { cc_status_t res = cc_agent_add(agent_name, type); @@ -1225,6 +1235,9 @@ static switch_status_t load_agent(const char *agent_name) if (busy_delay_time) { cc_agent_update("busy_delay_time", busy_delay_time, agent_name); } + if (no_answer_delay_time) { + cc_agent_update("no_answer_delay_time", no_answer_delay_time, agent_name); + } if (type && res == CC_STATUS_AGENT_ALREADY_EXIST) { cc_agent_update("type", type, agent_name); @@ -1565,8 +1578,8 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa } else { - int delay_next_agent_call = 0; /* Agent didn't answer or originate failed */ + int delay_next_agent_call = 0; sql = switch_mprintf("UPDATE members SET state = '%q', serving_agent = '', serving_system = ''" " WHERE serving_agent = '%q' AND serving_system = '%q' AND uuid = '%q' AND system = 'single_box'", cc_member_state2str(CC_MEMBER_STATE_WAITING), @@ -1577,30 +1590,22 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Agent %s Origination Canceled : %s\n", h->agent_name, switch_channel_cause2str(cause)); switch (cause) { - case SWITCH_CAUSE_USER_NOT_REGISTERED: /* When we are calling a unregistred device */ - case SWITCH_CAUSE_USER_BUSY: /* Could be the phone is in Do Not Disturb */ - delay_next_agent_call = (h->busy_delay_time > delay_next_agent_call?h->busy_delay_time:delay_next_agent_call); - break; - case SWITCH_CAUSE_CALL_REJECTED: /* User could have press the reject call on their phone */ - delay_next_agent_call = (h->reject_delay_time > delay_next_agent_call?h->reject_delay_time:delay_next_agent_call); - break; - default: - break; - } - - switch (cause) { - case SWITCH_CAUSE_USER_NOT_REGISTERED: /* When we are calling a unregistred device */ - case SWITCH_CAUSE_USER_BUSY: /* Could be the phone is in Do Not Disturb */ - case SWITCH_CAUSE_CALL_REJECTED: /* User could have press the reject call on their phone */ + /* When we hang-up agents that did not answer in ring-all strategy */ case SWITCH_CAUSE_ORIGINATOR_CANCEL: - if (delay_next_agent_call > 0) { - char ready_epoch[64]; - switch_snprintf(ready_epoch, sizeof(ready_epoch), "%" SWITCH_TIME_T_FMT, switch_epoch_time_now(NULL) + delay_next_agent_call); /* Make the time configurable */ - cc_agent_update("ready_time", ready_epoch , h->agent_name); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Agent %s Sleeping for %d secondes\n", h->agent_name, delay_next_agent_call); - } break; + /* Busy: Do Not Disturb, Circuit congestion */ + case SWITCH_CAUSE_NORMAL_CIRCUIT_CONGESTION: + case SWITCH_CAUSE_USER_BUSY: + delay_next_agent_call = (h->busy_delay_time > delay_next_agent_call? h->busy_delay_time : delay_next_agent_call); + break; + /* Reject: User rejected the call */ + case SWITCH_CAUSE_CALL_REJECTED: + delay_next_agent_call = (h->reject_delay_time > delay_next_agent_call? h->reject_delay_time : delay_next_agent_call); + break; + /* No answer: Destination does not answer for some other reason */ default: + delay_next_agent_call = (h->no_answer_delay_time > delay_next_agent_call? h->no_answer_delay_time : delay_next_agent_call); + tiers_state = CC_TIER_STATE_NO_ANSWER; /* Update Agent NO Answer count */ @@ -1615,6 +1620,15 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa h->agent_name, h->max_no_answer); cc_agent_update("status", cc_agent_status2str(CC_AGENT_STATUS_ON_BREAK), h->agent_name); } + break; + } + + /* Put agent to sleep for some time if necessary */ + if (delay_next_agent_call > 0) { + char ready_epoch[64]; + switch_snprintf(ready_epoch, sizeof(ready_epoch), "%" SWITCH_TIME_T_FMT, switch_epoch_time_now(NULL) + delay_next_agent_call); + cc_agent_update("ready_time", ready_epoch , h->agent_name); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Agent %s sleeping for %d seconds\n", h->agent_name, delay_next_agent_call); } /* Fire up event when contact agent fails */ @@ -1691,14 +1705,14 @@ static int agents_callback(void *pArg, int argc, char **argv, char **columnNames char *sql = NULL; char res[256]; char *agent_status = argv[2]; - char *agent_tier_state = argv[8]; - char *agent_last_bridge_end = argv[9]; - char *agent_wrap_up_time = argv[10]; - char *agent_state = argv[11]; - char *agent_ready_time = argv[12]; - char *agent_tier_level = argv[13]; - char *agent_type = argv[14]; - char *agent_uuid = argv[15]; + char *agent_tier_state = argv[9]; + char *agent_last_bridge_end = argv[10]; + char *agent_wrap_up_time = argv[11]; + char *agent_state = argv[12]; + char *agent_ready_time = argv[13]; + char *agent_tier_level = argv[14]; + char *agent_type = argv[15]; + char *agent_uuid = argv[16]; switch_bool_t contact_agent = SWITCH_TRUE; @@ -1808,6 +1822,7 @@ static int agents_callback(void *pArg, int argc, char **argv, char **columnNames h->max_no_answer = atoi(argv[5]); h->reject_delay_time = atoi(argv[6]); h->busy_delay_time = atoi(argv[7]); + h->no_answer_delay_time = atoi(argv[8]); cc_agent_update("state", cc_agent_state2str(CC_AGENT_STATE_RECEIVING), h->agent_name); @@ -1922,7 +1937,7 @@ static int members_callback(void *pArg, int argc, char **argv, char **columnName sql_order_by = switch_mprintf("level, position"); } - sql = switch_mprintf("SELECT system, name, status, contact, no_answer_count, max_no_answer, reject_delay_time, busy_delay_time,tiers.state, agents.last_bridge_end, agents.wrap_up_time, agents.state, agents.ready_time, tiers.level, agents.type, agents.uuid FROM agents LEFT JOIN tiers ON (agents.name = tiers.agent)" + sql = switch_mprintf("SELECT system, name, status, contact, no_answer_count, max_no_answer, reject_delay_time, busy_delay_time, no_answer_delay_time, tiers.state, agents.last_bridge_end, agents.wrap_up_time, agents.state, agents.ready_time, tiers.level, agents.type, agents.uuid FROM agents LEFT JOIN tiers ON (agents.name = tiers.agent)" " WHERE tiers.queue = '%q'" " AND (agents.status = '%q' OR agents.status = '%q' OR agents.status = '%q')" " ORDER BY %q", @@ -2066,7 +2081,7 @@ void *SWITCH_THREAD_FUNC cc_member_thread_run(switch_thread_t *thread, void *obj switch_channel_set_flag_value(member_channel, CF_BREAK, 2); } - /* Will drop the caller if no agent was found for more than X secondes */ + /* Will drop the caller if no agent was found for more than X seconds */ if (queue->max_wait_time_with_no_agent > 0 && m->t_member_called < queue->last_agent_exist_check - queue->max_wait_time_with_no_agent_time_reached && queue->last_agent_exist_check - queue->last_agent_exist >= queue->max_wait_time_with_no_agent) { m->member_cancel_reason = CC_MEMBER_CANCEL_REASON_NO_AGENT_TIMEOUT; @@ -2416,6 +2431,7 @@ static int list_result_callback(void *pArg, int argc, char **argv, char **column "callcenter_config agent set ready_time [agent_name] [wait till epoch] | "\ "callcenter_config agent set reject_delay_time [agent_name] [wait second] | "\ "callcenter_config agent set busy_delay_time [agent_name] [wait second] | "\ +"callcenter_config agent set no_answer_delay_time [agent_name] [wait second] | "\ "callcenter_config agent get status [agent_name] | " \ "callcenter_config agent list | " \ "callcenter_config tier add [queue_name] [agent_name] [level] [position] | " \ @@ -2865,6 +2881,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_callcenter_load) switch_console_set_complete("add callcenter_config agent set ready_time"); switch_console_set_complete("add callcenter_config agent set reject_delay_time"); switch_console_set_complete("add callcenter_config agent set busy_delay_time"); + switch_console_set_complete("add callcenter_config agent set no_answer_delay_time"); switch_console_set_complete("add callcenter_config agent get status"); switch_console_set_complete("add callcenter_config agent list"); From 233d3164be4412aaaf8f9f42d8042e48279a018a Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Sun, 13 Mar 2011 18:43:23 -0500 Subject: [PATCH 046/126] wait --- src/switch_ivr_originate.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/switch_ivr_originate.c b/src/switch_ivr_originate.c index fe5edac504..c418d40e36 100644 --- a/src/switch_ivr_originate.c +++ b/src/switch_ivr_originate.c @@ -3613,6 +3613,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess } if (*bleg) { + switch_channel_t *bchan = switch_core_session_get_channel(*bleg); + if (session && caller_channel) { switch_caller_profile_t *cloned_profile, *peer_profile = switch_channel_get_caller_profile(switch_core_session_get_channel(*bleg)); @@ -3622,7 +3624,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess } } } - + + while(switch_channel_get_state(bchan) != switch_channel_get_running_state(bchan) && switch_channel_up(bchan)) switch_cond_next(); switch_ivr_sleep(*bleg, 0, SWITCH_TRUE, NULL); } From 34a3800954cb374c91590f6415df4935bb975137 Mon Sep 17 00:00:00 2001 From: Jeff Lenk Date: Sun, 13 Mar 2011 22:26:43 -0500 Subject: [PATCH 047/126] FS-2815 --- src/mod/xml_int/mod_xml_cdr/mod_xml_cdr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mod/xml_int/mod_xml_cdr/mod_xml_cdr.c b/src/mod/xml_int/mod_xml_cdr/mod_xml_cdr.c index 78d97ce259..30889cad4c 100644 --- a/src/mod/xml_int/mod_xml_cdr/mod_xml_cdr.c +++ b/src/mod/xml_int/mod_xml_cdr/mod_xml_cdr.c @@ -599,8 +599,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_xml_cdr_load) } if (globals.retries && globals.delay <= 0) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Retries set but delay 0 setting to 5000ms\n"); - globals.delay = 5000; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Retries set but delay 0 setting to 5 seconds\n"); + globals.delay = 5; } globals.retries++; From 25cee25547e26399a94eceb1fa271d6d3f1739ba Mon Sep 17 00:00:00 2001 From: Marc Olivier Chouinard Date: Mon, 14 Mar 2011 12:31:56 -0400 Subject: [PATCH 048/126] =?UTF-8?q?mod=5Fcallcenter:=20Add=20better=20hand?= =?UTF-8?q?le=20of=20failed=20agent,=20member=20channel=20getting=20a=20br?= =?UTF-8?q?eak,=20and=20debuging=20info=20upon=20leaving.=20=20Thanks=20to?= =?UTF-8?q?=20Fran=C3=A7ois=20Delawarde=20(with=20some=20changes)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mod_callcenter/mod_callcenter.c | 62 ++++++++++++------- 1 file changed, 38 insertions(+), 24 deletions(-) diff --git a/src/mod/applications/mod_callcenter/mod_callcenter.c b/src/mod/applications/mod_callcenter/mod_callcenter.c index 6d09479714..84ff411b4d 100644 --- a/src/mod/applications/mod_callcenter/mod_callcenter.c +++ b/src/mod/applications/mod_callcenter/mod_callcenter.c @@ -160,13 +160,15 @@ struct cc_member_cancel_reason_table { typedef enum { CC_MEMBER_CANCEL_REASON_NONE, CC_MEMBER_CANCEL_REASON_TIMEOUT, - CC_MEMBER_CANCEL_REASON_NO_AGENT_TIMEOUT + CC_MEMBER_CANCEL_REASON_NO_AGENT_TIMEOUT, + CC_MEMBER_CANCEL_REASON_BREAK_OUT } cc_member_cancel_reason_t; static struct cc_member_cancel_reason_table MEMBER_CANCEL_REASON_CHART[] = { {"NONE", CC_MEMBER_CANCEL_REASON_NONE}, {"TIMEOUT", CC_MEMBER_CANCEL_REASON_TIMEOUT}, {"NO_AGENT_TIMEOUT", CC_MEMBER_CANCEL_REASON_NO_AGENT_TIMEOUT}, + {"BREAK_OUT", CC_MEMBER_CANCEL_REASON_BREAK_OUT}, {NULL, 0} }; @@ -1524,7 +1526,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa while(switch_channel_up(member_channel) && switch_channel_up(agent_channel) && globals.running) { switch_yield(100000); } - tiers_state = CC_TIER_STATE_READY; + tiers_state = CC_TIER_STATE_READY; if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) { switch_channel_event_set_data(agent_channel, event); @@ -1563,16 +1565,18 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa switch_channel_event_set_data(member_channel, event); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", h->queue_name); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "member-queue-end"); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Hangup-Cause", switch_channel_cause2str(cause)); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Cause", "Terminated"); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent", h->agent_name); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-System", h->agent_system); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-UUID", agent_uuid); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Agent-Called-Time", "%ld", (long) t_agent_called); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Agent-Answered-Time", "%ld", (long) t_agent_answered); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Caller-Leaving-Time", "%ld", (long) switch_epoch_time_now(NULL)); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Caller-Joined-Time", "%ld", (long) t_member_called); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-UUID", h->member_uuid); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Name", - switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_name"))); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Number", - switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_number"))); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Name", h->member_caller_name); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Number", h->member_caller_number); switch_event_fire(&event); } @@ -2337,53 +2341,63 @@ SWITCH_STANDARD_APP(callcenter_function) h->running = 0; } - /* Hangup any agents been callback */ - if (!switch_channel_up(member_channel) || !switch_channel_get_variable(member_channel, "cc_agent_uuid")) { /* If channel is still up, it mean that the member didn't hangup, so we should leave the agent alone */ - switch_core_session_hupall_matching_var("cc_member_uuid", member_uuid, SWITCH_CAUSE_ORIGINATOR_CANCEL); + /* Check if we were removed be cause FS Core(BREAK) asked us too */ + if (h->member_cancel_reason == CC_MEMBER_CANCEL_REASON_NONE && !switch_channel_get_variable(member_channel, "cc_agent_uuid")) { + h->member_cancel_reason = CC_MEMBER_CANCEL_REASON_BREAK_OUT; + } + + /* Canceled for some reason */ + if (!switch_channel_up(member_channel) || h->member_cancel_reason != CC_MEMBER_CANCEL_REASON_NONE) { + /* Update member state */ sql = switch_mprintf("UPDATE members SET state = '%q', uuid = '', abandoned_epoch = '%ld' WHERE system = 'single_box' AND uuid = '%q'", cc_member_state2str(CC_MEMBER_STATE_ABANDONED), (long) switch_epoch_time_now(NULL), member_uuid); cc_execute_sql(NULL, sql, NULL); switch_safe_free(sql); - /* Generate an Event and update some channel variable */ + /* Hangup any callback agents */ + switch_core_session_hupall_matching_var("cc_member_uuid", member_uuid, SWITCH_CAUSE_ORIGINATOR_CANCEL); + + /* Generate an event */ if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) { switch_channel_event_set_data(member_channel, event); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", queue_name); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "member-queue-end"); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Caller-Leaving-Time", "%ld", (long) switch_epoch_time_now(NULL)); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Caller-Joined-Time", "%ld", (long) t_member_called); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Member \"%s\" <%s> exit queue %s due to %s\n", - switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_name")), - switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_number")), - queue_name, cc_member_cancel_reason2str(h->member_cancel_reason)); - - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Cause", cc_member_cancel_reason2str(h->member_cancel_reason)); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Cause", "Cancel"); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Cancel-Reason", cc_member_cancel_reason2str(h->member_cancel_reason)); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-UUID", member_uuid); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Name", switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_name"))); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Number", switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_number"))); switch_event_fire(&event); } - /* for xml_cdr needs */ + /* Update some channel variables for xml_cdr needs */ switch_channel_set_variable_printf(member_channel, "cc_queue_canceled_epoch", "%ld", (long) switch_epoch_time_now(NULL)); - switch_channel_set_variable_printf(member_channel, "cc_cause", "%s", cc_member_cancel_reason2str(h->member_cancel_reason)); + switch_channel_set_variable_printf(member_channel, "cc_cause", "%s", "cancel"); + switch_channel_set_variable_printf(member_channel, "cc_cancel_reason", "%s", cc_member_cancel_reason2str(h->member_cancel_reason)); - - /* Send Event with queue count */ - cc_queue_count(queue_name); + /* Print some debug log information */ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Member \"%s\" <%s> exit queue %s due to %s\n", + switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_name")), + switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_number")), + queue_name, cc_member_cancel_reason2str(h->member_cancel_reason)); } else { - switch_channel_set_variable_printf(member_channel, "cc_cause", "%s", "answered"); + /* Update member state */ sql = switch_mprintf("UPDATE members SET state = '%q', bridge_epoch = '%ld' WHERE system = 'single_box' AND uuid = '%q'", cc_member_state2str(CC_MEMBER_STATE_ANSWERED), (long) switch_epoch_time_now(NULL), member_uuid); cc_execute_sql(NULL, sql, NULL); switch_safe_free(sql); - /* Send Event with queue count */ - cc_queue_count(queue_name); + /* Update some channel variables for xml_cdr needs */ + switch_channel_set_variable_printf(member_channel, "cc_cause", "%s", "answered"); } + /* Send Event with queue count */ + cc_queue_count(queue_name); + end: return; From d4f845ed0832659791bc07abd63350e1c901ba98 Mon Sep 17 00:00:00 2001 From: Marc Olivier Chouinard Date: Mon, 14 Mar 2011 12:42:02 -0400 Subject: [PATCH 049/126] =?UTF-8?q?mod=5Fcallcenter:=20Should=20resolve=20?= =?UTF-8?q?lot=20of=20loopback=20issues=20mentioned.=20=20Thanks=20to=20Fr?= =?UTF-8?q?an=C3=A7ois=20Delawarde?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mod_callcenter/mod_callcenter.c | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/mod/applications/mod_callcenter/mod_callcenter.c b/src/mod/applications/mod_callcenter/mod_callcenter.c index 84ff411b4d..65ad78f5d8 100644 --- a/src/mod/applications/mod_callcenter/mod_callcenter.c +++ b/src/mod/applications/mod_callcenter/mod_callcenter.c @@ -1399,8 +1399,6 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "cc_agent", "%s", h->agent_name); switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "cc_agent_type", "%s", h->agent_type); switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "ignore_early_media", "true"); - /* Force loopback to remain live, if not, the loop will detect the actual channel to gone */ - switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "loopback_bowout", "false"); t_agent_called = switch_epoch_time_now(NULL); dialstr = switch_mprintf("%s", h->originate_string); @@ -1445,9 +1443,36 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa const char *agent_uuid = switch_core_session_get_uuid(agent_session); switch_channel_t *member_channel = switch_core_session_get_channel(member_session); switch_channel_t *agent_channel = switch_core_session_get_channel(agent_session); + const char *other_loopback_leg_uuid = switch_channel_get_variable(agent_channel, "other_loopback_leg_uuid"); switch_channel_set_variable(agent_channel, "cc_member_pre_answer_uuid", NULL); + /* Loopback special case */ + if (other_loopback_leg_uuid) { + switch_core_session_t *other_loopback_session = switch_core_session_locate(other_loopback_leg_uuid); + if (other_loopback_session) { + switch_channel_t *other_loopback_channel = switch_core_session_get_channel(other_loopback_session); + const char *real_uuid = switch_channel_get_variable(other_loopback_channel, SWITCH_SIGNAL_BOND_VARIABLE); + + switch_channel_set_variable(other_loopback_channel, "cc_member_pre_answer_uuid", NULL); + + /* Switch the agent session */ + if (real_uuid) { + switch_core_session_rwunlock(agent_session); + agent_uuid = real_uuid; + agent_session = switch_core_session_locate(agent_uuid); + agent_channel = switch_core_session_get_channel(agent_session); + + switch_channel_set_variable(agent_channel, "cc_queue", h->queue_name); + switch_channel_set_variable(agent_channel, "cc_agent", h->agent_name); + switch_channel_set_variable(agent_channel, "cc_agent_type", h->agent_type); + switch_channel_set_variable(agent_channel, "cc_member_uuid", h->member_uuid); + } + switch_core_session_rwunlock(other_loopback_session); + } + } + + if (!strcasecmp(h->queue_strategy,"ring-all")) { char res[256]; /* Map the Agent to the member */ From 69a5b300610e5a87dd0eb58c5bbbfad671260c96 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Mon, 14 Mar 2011 11:43:42 -0500 Subject: [PATCH 050/126] FS-3150 --comment-only this looks like an unhandled parse error, try this patch, though the call will likely fail but we can see what it doesn't like about the sdp now --- src/mod/endpoints/mod_sofia/sofia.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index d612e30f0b..d657fdd410 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -4422,10 +4422,15 @@ static void sofia_handle_sip_r_invite(switch_core_session_t *session, int status } switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Passing %d %s to other leg\n", status, phrase); - - if (status == 200 && sofia_test_flag(tech_pvt, TFLAG_T38_PASSTHRU) && has_t38) { - if (sip->sip_payload && sip->sip_payload->pl_data) { - switch_t38_options_t *t38_options = sofia_glue_extract_t38_options(session, sip->sip_payload->pl_data); + + if (status == 200 && sofia_test_flag(tech_pvt, TFLAG_T38_PASSTHRU) && has_t38 && sip->sip_payload && sip->sip_payload->pl_data) { + switch_t38_options_t *t38_options = sofia_glue_extract_t38_options(session, sip->sip_payload->pl_data); + + if (!t38_options) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_WARNING, "%s Error parsing SDP:\n%s\n", + switch_channel_get_name(tech_pvt->channel), sip->sip_payload->pl_data); + goto end; + } else { char *remote_host = switch_rtp_get_remote_host(tech_pvt->rtp_session); switch_port_t remote_port = switch_rtp_get_remote_port(tech_pvt->rtp_session); char tmp[32] = ""; From 4c435ec53032efc543f32cf4220547af3fb20363 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Mon, 14 Mar 2011 11:54:08 -0500 Subject: [PATCH 051/126] change text of error message to be more descriptive --- src/mod/endpoints/mod_sofia/sofia_reg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mod/endpoints/mod_sofia/sofia_reg.c b/src/mod/endpoints/mod_sofia/sofia_reg.c index 6e3649a68f..766c6ceee1 100644 --- a/src/mod/endpoints/mod_sofia/sofia_reg.c +++ b/src/mod/endpoints/mod_sofia/sofia_reg.c @@ -1914,7 +1914,7 @@ void sofia_reg_handle_sip_r_challenge(int status, } else if (gateway) { switch_snprintf(authentication, sizeof(authentication), "%s:%s:%s:%s", scheme, realm, gateway->auth_username, gateway->register_password); } else { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "No Matching gateway found\n"); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot locate any authentication credentials to complete an authentication request for realm '%s'\n", realm); goto cancel; } From 2c009dd954f2480ab9dcace77b596ecdd9229363 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Tue, 15 Mar 2011 14:29:04 -0500 Subject: [PATCH 052/126] doh --- src/mod/applications/mod_conference/mod_conference.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/mod/applications/mod_conference/mod_conference.c b/src/mod/applications/mod_conference/mod_conference.c index 762bc1aa40..9c85d40c8b 100644 --- a/src/mod/applications/mod_conference/mod_conference.c +++ b/src/mod/applications/mod_conference/mod_conference.c @@ -564,7 +564,10 @@ static conference_member_t *conference_member_get(conference_obj_t *conference, member = NULL; } - switch_thread_rwlock_rdlock(member->rwlock); + if (member) { + switch_thread_rwlock_rdlock(member->rwlock); + } + switch_mutex_unlock(conference->member_mutex); return member; From c6f67322312bf02be37346be22d7e086fff3aed2 Mon Sep 17 00:00:00 2001 From: Steve Underwood Date: Wed, 16 Mar 2011 23:31:43 +0800 Subject: [PATCH 053/126] Fixed a vulnerability in T.4 and T.6 processing which is similar to http://bugzilla.maptools.org/show_bug.cgi?id=2297 in libtiff. A really screwed up 2D T.4 image, or a maliciously constructed T.4 2D or T.6 image should potential run off the end of an image decoder buffer. --- libs/spandsp/src/t4_rx.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/libs/spandsp/src/t4_rx.c b/libs/spandsp/src/t4_rx.c index dfdf914804..131bfc0179 100644 --- a/libs/spandsp/src/t4_rx.c +++ b/libs/spandsp/src/t4_rx.c @@ -652,6 +652,7 @@ static __inline__ void force_drop_rx_bits(t4_state_t *s, int bits) static int rx_put_bits(t4_state_t *s, uint32_t bit_string, int quantity) { int bits; + int old_a0; /* We decompress bit by bit, as the data stream is received. We need to scan continuously for EOLs, so we might as well work this way. */ @@ -809,8 +810,23 @@ static int rx_put_bits(t4_state_t *s, uint32_t bit_string, int quantity) s->t4_t6_rx.a0, s->t4_t6_rx.b1, s->t4_t6_rx.run_length); - s->t4_t6_rx.run_length += (s->t4_t6_rx.b1 - s->t4_t6_rx.a0 + t4_2d_table[bits].param); + old_a0 = s->t4_t6_rx.a0; s->t4_t6_rx.a0 = s->t4_t6_rx.b1 + t4_2d_table[bits].param; + /* We need to check if a bad or malicious image is failing to move forward along the row. + Going back is obviously bad. We also need to avoid a stall on the spot, except for the + special case of the start of the row. Zero movement as the very first element in the + row is perfectly normal. */ + if (s->t4_t6_rx.a0 <= old_a0) + { + if (s->t4_t6_rx.a0 < old_a0 || s->t4_t6_rx.b_cursor > 1) + { + /* Undo the update we just started, and carry on as if this code does not exist */ + /* TODO: we really should record that something wasn't right at this point. */ + s->t4_t6_rx.a0 = old_a0; + break; + } + } + s->t4_t6_rx.run_length += (s->t4_t6_rx.a0 - old_a0); add_run_to_row(s); /* We need to move one step in one direction or the other, to change to the opposite colour */ @@ -832,8 +848,9 @@ static int rx_put_bits(t4_state_t *s, uint32_t bit_string, int quantity) s->ref_runs[s->t4_t6_rx.b_cursor], s->ref_runs[s->t4_t6_rx.b_cursor + 1]); s->t4_t6_rx.b1 += s->ref_runs[s->t4_t6_rx.b_cursor++]; - s->t4_t6_rx.run_length += (s->t4_t6_rx.b1 - s->t4_t6_rx.a0); + old_a0 = s->t4_t6_rx.a0; s->t4_t6_rx.a0 = s->t4_t6_rx.b1; + s->t4_t6_rx.run_length += (s->t4_t6_rx.a0 - old_a0); s->t4_t6_rx.b1 += s->ref_runs[s->t4_t6_rx.b_cursor++]; break; case S_Ext: From 2d3d8f8d34dd365b32f63a0b9906112d508d221c Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Wed, 16 Mar 2011 16:19:39 -0500 Subject: [PATCH 054/126] Add mod_ladspa (Audio plugin framework for linux) http://http://www.ladspa.org/ try it with autotalent http://web.mit.edu/tbaran/www/autotalent.html --- conf/dialplan/default/ladspa.xml | 73 +++ src/mod/applications/mod_ladspa/Makefile | 5 + src/mod/applications/mod_ladspa/load.c | 173 ++++++ src/mod/applications/mod_ladspa/mod_ladspa.c | 579 +++++++++++++++++++ src/mod/applications/mod_ladspa/utils.h | 72 +++ 5 files changed, 902 insertions(+) create mode 100644 conf/dialplan/default/ladspa.xml create mode 100644 src/mod/applications/mod_ladspa/Makefile create mode 100644 src/mod/applications/mod_ladspa/load.c create mode 100644 src/mod/applications/mod_ladspa/mod_ladspa.c create mode 100644 src/mod/applications/mod_ladspa/utils.h diff --git a/conf/dialplan/default/ladspa.xml b/conf/dialplan/default/ladspa.xml new file mode 100644 index 0000000000..926c31a87a --- /dev/null +++ b/conf/dialplan/default/ladspa.xml @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mod/applications/mod_ladspa/Makefile b/src/mod/applications/mod_ladspa/Makefile new file mode 100644 index 0000000000..1a77c52a0d --- /dev/null +++ b/src/mod/applications/mod_ladspa/Makefile @@ -0,0 +1,5 @@ +BASE=../../../.. + +LOCAL_OBJS += load.o +include $(BASE)/build/modmake.rules + diff --git a/src/mod/applications/mod_ladspa/load.c b/src/mod/applications/mod_ladspa/load.c new file mode 100644 index 0000000000..652ecfa0f2 --- /dev/null +++ b/src/mod/applications/mod_ladspa/load.c @@ -0,0 +1,173 @@ +/* load.c + + Free software by Richard W.E. Furse. Do with as you will. No + warranty. */ + +/*****************************************************************************/ + +#include +#include +#include +#include + +/*****************************************************************************/ + +#include "ladspa.h" +#include "utils.h" +#include "inttypes.h" +#include "switch.h" +/*****************************************************************************/ + +/* This function provides a wrapping of dlopen(). When the filename is + not an absolute path (i.e. does not begin with / character), this + routine will search the LADSPA_PATH for the file. */ +static void *dlopenLADSPA(const char *pcFilename, int iFlag) +{ + + char *pcBuffer; + const char *pcEnd; + const char *pcLADSPAPath; + const char *pcStart; + int iEndsInSO; + int iNeedSlash; + size_t iFilenameLength; + void *pvResult; + + iFilenameLength = strlen(pcFilename); + pvResult = NULL; + + if (pcFilename[0] == '/') { + + /* The filename is absolute. Assume the user knows what he/she is + doing and simply dlopen() it. */ + + pvResult = dlopen(pcFilename, iFlag); + if (pvResult != NULL) + return pvResult; + + } else { + + /* If the filename is not absolute then we wish to check along the + LADSPA_PATH path to see if we can find the file there. We do + NOT call dlopen() directly as this would find plugins on the + LD_LIBRARY_PATH, whereas the LADSPA_PATH is the correct place + to search. */ + + pcLADSPAPath = getenv("LADSPA_PATH"); + + if (pcLADSPAPath) { + + pcStart = pcLADSPAPath; + while (*pcStart != '\0') { + pcEnd = pcStart; + while (*pcEnd != ':' && *pcEnd != '\0') + pcEnd++; + + pcBuffer = malloc(iFilenameLength + 2 + (pcEnd - pcStart)); + if (pcEnd > pcStart) + strncpy(pcBuffer, pcStart, pcEnd - pcStart); + iNeedSlash = 0; + if (pcEnd > pcStart) + if (*(pcEnd - 1) != '/') { + iNeedSlash = 1; + pcBuffer[pcEnd - pcStart] = '/'; + } + strcpy(pcBuffer + iNeedSlash + (pcEnd - pcStart), pcFilename); + + pvResult = dlopen(pcBuffer, iFlag); + + free(pcBuffer); + if (pvResult != NULL) + return pvResult; + + pcStart = pcEnd; + if (*pcStart == ':') + pcStart++; + } + } + } + + /* As a last ditch effort, check if filename does not end with + ".so". In this case, add this suffix and recurse. */ + iEndsInSO = 0; + if (iFilenameLength > 3) + iEndsInSO = (strcmp(pcFilename + iFilenameLength - 3, ".so") == 0); + if (!iEndsInSO) { + pcBuffer = malloc(iFilenameLength + 4); + strcpy(pcBuffer, pcFilename); + strcat(pcBuffer, ".so"); + pvResult = dlopenLADSPA(pcBuffer, iFlag); + free(pcBuffer); + } + + if (pvResult != NULL) + return pvResult; + + /* If nothing has worked, then at least we can make sure we set the + correct error message - and this should correspond to a call to + dlopen() with the actual filename requested. The dlopen() manual + page does not specify whether the first or last error message + will be kept when multiple calls are made to dlopen(). We've + covered the former case - now we can handle the latter by calling + dlopen() again here. */ + return dlopen(pcFilename, iFlag); +} + +/*****************************************************************************/ + +void *loadLADSPAPluginLibrary(const char *pcPluginFilename) +{ + + void *pvPluginHandle; + + pvPluginHandle = dlopenLADSPA(pcPluginFilename, RTLD_NOW); + if (!pvPluginHandle) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to load plugin \"%s\": %s\n", pcPluginFilename, dlerror()); + } + + return pvPluginHandle; +} + +/*****************************************************************************/ + +void unloadLADSPAPluginLibrary(void *pvLADSPAPluginLibrary) +{ + dlclose(pvLADSPAPluginLibrary); +} + +/*****************************************************************************/ + +const LADSPA_Descriptor *findLADSPAPluginDescriptor(void *pvLADSPAPluginLibrary, const char *pcPluginLibraryFilename, const char *pcPluginLabel) +{ + + const LADSPA_Descriptor *psDescriptor; + LADSPA_Descriptor_Function pfDescriptorFunction; + unsigned long lPluginIndex; + + dlerror(); + pfDescriptorFunction = (LADSPA_Descriptor_Function) (intptr_t)dlsym(pvLADSPAPluginLibrary, "ladspa_descriptor"); + if (!pfDescriptorFunction) { + const char *pcError = dlerror(); + if (pcError) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, + "Unable to find ladspa_descriptor() function in plugin " + "library file \"%s\": %s.\n" "Are you sure this is a LADSPA plugin file?\n", pcPluginLibraryFilename, pcError); + return NULL; + } + } + + for (lPluginIndex = 0;; lPluginIndex++) { + psDescriptor = pfDescriptorFunction(lPluginIndex); + if (psDescriptor == NULL) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, + "Unable to find label \"%s\" in plugin library file \"%s\".\n", pcPluginLabel, pcPluginLibraryFilename); + return NULL; + } + if (strcmp(psDescriptor->Label, pcPluginLabel) == 0) + return psDescriptor; + } +} + +/*****************************************************************************/ + +/* EOF */ diff --git a/src/mod/applications/mod_ladspa/mod_ladspa.c b/src/mod/applications/mod_ladspa/mod_ladspa.c new file mode 100644 index 0000000000..871d203646 --- /dev/null +++ b/src/mod/applications/mod_ladspa/mod_ladspa.c @@ -0,0 +1,579 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2005-2011, 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_ladspa.c -- LADSPA + * + */ +#include +#include "ladspa.h" +#include "utils.h" + +/* Prototypes */ +SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_ladspa_shutdown); +SWITCH_MODULE_RUNTIME_FUNCTION(mod_ladspa_runtime); +SWITCH_MODULE_LOAD_FUNCTION(mod_ladspa_load); + +/* SWITCH_MODULE_DEFINITION(name, load, shutdown, runtime) + * Defines a switch_loadable_module_function_table_t and a static const char[] modname + */ +SWITCH_MODULE_DEFINITION(mod_ladspa, mod_ladspa_load, mod_ladspa_shutdown, NULL); + +#define MAX_INDEX 256 + +typedef struct { + switch_core_session_t *session; + char *plugin_name; + char *label_name; + void *library_handle; + const LADSPA_Descriptor *ldesc; + LADSPA_Handle handle; + LADSPA_Data config[MAX_INDEX]; + uint8_t has_config[MAX_INDEX]; + int skip; + LADSPA_Data in_buf[SWITCH_RECOMMENDED_BUFFER_SIZE]; + LADSPA_Data out_buf[SWITCH_RECOMMENDED_BUFFER_SIZE]; + LADSPA_Data out_ports[MAX_INDEX]; +} switch_ladspa_t; + + + +int check_range(const LADSPA_Descriptor *ldesc, int i, LADSPA_Data val) +{ + if (ldesc->PortRangeHints[i].LowerBound && ldesc->PortRangeHints[i].UpperBound && + (val < ldesc->PortRangeHints[i].LowerBound || val > ldesc->PortRangeHints[i].UpperBound)) { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, "Param %f out of bounds %f-%f\n", + val, ldesc->PortRangeHints[i].LowerBound, ldesc->PortRangeHints[i].UpperBound); + return 0; + } + + return 1; +} + +int find_default(const LADSPA_Descriptor *ldesc, int i, LADSPA_Data *ptr) + +{ + LADSPA_Data dftval = 0; + int fail = 0; + + LADSPA_PortRangeHintDescriptor port_hint = ldesc->PortRangeHints[i].HintDescriptor; + + switch (port_hint & LADSPA_HINT_DEFAULT_MASK) { + case LADSPA_HINT_DEFAULT_NONE: + break; + case LADSPA_HINT_DEFAULT_MINIMUM: + dftval = ldesc->PortRangeHints[i].LowerBound; + break; + case LADSPA_HINT_DEFAULT_LOW: + if (LADSPA_IS_HINT_LOGARITHMIC(port_hint)) { + dftval = exp(log(ldesc->PortRangeHints[i].LowerBound) + * 0.75 + log(ldesc->PortRangeHints[i].UpperBound) + * 0.25); + } else { + dftval = (ldesc->PortRangeHints[i].LowerBound * 0.75 + ldesc->PortRangeHints[i].UpperBound * 0.25); + } + break; + case LADSPA_HINT_DEFAULT_MIDDLE: + if (LADSPA_IS_HINT_LOGARITHMIC(port_hint)) { + dftval = sqrt(ldesc->PortRangeHints[i].LowerBound * ldesc->PortRangeHints[i].UpperBound); + } else { + dftval = 0.5 * (ldesc->PortRangeHints[i].LowerBound + ldesc->PortRangeHints[i].UpperBound); + } + break; + case LADSPA_HINT_DEFAULT_HIGH: + if (LADSPA_IS_HINT_LOGARITHMIC(port_hint)) { + dftval = exp(log(ldesc->PortRangeHints[i].LowerBound) + * 0.25 + log(ldesc->PortRangeHints[i].UpperBound) + * 0.75); + } else { + dftval = (ldesc->PortRangeHints[i].LowerBound * 0.25 + ldesc->PortRangeHints[i].UpperBound * 0.75); + } + break; + case LADSPA_HINT_DEFAULT_MAXIMUM: + dftval = ldesc->PortRangeHints[i].UpperBound; + break; + case LADSPA_HINT_DEFAULT_0: + dftval = 0; + break; + case LADSPA_HINT_DEFAULT_1: + dftval = 1; + break; + case LADSPA_HINT_DEFAULT_100: + dftval = 100; + break; + case LADSPA_HINT_DEFAULT_440: + dftval = 440; + break; + default: + fail = 1; + break; + } + + if (!fail) { + *ptr = dftval; + } + + return !fail; +} + +static void dump_info(const LADSPA_Descriptor *ldesc) +{ + int i = 0; + + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Plugin Name: \"%s\"\n", ldesc->Name); + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Plugin Label: \"%s\"\n", ldesc->Label); + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Plugin Unique ID: %lu\n", ldesc->UniqueID); + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Maker: \"%s\"\n", ldesc->Maker); + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Copyright: \"%s\"\n", ldesc->Copyright); + + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Must Run Real-Time: "); + if (LADSPA_IS_REALTIME(ldesc->Properties)) + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Yes\n"); + else + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "No\n"); + + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Has activate() Function: "); + if (ldesc->activate != NULL) + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Yes\n"); + else + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "No\n"); + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Has deactivate() Function: "); + if (ldesc->deactivate != NULL) + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Yes\n"); + else + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "No\n"); + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Has run_adding() Function: "); + if (ldesc->run_adding != NULL) + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Yes\n"); + else + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "No\n"); + + if (ldesc->instantiate == NULL) + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "ERROR: PLUGIN HAS NO INSTANTIATE FUNCTION.\n"); + if (ldesc->connect_port == NULL) + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "ERROR: PLUGIN HAS NO CONNECT_PORT FUNCTION.\n"); + if (ldesc->run == NULL) + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "ERROR: PLUGIN HAS NO RUN FUNCTION.\n"); + if (ldesc->run_adding != NULL && ldesc->set_run_adding_gain == NULL) + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "ERROR: PLUGIN HAS RUN_ADDING FUNCTION BUT " "NOT SET_RUN_ADDING_GAIN.\n"); + if (ldesc->run_adding == NULL && ldesc->set_run_adding_gain != NULL) + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "ERROR: PLUGIN HAS SET_RUN_ADDING_GAIN FUNCTION BUT " "NOT RUN_ADDING.\n"); + if (ldesc->cleanup == NULL) + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "ERROR: PLUGIN HAS NO CLEANUP FUNCTION.\n"); + + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Environment: "); + if (LADSPA_IS_HARD_RT_CAPABLE(ldesc->Properties)) + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Normal or Hard Real-Time\n"); + else + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Normal\n"); + + if (LADSPA_IS_INPLACE_BROKEN(ldesc->Properties)) + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "This plugin cannot use in-place processing. " "It will not work with all hosts.\n"); + + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Ports:"); + + if (ldesc->PortCount == 0) + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "\tERROR: PLUGIN HAS NO PORTS.\n"); + + for (i = 0; i < ldesc->PortCount; i++) { + LADSPA_Data dft = 0.0f; + int found = 0; + + if (LADSPA_IS_PORT_CONTROL(ldesc->PortDescriptors[i])) { + found = find_default(ldesc, i, &dft); + } + + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "\n \"%s\" ", ldesc->PortNames[i]); + + if (LADSPA_IS_PORT_INPUT(ldesc->PortDescriptors[i]) + && LADSPA_IS_PORT_OUTPUT(ldesc->PortDescriptors[i])) + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "ERROR: INPUT AND OUTPUT"); + else if (LADSPA_IS_PORT_INPUT(ldesc->PortDescriptors[i])) + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "input"); + else if (LADSPA_IS_PORT_OUTPUT(ldesc->PortDescriptors[i])) + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "output"); + else + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "ERROR: NEITHER INPUT NOR OUTPUT"); + + if (LADSPA_IS_PORT_CONTROL(ldesc->PortDescriptors[i]) + && LADSPA_IS_PORT_AUDIO(ldesc->PortDescriptors[i])) + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, ", ERROR: CONTROL AND AUDIO"); + else if (LADSPA_IS_PORT_CONTROL(ldesc->PortDescriptors[i])) + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, ", control"); + else if (LADSPA_IS_PORT_AUDIO(ldesc->PortDescriptors[i])) + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, ", audio"); + else + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, ", ERROR: NEITHER CONTROL NOR AUDIO"); + + if (LADSPA_IS_PORT_CONTROL(ldesc->PortDescriptors[i])) { + if (found) { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "\n RANGE: %f-%f DEFAULT: %f\n", + ldesc->PortRangeHints[i].LowerBound, ldesc->PortRangeHints[i].UpperBound, dft); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "\n RANGE: %f-%f DEFAULT: none.\n", + ldesc->PortRangeHints[i].LowerBound, ldesc->PortRangeHints[i].UpperBound); + } + } + + + + } + + switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "\n\n"); +} + + + + + +static switch_bool_t ladspa_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type) +{ + switch_ladspa_t *pvt = (switch_ladspa_t *) user_data; + //switch_frame_t *frame = NULL; + switch_channel_t *channel = switch_core_session_get_channel(pvt->session); + + switch (type) { + case SWITCH_ABC_TYPE_INIT: + { + switch_codec_implementation_t read_impl = { 0 }; + LADSPA_PortDescriptor port_desc; + int i = 0, j = 0, k = 0; + + switch_core_session_get_read_impl(pvt->session, &read_impl); + + if (!(pvt->library_handle = loadLADSPAPluginLibrary(pvt->plugin_name))) { + return SWITCH_FALSE; + } + + if (!(pvt->ldesc = findLADSPAPluginDescriptor(pvt->library_handle, pvt->plugin_name, pvt->label_name))) { + return SWITCH_FALSE; + } + + + pvt->handle = pvt->ldesc->instantiate(pvt->ldesc, read_impl.actual_samples_per_second); + + dump_info(pvt->ldesc); + + + for (i = 0; i < pvt->ldesc->PortCount; i++) { + port_desc = pvt->ldesc->PortDescriptors[i]; + + if (LADSPA_IS_PORT_CONTROL(port_desc) && LADSPA_IS_PORT_INPUT(port_desc)) { + LADSPA_Data dft = 0.0f; + int found = find_default(pvt->ldesc, i, &dft); + + if (found && !pvt->has_config[j]) { + pvt->config[j] = dft; + pvt->has_config[j] = 1; + } + + if (pvt->has_config[j]) { + if (!check_range(pvt->ldesc, i, pvt->config[j])) { + pvt->config[j] = dft; + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session), SWITCH_LOG_WARNING, "FALLING TO DEFAULT PARAM %d [%s] (%f)\n", + j+1, + pvt->ldesc->PortNames[i], + pvt->config[j]); + } + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session), SWITCH_LOG_DEBUG, "ADDING PARAM %d [%s] (%f)\n", + j+1, + pvt->ldesc->PortNames[i], + pvt->config[j]); + pvt->ldesc->connect_port(pvt->handle, i, &pvt->config[j++]); + usleep(10000); + } + } + + if (LADSPA_IS_PORT_INPUT(port_desc) && LADSPA_IS_PORT_AUDIO(port_desc)) { + pvt->ldesc->connect_port(pvt->handle, i, pvt->in_buf); + } + + if (LADSPA_IS_PORT_OUTPUT(port_desc)) { + if (LADSPA_IS_PORT_AUDIO(port_desc)) { + pvt->ldesc->connect_port(pvt->handle, i, pvt->out_buf); + } else if (k < MAX_INDEX) { + pvt->ldesc->connect_port(pvt->handle, i, &pvt->out_ports[k++]); + } + } + } + } + + break; + + case SWITCH_ABC_TYPE_CLOSE: + { + + if (pvt->handle && pvt->ldesc) { + pvt->ldesc->cleanup(pvt->handle); + } + + if (pvt->library_handle) { + unloadLADSPAPluginLibrary(pvt->library_handle); + } + } + break; + + case SWITCH_ABC_TYPE_WRITE_REPLACE: + case SWITCH_ABC_TYPE_READ_REPLACE: + { + switch_frame_t *rframe; + int16_t *slin; + + if (type == SWITCH_ABC_TYPE_READ_REPLACE) { + rframe = switch_core_media_bug_get_read_replace_frame(bug); + } else { + rframe = switch_core_media_bug_get_write_replace_frame(bug); + } + + slin = rframe->data; + + if (switch_channel_media_ready(channel)) { + switch_short_to_float(slin, pvt->in_buf, rframe->samples); + pvt->ldesc->run(pvt->handle, rframe->samples); + switch_float_to_short(pvt->out_buf, slin, rframe->samples); + } + + if (type == SWITCH_ABC_TYPE_READ_REPLACE) { + switch_core_media_bug_set_read_replace_frame(bug, rframe); + } else { + switch_core_media_bug_set_write_replace_frame(bug, rframe); + } + + if (pvt->skip && !--pvt->skip) { + return SWITCH_FALSE; + } + + } + break; + case SWITCH_ABC_TYPE_WRITE: + default: + break; + } + + return SWITCH_TRUE; +} + +switch_status_t stop_ladspa_session(switch_core_session_t *session) +{ + switch_media_bug_t *bug; + switch_channel_t *channel = switch_core_session_get_channel(session); + + if ((bug = switch_channel_get_private(channel, "ladspa"))) { + switch_channel_set_private(channel, "ladspa", NULL); + switch_core_media_bug_remove(session, &bug); + return SWITCH_STATUS_SUCCESS; + } + + return SWITCH_STATUS_FALSE; +} + +switch_status_t ladspa_session(switch_core_session_t *session, const char *flags, const char *plugin_name, const char *label, const char *params) +{ + switch_channel_t *channel = switch_core_session_get_channel(session); + switch_media_bug_t *bug; + switch_status_t status; + switch_ladspa_t *pvt = { 0 }; + switch_codec_implementation_t read_impl = { 0 }; + int i, bflags = SMBF_READ_REPLACE | SMBF_ANSWER_REQ; + char *pstr; + int argc; + char *argv[50]; + char *dparams = NULL; + + if (zstr(plugin_name)) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "%s INVALID PLUGIN\n", switch_channel_get_name(channel)); + return SWITCH_STATUS_FALSE; + } + + if (zstr(flags)) { + flags = "r"; + } + + if (strchr(flags, 'w')) { + bflags = SMBF_WRITE_REPLACE; + } + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "FLAGS: %s PLUGIN: %s LABEL: %s PARAMS: %s\n", + flags, plugin_name, label, params); + + switch_core_session_get_read_impl(session, &read_impl); + + pvt = switch_core_session_alloc(session, sizeof(*pvt)); + + pvt->session = session; + if (!zstr(label)) { + pvt->label_name = switch_core_session_strdup(session, label); + } else { + char *p; + pvt->label_name = switch_core_session_strdup(session, plugin_name); + if ((p = strrchr(pvt->label_name, '.'))) { + *p = '\0'; + } + } + + if (strstr(plugin_name, ".so")) { + pvt->plugin_name = switch_core_session_strdup(session, plugin_name); + } else { + pvt->plugin_name = switch_core_session_sprintf(session, "%s.so", plugin_name); + } + + dparams = switch_core_session_strdup(session, params); + + argc = switch_split(dparams, ' ', argv); + + for (i = 0; i < argc; i++) { + pvt->config[i] = atof(argv[i]); + pvt->has_config[i] = 1; + } + + if (switch_channel_pre_answer(channel) != SWITCH_STATUS_SUCCESS) { + return SWITCH_STATUS_FALSE; + } + + pstr = switch_core_session_sprintf(session, "%s|%s|%s|%s", flags, plugin_name, label, params); + + if ((status = switch_core_media_bug_add(session, "ladspa", pstr, + ladspa_callback, pvt, 0, bflags | SMBF_NO_PAUSE, &bug)) != SWITCH_STATUS_SUCCESS) { + return status; + } + + switch_channel_set_private(channel, "ladspa", bug); + + return SWITCH_STATUS_SUCCESS; +} + + +static void ladspa_parse(switch_core_session_t *session, const char *data) +{ + char *argv[5] = { 0 }; + int argc; + char *lbuf; + + if (data) { + lbuf = strdup(data); + argc = switch_separate_string(lbuf, '|', argv, (sizeof(argv) / sizeof(argv[0]))); + ladspa_session(session, argv[0], argv[1], argv[2], argv[3]); + free(lbuf); + } +} + +#define APP_SYNTAX "||