Merge branch 'master' into smgmaster

This commit is contained in:
Moises Silva committed 2011-03-24 19:08:24 -04:00
commit bf23a0a38b
127 files changed
+3185 -8895

No files matched your search

+60
View File
@@ -24,6 +24,7 @@
* Contributor(s):
*
* Anthony Minessale II <anthm@freeswitch.org>
* Eliot Gable <egable@gmail.com>
*
* switch_apr.h -- APR includes header
*
@@ -410,6 +411,65 @@ SWITCH_DECLARE(switch_status_t) switch_mutex_trylock(switch_mutex_t *lock);
/** @} */
/**
* @defgroup switch_atomic Multi-Threaded Adtomic Operations Routines
* @ingroup switch_apr
* @{
*/
/** Opaque type used for the atomic operations */
#ifdef apr_atomic_t
typedef apr_atomic_t switch_atomic_t;
#else
typedef uint32_t switch_atomic_t;
#endif
/**
* Some architectures require atomic operations internal structures to be
* initialized before use.
* @param pool The memory pool to use when initializing the structures.
*/
SWITCH_DECLARE(switch_status_t) switch_atomic_init(switch_memory_pool_t *pool);
/**
* Uses an atomic operation to read the uint32 value at the location specified
* by mem.
* @param mem The location of memory which stores the value to read.
*/
SWITCH_DECLARE(uint32_t) switch_atomic_read(volatile switch_atomic_t *mem);
/**
* Uses an atomic operation to set a uint32 value at a specified location of
* memory.
* @param mem The location of memory to set.
* @param val The uint32 value to set at the memory location.
*/
SWITCH_DECLARE(void) switch_atomic_set(volatile switch_atomic_t *mem, uint32_t val);
/**
* Uses an atomic operation to add the uint32 value to the value at the
* specified location of memory.
* @param mem The location of the value to add to.
* @param val The uint32 value to add to the value at the memory location.
*/
SWITCH_DECLARE(void) switch_atomic_add(volatile switch_atomic_t *mem, uint32_t val);
/**
* Uses an atomic operation to increment the value at the specified memroy
* location.
* @param mem The location of the value to increment.
*/
SWITCH_DECLARE(void) switch_atomic_inc(volatile switch_atomic_t *mem);
/**
* Uses an atomic operation to decrement the value at the specified memroy
* location.
* @param mem The location of the value to decrement.
*/
SWITCH_DECLARE(int) switch_atomic_dec(volatile switch_atomic_t *mem);
/** @} */
/**
* @defgroup switch_thread_rwlock Thread Read/Write lock Routines
* @ingroup switch_apr
+1
View File
@@ -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);
/*!
+2
View File
@@ -1940,6 +1940,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_management_exec(char *relative_oid,
\return 0 on success
*/
SWITCH_DECLARE(int32_t) set_high_priority(void);
SWITCH_DECLARE(int32_t) set_normal_priority(void);
/*!
\brief Change user and/or group of the running process
@@ -2050,6 +2051,7 @@ SWITCH_DECLARE(void) switch_load_network_lists(switch_bool_t reload);
SWITCH_DECLARE(switch_bool_t) switch_check_network_list_ip_token(const char *ip_str, const char *list_name, const char **token);
#define switch_check_network_list_ip(_ip_str, _list_name) switch_check_network_list_ip_token(_ip_str, _list_name, NULL)
SWITCH_DECLARE(void) switch_time_set_monotonic(switch_bool_t enable);
SWITCH_DECLARE(void) switch_time_set_timerfd(switch_bool_t enable);
SWITCH_DECLARE(void) switch_time_set_nanosleep(switch_bool_t enable);
SWITCH_DECLARE(void) switch_time_set_matrix(switch_bool_t enable);
SWITCH_DECLARE(void) switch_time_set_cond_yield(switch_bool_t enable);
+3 -1
View File
@@ -542,7 +542,7 @@ typedef enum {
SWITCH_RTP_FLAG_BREAK = (1 << 10),
SWITCH_RTP_FLAG_UDPTL = (1 << 11),
SWITCH_RTP_FLAG_DATAWAIT = (1 << 12),
SWITCH_RTP_FLAG_BUGGY_2833 = (1 << 13),
SWITCH_RTP_FLAG_BYTESWAP = (1 << 13),
SWITCH_RTP_FLAG_PASS_RFC2833 = (1 << 14),
SWITCH_RTP_FLAG_AUTO_CNG = (1 << 15),
SWITCH_RTP_FLAG_SECURE_SEND_RESET = (1 << 16),
@@ -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;
+1
View File
@@ -31,6 +31,7 @@
/endpoints/mod_portaudio/Makefile.in
/endpoints/mod_skinny/Makefile
/endpoints/mod_skinny/Makefile.in
/endpoints/mod_skinny/mod_skinny.log
/endpoints/mod_skypopen/Makefile
/endpoints/mod_skypopen/Makefile.in
/endpoints/mod_sofia/Makefile
@@ -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}
};
@@ -216,6 +218,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 +708,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 +772,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 +1012,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 +1214,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 +1237,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);
@@ -1384,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);
@@ -1430,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 */
@@ -1466,6 +1506,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);
@@ -1508,15 +1551,20 @@ 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);
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);
@@ -1542,23 +1590,25 @@ 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(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_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);
}
} 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),
@@ -1566,33 +1616,25 @@ 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 */
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 */
@@ -1607,6 +1649,28 @@ 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 */
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);
}
}
@@ -1670,14 +1734,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;
@@ -1787,6 +1851,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);
@@ -1895,13 +1960,13 @@ static int members_callback(void *pArg, int argc, char **argv, char **columnName
switch_safe_free(sql);
sql_order_by = switch_mprintf("level, position");
} else if(!strcasecmp(queue_strategy, "sequentially-by-agent-order")) {
sql_order_by = switch_mprintf("level, position");
sql_order_by = switch_mprintf("level, position, agents.last_offered_call"); /* Default to last_offered_call, let add new strategy if needing it differently */
} else {
/* If the strategy doesn't exist, just fallback to the following */
sql_order_by = switch_mprintf("level, position");
sql_order_by = switch_mprintf("level, position, agents.last_offered_call");
}
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",
@@ -2045,7 +2110,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;
@@ -2301,52 +2366,63 @@ SWITCH_STANDARD_APP(callcenter_function)
h->running = 0;
}
/* 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 */
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-Wait-Time", "%ld", (long) (switch_epoch_time_now(NULL) - 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(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-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;
@@ -2394,18 +2470,26 @@ 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] | " \
"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 +2597,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 +2623,7 @@ SWITCH_STANDARD_API(cc_config_api_function)
}
}
} else if (action && !strcasecmp(action, "list")) {
struct list_result cbt;
cbt.row_process = 0;
@@ -2616,6 +2702,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 +2722,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 +2745,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 +2756,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 +2772,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 +2793,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);
}
}
}
}
@@ -2789,10 +2920,10 @@ 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");
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 +2935,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;
@@ -37,6 +37,7 @@
*/
#include <switch.h>
#define DEFAULT_AGC_LEVEL 1100
#define CONFERENCE_UUID_VARIABLE "conference_uuid"
SWITCH_MODULE_LOAD_FUNCTION(mod_conference_load);
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_conference_shutdown);
@@ -564,7 +565,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;
@@ -702,6 +706,7 @@ static switch_status_t conference_add_member(conference_obj_t *conference, confe
channel = switch_core_session_get_channel(member->session);
switch_channel_set_variable_printf(channel, "conference_member_id", "%d", member->id);
switch_channel_set_variable(channel, CONFERENCE_UUID_VARIABLE, conference->uuid_str);
if (conference->count > 1) {
if (conference->moh_sound && !switch_test_flag(conference, CFLAG_WAIT_MOD)) {
@@ -4625,6 +4630,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 +4666,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) {
+34
View File
@@ -0,0 +1,34 @@
# LDNS=ldns-1.6.9
# BASE=../../../..
# LDNS_DIR=$(switch_srcdir)/libs/$(LDNS)
# LDNS_BUILDDIR=$(switch_builddir)/libs/$(LDNS)
# LDNSLA=$(LDNS_BUILDDIR)/libldns.la
# include $(BASE)/build/modmake.rules
# LOCAL_LIBADD=$(LDNSLA)
BASE=../../../..
LDNS=ldns-1.6.9
LDNS_DIR=$(switch_srcdir)/libs/$(LDNS)
LDNS_BUILDDIR=$(switch_builddir)/libs/$(LDNS)
LOCAL_CFLAGS=-I$(LDNS_DIR) -I$(LDNS_DIR)/include
LDNS_LA=$(LDNS_BUILDDIR)/libldns.la
LOCAL_LIBADD=$(LDNS_LA)
include $(BASE)/build/modmake.rules
$(LDNS_DIR)/Makefile.in:
$(GETLIB) $(LDNS).tar.gz
$(LDNS_BUILDDIR)/Makefile: $(LDNS_DIR)/Makefile.in
mkdir -p $(LDNS_BUILDDIR)
cd $(LDNS_BUILDDIR) && $(DEFAULT_VARS) $(LDNS_DIR)/configure $(DEFAULT_ARGS) --srcdir=$(LDNS_DIR) --disable-gost --without-ssl --disable-sha2
$(TOUCH_TARGET)
$(LDNS_LA): $(LDNS_BUILDDIR)/Makefile
cd $(LDNS_BUILDDIR) && $(MAKE)
$(TOUCH_TARGET)
-13
View File
@@ -1,13 +0,0 @@
include $(top_srcdir)/build/modmake.rulesam
MODNAME=mod_enum
UDNS_DIR=$(switch_srcdir)/libs/udns
mod_enum_la_CFLAGS = -I$(UDNS_DIR) -DHAVE_POLL $(AM_CFLAGS)
mod_LTLIBRARIES = mod_enum.la
mod_enum_la_SOURCES = mod_enum.c
mod_enum_la_SOURCES += $(UDNS_DIR)/udns_dn.c $(UDNS_DIR)/udns_dntosp.c $(UDNS_DIR)/udns_parse.c $(UDNS_DIR)/udns_misc.c
mod_enum_la_SOURCES += $(UDNS_DIR)/udns_rr_a.c $(UDNS_DIR)/udns_rr_ptr.c $(UDNS_DIR)/udns_rr_mx.c $(UDNS_DIR)/udns_rr_txt.c $(UDNS_DIR)/udns_bl.c
mod_enum_la_SOURCES += $(UDNS_DIR)/udns_rr_srv.c $(UDNS_DIR)/udns_rr_naptr.c $(UDNS_DIR)/udns_codes.c $(UDNS_DIR)/udns_resolver.c
mod_enum_la_LIBADD = $(switch_builddir)/libfreeswitch.la
mod_enum_la_LDFLAGS = -avoid-version -module -no-undefined -shared
+235 -312
View File
@@ -30,11 +30,7 @@
*/
#include <switch.h>
#include <udns.h>
#ifndef WIN32
#define closesocket close
#endif
#include <ldns/ldns.h>
SWITCH_MODULE_LOAD_FUNCTION(mod_enum_load);
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_enum_shutdown);
@@ -49,19 +45,10 @@ struct enum_record {
char *route;
int supported;
struct enum_record *next;
struct enum_record *tail;
};
typedef struct enum_record enum_record_t;
struct query {
const char *name; /* original query string */
char *number;
unsigned char dn[DNS_MAXDN];
enum dns_type qtyp; /* type of the query */
enum_record_t *results;
int errs;
};
typedef struct query enum_query_t;
struct route {
char *service;
char *regex;
@@ -70,12 +57,11 @@ struct route {
};
typedef struct route enum_route_t;
static enum dns_class qcls = DNS_C_IN;
static switch_event_node_t *NODE = NULL;
static struct {
char *root;
char *server;
char *isn_root;
enum_route_t *route_order;
switch_memory_pool_t *pool;
@@ -84,6 +70,7 @@ static struct {
} globals;
SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_root, globals.root);
SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_server, globals.server);
SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_isn_root, globals.isn_root);
static void add_route(char *service, char *regex, char *replace)
@@ -125,6 +112,8 @@ static switch_status_t load_config(void)
const char *val = switch_xml_attr_soft(param, "value");
if (!strcasecmp(var, "default-root")) {
set_global_root(val);
} else if (!strcasecmp(var, "use-server")) {
set_global_server(val);
} else if (!strcasecmp(var, "auto-reload")) {
globals.auto_reload = switch_true(val);
} else if (!strcasecmp(var, "query-timeout")) {
@@ -168,11 +157,12 @@ static switch_status_t load_config(void)
return status;
}
static char *reverse_number(char *in, char *root)
static char *reverse_number(const char *in, const char *root)
{
switch_size_t len;
char *out = NULL;
char *y, *z;
const char *y;
char *z;
if (!(in && root)) {
return NULL;
@@ -198,59 +188,33 @@ static char *reverse_number(char *in, char *root)
return out;
}
static void dnserror(enum_query_t *q, int errnum)
{
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Unable to lookup %s record for %s: %s\n",
dns_typename(q->qtyp), dns_dntosp(q->dn), dns_strerror(errnum));
q->errs++;
}
static void add_result(enum_query_t *q, int order, int preference, char *service, char *route, int supported)
static void add_result(enum_record_t **results, int order, int preference, char *service, char *route, int supported)
{
enum_record_t *new_result, *rp, *prev = NULL;
enum_record_t *new_result;
new_result = malloc(sizeof(*new_result));
switch_assert(new_result);
memset(new_result, 0, sizeof(*new_result));
memset(new_result, 0, sizeof(*new_result));
new_result->order = order;
new_result->preference = preference;
new_result->service = strdup(service);
new_result->route = strdup(route);
new_result->supported = supported;
if (!q->results) {
q->results = new_result;
return;
}
rp = q->results;
while (rp && strcasecmp(rp->service, new_result->service)) {
prev = rp;
rp = rp->next;
}
while (rp && !strcasecmp(rp->service, new_result->service) && new_result->order > rp->order) {
prev = rp;
rp = rp->next;
}
while (rp && !strcasecmp(rp->service, new_result->service) && new_result->preference > rp->preference) {
prev = rp;
rp = rp->next;
}
if (prev) {
new_result->next = rp;
prev->next = new_result;
if (!*results) {
*results = new_result;
(*results)->tail = new_result;
} else {
new_result->next = rp;
q->results = new_result;
(*results)->tail->next = new_result;
(*results)->tail = new_result;
}
}
static void free_results(enum_record_t ** results)
{
enum_record_t *fp, *rp;
@@ -265,201 +229,234 @@ static void free_results(enum_record_t ** results)
*results = NULL;
}
static void parse_rr(const struct dns_parse *p, enum_query_t *q, struct dns_rr *rr)
static ldns_rdf *ldns_rdf_new_addr_frm_str(const char *str)
{
const unsigned char *pkt = p->dnsp_pkt;
const unsigned char *end = p->dnsp_end;
const unsigned char *dptr = rr->dnsrr_dptr;
const unsigned char *dend = rr->dnsrr_dend;
unsigned char *dn = rr->dnsrr_dn;
const unsigned char *c;
char flags;
int order;
int preference;
ldns_rdf *a;
ldns_str2rdf_a(&a, str);
if (!a) {
/* maybe ip6 */
ldns_str2rdf_aaaa(&a, str);
if (!a) {
return NULL;
}
}
return a;
}
#define strip_quotes(_s) if (*_s == '"') _s++; if (end_of(_s) == '"') end_of(_s) = '\0'
static void parse_naptr(const ldns_rr *naptr, const char *number, enum_record_t **results)
{
char *str = ldns_rr2str(naptr);
char *argv[11] = { 0 };
int i, argc;
char *pack[4] = { 0 };
int packc;
char *p;
int order = 10;
int preference = 100;
char *service = NULL;
char *regex = NULL;
char *replace = NULL;
char *ptr;
int argc = 0;
char *argv[4] = { 0 };
int n;
char string_arg[3][256] = { {0} };
char *packstr;
switch (rr->dnsrr_typ) {
case DNS_T_NAPTR: /* prio weight port targetDN */
c = dptr;
c += 4; /* order, pref */
for (n = 0; n < 3; ++n) {
if (c >= dend) {
goto xperr;
} else {
c += *c + 1;
}
}
if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 || c != dend) {
goto xperr;
}
c = dptr;
order = dns_get16(c + 0);
preference = dns_get16(c + 2);
flags = (char) dns_get16(c + 4);
c += 4;
for (n = 0; n < 3; n++) {
uint32_t len = *c++, cpylen = len;
switch_assert(string_arg[n]);
if (len > sizeof(string_arg[n]) - 1) {
cpylen = sizeof(string_arg[n]) - 1;
}
strncpy(string_arg[n], (char *) c, cpylen);
*(string_arg[n] + len) = '\0';
c += len;
}
service = string_arg[1];
if ((argc = switch_separate_string(string_arg[2], '!', argv, (sizeof(argv) / sizeof(argv[0]))))) {
regex = argv[1];
replace = argv[2];
} else {
goto xperr;
}
for (ptr = replace; ptr && *ptr; ptr++) {
if (*ptr == '\\') {
*ptr = '$';
}
}
if (flags && service && regex && replace) {
switch_regex_t *re = NULL;
int proceed = 0, ovector[30];
char substituted[1024] = "";
char rbuf[1024] = "";
char *uri;
enum_route_t *route;
int supported = 0;
switch_regex_safe_free(re);
if ((proceed = switch_regex_perform(q->number, regex, &re, ovector, sizeof(ovector) / sizeof(ovector[0])))) {
if (strchr(regex, '(')) {
switch_perform_substitution(re, proceed, replace, q->number, substituted, sizeof(substituted), ovector);
uri = substituted;
} else {
uri = replace;
}
switch_mutex_lock(MUTEX);
for (route = globals.route_order; route; route = route->next) {
if (strcasecmp(service, route->service)) {
continue;
}
switch_regex_safe_free(re);
if ((proceed = switch_regex_perform(uri, route->regex, &re, ovector, sizeof(ovector) / sizeof(ovector[0])))) {
if (strchr(route->regex, '(')) {
switch_perform_substitution(re, proceed, route->replace, uri, rbuf, sizeof(rbuf), ovector);
uri = rbuf;
} else {
uri = route->replace;
}
supported++;
add_result(q, order, preference, service, uri, supported);
}
}
if (!supported) {
add_result(q, order, preference, service, uri, 0);
}
}
switch_mutex_unlock(MUTEX);
switch_regex_safe_free(re);
}
break;
default:
break;
char *regex, *replace;
if (zstr(str)) {
return;
}
return;
for (p = str; p && *p; p++) {
if (*p == '\t') *p = ' ';
if (*p == ' ' && *(p+1) == '.') *p = '\0';
}
xperr:
argc = switch_split(str, ' ', argv);
for (i = 0; i < argc; i++) {
if (i > 0) {
strip_quotes(argv[i]);
}
}
service = argv[7];
packstr = argv[8];
if (zstr(service) || zstr(packstr)) {
goto end;
}
if (!zstr(argv[4])) {
order = atoi(argv[4]);
}
if (!zstr(argv[5])) {
preference = atoi(argv[5]);
}
if ((packc = switch_split(packstr, '!', pack))) {
regex = pack[1];
replace = pack[2];
} else {
goto end;
}
for (p = replace; p && *p; p++) {
if (*p == '\\') {
*p = '$';
}
}
if (service && regex && replace) {
switch_regex_t *re = NULL, *re2 = NULL;
int proceed = 0, ovector[30];
char substituted[1024] = "";
char rbuf[1024] = "";
char *uri;
enum_route_t *route;
int supported = 0;
if ((proceed = switch_regex_perform(number, regex, &re, ovector, sizeof(ovector) / sizeof(ovector[0])))) {
if (strchr(regex, '(')) {
switch_perform_substitution(re, proceed, replace, number, substituted, sizeof(substituted), ovector);
uri = substituted;
} else {
uri = replace;
}
switch_mutex_lock(MUTEX);
for (route = globals.route_order; route; route = route->next) {
if (strcasecmp(service, route->service)) {
continue;
}
if ((proceed = switch_regex_perform(uri, route->regex, &re2, ovector, sizeof(ovector) / sizeof(ovector[0])))) {
if (strchr(route->regex, '(')) {
switch_perform_substitution(re2, proceed, route->replace, uri, rbuf, sizeof(rbuf), ovector);
uri = rbuf;
} else {
uri = route->replace;
}
supported++;
add_result(results, order, preference, service, uri, supported);
}
switch_regex_safe_free(re2);
}
switch_mutex_unlock(MUTEX);
if (!supported) {
add_result(results, order, preference, service, uri, 0);
}
switch_regex_safe_free(re);
}
}
end:
switch_safe_free(str);
return;
}
static void dnscb(struct dns_ctx *ctx, void *result, void *data)
switch_status_t ldns_lookup(const char *number, const char *root, const char *server_name, enum_record_t **results)
{
int r = dns_status(ctx);
enum_query_t *q = data;
struct dns_parse p;
struct dns_rr rr;
unsigned nrr;
unsigned char dn[DNS_MAXDN];
const unsigned char *pkt, *cur, *end, *qdn;
if (!result) {
dnserror(q, r);
return;
ldns_resolver *res = NULL;
ldns_rdf *domain = NULL;
ldns_pkt *p = NULL;
ldns_rr_list *naptr = NULL;
ldns_status s = LDNS_STATUS_ERR;
ldns_rdf *serv_rdf;
switch_status_t status = SWITCH_STATUS_FALSE;
char *name = NULL;
if (!(name = reverse_number(number, root))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Parse Error!\n");
goto end;
}
pkt = result;
end = pkt + r;
cur = dns_payload(pkt);
dns_getdn(pkt, &cur, end, dn, sizeof(dn));
dns_initparse(&p, NULL, pkt, cur, end);
p.dnsp_qcls = 0;
p.dnsp_qtyp = 0;
qdn = dn;
nrr = 0;
while ((r = dns_nextrr(&p, &rr)) > 0) {
if (!dns_dnequal(qdn, rr.dnsrr_dn))
continue;
if ((qcls == DNS_C_ANY || qcls == rr.dnsrr_cls) && (q->qtyp == DNS_T_ANY || q->qtyp == rr.dnsrr_typ))
++nrr;
else if (rr.dnsrr_typ == DNS_T_CNAME && !nrr) {
if (dns_getdn(pkt, &rr.dnsrr_dptr, end, p.dnsp_dnbuf, sizeof(p.dnsp_dnbuf)) <= 0 || rr.dnsrr_dptr != rr.dnsrr_dend) {
r = DNS_E_PROTOCOL;
break;
} else {
qdn = p.dnsp_dnbuf;
domain = ldns_dname_new_frm_str(name);
if (!domain) {
goto end;
}
if (!zstr(server_name)) {
res = ldns_resolver_new();
switch_assert(res);
if ((serv_rdf = ldns_rdf_new_addr_frm_str(server_name))) {
s = ldns_resolver_push_nameserver(res, serv_rdf);
ldns_rdf_deep_free(serv_rdf);
}
} else {
/* create a new resolver from /etc/resolv.conf */
s = ldns_resolver_new_frm_file(&res, NULL);
}
if (s != LDNS_STATUS_OK) {
goto end;
}
/* use the resolver to send a query for the naptr
* records of the domain given on the command line
*/
if ((p = ldns_resolver_query(res,
domain,
LDNS_RR_TYPE_NAPTR,
LDNS_RR_CLASS_IN,
LDNS_RD))) {
/* retrieve the NAPTR records from the answer section of that
* packet
*/
if ((naptr = ldns_pkt_rr_list_by_type(p, LDNS_RR_TYPE_NAPTR, LDNS_SECTION_ANSWER))) {
size_t i;
ldns_rr_list_sort(naptr);
for (i = 0; i < ldns_rr_list_rr_count(naptr); i++) {
parse_naptr(ldns_rr_list_rr(naptr, i), number, results);
}
//ldns_rr_list_print(stdout, naptr);
ldns_rr_list_deep_free(naptr);
status = SWITCH_STATUS_SUCCESS;
}
}
if (!r && !nrr)
r = DNS_E_NODATA;
if (r < 0) {
dnserror(q, r);
free(result);
return;
end:
switch_safe_free(name);
if (domain) {
ldns_rdf_deep_free(domain);
}
dns_rewind(&p, NULL);
p.dnsp_qtyp = q->qtyp;
p.dnsp_qcls = qcls;
while (dns_nextrr(&p, &rr)) {
parse_rr(&p, q, &rr);
if (p) {
ldns_pkt_free(p);
}
free(result);
if (res) {
ldns_resolver_deep_free(res);
}
return status;
}
static switch_status_t enum_lookup(char *root, char *in, enum_record_t ** results)
static switch_status_t enum_lookup(char *root, char *in, enum_record_t **results)
{
switch_status_t sstatus = SWITCH_STATUS_SUCCESS;
char *name = NULL;
enum_query_t query = { 0 };
enum dns_type l_qtyp = DNS_T_NAPTR;
int i = 0, abs = 0, j = 0;
dns_socket fd = (dns_socket) - 1;
fd_set fds;
struct timeval tv = { 0 };
time_t now = 0;
struct dns_ctx *nctx = NULL;
char *num, *mnum = NULL, *mroot = NULL, *p;
char *mnum = NULL, *mroot = NULL, *p;
char *server = NULL;
*results = NULL;
@@ -475,87 +472,14 @@ static switch_status_t enum_lookup(char *root, char *in, enum_record_t ** result
root = globals.root;
}
num = mnum;
if (!(name = reverse_number(num, root))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Parse Error!\n");
sstatus = SWITCH_STATUS_FALSE;
goto done;
#if 0
if (!(server = switch_core_get_variable("enum-server"))) {
server = globals.server;
}
if (!(nctx = dns_new(NULL))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Memory Error!\n");
sstatus = SWITCH_STATUS_MEMERR;
goto done;
}
fd = dns_open(nctx);
if (fd < 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FD Error!\n");
sstatus = SWITCH_STATUS_FALSE;
goto done;
}
dns_ptodn(name, (unsigned int) strlen(name), query.dn, sizeof(query.dn), &abs);
query.name = name;
query.number = num;
query.qtyp = l_qtyp;
if (abs) {
abs = DNS_NOSRCH;
}
if (!dns_submit_dn(nctx, query.dn, qcls, l_qtyp, abs, 0, dnscb, &query)) {
dnserror(&query, dns_status(nctx));
}
FD_ZERO(&fds);
now = 0;
while ((i = dns_timeouts(nctx, 1, now)) > 0) {
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4389 4127)
#endif
FD_SET(fd, &fds);
#ifdef _MSC_VER
#pragma warning(pop)
#endif
j += i;
ldns_lookup(mnum, root, server, results);
if (j > globals.timeout || query.results || query.errs) {
break;
}
tv.tv_sec = i;
tv.tv_usec = 0;
i = select((int) (fd + 1), &fds, 0, 0, &tv);
now = switch_epoch_time_now(NULL);
if (i > 0) {
dns_ioevent(nctx, now);
}
}
if (!query.results) {
sstatus = SWITCH_STATUS_FALSE;
}
*results = query.results;
query.results = NULL;
done:
if (fd > -1) {
closesocket(fd);
fd = (dns_socket) - 1;
}
if (nctx) {
dns_free(nctx);
}
switch_safe_free(name);
switch_safe_free(mnum);
switch_safe_free(mroot);
@@ -623,15 +547,17 @@ SWITCH_STANDARD_APP(enum_app_function)
dest = argv[0];
root = argv[1];
if (enum_lookup(root, dest, &results) == SWITCH_STATUS_SUCCESS) {
switch_event_header_t *hi;
if ((hi = switch_channel_variable_first(channel))) {
for (; hi; hi = hi->next) {
switch_event_t *vars;
if (switch_channel_get_variables(channel, &vars) == SWITCH_STATUS_SUCCESS) {
switch_event_header_t *hi;
for (hi = vars->headers; hi; hi = hi->next) {
char *vvar = hi->name;
if (vvar && !strncmp(vvar, "enum_", 5)) {
switch_channel_set_variable(channel, (char *) vvar, NULL);
}
}
switch_channel_variable_last(channel);
switch_event_destroy(&vars);
}
for (rp = results; rp; rp = rp->next) {
@@ -823,9 +749,6 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_enum_load)
return SWITCH_STATUS_TERM;
}
if (dns_init(0) < 0) {
return SWITCH_STATUS_FALSE;
}
memset(&globals, 0, sizeof(globals));
do_load();
+5
View File
@@ -0,0 +1,5 @@
BASE=../../../..
LOCAL_OBJS += load.o
include $(BASE)/build/modmake.rules
+173
View File
@@ -0,0 +1,173 @@
/* load.c
Free software by Richard W.E. Furse. Do with as you will. No
warranty. */
/*****************************************************************************/
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*****************************************************************************/
#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 */
@@ -0,0 +1,674 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
*
* 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 <anthm@freeswitch.org>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Anthony Minessale II <anthm@freeswitch.org>
*
* mod_ladspa.c -- LADSPA
*
*/
#include <switch.h>
#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];
int num_idx;
char *str_config[MAX_INDEX];
int str_idx;
uint8_t has_config[MAX_INDEX];
int skip;
LADSPA_Data in_buf[SWITCH_RECOMMENDED_BUFFER_SIZE];
LADSPA_Data file_buf[SWITCH_RECOMMENDED_BUFFER_SIZE];
LADSPA_Data out_buf[SWITCH_RECOMMENDED_BUFFER_SIZE];
LADSPA_Data out_ports[MAX_INDEX];
switch_file_handle_t fh;
} 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, str_idx = 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)) {
int mapped = 0;
if (pvt->str_idx && !zstr(pvt->str_config[str_idx])) {
if (!strcasecmp(pvt->str_config[str_idx], "none")) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session), SWITCH_LOG_DEBUG, "CONNECT NOTHING to port: %s\n",
pvt->ldesc->PortNames[i]
);
mapped = 1;
} else if (!strncasecmp(pvt->str_config[str_idx], "file:", 5)) {
char *file = pvt->str_config[str_idx] + 5;
if (switch_test_flag((&pvt->fh), SWITCH_FILE_OPEN)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session),
SWITCH_LOG_ERROR, "CAN'T CONNECT FILE [%s] File already mapped\n", file);
} else {
if (switch_core_file_open(&pvt->fh,
file,
read_impl.number_of_channels,
read_impl.actual_samples_per_second,
SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session), SWITCH_LOG_ERROR, "Cannot open file: %s\n", file);
return SWITCH_FALSE;
}
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session), SWITCH_LOG_DEBUG, "CONNECT FILE [%s] to port: %s\n",
file,
pvt->ldesc->PortNames[i]
);
pvt->ldesc->connect_port(pvt->handle, i, pvt->file_buf);
mapped = 1;
}
}
str_idx++;
}
if (!mapped) {
pvt->ldesc->connect_port(pvt->handle, i, pvt->in_buf);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session), SWITCH_LOG_DEBUG, "CONNECT CHANNEL AUDIO to port: %s\n",
pvt->ldesc->PortNames[i]
);
}
}
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 (switch_test_flag((&pvt->fh), SWITCH_FILE_OPEN)) {
switch_core_file_close(&pvt->fh);
}
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, abuf[SWITCH_RECOMMENDED_BUFFER_SIZE] = { 0 };
switch_size_t olen = 0;
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);
if (switch_test_flag((&pvt->fh), SWITCH_FILE_OPEN)) {
olen = rframe->samples;
if (switch_core_file_read(&pvt->fh, abuf, &olen) != SWITCH_STATUS_SUCCESS) {
switch_codec_implementation_t read_impl = { 0 };
char *file = switch_core_session_strdup(pvt->session, pvt->fh.file_path);
switch_core_session_get_read_impl(pvt->session, &read_impl);
switch_core_file_close(&pvt->fh);
if (switch_core_file_open(&pvt->fh,
file,
read_impl.number_of_channels,
read_impl.actual_samples_per_second,
SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session), SWITCH_LOG_ERROR, "Cannot open file: %s\n", file);
return SWITCH_FALSE;
}
olen = rframe->samples;
if (switch_core_file_read(&pvt->fh, abuf, &olen) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session), SWITCH_LOG_ERROR, "Cannot READ file: %s\n", file);
return SWITCH_FALSE;
}
}
switch_short_to_float(abuf, pvt->file_buf, olen);
}
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++) {
if (switch_is_number(argv[i])) {
if (pvt->num_idx < MAX_INDEX) {
pvt->config[pvt->num_idx] = atof(argv[i]);
pvt->has_config[pvt->num_idx] = 1;
pvt->num_idx++;
}
} else {
if (pvt->str_idx < MAX_INDEX) {
pvt->str_config[pvt->str_idx++] = switch_core_session_strdup(session, argv[i]);
}
}
}
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 "<flags>|<plugin>|<label>|<params>"
SWITCH_STANDARD_APP(ladspa_run_function)
{
ladspa_parse(session, data);
}
#define API_SYNTAX "<uuid>|<flags>|<plugin>|<label>|<params>"
SWITCH_STANDARD_API(ladspa_api)
{
char *uuid = NULL;
char *data;
char *p;
switch_core_session_t *ksession = NULL;
if (!cmd) goto err;
data = strdup(cmd);
if ((p = strchr(data, ' '))) {
uuid = data;
*p++ = '\0';
if ((ksession = switch_core_session_locate(uuid))) {
ladspa_parse(ksession, p);
switch_core_session_rwunlock(ksession);
stream->write_function(stream, "+OK\n");
} else {
stream->write_function(stream, "-ERR non-existant UUID\n");
}
} else {
stream->write_function(stream, "-ERR Usage %s\n", API_SYNTAX);
}
free(data);
return SWITCH_STATUS_SUCCESS;
err:
stream->write_function(stream, "-ERR Operation Failed\n");
return SWITCH_STATUS_SUCCESS;
}
/* Macro expands to: switch_status_t mod_ladspa_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool) */
SWITCH_MODULE_LOAD_FUNCTION(mod_ladspa_load)
{
switch_application_interface_t *app_interface;
switch_api_interface_t *api_interface;
char *path = getenv("LADSPA_PATH");
if (zstr(path)) {
if (switch_directory_exists("/usr/lib64/ladspa/", pool) == SWITCH_STATUS_SUCCESS) {
putenv("LADSPA_PATH=/usr/lib64/ladspa/:/usr/local/lib/ladspa");
} else if (switch_directory_exists("/usr/lib/ladspa/", pool) == SWITCH_STATUS_SUCCESS) {
putenv("LADSPA_PATH=/usr/lib/ladspa/:/usr/local/lib/ladspa");
}
}
/* connect my internal structure to the blank pointer passed to me */
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
SWITCH_ADD_APP(app_interface, "ladspa_run", "ladspa_run", NULL, ladspa_run_function, APP_SYNTAX, SAF_NONE);
SWITCH_ADD_API(api_interface, "uuid_ladspa", "ladspa", ladspa_api, API_SYNTAX);
switch_console_set_complete("add uuid_ladspa ::console::list_uuid");
/* indicate that the module should continue to be loaded */
return SWITCH_STATUS_SUCCESS;
}
/*
Called when the system shuts down
Macro expands to: switch_status_t mod_ladspa_shutdown() */
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_ladspa_shutdown)
{
/* Cleanup dynamically allocated config settings */
return SWITCH_STATUS_SUCCESS;
}
/* For Emacs:
* Local Variables:
* mode:c
* indent-tabs-mode:t
* tab-width:4
* c-basic-offset:4
* End:
* For VIM:
* vim:set softtabstop=4 shiftwidth=4 tabstop=4
*/
+72
View File
@@ -0,0 +1,72 @@
/* utils.h
Free software by Richard W.E. Furse. Do with as you will. No
warranty. */
#ifndef LADSPA_SDK_LOAD_PLUGIN_LIB
#define LADSPA_SDK_LOAD_PLUGIN_LIB
/*****************************************************************************/
#include "ladspa.h"
/*****************************************************************************/
/* Functions in load.c: */
/* This function call takes a plugin library filename, searches for
the library along the LADSPA_PATH, loads it with dlopen() and
returns a plugin handle for use with findPluginDescriptor() or
unloadLADSPAPluginLibrary(). Errors are handled by writing a
message to stderr and calling exit(1). It is alright (although
inefficient) to call this more than once for the same file. */
void * loadLADSPAPluginLibrary(const char * pcPluginFilename);
/* This function unloads a LADSPA plugin library. */
void unloadLADSPAPluginLibrary(void * pvLADSPAPluginLibrary);
/* This function locates a LADSPA plugin within a plugin library
loaded with loadLADSPAPluginLibrary(). Errors are handled by
writing a message to stderr and calling exit(1). Note that the
plugin library filename is only included to help provide
informative error messages. */
const LADSPA_Descriptor *
findLADSPAPluginDescriptor(void * pvLADSPAPluginLibrary,
const char * pcPluginLibraryFilename,
const char * pcPluginLabel);
/*****************************************************************************/
/* Functions in search.c: */
/* Callback function for use with LADSPAPluginSearch(). The callback
function passes the filename (full path), a plugin handle (dlopen()
style) and a LADSPA_DescriptorFunction (from which
LADSPA_Descriptors can be acquired). */
typedef void LADSPAPluginSearchCallbackFunction
(const char * pcFullFilename,
void * pvPluginHandle,
LADSPA_Descriptor_Function fDescriptorFunction);
/* Search through the $(LADSPA_PATH) (or a default path) for any
LADSPA plugin libraries. Each plugin library is tested using
dlopen() and dlsym(,"ladspa_descriptor"). After loading each
library, the callback function is called to process it. This
function leaves items passed to the callback function open. */
void LADSPAPluginSearch(LADSPAPluginSearchCallbackFunction fCallbackFunction);
/*****************************************************************************/
/* Function in default.c: */
/* Find the default value for a port. Return 0 if a default is found
and -1 if not. */
int getLADSPADefault(const LADSPA_PortRangeHint * psPortRangeHint,
const unsigned long lSampleRate,
LADSPA_Data * pfResult);
/*****************************************************************************/
#endif
/* EOF */
@@ -2492,6 +2492,7 @@ static switch_status_t deliver_vm(vm_profile_t *profile,
if (copy) {
switch_file_copy(path, file_path, SWITCH_FPROT_FILE_SOURCE_PERMS, pool);
} else {
switch_safe_free(file_path);
file_path = (char *) path;
}
+7 -2
View File
@@ -3161,12 +3161,15 @@ static switch_status_t recog_asr_close(switch_asr_handle_t *ah, switch_asr_flag_
if (schannel != NULL && !switch_test_flag(ah, SWITCH_ASR_FLAG_CLOSED)) {
r = (recognizer_data_t *) schannel->data;
speech_channel_stop(schannel);
speech_channel_destroy(schannel);
switch_core_hash_destroy(&r->grammars);
switch_core_hash_destroy(&r->enabled_grammars);
switch_mutex_lock(schannel->mutex);
if (r->dtmf_generator) {
r->dtmf_generator_active = 0;
mpf_dtmf_generator_destroy(r->dtmf_generator);
}
switch_mutex_unlock(schannel->mutex);
speech_channel_destroy(schannel);
}
/* this lets FreeSWITCH's speech_thread know the handle is closed */
switch_set_flag(ah, SWITCH_ASR_FLAG_CLOSED);
@@ -3502,13 +3505,15 @@ static apt_bool_t recog_stream_read(mpf_audio_stream_t *stream, mpf_frame_t *fra
}
frame->type |= MEDIA_FRAME_TYPE_AUDIO;
}
switch_mutex_lock(schannel->mutex);
if (r->dtmf_generator_active) {
if (!mpf_dtmf_generator_put_frame(r->dtmf_generator, frame)) {
if (!mpf_dtmf_generator_sending(r->dtmf_generator))
r->dtmf_generator_active = 0;
}
}
switch_mutex_unlock(schannel->mutex);
return TRUE;
}
+1 -1
View File
@@ -1,7 +1,7 @@
include $(top_srcdir)/build/modmake.rulesam
MODNAME=mod_com_g729
VERSION=193
VERSION=194
if ISLINUX
+67 -22
View File
@@ -1373,6 +1373,9 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
if ((len = atoi(msg->string_arg))) {
qlen = len / (tech_pvt->read_impl.microseconds_per_packet / 1000);
if (qlen < 1) {
qlen = 3;
}
}
if (qlen) {
@@ -1393,6 +1396,9 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
}
if (qlen) {
if (maxqlen < qlen) {
maxqlen = qlen * 5;
}
if (switch_rtp_activate_jitter_buffer(tech_pvt->rtp_session, qlen, maxqlen,
tech_pvt->read_impl.samples_per_packet,
tech_pvt->read_impl.samples_per_second, max_drift) == SWITCH_STATUS_SUCCESS) {
@@ -1444,69 +1450,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_clear_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_set_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);
}
@@ -1850,6 +1884,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());
+9 -1
View File
@@ -230,6 +230,9 @@ typedef enum {
PFLAG_PRESENCE_ON_REGISTER,
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
} PFLAGS;
@@ -288,6 +291,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;
@@ -598,6 +604,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;
@@ -984,7 +992,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);
+67 -7
View File
@@ -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) {
@@ -2436,6 +2450,18 @@ 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, "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);
@@ -2519,6 +2545,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);
@@ -3119,6 +3151,18 @@ 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, "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);
@@ -3190,6 +3234,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);
@@ -4372,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] = "";
@@ -5681,9 +5736,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);
}
+77 -9
View File
@@ -2965,6 +2965,17 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f
flags |= SWITCH_RTP_FLAG_AUTO_CNG;
}
#if __BYTE_ORDER == __LITTLE_ENDIAN
if (!strcasecmp(tech_pvt->read_impl.iananame, "L16")) {
flags |= SWITCH_RTP_FLAG_BYTESWAP;
}
#endif
if ((flags & SWITCH_RTP_FLAG_BYTESWAP) && (val = switch_channel_get_variable(tech_pvt->channel, "rtp_disable_byteswap")) && switch_true(val)) {
flags &= ~SWITCH_RTP_FLAG_BYTESWAP;
}
if (tech_pvt->rtp_session && sofia_test_flag(tech_pvt, TFLAG_REINVITE)) {
//const char *ip = switch_channel_get_variable(tech_pvt->channel, SWITCH_LOCAL_MEDIA_IP_VARIABLE);
//const char *port = switch_channel_get_variable(tech_pvt->channel, SWITCH_LOCAL_MEDIA_PORT_VARIABLE);
@@ -2996,6 +3007,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);
}
}
}
@@ -3186,10 +3207,17 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f
qlen = jb_msec / (tech_pvt->read_impl.microseconds_per_packet / 1000);
if (qlen < 1) {
qlen = 3;
}
if (maxlen) {
maxqlen = maxlen / (tech_pvt->read_impl.microseconds_per_packet / 1000);
}
if (maxqlen < qlen) {
maxqlen = qlen * 5;
}
if (switch_rtp_activate_jitter_buffer(tech_pvt->rtp_session, qlen, maxqlen,
tech_pvt->read_impl.samples_per_packet,
tech_pvt->read_impl.samples_per_second, max_drift) == SWITCH_STATUS_SUCCESS) {
@@ -3749,8 +3777,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;
@@ -3769,6 +3799,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);
@@ -3795,6 +3826,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);
@@ -3828,8 +3860,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)
@@ -4154,6 +4189,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;
@@ -4254,10 +4297,30 @@ 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)) {
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) {
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;
}
for (m = sdp->sdp_media; m; m = m->m_next) {
sdp_connection_t *connection;
switch_core_session_t *other_session;
@@ -4351,6 +4414,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) {
@@ -4561,8 +4625,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) {
@@ -4649,12 +4714,14 @@ 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);
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);
}
@@ -4690,7 +4757,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;
@@ -4729,8 +4796,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;
@@ -4792,8 +4859,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);
+1 -1
View File
@@ -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);
+3 -3
View File
@@ -1124,8 +1124,8 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand
}
}
if ((v_contact_str = switch_event_get_header(*v_event, "sip-force-contact")) || auto_connectile) {
if ((!strcasecmp(v_contact_str, "NDLB-connectile-dysfunction-2.0")) || auto_connectile) {
if (auto_connectile || (v_contact_str = switch_event_get_header(*v_event, "sip-force-contact"))) {
if (auto_connectile || (!strcasecmp(v_contact_str, "NDLB-connectile-dysfunction-2.0"))) {
char *path_encoded;
size_t path_encoded_len;
char my_contact_str[1024];
@@ -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;
}
@@ -305,55 +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);
}
@@ -101,7 +101,6 @@ static int next_file(switch_file_handle_t *handle)
handle->seekable = context->fh.seekable;
handle->speed = context->fh.speed;
handle->interval = context->fh.interval;
handle->flags = context->fh.flags;
if (context->index == 0) {
context->samples = (handle->samplerate / 1000) * 250;
+9 -4
View File
@@ -3,6 +3,10 @@
#include "freeswitch_lua.h"
using namespace LUA;
extern "C" {
int docall(lua_State * L, int narg, int clear, int perror);
};
Session::Session():CoreSession()
{
cb_function = cb_arg = hangup_func_str = hangup_func_arg = NULL;
@@ -137,7 +141,7 @@ void Session::do_hangup_hook()
arg_count++;
}
lua_call(L, arg_count, 1);
docall(L, arg_count, 1, 1);
err = lua_tostring(L, -1);
if (!zstr(err)) {
@@ -273,7 +277,8 @@ switch_status_t Session::run_dtmf_callback(void *input, switch_input_type_t ityp
arg_count++;
}
lua_call(L, arg_count, 1);
docall(L, arg_count, 0, 1);
ret = lua_tostring(L, -1);
lua_pop(L, 1);
@@ -297,7 +302,7 @@ switch_status_t Session::run_dtmf_callback(void *input, switch_input_type_t ityp
arg_count++;
}
lua_call(L, arg_count, 1);
docall(L, arg_count, 1, 1);
ret = lua_tostring(L, -1);
lua_pop(L, 1);
@@ -374,7 +379,7 @@ int Dbh::query_callback(void *pArg, int argc, char **argv, char **cargv)
lua_settable(lua_fun->L, -3);
}
lua_call(lua_fun->L, 1, 1); /* 1 in, 1 out */
docall(lua_fun->L, 1, 1, 1); /* 1 in, 1 out */
if (lua_isnumber(lua_fun->L, -1)) {
if (lua_tonumber(lua_fun->L, -1) != 0) {
+17 -8
View File
@@ -80,7 +80,7 @@ static int traceback(lua_State * L)
return 1;
}
static int docall(lua_State * L, int narg, int clear)
int docall(lua_State * L, int narg, int clear, int perror)
{
int status;
int base = lua_gettop(L) - narg; /* function index */
@@ -92,13 +92,22 @@ static int docall(lua_State * L, int narg, int clear)
lua_remove(L, base); /* remove traceback function */
/* force a complete garbage collection in case of errors */
if (status != 0)
if (status != 0) {
lua_gc(L, LUA_GCCOLLECT, 0);
}
if (status && perror) {
const char *err = lua_tostring(L, -1);
if (!zstr(err)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s\n", err);
}
lua_pop(L, 1); /* pop error message from the stack */
}
return status;
}
static lua_State *lua_init(void)
{
lua_State *L = lua_open();
@@ -111,7 +120,7 @@ static lua_State *lua_init(void)
luaopen_freeswitch(L);
lua_gc(L, LUA_GCRESTART, 0);
lua_atpanic(L, panic);
error = luaL_loadbuffer(L, buff, strlen(buff), "line") || docall(L, 0, 1);
error = luaL_loadbuffer(L, buff, strlen(buff), "line") || docall(L, 0, 1, 0);
}
return L;
}
@@ -128,7 +137,7 @@ static int lua_parse_and_execute(lua_State * L, char *input_code)
if (*input_code == '~') {
char *buff = input_code + 1;
error = luaL_loadbuffer(L, buff, strlen(buff), "line") || docall(L, 0, 1); //lua_pcall(L, 0, 0, 0);
error = luaL_loadbuffer(L, buff, strlen(buff), "line") || docall(L, 0, 1, 0); //lua_pcall(L, 0, 0, 0);
} else {
char *args = strchr(input_code, ' ');
if (args) {
@@ -152,14 +161,14 @@ static int lua_parse_and_execute(lua_State * L, char *input_code)
}
if (code) {
error = luaL_loadbuffer(L, code, strlen(code), "line") || docall(L, 0, 1);
error = luaL_loadbuffer(L, code, strlen(code), "line") || docall(L, 0, 1, 0);
switch_safe_free(code);
}
} else {
// Force empty argv table
char *code = NULL;
code = switch_mprintf("argv = {[0]='%s'};", input_code);
error = luaL_loadbuffer(L, code, strlen(code), "line") || docall(L, 0, 1);
error = luaL_loadbuffer(L, code, strlen(code), "line") || docall(L, 0, 1, 0);
switch_safe_free(code);
}
@@ -171,7 +180,7 @@ static int lua_parse_and_execute(lua_State * L, char *input_code)
switch_assert(fdup);
file = fdup;
}
error = luaL_loadfile(L, file) || docall(L, 0, 1);
error = luaL_loadfile(L, file) || docall(L, 0, 1, 0);
switch_safe_free(fdup);
}
}
@@ -9315,6 +9315,16 @@ SWIGEXPORT int SWIGSTDCALL CSharp_set_high_priority() {
}
SWIGEXPORT int SWIGSTDCALL CSharp_set_normal_priority() {
int jresult ;
int32_t result;
result = (int32_t)set_normal_priority();
jresult = result;
return jresult;
}
SWIGEXPORT int SWIGSTDCALL CSharp_change_user_group(char * jarg1, char * jarg2) {
int jresult ;
char *arg1 = (char *) 0 ;
@@ -9638,6 +9648,14 @@ SWIGEXPORT void SWIGSTDCALL CSharp_switch_time_set_monotonic(int jarg1) {
}
SWIGEXPORT void SWIGSTDCALL CSharp_switch_time_set_timerfd(int jarg1) {
switch_bool_t arg1 ;
arg1 = (switch_bool_t)jarg1;
switch_time_set_timerfd(arg1);
}
SWIGEXPORT void SWIGSTDCALL CSharp_switch_time_set_nanosleep(int jarg1) {
switch_bool_t arg1 ;
@@ -23128,6 +23146,14 @@ SWIGEXPORT void SWIGSTDCALL CSharp_switch_channel_set_caller_extension(void * ja
}
SWIGEXPORT void SWIGSTDCALL CSharp_switch_channel_flip_cid(void * jarg1) {
switch_channel_t *arg1 = (switch_channel_t *) 0 ;
arg1 = (switch_channel_t *)jarg1;
switch_channel_flip_cid(arg1);
}
SWIGEXPORT void SWIGSTDCALL CSharp_switch_channel_sort_cid(void * jarg1, int jarg2) {
switch_channel_t *arg1 = (switch_channel_t *) 0 ;
switch_bool_t arg2 ;
@@ -9606,6 +9606,16 @@ SWIGEXPORT int SWIGSTDCALL CSharp_set_high_priority() {
}
SWIGEXPORT int SWIGSTDCALL CSharp_set_normal_priority() {
int jresult ;
int32_t result;
result = (int32_t)set_normal_priority();
jresult = result;
return jresult;
}
SWIGEXPORT int SWIGSTDCALL CSharp_change_user_group(char * jarg1, char * jarg2) {
int jresult ;
char *arg1 = (char *) 0 ;
@@ -9929,6 +9939,14 @@ SWIGEXPORT void SWIGSTDCALL CSharp_switch_time_set_monotonic(int jarg1) {
}
SWIGEXPORT void SWIGSTDCALL CSharp_switch_time_set_timerfd(int jarg1) {
switch_bool_t arg1 ;
arg1 = (switch_bool_t)jarg1;
switch_time_set_timerfd(arg1);
}
SWIGEXPORT void SWIGSTDCALL CSharp_switch_time_set_nanosleep(int jarg1) {
switch_bool_t arg1 ;
@@ -23791,6 +23809,14 @@ SWIGEXPORT void SWIGSTDCALL CSharp_switch_channel_set_caller_extension(void * ja
}
SWIGEXPORT void SWIGSTDCALL CSharp_switch_channel_flip_cid(void * jarg1) {
switch_channel_t *arg1 = (switch_channel_t *) 0 ;
arg1 = (switch_channel_t *)jarg1;
switch_channel_flip_cid(arg1);
}
SWIGEXPORT void SWIGSTDCALL CSharp_switch_channel_sort_cid(void * jarg1, int jarg2) {
switch_channel_t *arg1 = (switch_channel_t *) 0 ;
switch_bool_t arg2 ;
@@ -2134,6 +2134,11 @@ public class freeswitch {
return ret;
}
public static int set_normal_priority() {
int ret = freeswitchPINVOKE.set_normal_priority();
return ret;
}
public static int change_user_group(string user, string group) {
int ret = freeswitchPINVOKE.change_user_group(user, group);
return ret;
@@ -2275,6 +2280,10 @@ public class freeswitch {
freeswitchPINVOKE.switch_time_set_monotonic((int)enable);
}
public static void switch_time_set_timerfd(switch_bool_t enable) {
freeswitchPINVOKE.switch_time_set_timerfd((int)enable);
}
public static void switch_time_set_nanosleep(switch_bool_t enable) {
freeswitchPINVOKE.switch_time_set_nanosleep((int)enable);
}
@@ -3415,6 +3424,10 @@ public class freeswitch {
freeswitchPINVOKE.switch_channel_set_caller_extension(SWIGTYPE_p_switch_channel.getCPtr(channel), switch_caller_extension.getCPtr(caller_extension));
}
public static void switch_channel_flip_cid(SWIGTYPE_p_switch_channel channel) {
freeswitchPINVOKE.switch_channel_flip_cid(SWIGTYPE_p_switch_channel.getCPtr(channel));
}
public static void switch_channel_sort_cid(SWIGTYPE_p_switch_channel channel, switch_bool_t arg1) {
freeswitchPINVOKE.switch_channel_sort_cid(SWIGTYPE_p_switch_channel.getCPtr(channel), (int)arg1);
}
@@ -8068,6 +8081,9 @@ class freeswitchPINVOKE {
[DllImport("mod_managed", EntryPoint="CSharp_set_high_priority")]
public static extern int set_high_priority();
[DllImport("mod_managed", EntryPoint="CSharp_set_normal_priority")]
public static extern int set_normal_priority();
[DllImport("mod_managed", EntryPoint="CSharp_change_user_group")]
public static extern int change_user_group(string jarg1, string jarg2);
@@ -8155,6 +8171,9 @@ class freeswitchPINVOKE {
[DllImport("mod_managed", EntryPoint="CSharp_switch_time_set_monotonic")]
public static extern void switch_time_set_monotonic(int jarg1);
[DllImport("mod_managed", EntryPoint="CSharp_switch_time_set_timerfd")]
public static extern void switch_time_set_timerfd(int jarg1);
[DllImport("mod_managed", EntryPoint="CSharp_switch_time_set_nanosleep")]
public static extern void switch_time_set_nanosleep(int jarg1);
@@ -11500,6 +11519,9 @@ class freeswitchPINVOKE {
[DllImport("mod_managed", EntryPoint="CSharp_switch_channel_set_caller_extension")]
public static extern void switch_channel_set_caller_extension(HandleRef jarg1, HandleRef jarg2);
[DllImport("mod_managed", EntryPoint="CSharp_switch_channel_flip_cid")]
public static extern void switch_channel_flip_cid(HandleRef jarg1);
[DllImport("mod_managed", EntryPoint="CSharp_switch_channel_sort_cid")]
public static extern void switch_channel_sort_cid(HandleRef jarg1, int jarg2);
@@ -21716,6 +21738,8 @@ public enum switch_channel_flag_t {
CF_DIALPLAN,
CF_BLOCK_BROADCAST_UNTIL_MEDIA,
CF_CNG_PLC,
CF_ATTENDED_TRANSFER,
CF_LAZY_ATTENDED_TRANSFER,
CF_FLAG_MAX
}
@@ -28777,7 +28801,7 @@ namespace FreeSWITCH.Native {
SWITCH_RTP_FLAG_BREAK = (1 << 10),
SWITCH_RTP_FLAG_UDPTL = (1 << 11),
SWITCH_RTP_FLAG_DATAWAIT = (1 << 12),
SWITCH_RTP_FLAG_BUGGY_2833 = (1 << 13),
SWITCH_RTP_FLAG_BYTESWAP = (1 << 13),
SWITCH_RTP_FLAG_PASS_RFC2833 = (1 << 14),
SWITCH_RTP_FLAG_AUTO_CNG = (1 << 15),
SWITCH_RTP_FLAG_SECURE_SEND_RESET = (1 << 16),
+25 -1
View File
@@ -2124,6 +2124,11 @@ public class freeswitch {
return ret;
}
public static int set_normal_priority() {
int ret = freeswitchPINVOKE.set_normal_priority();
return ret;
}
public static int change_user_group(string user, string group) {
int ret = freeswitchPINVOKE.change_user_group(user, group);
return ret;
@@ -2265,6 +2270,10 @@ public class freeswitch {
freeswitchPINVOKE.switch_time_set_monotonic((int)enable);
}
public static void switch_time_set_timerfd(switch_bool_t enable) {
freeswitchPINVOKE.switch_time_set_timerfd((int)enable);
}
public static void switch_time_set_nanosleep(switch_bool_t enable) {
freeswitchPINVOKE.switch_time_set_nanosleep((int)enable);
}
@@ -3405,6 +3414,10 @@ public class freeswitch {
freeswitchPINVOKE.switch_channel_set_caller_extension(SWIGTYPE_p_switch_channel.getCPtr(channel), switch_caller_extension.getCPtr(caller_extension));
}
public static void switch_channel_flip_cid(SWIGTYPE_p_switch_channel channel) {
freeswitchPINVOKE.switch_channel_flip_cid(SWIGTYPE_p_switch_channel.getCPtr(channel));
}
public static void switch_channel_sort_cid(SWIGTYPE_p_switch_channel channel, switch_bool_t arg1) {
freeswitchPINVOKE.switch_channel_sort_cid(SWIGTYPE_p_switch_channel.getCPtr(channel), (int)arg1);
}
@@ -8054,6 +8067,9 @@ class freeswitchPINVOKE {
[DllImport("mod_managed", EntryPoint="CSharp_set_high_priority")]
public static extern int set_high_priority();
[DllImport("mod_managed", EntryPoint="CSharp_set_normal_priority")]
public static extern int set_normal_priority();
[DllImport("mod_managed", EntryPoint="CSharp_change_user_group")]
public static extern int change_user_group(string jarg1, string jarg2);
@@ -8141,6 +8157,9 @@ class freeswitchPINVOKE {
[DllImport("mod_managed", EntryPoint="CSharp_switch_time_set_monotonic")]
public static extern void switch_time_set_monotonic(int jarg1);
[DllImport("mod_managed", EntryPoint="CSharp_switch_time_set_timerfd")]
public static extern void switch_time_set_timerfd(int jarg1);
[DllImport("mod_managed", EntryPoint="CSharp_switch_time_set_nanosleep")]
public static extern void switch_time_set_nanosleep(int jarg1);
@@ -11486,6 +11505,9 @@ class freeswitchPINVOKE {
[DllImport("mod_managed", EntryPoint="CSharp_switch_channel_set_caller_extension")]
public static extern void switch_channel_set_caller_extension(HandleRef jarg1, HandleRef jarg2);
[DllImport("mod_managed", EntryPoint="CSharp_switch_channel_flip_cid")]
public static extern void switch_channel_flip_cid(HandleRef jarg1);
[DllImport("mod_managed", EntryPoint="CSharp_switch_channel_sort_cid")]
public static extern void switch_channel_sort_cid(HandleRef jarg1, int jarg2);
@@ -21664,6 +21686,8 @@ public enum switch_channel_flag_t {
CF_DIALPLAN,
CF_BLOCK_BROADCAST_UNTIL_MEDIA,
CF_CNG_PLC,
CF_ATTENDED_TRANSFER,
CF_LAZY_ATTENDED_TRANSFER,
CF_FLAG_MAX
}
@@ -28627,7 +28651,7 @@ namespace FreeSWITCH.Native {
SWITCH_RTP_FLAG_BREAK = (1 << 10),
SWITCH_RTP_FLAG_UDPTL = (1 << 11),
SWITCH_RTP_FLAG_DATAWAIT = (1 << 12),
SWITCH_RTP_FLAG_BUGGY_2833 = (1 << 13),
SWITCH_RTP_FLAG_BYTESWAP = (1 << 13),
SWITCH_RTP_FLAG_PASS_RFC2833 = (1 << 14),
SWITCH_RTP_FLAG_AUTO_CNG = (1 << 15),
SWITCH_RTP_FLAG_SECURE_SEND_RESET = (1 << 16),
@@ -240,7 +240,6 @@ void Session::unsetInputCallback(void)
cb_arg = NULL;
}
switch_channel_set_private(channel, "CoreSession", NULL);
args.input_callback = NULL;
ap = NULL;
+257
View File
@@ -0,0 +1,257 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* 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 Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II <anthm@freeswitch.org>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Timo Teräs <timo.teras@iki.fi>
*
*
* mod_timerfd.c -- Timer implementation using Linux timerfd
*
*/
#include <switch.h>
#include <sys/timerfd.h>
#include <sys/epoll.h>
SWITCH_MODULE_LOAD_FUNCTION(mod_timerfd_load);
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_timerfd_shutdown);
SWITCH_MODULE_RUNTIME_FUNCTION(mod_timerfd_runtime);
SWITCH_MODULE_DEFINITION(mod_timerfd, mod_timerfd_load, mod_timerfd_shutdown, mod_timerfd_runtime);
#define MAX_INTERVAL 2000 /* ms */
struct interval_timer {
int fd;
int users;
switch_size_t tick;
switch_mutex_t *mutex;
switch_thread_cond_t *cond;
};
typedef struct interval_timer interval_timer_t;
static switch_memory_pool_t *module_pool = NULL;
static switch_mutex_t *interval_timers_mutex;
static interval_timer_t interval_timers[MAX_INTERVAL + 1];
static int interval_poll_fd;
static switch_status_t timerfd_start_interval(interval_timer_t *it, int interval)
{
struct itimerspec val;
struct epoll_event e;
int fd;
it->users++;
if (it->users > 1)
return SWITCH_STATUS_SUCCESS;
it->tick = 0;
switch_mutex_init(&it->mutex, SWITCH_MUTEX_NESTED, module_pool);
switch_thread_cond_create(&it->cond, module_pool);
fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
if (fd < 0)
return SWITCH_STATUS_GENERR;
val.it_interval.tv_sec = interval / 1000;
val.it_interval.tv_nsec = (interval % 1000) * 1000000;
val.it_value.tv_sec = 0;
val.it_value.tv_nsec = 100000;
if (timerfd_settime(fd, 0, &val, NULL) < 0) {
close(fd);
return SWITCH_STATUS_GENERR;
}
e.events = EPOLLIN | EPOLLERR;
e.data.ptr = it;
if (epoll_ctl(interval_poll_fd, EPOLL_CTL_ADD, fd, &e) < 0) {
close(fd);
return SWITCH_STATUS_GENERR;
}
it->fd = fd;
return SWITCH_STATUS_SUCCESS;
}
static switch_status_t timerfd_stop_interval(interval_timer_t *it)
{
it->users--;
if (it->users > 0)
return SWITCH_STATUS_SUCCESS;
close(it->fd);
it->fd = -1;
return SWITCH_STATUS_SUCCESS;
}
static switch_status_t timerfd_init(switch_timer_t *timer)
{
interval_timer_t *it;
int rc;
if (timer->interval < 1 || timer->interval > MAX_INTERVAL)
return SWITCH_STATUS_GENERR;
it = &interval_timers[timer->interval];
switch_mutex_lock(interval_timers_mutex);
rc = timerfd_start_interval(it, timer->interval);
timer->private_info = it;
switch_mutex_unlock(interval_timers_mutex);
return rc;
}
static switch_status_t timerfd_step(switch_timer_t *timer)
{
timer->tick++;
timer->samplecount += timer->samples;
return SWITCH_STATUS_SUCCESS;
}
static switch_status_t timerfd_next(switch_timer_t *timer)
{
interval_timer_t *it = timer->private_info;
if ((int)(timer->tick - it->tick) < -1)
timer->tick = it->tick;
timerfd_step(timer);
switch_mutex_lock(it->mutex);
while ((int)(timer->tick - it->tick) > 0)
switch_thread_cond_wait(it->cond, it->mutex);
switch_mutex_unlock(it->mutex);
return SWITCH_STATUS_SUCCESS;
}
static switch_status_t timerfd_sync(switch_timer_t *timer)
{
interval_timer_t *it = timer->private_info;
timer->tick = it->tick;
return SWITCH_STATUS_SUCCESS;
}
static switch_status_t timerfd_check(switch_timer_t *timer, switch_bool_t step)
{
interval_timer_t *it = timer->private_info;
int diff = (int)(timer->tick - it->tick);
if (diff > 0) {
/* still pending */
timer->diff = diff;
return SWITCH_STATUS_FALSE;
} else {
/* timer pending */
timer->diff = 0;
if (step)
timerfd_step(timer);
return SWITCH_STATUS_SUCCESS;
}
}
static switch_status_t timerfd_destroy(switch_timer_t *timer)
{
interval_timer_t *it = timer->private_info;
int rc;
switch_mutex_lock(interval_timers_mutex);
rc = timerfd_stop_interval(it);
switch_mutex_unlock(interval_timers_mutex);
return rc;
}
SWITCH_MODULE_LOAD_FUNCTION(mod_timerfd_load)
{
switch_timer_interface_t *timer_interface;
module_pool = pool;
interval_poll_fd = epoll_create(16);
if (interval_poll_fd < 0)
return SWITCH_STATUS_GENERR;
switch_mutex_init(&interval_timers_mutex, SWITCH_MUTEX_NESTED, module_pool);
memset(interval_timers, 0, sizeof(interval_timers));
/* connect my internal structure to the blank pointer passed to me */
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
timer_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_TIMER_INTERFACE);
timer_interface->interface_name = "timerfd";
timer_interface->timer_init = timerfd_init;
timer_interface->timer_next = timerfd_next;
timer_interface->timer_step = timerfd_step;
timer_interface->timer_sync = timerfd_sync;
timer_interface->timer_check = timerfd_check;
timer_interface->timer_destroy = timerfd_destroy;
return SWITCH_STATUS_SUCCESS;
}
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_timerfd_shutdown)
{
close(interval_poll_fd);
return SWITCH_STATUS_SUCCESS;
}
SWITCH_MODULE_RUNTIME_FUNCTION(mod_timerfd_runtime)
{
struct epoll_event e[16];
interval_timer_t *it;
uint64_t u64;
int i, r;
do {
r = epoll_wait(interval_poll_fd, e, sizeof(e) / sizeof(e[0]), 1000);
if (r < 0)
break;
for (i = 0; i < r; i++) {
it = e[i].data.ptr;
if ((e[i].events & EPOLLIN) &&
read(it->fd, &u64, sizeof(u64)) == sizeof(u64)) {
switch_mutex_lock(it->mutex);
it->tick += u64;
switch_thread_cond_broadcast(it->cond);
switch_mutex_unlock(it->mutex);
}
}
} while (1);
return SWITCH_STATUS_TERM;
}
/* For Emacs:
* Local Variables:
* mode:c
* indent-tabs-mode:t
* tab-width:4
* c-basic-offset:4
* End:
* For VIM:
* vim:set softtabstop=4 shiftwidth=4 tabstop=4:
*/
+2 -2
View File
@@ -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++;
+2
View File
@@ -841,6 +841,8 @@ int main(int argc, char *argv[])
if (high_prio) {
set_high_priority();
} else {
set_normal_priority();
}
switch_core_setrlimits();
+53 -2
View File
@@ -24,7 +24,7 @@
* Contributor(s):
*
* Michael Jerris <mike@jerris.com>
*
* Eliot Gable <egable@gmail.com>
*
* switch_apr.c -- apr wrappers and extensions
*
@@ -38,6 +38,7 @@
/* apr headers*/
#include <apr.h>
#include <apr_atomic.h>
#include <apr_pools.h>
#include <apr_hash.h>
#include <apr_network_io.h>
@@ -642,7 +643,7 @@ SWITCH_DECLARE(switch_status_t) switch_threadattr_priority_increase(switch_threa
struct apr_threadattr_t *myattr = attr;
pthread_attr_getschedparam(&myattr->attr, &param);
param.sched_priority = 50;
param.sched_priority = 1;
stat = pthread_attr_setschedparam(&myattr->attr, &param);
if (stat == 0) {
@@ -1154,6 +1155,56 @@ SWITCH_DECLARE(switch_status_t) switch_thread_join(switch_status_t *retval, swit
}
SWITCH_DECLARE(switch_status_t) switch_atomic_init(switch_memory_pool_t *pool)
{
return apr_atomic_init((apr_pool_t *) pool);
}
SWITCH_DECLARE(uint32_t) switch_atomic_read(volatile switch_atomic_t *mem)
{
#ifdef apr_atomic_t
return apr_atomic_read((apr_atomic_t *)mem);
#else
return apr_atomic_read32((apr_uint32_t *)mem);
#endif
}
SWITCH_DECLARE(void) switch_atomic_set(volatile switch_atomic_t *mem, uint32_t val)
{
#ifdef apr_atomic_t
apr_atomic_set((apr_atomic_t *)mem, val);
#else
apr_atomic_set32((apr_uint32_t *)mem, val);
#endif
}
SWITCH_DECLARE(void) switch_atomic_add(volatile switch_atomic_t *mem, uint32_t val)
{
#ifdef apr_atomic_t
apr_atomic_add((apr_atomic_t *)mem, val);
#else
apr_atomic_add32((apr_uint32_t *)mem, val);
#endif
}
SWITCH_DECLARE(void) switch_atomic_inc(volatile switch_atomic_t *mem)
{
#ifdef apr_atomic_t
apr_atomic_inc((apr_atomic_t *)mem);
#else
apr_atomic_inc32((apr_uint32_t *)mem);
#endif
}
SWITCH_DECLARE(int) switch_atomic_dec(volatile switch_atomic_t *mem)
{
#ifdef apr_atomic_t
return apr_atomic_dec((apr_atomic_t *)mem);
#else
return apr_atomic_dec32((apr_uint32_t *)mem);
#endif
}
/* For Emacs:
* Local Variables:
+33 -15
View File
@@ -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);
@@ -1562,6 +1562,10 @@ SWITCH_DECLARE(switch_channel_state_t) switch_channel_get_running_state(switch_c
SWITCH_DECLARE(int) switch_channel_state_change_pending(switch_channel_t *channel)
{
if (switch_channel_down(channel) || !switch_core_session_in_thread(channel->session)) {
return 0;
}
return channel->running_state != channel->state;
}
@@ -2434,26 +2438,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;
@@ -2539,6 +2556,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);
}
+33 -7
View File
@@ -609,16 +609,11 @@ SWITCH_DECLARE(void) switch_core_set_globals(void)
switch_assert(SWITCH_GLOBAL_dirs.temp_dir);
}
SWITCH_DECLARE(int32_t) set_high_priority(void)
static int32_t set_priority(void)
{
#ifdef WIN32
SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS);
#else
#ifdef USE_SETRLIMIT
struct rlimit lim = { RLIM_INFINITY, RLIM_INFINITY };
#endif
#ifdef USE_SCHED_SETSCHEDULER
/*
* Try to use a round-robin scheduler
@@ -640,12 +635,38 @@ SWITCH_DECLARE(int32_t) set_high_priority(void)
*/
if (setpriority(PRIO_PROCESS, getpid(), -10) < 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Could not set nice level\n");
return -1;
}
#else
if (nice(-10) != -10) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Could not set nice level\n");
return -1;
}
#endif
#endif
return 0;
}
SWITCH_DECLARE(int32_t) set_normal_priority(void)
{
return set_priority();
}
SWITCH_DECLARE(int32_t) set_high_priority(void)
{
#ifdef WIN32
SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
#else
int pri;
#ifdef USE_SETRLIMIT
struct rlimit lim = { RLIM_INFINITY, RLIM_INFINITY };
#endif
if ((pri = set_priority())) {
return pri;
}
#ifdef USE_SETRLIMIT
/*
@@ -1641,6 +1662,11 @@ static void switch_load_core_config(const char *file)
}
} else if (!strcasecmp(var, "enable-monotonic-timing")) {
switch_time_set_monotonic(switch_true(var));
} else if (!strcasecmp(var, "enable-softtimer-timerfd")) {
switch_time_set_timerfd(switch_true(var));
if (switch_true(val)) {
switch_clear_flag((&runtime), SCF_CALIBRATE_CLOCK);
}
} else if (!strcasecmp(var, "enable-clock-nanosleep")) {
switch_time_set_nanosleep(switch_true(var));
} else if (!strcasecmp(var, "enable-cond-yield")) {
+77 -39
View File
@@ -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:
@@ -1676,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;
@@ -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);
+1
View File
@@ -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);
}
}
}
+14 -2
View File
@@ -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);
}
@@ -3262,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;
@@ -3333,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 {
@@ -3609,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));
@@ -3618,6 +3624,12 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
}
}
}
while(switch_channel_state_change_pending(bchan)) {
switch_cond_next();
}
switch_ivr_sleep(*bleg, 0, SWITCH_TRUE, NULL);
}
+2 -2
View File
@@ -374,7 +374,7 @@ SWITCH_MODULE_LOAD_FUNCTION(core_pcm_load)
}
for (; countb > 0; countb--) {
switch_core_codec_add_implementation(pool, codec_interface,
SWITCH_CODEC_TYPE_AUDIO, 10, "L16", NULL, rate, rate, bps,
SWITCH_CODEC_TYPE_AUDIO, 70, "L16", NULL, rate, rate, bps,
mpf * countb, spf * countb, bpf * countb, ebpf * countb, 1, spf * countb,
switch_raw_init, switch_raw_encode, switch_raw_decode, switch_raw_destroy);
}
@@ -391,7 +391,7 @@ SWITCH_MODULE_LOAD_FUNCTION(core_pcm_load)
for (x = 0; x < 5; x++) {
switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */
10, /* the IANA code number */
70, /* the IANA code number */
"L16", /* the IANA code name */
NULL, /* default fmtp to send (can be overridden by the init function) */
12000, /* samples transferred per second */
+118 -80
View File
@@ -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
@@ -1917,6 +1919,14 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_activate_jitter_buffer(switch_rtp_t *
return SWITCH_STATUS_FALSE;
}
if (queue_frames < 1) {
queue_frames = 3;
}
if (max_queue_frames < queue_frames) {
max_queue_frames = queue_frames * 3;
}
READ_INC(rtp_session);
if (rtp_session->jb) {
stfu_n_resize(rtp_session->jb, queue_frames);
@@ -2182,7 +2192,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 +2206,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)
@@ -2202,6 +2219,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;
@@ -2240,7 +2258,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 +2269,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 +2293,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);
@@ -2409,9 +2427,9 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t
status = switch_socket_recvfrom(rtp_session->from_addr, rtp_session->sock_input, 0, (void *) &rtp_session->recv_msg, bytes);
ts = ntohl(rtp_session->recv_msg.header.ts);
if (*bytes ) {
if (*bytes) {
uint16_t seq = ntohs((uint16_t) rtp_session->recv_msg.header.seq);
if (rtp_session->last_seq && rtp_session->last_seq+1 != seq) {
#ifdef DEBUG_MISSED_SEQ
switch_size_t flushed_packets_diff = rtp_session->stats.inbound.flush_packet_count - rtp_session->last_flush_packet_count;
@@ -2473,6 +2491,70 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t
}
rtp_session->stats.inbound.packet_count++;
if (!switch_test_flag(rtp_session, SWITCH_RTP_FLAG_PROXY_MEDIA) && !switch_test_flag(rtp_session, SWITCH_RTP_FLAG_UDPTL)) {
#ifdef ENABLE_ZRTP
/* ZRTP Recv */
unsigned int sbytes = (int) *bytes;
zrtp_status_t stat = 0;
stat = zrtp_process_srtp(rtp_session->zrtp_stream, (void *) &rtp_session->recv_msg, &sbytes);
switch (stat) {
case zrtp_status_ok:
*bytes = sbytes;
break;
case zrtp_status_drop:
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error: zRTP protection drop with code %d\n", stat);
*bytes = 0;
return SWITCH_STATUS_SUCCESS;
case zrtp_status_fail:
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error: zRTP protection fail with code %d\n", stat);
return SWITCH_STATUS_FALSE;
default:
break;
}
#endif
if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_SECURE_RECV)) {
int sbytes = (int) *bytes;
err_status_t stat = 0;
if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_SECURE_RECV_RESET)) {
switch_clear_flag_locked(rtp_session, SWITCH_RTP_FLAG_SECURE_RECV_RESET);
srtp_dealloc(rtp_session->recv_ctx);
rtp_session->recv_ctx = NULL;
if ((stat = srtp_create(&rtp_session->recv_ctx, &rtp_session->recv_policy))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error! RE-Activating Secure RTP RECV\n");
return SWITCH_STATUS_FALSE;
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "RE-Activating Secure RTP RECV\n");
rtp_session->srtp_errs = 0;
}
}
if (!(*flags & SFF_PLC)) {
stat = srtp_unprotect(rtp_session->recv_ctx, &rtp_session->recv_msg.header, &sbytes);
}
if (stat && rtp_session->recv_msg.header.pt != rtp_session->recv_te && rtp_session->recv_msg.header.pt != rtp_session->cng_pt) {
if (++rtp_session->srtp_errs >= MAX_SRTP_ERRS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
"Error: SRTP unprotect failed with code %d%s\n", stat,
stat == err_status_replay_fail ? " (replay check failed)" : stat ==
err_status_auth_fail ? " (auth check failed)" : "");
return SWITCH_STATUS_FALSE;
} else {
sbytes = 0;
}
} else {
rtp_session->srtp_errs = 0;
}
*bytes = sbytes;
}
}
}
@@ -2484,6 +2566,11 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t
rtp_session->last_read_ts = ts;
if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_BYTESWAP) && rtp_session->recv_msg.header.pt == rtp_session->rpayload) {
switch_swap_linear((int16_t *)rtp_session->recv_msg.body, (int) *bytes - rtp_header_len);
}
if (rtp_session->jb && !rtp_session->pause_jb && rtp_session->recv_msg.header.version == 2 && *bytes) {
if (rtp_session->recv_msg.header.m && rtp_session->recv_msg.header.pt != rtp_session->recv_te &&
@@ -2491,10 +2578,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 +2748,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 +2759,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,11 +2813,14 @@ 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) {
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;
}
@@ -2735,7 +2829,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();
@@ -3037,31 +3130,6 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
if (check || bytes) {
do_2833(rtp_session, session);
}
#ifdef ENABLE_ZRTP
/* ZRTP Recv */
if (bytes) {
unsigned int sbytes = (int) bytes;
zrtp_status_t stat = 0;
stat = zrtp_process_srtp(rtp_session->zrtp_stream, (void *) &rtp_session->recv_msg, &sbytes);
switch (stat) {
case zrtp_status_ok:
bytes = sbytes;
break;
case zrtp_status_drop:
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error: zRTP protection drop with code %d\n", stat);
bytes = 0;
goto do_continue;
case zrtp_status_fail:
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error: zRTP protection fail with code %d\n", stat);
ret = -1;
goto end;
default:
break;
}
}
#endif
if (bytes && rtp_session->recv_msg.header.version != 2) {
uint8_t *data = (uint8_t *) rtp_session->recv_msg.body;
@@ -3088,43 +3156,6 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
goto end;
}
if (bytes && switch_test_flag(rtp_session, SWITCH_RTP_FLAG_SECURE_RECV)) {
int sbytes = (int) bytes;
err_status_t stat = 0;
if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_SECURE_RECV_RESET)) {
switch_clear_flag_locked(rtp_session, SWITCH_RTP_FLAG_SECURE_RECV_RESET);
srtp_dealloc(rtp_session->recv_ctx);
rtp_session->recv_ctx = NULL;
if ((stat = srtp_create(&rtp_session->recv_ctx, &rtp_session->recv_policy))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error! RE-Activating Secure RTP RECV\n");
ret = -1;
goto end;
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "RE-Activating Secure RTP RECV\n");
rtp_session->srtp_errs = 0;
}
}
stat = srtp_unprotect(rtp_session->recv_ctx, &rtp_session->recv_msg.header, &sbytes);
if (stat && rtp_session->recv_msg.header.pt != rtp_session->recv_te && rtp_session->recv_msg.header.pt != rtp_session->cng_pt) {
if (++rtp_session->srtp_errs >= MAX_SRTP_ERRS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
"Error: SRTP unprotect failed with code %d%s\n", stat,
stat == err_status_replay_fail ? " (replay check failed)" : stat ==
err_status_auth_fail ? " (auth check failed)" : "");
ret = -1;
goto end;
} else {
sbytes = 0;
}
} else {
rtp_session->srtp_errs = 0;
}
bytes = sbytes;
}
/* Handle incoming RFC2833 packets */
switch (handle_rfc2833(rtp_session, bytes, &do_cng)) {
@@ -3160,7 +3191,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 +3218,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 +3554,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 +3572,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++;
}
@@ -3676,6 +3709,11 @@ static int rtp_common_write(switch_rtp_t *rtp_session,
if (send) {
send_msg->header.seq = htons(++rtp_session->seq);
if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_BYTESWAP) && send_msg->header.pt == rtp_session->payload) {
switch_swap_linear((int16_t *)send_msg->body, (int) datalen);
}
if (switch_test_flag(rtp_session, SWITCH_RTP_FLAG_SECURE_SEND)) {
int sbytes = (int) bytes;
err_status_t stat;
@@ -3785,7 +3823,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();
+60 -15
View File
@@ -34,6 +34,9 @@
#include <switch.h>
#include <stdio.h>
#include "private/switch_core_pvt.h"
#ifdef HAVE_TIMERFD_CREATE
#include <sys/timerfd.h>
#endif
//#if defined(DARWIN)
#define DISABLE_1MS_COND
@@ -58,6 +61,13 @@ static int MONO = 1;
static int MONO = 0;
#endif
#if defined(HAVE_TIMERFD_CREATE)
// We'll default this to 1 after we have had some positive feedback that it works well
static int TFD = 0;
#else
static int TFD = 0;
#endif
static int NANO = 0;
static int OFFSET = 0;
@@ -72,18 +82,10 @@ static DWORD win32_last_get_time_tick = 0;
CRITICAL_SECTION timer_section;
#endif
#define ONEMS
#ifdef ONEMS
static int STEP_MS = 1;
static int STEP_MIC = 1000;
static uint32_t TICK_PER_SEC = 1000;
static int MS_PER_TICK = 10;
#else
static int STEP_MS = 10;
static int STEP_MIC = 10000;
static uint32_t TICK_PER_SEC = 1000;
static int MS_PER_TICK = 10;
#endif
static switch_memory_pool_t *module_pool = NULL;
@@ -208,9 +210,6 @@ SWITCH_DECLARE(void) switch_time_calibrate_clock(void)
}
if (res > 1500) {
STEP_MS = res / 1000;
STEP_MIC = res;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
"Timer resolution of %ld microseconds detected!\n"
"Do you have your kernel timer frequency set to lower than 1,000Hz? "
@@ -313,8 +312,23 @@ SWITCH_DECLARE(time_t) switch_epoch_time_now(time_t *t)
SWITCH_DECLARE(void) switch_time_set_monotonic(switch_bool_t enable)
{
#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
MONO = enable ? 1 : 0;
switch_time_sync();
#else
MONO = 0;
#endif
}
SWITCH_DECLARE(void) switch_time_set_timerfd(switch_bool_t enable)
{
#if defined(HAVE_TIMERFD_CREATE)
TFD = enable ? 1 : 0;
switch_time_sync();
#else
TFD = 0;
#endif
}
@@ -490,9 +504,6 @@ static switch_status_t timer_init(switch_timer_t *timer)
if (timer->interval > 0 && timer->interval < MS_PER_TICK) {
MS_PER_TICK = timer->interval;
STEP_MS = 1;
STEP_MIC = 1000;
TICK_PER_SEC = 10000;
switch_time_sync();
}
@@ -665,6 +676,29 @@ SWITCH_MODULE_RUNTIME_FUNCTION(softtimer_runtime)
switch_time_t ts = 0, last = 0;
int fwd_errs = 0, rev_errs = 0;
int profile_tick = 0;
int tfd = -1;
#ifdef HAVE_TIMERFD_CREATE
struct itimerspec spec = { { 0 } };
if (MONO && TFD) {
tfd = timerfd_create(CLOCK_MONOTONIC, 0);
if (tfd > -1) {
spec.it_interval.tv_sec = 0;
spec.it_interval.tv_nsec = 1000000;
spec.it_value.tv_sec = spec.it_interval.tv_sec;
spec.it_value.tv_nsec = spec.it_interval.tv_nsec;
if (timerfd_settime(tfd, TFD_TIMER_ABSTIME, &spec, NULL)) {
close(tfd);
tfd = -1;
}
}
}
#else
tfd = -1;
#endif
runtime.profile_timer = switch_new_profile_timer();
switch_get_system_idle_time(runtime.profile_timer, &runtime.profile_time);
@@ -743,7 +777,13 @@ SWITCH_MODULE_RUNTIME_FUNCTION(softtimer_runtime)
if (globals.timer_count >= runtime.tipping_point) {
os_yield();
} else {
do_sleep(1000);
if (tfd > -1 && globals.RUNNING == 1) {
uint64_t exp;
int r;
r = read(tfd, &exp, sizeof(exp));
} else {
do_sleep(1000);
}
}
last = ts;
@@ -841,6 +881,11 @@ SWITCH_MODULE_RUNTIME_FUNCTION(softtimer_runtime)
}
}
if (tfd > -1) {
close(tfd);
tfd = -1;
}
switch_mutex_lock(globals.mutex);
globals.RUNNING = 0;
+83 -60
View File
@@ -95,13 +95,6 @@ typedef struct {
int glob(const char *, int, int (*)(const char *, int), glob_t *);
void globfree(glob_t *);
#endif
#undef HAVE_MMAP
#ifdef HAVE_MMAP
#include <sys/mman.h>
#ifdef __sun
extern int madvise(caddr_t, size_t, int);
#endif
#endif
#define SWITCH_XML_WS "\t\r\n " /* whitespace */
@@ -114,7 +107,7 @@ struct switch_xml_root { /* additional data for the root tag */
struct switch_xml xml; /* is a super-struct built on top of switch_xml struct */
switch_xml_t cur; /* current xml tree insertion point */
char *m; /* original xml string */
switch_size_t len; /* length of allocated memory for mmap */
switch_size_t len; /* length of allocated memory */
uint8_t dynamic; /* Free the original string when calling switch_xml_free */
char *u; /* UTF-8 conversion of string if original was UTF-16 */
char *s; /* start of work area */
@@ -124,6 +117,11 @@ struct switch_xml_root { /* additional data for the root tag */
char ***pi; /* processing instructions */
short standalone; /* non-zero if <?xml standalone="yes"?> */
char err[SWITCH_XML_ERRL]; /* error string */
/*! is_main_xml_root */
switch_bool_t is_main_xml_root;
/*! rwlock */
switch_thread_rwlock_t *rwlock;
};
char *SWITCH_XML_NIL[] = { NULL }; /* empty, null terminated array of strings */
@@ -139,11 +137,11 @@ struct switch_xml_binding {
static switch_xml_binding_t *BINDINGS = NULL;
static switch_xml_t MAIN_XML_ROOT = NULL;
static switch_memory_pool_t *XML_MEMORY_POOL = NULL;
static switch_thread_rwlock_t *RWLOCK = NULL;
static switch_thread_rwlock_t *B_RWLOCK = NULL;
static switch_mutex_t *XML_LOCK = NULL;
static switch_thread_rwlock_t *XML_RWLOCK = NULL;
static switch_mutex_t *XML_GEN_LOCK = NULL;
static switch_mutex_t *XML_FREE_LOCK = NULL;
static switch_mutex_t *XML_RWFILE_LOCK = NULL;
struct xml_section_t {
const char *name;
@@ -1161,28 +1159,16 @@ SWITCH_DECLARE(switch_xml_t) switch_xml_parse_fd(int fd)
return NULL;
}
#ifdef HAVE_MMAP
l = (st.st_size + sysconf(_SC_PAGESIZE) - 1) & ~(sysconf(_SC_PAGESIZE) - 1);
if ((m = mmap(NULL, l, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0)) != MAP_FAILED) {
madvise(m, l, MADV_SEQUENTIAL); /* optimize for sequential access */
if (!(root = (switch_xml_root_t) switch_xml_parse_str(m, st.st_size))) {
munmap(m, l);
}
madvise(m, root->len = l, MADV_NORMAL); /* put it back to normal */
} else { /* mmap failed, read file into memory */
#endif /* HAVE_MMAP */
m = malloc(st.st_size);
if (!m)
return NULL;
l = read(fd, m, st.st_size);
if (!l || !(root = (switch_xml_root_t) switch_xml_parse_str((char *) m, l))) {
free(m);
return NULL;
}
root->dynamic = 1; /* so we know to free s in switch_xml_free() */
#ifdef HAVE_MMAP
m = malloc(st.st_size);
if (!m)
return NULL;
l = read(fd, m, st.st_size);
if (!l || !(root = (switch_xml_root_t) switch_xml_parse_str((char *) m, l))) {
free(m);
return NULL;
}
#endif /* HAVE_MMAP */
root->dynamic = 1; /* so we know to free s in switch_xml_free() */
return &root->xml;
}
@@ -1542,9 +1528,11 @@ SWITCH_DECLARE(switch_xml_t) switch_xml_parse_file(const char *file)
} else {
abs = file;
}
/* Protection against running this code twice on the same filename */
switch_mutex_lock(XML_RWFILE_LOCK);
if (!(new_file = switch_mprintf("%s%s%s.fsxml", SWITCH_GLOBAL_dirs.log_dir, SWITCH_PATH_SEPARATOR, abs))) {
return NULL;
goto done;
}
if ((write_fd = open(new_file, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)) < 0) {
@@ -1571,6 +1559,7 @@ SWITCH_DECLARE(switch_xml_t) switch_xml_parse_file(const char *file)
if (fd > -1) {
close(fd);
}
switch_mutex_unlock(XML_RWFILE_LOCK);
switch_safe_free(new_file);
return xml;
}
@@ -1933,8 +1922,16 @@ SWITCH_DECLARE(switch_status_t) switch_xml_locate_user(const char *key,
SWITCH_DECLARE(switch_xml_t) switch_xml_root(void)
{
switch_thread_rwlock_rdlock(RWLOCK);
return MAIN_XML_ROOT;
switch_xml_root_t root = NULL;
switch_thread_rwlock_rdlock(XML_RWLOCK);
if (MAIN_XML_ROOT) {
root = (switch_xml_root_t) MAIN_XML_ROOT;
switch_thread_rwlock_rdlock(root->rwlock);
}
switch_thread_rwlock_unlock(XML_RWLOCK);
return (switch_xml_t) root;
}
struct destroy_xml {
@@ -1978,15 +1975,14 @@ SWITCH_DECLARE(switch_xml_t) switch_xml_open_root(uint8_t reload, const char **e
{
char path_buf[1024];
uint8_t errcnt = 0;
switch_xml_t new_main, r = NULL;
switch_xml_t r = NULL, new_main;
switch_mutex_lock(XML_LOCK);
if (!reload) {
r = switch_xml_root();
}
if (MAIN_XML_ROOT) {
if (!reload) {
r = switch_xml_root();
goto done;
}
if (r) {
goto done;
}
switch_snprintf(path_buf, sizeof(path_buf), "%s%s%s", SWITCH_GLOBAL_dirs.conf_dir, SWITCH_PATH_SEPARATOR, "freeswitch.xml");
@@ -1999,18 +1995,27 @@ SWITCH_DECLARE(switch_xml_t) switch_xml_open_root(uint8_t reload, const char **e
new_main = NULL;
errcnt++;
} else {
switch_xml_t old_root;
switch_xml_t old_root = NULL;
switch_xml_root_t new_main_root = (switch_xml_root_t) new_main;
new_main_root->is_main_xml_root = SWITCH_TRUE;
*err = "Success";
switch_thread_rwlock_wrlock(RWLOCK);
old_root = switch_xml_root();
old_root = MAIN_XML_ROOT;
switch_set_flag(new_main, SWITCH_XML_ROOT);
switch_thread_rwlock_wrlock(XML_RWLOCK);
MAIN_XML_ROOT = new_main;
switch_set_flag(MAIN_XML_ROOT, SWITCH_XML_ROOT);
switch_thread_rwlock_unlock(XML_RWLOCK);
switch_thread_rwlock_unlock(RWLOCK);
if (old_root) {
switch_clear_flag(old_root, SWITCH_XML_ROOT);
}
switch_xml_free(old_root);
/* switch_xml_free_in_thread(old_root); */
}
} else {
@@ -2030,8 +2035,6 @@ SWITCH_DECLARE(switch_xml_t) switch_xml_open_root(uint8_t reload, const char **e
done:
switch_mutex_unlock(XML_LOCK);
return r;
}
@@ -2053,10 +2056,11 @@ SWITCH_DECLARE(switch_status_t) switch_xml_init(switch_memory_pool_t *pool, cons
XML_MEMORY_POOL = pool;
*err = "Success";
switch_mutex_init(&XML_LOCK, SWITCH_MUTEX_NESTED, XML_MEMORY_POOL);
switch_mutex_init(&XML_GEN_LOCK, SWITCH_MUTEX_NESTED, XML_MEMORY_POOL);
switch_thread_rwlock_create(&RWLOCK, XML_MEMORY_POOL);
switch_mutex_init(&XML_FREE_LOCK, SWITCH_MUTEX_NESTED, XML_MEMORY_POOL);
switch_mutex_init(&XML_RWFILE_LOCK, SWITCH_MUTEX_NESTED, XML_MEMORY_POOL);
switch_thread_rwlock_create(&B_RWLOCK, XML_MEMORY_POOL);
switch_thread_rwlock_create(&XML_RWLOCK, XML_MEMORY_POOL);
assert(pool != NULL);
@@ -2071,7 +2075,7 @@ SWITCH_DECLARE(switch_status_t) switch_xml_init(switch_memory_pool_t *pool, cons
SWITCH_DECLARE(switch_status_t) switch_xml_destroy(void)
{
switch_status_t status = SWITCH_STATUS_FALSE;
switch_mutex_lock(XML_LOCK);
switch_thread_rwlock_wrlock(XML_RWLOCK);
if (MAIN_XML_ROOT) {
switch_xml_t xml = MAIN_XML_ROOT;
@@ -2080,7 +2084,7 @@ SWITCH_DECLARE(switch_status_t) switch_xml_destroy(void)
status = SWITCH_STATUS_SUCCESS;
}
switch_mutex_unlock(XML_LOCK);
switch_thread_rwlock_unlock(XML_RWLOCK);
return status;
}
@@ -2367,14 +2371,34 @@ SWITCH_DECLARE(void) switch_xml_free(switch_xml_t xml)
char **a, *s;
switch_xml_t orig_xml;
tailrecurse:
root = (switch_xml_root_t) xml;
if (!xml) {
return;
}
if (xml == MAIN_XML_ROOT) {
switch_thread_rwlock_unlock(RWLOCK);
/* If xml is currenly the MAIN_XML_ROOT, dont even bother to check to empty it */
if (switch_test_flag(xml, SWITCH_XML_ROOT)) {
switch_thread_rwlock_unlock(root->rwlock);
return;
}
/* This is a trick to find if the struct is still in use or not */
switch_mutex_lock(XML_FREE_LOCK);
if (xml->is_switch_xml_root_t == SWITCH_TRUE && root->is_main_xml_root == SWITCH_TRUE) {
switch_thread_rwlock_unlock(root->rwlock);
if (switch_thread_rwlock_trywrlock(root->rwlock) != SWITCH_STATUS_SUCCESS) {
/* XML Struct is still in used, person who free it will clean it */
switch_mutex_unlock(XML_FREE_LOCK);
return;
}
switch_thread_rwlock_unlock(root->rwlock);
switch_thread_rwlock_destroy(root->rwlock);
}
switch_mutex_unlock(XML_FREE_LOCK);
tailrecurse:
root = (switch_xml_root_t) xml;
if (!xml) {
return;
}
@@ -2418,15 +2442,12 @@ SWITCH_DECLARE(void) switch_xml_free(switch_xml_t xml)
if (root->dynamic == 1)
free(root->m); /* malloced xml data */
#ifdef HAVE_MMAP
else if (root->len)
munmap(root->m, root->len); /* mem mapped xml data */
#endif /* HAVE_MMAP */
if (root->u)
free(root->u); /* utf8 conversion */
}
switch_xml_free_attr(xml->attr); /* tag attributes */
if ((xml->flags & SWITCH_XML_TXTM))
free(xml->txt); /* character content */
if ((xml->flags & SWITCH_XML_NAMEM))
@@ -2464,6 +2485,8 @@ SWITCH_DECLARE(switch_xml_t) switch_xml_new(const char *name)
root->ent = (char **) memcpy(malloc(sizeof(ent)), ent, sizeof(ent));
root->attr = root->pi = (char ***) (root->xml.attr = SWITCH_XML_NIL);
root->xml.is_switch_xml_root_t = SWITCH_TRUE;
root->is_main_xml_root = SWITCH_FALSE;
switch_thread_rwlock_create(&root->rwlock, XML_MEMORY_POOL);
return &root->xml;
}