mirror of
https://github.com/signalwire/freeswitch.git
synced 2026-10-23 03:34:15 +00:00
Merge branch 'master' into smgmaster
This commit is contained in:
commit
bf23a0a38b
127 files changed
+3185
-8895
No files matched your search
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
/*!
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
@@ -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();
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
BASE=../../../..
|
||||
|
||||
LOCAL_OBJS += load.o
|
||||
include $(BASE)/build/modmake.rules
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,7 +1,7 @@
|
||||
include $(top_srcdir)/build/modmake.rulesam
|
||||
|
||||
MODNAME=mod_com_g729
|
||||
VERSION=193
|
||||
VERSION=194
|
||||
|
||||
if ISLINUX
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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:
|
||||
*/
|
||||
@@ -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++;
|
||||
|
||||
@@ -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
@@ -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, ¶m);
|
||||
param.sched_priority = 50;
|
||||
param.sched_priority = 1;
|
||||
stat = pthread_attr_setschedparam(&myattr->attr, ¶m);
|
||||
|
||||
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
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user