Merge branch 'master' into smgmaster

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

No files matched your search

+1
View File
@@ -31,6 +31,7 @@
/endpoints/mod_portaudio/Makefile.in
/endpoints/mod_skinny/Makefile
/endpoints/mod_skinny/Makefile.in
/endpoints/mod_skinny/mod_skinny.log
/endpoints/mod_skypopen/Makefile
/endpoints/mod_skypopen/Makefile.in
/endpoints/mod_sofia/Makefile
@@ -160,13 +160,15 @@ struct cc_member_cancel_reason_table {
typedef enum {
CC_MEMBER_CANCEL_REASON_NONE,
CC_MEMBER_CANCEL_REASON_TIMEOUT,
CC_MEMBER_CANCEL_REASON_NO_AGENT_TIMEOUT
CC_MEMBER_CANCEL_REASON_NO_AGENT_TIMEOUT,
CC_MEMBER_CANCEL_REASON_BREAK_OUT
} cc_member_cancel_reason_t;
static struct cc_member_cancel_reason_table MEMBER_CANCEL_REASON_CHART[] = {
{"NONE", CC_MEMBER_CANCEL_REASON_NONE},
{"TIMEOUT", CC_MEMBER_CANCEL_REASON_TIMEOUT},
{"NO_AGENT_TIMEOUT", CC_MEMBER_CANCEL_REASON_NO_AGENT_TIMEOUT},
{"BREAK_OUT", CC_MEMBER_CANCEL_REASON_BREAK_OUT},
{NULL, 0}
};
@@ -216,6 +218,7 @@ static char agents_sql[] =
" wrap_up_time INTEGER NOT NULL DEFAULT 0,\n"
" reject_delay_time INTEGER NOT NULL DEFAULT 0,\n"
" busy_delay_time INTEGER NOT NULL DEFAULT 0,\n"
" no_answer_delay_time INTEGER NOT NULL DEFAULT 0,\n"
" last_bridge_start INTEGER NOT NULL DEFAULT 0,\n"
" last_bridge_end INTEGER NOT NULL DEFAULT 0,\n"
" last_offered_call INTEGER NOT NULL DEFAULT 0,\n"
@@ -705,6 +708,7 @@ static cc_queue_t *load_queue(const char *queue_name)
switch_cache_db_test_reactive(dbh, "select count(ready_time) from agents", NULL, "alter table agents add ready_time integer not null default 0;"
"alter table agents add reject_delay_time integer not null default 0;"
"alter table agents add busy_delay_time integer not null default 0;");
switch_cache_db_test_reactive(dbh, "select count(no_answer_delay_time) from agents", NULL, "alter table agents add no_answer_delay_time integer not null default 0;");
switch_cache_db_test_reactive(dbh, "select count(ready_time) from agents", "drop table agents", agents_sql);
switch_cache_db_test_reactive(dbh, "select count(queue) from tiers", "drop table tiers" , tiers_sql);
switch_mutex_init(&queue->mutex, SWITCH_MUTEX_NESTED, queue->pool);
@@ -768,6 +772,7 @@ struct call_helper {
int max_no_answer;
int reject_delay_time;
int busy_delay_time;
int no_answer_delay_time;
switch_memory_pool_t *pool;
};
@@ -1007,6 +1012,12 @@ cc_status_t cc_agent_update(const char *key, const char *value, const char *agen
cc_execute_sql(NULL, sql, NULL);
switch_safe_free(sql);
result = CC_STATUS_SUCCESS;
} else if (!strcasecmp(key, "no_answer_delay_time")) {
sql = switch_mprintf("UPDATE agents SET no_answer_delay_time = '%ld', system = 'single_box' WHERE name = '%q'", atol(value), agent);
cc_execute_sql(NULL, sql, NULL);
switch_safe_free(sql);
result = CC_STATUS_SUCCESS;
} else if (!strcasecmp(key, "type")) {
if (strcasecmp(value, CC_AGENT_TYPE_CALLBACK) && strcasecmp(value, CC_AGENT_TYPE_UUID_STANDBY)) {
@@ -1203,6 +1214,7 @@ static switch_status_t load_agent(const char *agent_name)
const char *wrap_up_time = switch_xml_attr(x_agent, "wrap-up-time");
const char *reject_delay_time = switch_xml_attr(x_agent, "reject-delay-time");
const char *busy_delay_time = switch_xml_attr(x_agent, "busy-delay-time");
const char *no_answer_delay_time = switch_xml_attr(x_agent, "no-answer-delay-time");
if (type) {
cc_status_t res = cc_agent_add(agent_name, type);
@@ -1225,6 +1237,9 @@ static switch_status_t load_agent(const char *agent_name)
if (busy_delay_time) {
cc_agent_update("busy_delay_time", busy_delay_time, agent_name);
}
if (no_answer_delay_time) {
cc_agent_update("no_answer_delay_time", no_answer_delay_time, agent_name);
}
if (type && res == CC_STATUS_AGENT_ALREADY_EXIST) {
cc_agent_update("type", type, agent_name);
@@ -1384,8 +1399,6 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "cc_agent", "%s", h->agent_name);
switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "cc_agent_type", "%s", h->agent_type);
switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "ignore_early_media", "true");
/* Force loopback to remain live, if not, the loop will detect the actual channel to gone */
switch_event_add_header(ovars, SWITCH_STACK_BOTTOM, "loopback_bowout", "false");
t_agent_called = switch_epoch_time_now(NULL);
dialstr = switch_mprintf("%s", h->originate_string);
@@ -1430,9 +1443,36 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
const char *agent_uuid = switch_core_session_get_uuid(agent_session);
switch_channel_t *member_channel = switch_core_session_get_channel(member_session);
switch_channel_t *agent_channel = switch_core_session_get_channel(agent_session);
const char *other_loopback_leg_uuid = switch_channel_get_variable(agent_channel, "other_loopback_leg_uuid");
switch_channel_set_variable(agent_channel, "cc_member_pre_answer_uuid", NULL);
/* Loopback special case */
if (other_loopback_leg_uuid) {
switch_core_session_t *other_loopback_session = switch_core_session_locate(other_loopback_leg_uuid);
if (other_loopback_session) {
switch_channel_t *other_loopback_channel = switch_core_session_get_channel(other_loopback_session);
const char *real_uuid = switch_channel_get_variable(other_loopback_channel, SWITCH_SIGNAL_BOND_VARIABLE);
switch_channel_set_variable(other_loopback_channel, "cc_member_pre_answer_uuid", NULL);
/* Switch the agent session */
if (real_uuid) {
switch_core_session_rwunlock(agent_session);
agent_uuid = real_uuid;
agent_session = switch_core_session_locate(agent_uuid);
agent_channel = switch_core_session_get_channel(agent_session);
switch_channel_set_variable(agent_channel, "cc_queue", h->queue_name);
switch_channel_set_variable(agent_channel, "cc_agent", h->agent_name);
switch_channel_set_variable(agent_channel, "cc_agent_type", h->agent_type);
switch_channel_set_variable(agent_channel, "cc_member_uuid", h->member_uuid);
}
switch_core_session_rwunlock(other_loopback_session);
}
}
if (!strcasecmp(h->queue_strategy,"ring-all")) {
char res[256];
/* Map the Agent to the member */
@@ -1466,6 +1506,9 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent", h->agent_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-System", h->agent_system);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-UUID", agent_uuid);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Agent-Called-Time", "%ld", (long) t_agent_called);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Agent-Answered-Time", "%ld", (long) t_agent_answered);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Caller-Joined-Time", "%ld", (long) t_member_called);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-UUID", h->member_uuid);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Name", h->member_caller_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Number", h->member_caller_number);
@@ -1508,15 +1551,20 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
while(switch_channel_up(member_channel) && switch_channel_up(agent_channel) && globals.running) {
switch_yield(100000);
}
tiers_state = CC_TIER_STATE_READY;
tiers_state = CC_TIER_STATE_READY;
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) {
switch_channel_event_set_data(agent_channel, event);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", h->queue_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "bridge-agent-end");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Hangup-Cause", switch_channel_cause2str(cause));
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent", h->agent_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-System", h->agent_system);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-UUID", agent_uuid);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Agent-Called-Time", "%ld", (long) t_agent_called);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Agent-Answered-Time", "%ld", (long) t_agent_answered);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Caller-Joined-Time", "%ld", (long) t_member_called);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Bridge-Terminated-Time", "%ld", (long) switch_epoch_time_now(NULL));
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-UUID", h->member_uuid);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Name", h->member_caller_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Number", h->member_caller_number);
@@ -1542,23 +1590,25 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
switch_channel_event_set_data(member_channel, event);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", h->queue_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "member-queue-end");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Hangup-Cause", switch_channel_cause2str(cause));
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Cause", "Terminated");
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Agent-Answer-Time", "%ld", (long) (t_agent_answered - t_agent_called));
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Wait-Time", "%ld", (long) (t_agent_answered - t_member_called));
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Talk-Time", "%ld", (long) (switch_epoch_time_now(NULL) - t_agent_answered));
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Total-Time", "%ld", (long) (switch_epoch_time_now(NULL) - t_member_called));
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent", h->agent_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-System", h->agent_system);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-UUID", agent_uuid);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Agent-Called-Time", "%ld", (long) t_agent_called);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Agent-Answered-Time", "%ld", (long) t_agent_answered);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Caller-Leaving-Time", "%ld", (long) switch_epoch_time_now(NULL));
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Caller-Joined-Time", "%ld", (long) t_member_called);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-UUID", h->member_uuid);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Name",
switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_name")));
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Number",
switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_number")));
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Name", h->member_caller_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Number", h->member_caller_number);
switch_event_fire(&event);
}
} else {
int delay_next_agent_call = 0;
/* Agent didn't answer or originate failed */
int delay_next_agent_call = 0;
sql = switch_mprintf("UPDATE members SET state = '%q', serving_agent = '', serving_system = ''"
" WHERE serving_agent = '%q' AND serving_system = '%q' AND uuid = '%q' AND system = 'single_box'",
cc_member_state2str(CC_MEMBER_STATE_WAITING),
@@ -1566,33 +1616,25 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
cc_execute_sql(NULL, sql, NULL);
switch_safe_free(sql);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Agent %s Origination Canceled : %s\n",h->agent_name, switch_channel_cause2str(cause));
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Agent %s Origination Canceled : %s\n", h->agent_name, switch_channel_cause2str(cause));
switch (cause) {
case SWITCH_CAUSE_USER_NOT_REGISTERED: /* When we are calling a unregistred device */
case SWITCH_CAUSE_USER_BUSY: /* Could be the phone is in Do Not Disturb */
delay_next_agent_call = (h->busy_delay_time > delay_next_agent_call?h->busy_delay_time:delay_next_agent_call);
break;
case SWITCH_CAUSE_CALL_REJECTED: /* User could have press the reject call on their phone */
delay_next_agent_call = (h->reject_delay_time > delay_next_agent_call?h->reject_delay_time:delay_next_agent_call);
break;
default:
break;
}
switch (cause) {
case SWITCH_CAUSE_USER_NOT_REGISTERED: /* When we are calling a unregistred device */
case SWITCH_CAUSE_USER_BUSY: /* Could be the phone is in Do Not Disturb */
case SWITCH_CAUSE_CALL_REJECTED: /* User could have press the reject call on their phone */
/* When we hang-up agents that did not answer in ring-all strategy */
case SWITCH_CAUSE_ORIGINATOR_CANCEL:
if (delay_next_agent_call > 0) {
char ready_epoch[64];
switch_snprintf(ready_epoch, sizeof(ready_epoch), "%" SWITCH_TIME_T_FMT, switch_epoch_time_now(NULL) + delay_next_agent_call); /* Make the time configurable */
cc_agent_update("ready_time", ready_epoch , h->agent_name);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Agent %s Sleeping for %d secondes\n", h->agent_name, delay_next_agent_call);
}
break;
/* Busy: Do Not Disturb, Circuit congestion */
case SWITCH_CAUSE_NORMAL_CIRCUIT_CONGESTION:
case SWITCH_CAUSE_USER_BUSY:
delay_next_agent_call = (h->busy_delay_time > delay_next_agent_call? h->busy_delay_time : delay_next_agent_call);
break;
/* Reject: User rejected the call */
case SWITCH_CAUSE_CALL_REJECTED:
delay_next_agent_call = (h->reject_delay_time > delay_next_agent_call? h->reject_delay_time : delay_next_agent_call);
break;
/* No answer: Destination does not answer for some other reason */
default:
delay_next_agent_call = (h->no_answer_delay_time > delay_next_agent_call? h->no_answer_delay_time : delay_next_agent_call);
tiers_state = CC_TIER_STATE_NO_ANSWER;
/* Update Agent NO Answer count */
@@ -1607,6 +1649,28 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa
h->agent_name, h->max_no_answer);
cc_agent_update("status", cc_agent_status2str(CC_AGENT_STATUS_ON_BREAK), h->agent_name);
}
break;
}
/* Put agent to sleep for some time if necessary */
if (delay_next_agent_call > 0) {
char ready_epoch[64];
switch_snprintf(ready_epoch, sizeof(ready_epoch), "%" SWITCH_TIME_T_FMT, switch_epoch_time_now(NULL) + delay_next_agent_call);
cc_agent_update("ready_time", ready_epoch , h->agent_name);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Agent %s sleeping for %d seconds\n", h->agent_name, delay_next_agent_call);
}
/* Fire up event when contact agent fails */
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", h->queue_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "bridge-agent-fail");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Hangup-Cause", switch_channel_cause2str(cause));
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent", h->agent_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Agent-System", h->agent_system);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-UUID", h->member_uuid);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Name", h->member_caller_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Number", h->member_caller_number);
switch_event_fire(&event);
}
}
@@ -1670,14 +1734,14 @@ static int agents_callback(void *pArg, int argc, char **argv, char **columnNames
char *sql = NULL;
char res[256];
char *agent_status = argv[2];
char *agent_tier_state = argv[8];
char *agent_last_bridge_end = argv[9];
char *agent_wrap_up_time = argv[10];
char *agent_state = argv[11];
char *agent_ready_time = argv[12];
char *agent_tier_level = argv[13];
char *agent_type = argv[14];
char *agent_uuid = argv[15];
char *agent_tier_state = argv[9];
char *agent_last_bridge_end = argv[10];
char *agent_wrap_up_time = argv[11];
char *agent_state = argv[12];
char *agent_ready_time = argv[13];
char *agent_tier_level = argv[14];
char *agent_type = argv[15];
char *agent_uuid = argv[16];
switch_bool_t contact_agent = SWITCH_TRUE;
@@ -1787,6 +1851,7 @@ static int agents_callback(void *pArg, int argc, char **argv, char **columnNames
h->max_no_answer = atoi(argv[5]);
h->reject_delay_time = atoi(argv[6]);
h->busy_delay_time = atoi(argv[7]);
h->no_answer_delay_time = atoi(argv[8]);
cc_agent_update("state", cc_agent_state2str(CC_AGENT_STATE_RECEIVING), h->agent_name);
@@ -1895,13 +1960,13 @@ static int members_callback(void *pArg, int argc, char **argv, char **columnName
switch_safe_free(sql);
sql_order_by = switch_mprintf("level, position");
} else if(!strcasecmp(queue_strategy, "sequentially-by-agent-order")) {
sql_order_by = switch_mprintf("level, position");
sql_order_by = switch_mprintf("level, position, agents.last_offered_call"); /* Default to last_offered_call, let add new strategy if needing it differently */
} else {
/* If the strategy doesn't exist, just fallback to the following */
sql_order_by = switch_mprintf("level, position");
sql_order_by = switch_mprintf("level, position, agents.last_offered_call");
}
sql = switch_mprintf("SELECT system, name, status, contact, no_answer_count, max_no_answer, reject_delay_time, busy_delay_time,tiers.state, agents.last_bridge_end, agents.wrap_up_time, agents.state, agents.ready_time, tiers.level, agents.type, agents.uuid FROM agents LEFT JOIN tiers ON (agents.name = tiers.agent)"
sql = switch_mprintf("SELECT system, name, status, contact, no_answer_count, max_no_answer, reject_delay_time, busy_delay_time, no_answer_delay_time, tiers.state, agents.last_bridge_end, agents.wrap_up_time, agents.state, agents.ready_time, tiers.level, agents.type, agents.uuid FROM agents LEFT JOIN tiers ON (agents.name = tiers.agent)"
" WHERE tiers.queue = '%q'"
" AND (agents.status = '%q' OR agents.status = '%q' OR agents.status = '%q')"
" ORDER BY %q",
@@ -2045,7 +2110,7 @@ void *SWITCH_THREAD_FUNC cc_member_thread_run(switch_thread_t *thread, void *obj
switch_channel_set_flag_value(member_channel, CF_BREAK, 2);
}
/* Will drop the caller if no agent was found for more than X secondes */
/* Will drop the caller if no agent was found for more than X seconds */
if (queue->max_wait_time_with_no_agent > 0 && m->t_member_called < queue->last_agent_exist_check - queue->max_wait_time_with_no_agent_time_reached &&
queue->last_agent_exist_check - queue->last_agent_exist >= queue->max_wait_time_with_no_agent) {
m->member_cancel_reason = CC_MEMBER_CANCEL_REASON_NO_AGENT_TIMEOUT;
@@ -2301,52 +2366,63 @@ SWITCH_STANDARD_APP(callcenter_function)
h->running = 0;
}
/* Hangup any agents been callback */
if (!switch_channel_up(member_channel)) { /* If channel is still up, it mean that the member didn't hangup, so we should leave the agent alone */
switch_core_session_hupall_matching_var("cc_member_uuid", member_uuid, SWITCH_CAUSE_ORIGINATOR_CANCEL);
/* Check if we were removed be cause FS Core(BREAK) asked us too */
if (h->member_cancel_reason == CC_MEMBER_CANCEL_REASON_NONE && !switch_channel_get_variable(member_channel, "cc_agent_uuid")) {
h->member_cancel_reason = CC_MEMBER_CANCEL_REASON_BREAK_OUT;
}
/* Canceled for some reason */
if (!switch_channel_up(member_channel) || h->member_cancel_reason != CC_MEMBER_CANCEL_REASON_NONE) {
/* Update member state */
sql = switch_mprintf("UPDATE members SET state = '%q', uuid = '', abandoned_epoch = '%ld' WHERE system = 'single_box' AND uuid = '%q'",
cc_member_state2str(CC_MEMBER_STATE_ABANDONED), (long) switch_epoch_time_now(NULL), member_uuid);
cc_execute_sql(NULL, sql, NULL);
switch_safe_free(sql);
/* Generate an Event and update some channel variable */
/* Hangup any callback agents */
switch_core_session_hupall_matching_var("cc_member_uuid", member_uuid, SWITCH_CAUSE_ORIGINATOR_CANCEL);
/* Generate an event */
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) {
switch_channel_event_set_data(member_channel, event);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", queue_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "member-queue-end");
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Wait-Time", "%ld", (long) (switch_epoch_time_now(NULL) - t_member_called));
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Member \"%s\" <%s> exit queue %s due to %s\n",
switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_name")),
switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_number")),
queue_name, cc_member_cancel_reason2str(h->member_cancel_reason));
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Cause", cc_member_cancel_reason2str(h->member_cancel_reason));
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Caller-Leaving-Time", "%ld", (long) switch_epoch_time_now(NULL));
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "CC-Caller-Joined-Time", "%ld", (long) t_member_called);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Cause", "Cancel");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Cancel-Reason", cc_member_cancel_reason2str(h->member_cancel_reason));
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-UUID", member_uuid);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Name", switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_name")));
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Caller-CID-Number", switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_number")));
switch_event_fire(&event);
}
/* for xml_cdr needs */
/* Update some channel variables for xml_cdr needs */
switch_channel_set_variable_printf(member_channel, "cc_queue_canceled_epoch", "%ld", (long) switch_epoch_time_now(NULL));
switch_channel_set_variable_printf(member_channel, "cc_cause", "%s", cc_member_cancel_reason2str(h->member_cancel_reason));
switch_channel_set_variable_printf(member_channel, "cc_cause", "%s", "cancel");
switch_channel_set_variable_printf(member_channel, "cc_cancel_reason", "%s", cc_member_cancel_reason2str(h->member_cancel_reason));
/* Send Event with queue count */
cc_queue_count(queue_name);
/* Print some debug log information */
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Member \"%s\" <%s> exit queue %s due to %s\n",
switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_name")),
switch_str_nil(switch_channel_get_variable(member_channel, "caller_id_number")),
queue_name, cc_member_cancel_reason2str(h->member_cancel_reason));
} else {
switch_channel_set_variable_printf(member_channel, "cc_cause", "%s", "answered");
/* Update member state */
sql = switch_mprintf("UPDATE members SET state = '%q', bridge_epoch = '%ld' WHERE system = 'single_box' AND uuid = '%q'",
cc_member_state2str(CC_MEMBER_STATE_ANSWERED), (long) switch_epoch_time_now(NULL), member_uuid);
cc_execute_sql(NULL, sql, NULL);
switch_safe_free(sql);
/* Send Event with queue count */
cc_queue_count(queue_name);
/* Update some channel variables for xml_cdr needs */
switch_channel_set_variable_printf(member_channel, "cc_cause", "%s", "answered");
}
/* Send Event with queue count */
cc_queue_count(queue_name);
end:
return;
@@ -2394,18 +2470,26 @@ static int list_result_callback(void *pArg, int argc, char **argv, char **column
"callcenter_config agent set ready_time [agent_name] [wait till epoch] | "\
"callcenter_config agent set reject_delay_time [agent_name] [wait second] | "\
"callcenter_config agent set busy_delay_time [agent_name] [wait second] | "\
"callcenter_config agent set no_answer_delay_time [agent_name] [wait second] | "\
"callcenter_config agent get status [agent_name] | " \
"callcenter_config agent list | " \
"callcenter_config tier add [queue_name] [agent_name] [level] [position] | " \
"callcenter_config tier set state [queue_name] [agent_name] [state] | " \
"callcenter_config tier set level [queue_name] [agent_name] [level] | " \
"callcenter_config tier set position [queue_name] [agent_name] [position] | " \
"callcenter_config tier del [queue_name] [agent_name] | " \
"callcenter_config tier list | " \
"callcenter_config queue load [queue_name] | " \
"callcenter_config queue unload [queue_name] | " \
"callcenter_config queue reload [queue_name] | " \
"callcenter_config tier list [queue_name] | " \
"callcenter_config queue list [queue_name] | " \
"callcenter_config queue count [queue_name]"
"callcenter_config queue list | " \
"callcenter_config queue list agents [queue_name] [status] | " \
"callcenter_config queue list members [queue_name] | " \
"callcenter_config queue list tiers [queue_name] | " \
"callcenter_config queue count | " \
"callcenter_config queue count agents [queue_name] [status] | " \
"callcenter_config queue count members [queue_name] | " \
"callcenter_config queue count tiers [queue_name]"
SWITCH_STANDARD_API(cc_config_api_function)
{
@@ -2513,6 +2597,7 @@ SWITCH_STANDARD_API(cc_config_api_function)
}
}
} else if (action && !strcasecmp(action, "get")) {
if (argc-initial_argc < 2) {
stream->write_function(stream, "%s", "-ERR Invalid!\n");
@@ -2538,6 +2623,7 @@ SWITCH_STANDARD_API(cc_config_api_function)
}
}
} else if (action && !strcasecmp(action, "list")) {
struct list_result cbt;
cbt.row_process = 0;
@@ -2616,6 +2702,7 @@ SWITCH_STANDARD_API(cc_config_api_function)
goto done;
}
}
} else if (action && !strcasecmp(action, "del")) {
if (argc-initial_argc < 2) {
stream->write_function(stream, "%s", "-ERR Invalid!\n");
@@ -2635,19 +2722,13 @@ SWITCH_STANDARD_API(cc_config_api_function)
}
} else if (action && !strcasecmp(action, "list")) {
if (argc-initial_argc < 1) {
stream->write_function(stream, "%s", "-ERR Invalid!\n");
goto done;
} else {
const char *queue = argv[0 + initial_argc];
struct list_result cbt;
cbt.row_process = 0;
cbt.stream = stream;
sql = switch_mprintf("SELECT * FROM tiers WHERE queue = '%q' ORDER BY level, position", queue);
cc_execute_sql_callback(NULL /* queue */, NULL /* mutex */, sql, list_result_callback, &cbt /* Call back variables */);
switch_safe_free(sql);
stream->write_function(stream, "%s", "+OK\n");
}
struct list_result cbt;
cbt.row_process = 0;
cbt.stream = stream;
sql = switch_mprintf("SELECT * FROM tiers ORDER BY level, position");
cc_execute_sql_callback(NULL /* queue */, NULL /* mutex */, sql, list_result_callback, &cbt /* Call back variables */);
switch_safe_free(sql);
stream->write_function(stream, "%s", "+OK\n");
}
} else if (section && !strcasecmp(section, "queue")) {
if (action && !strcasecmp(action, "load")) {
@@ -2664,6 +2745,7 @@ SWITCH_STANDARD_API(cc_config_api_function)
stream->write_function(stream, "%s", "-ERR Invalid Queue not found!\n");
}
}
} else if (action && !strcasecmp(action, "unload")) {
if (argc-initial_argc < 1) {
stream->write_function(stream, "%s", "-ERR Invalid!\n");
@@ -2674,6 +2756,7 @@ SWITCH_STANDARD_API(cc_config_api_function)
stream->write_function(stream, "%s", "+OK\n");
}
} else if (action && !strcasecmp(action, "reload")) {
if (argc-initial_argc < 1) {
stream->write_function(stream, "%s", "-ERR Invalid!\n");
@@ -2689,7 +2772,9 @@ SWITCH_STANDARD_API(cc_config_api_function)
stream->write_function(stream, "%s", "-ERR Invalid Queue not found!\n");
}
}
} else if (action && !strcasecmp(action, "list")) {
/* queue list */
if (argc-initial_argc < 1) {
switch_hash_index_t *hi;
stream->write_function(stream, "%s", "name|strategy|moh_sound|time_base_score|tier_rules_apply|tier_rule_wait_second|tier_rule_wait_multiply_level|tier_rule_no_agent_no_wait|discard_abandoned_after|abandoned_resume_allowed|max_wait_time|max_wait_time_with_no_agent|max_wait_time_with_no_agent_time_reached|record_template\n");
@@ -2708,35 +2793,81 @@ SWITCH_STANDARD_API(cc_config_api_function)
stream->write_function(stream, "%s", "+OK\n");
goto done;
} else {
const char *queue_name = argv[0 + initial_argc];
const char *sub_action = argv[0 + initial_argc];
const char *queue_name = argv[1 + initial_argc];
const char *status = NULL;
struct list_result cbt;
/* queue list agents */
if (sub_action && !strcasecmp(sub_action, "agents")) {
if (argc-initial_argc > 2) {
status = argv[2 + initial_argc];
}
if (status) {
sql = switch_mprintf("SELECT agents.* FROM agents,tiers WHERE tiers.agent = agents.name AND tiers.queue = '%q' AND agents.status = '%q'", queue_name, status);
} else {
sql = switch_mprintf("SELECT agents.* FROM agents,tiers WHERE tiers.agent = agents.name AND tiers.queue = '%q'", queue_name);
}
/* queue list members */
} else if (sub_action && !strcasecmp(sub_action, "members")) {
sql = switch_mprintf("SELECT * FROM members WHERE queue = '%q';", queue_name);
/* queue list tiers */
} else if (sub_action && !strcasecmp(sub_action, "tiers")) {
sql = switch_mprintf("SELECT * FROM tiers WHERE queue = '%q';", queue_name);
} else {
stream->write_function(stream, "%s", "-ERR Invalid!\n");
goto done;
}
cbt.row_process = 0;
cbt.stream = stream;
sql = switch_mprintf("SELECT * FROM members WHERE queue = '%q'", queue_name);
cc_execute_sql_callback(NULL /* queue */, NULL /* mutex */, sql, list_result_callback, &cbt /* Call back variables */);
switch_safe_free(sql);
stream->write_function(stream, "%s", "+OK\n");
}
} else if (action && !strcasecmp(action, "count")) {
/* queue count */
if (argc-initial_argc < 1) {
stream->write_function(stream, "%s", "-ERR Invalid!\n");
switch_hash_index_t *hi;
int queue_count = 0;
switch_mutex_lock(globals.mutex);
for (hi = switch_hash_first(NULL, globals.queue_hash); hi; hi = switch_hash_next(hi)) {
queue_count++;
}
switch_mutex_unlock(globals.mutex);
stream->write_function(stream, "%d\n", queue_count);
goto done;
} else {
const char *queue_name = argv[0 + initial_argc];
const char *sub_action = argv[0 + initial_argc];
const char *queue_name = argv[1 + initial_argc];
const char *status = NULL;
char res[256] = "";
switch_event_t *event;
/* Check to see if agent already exist */
sql = switch_mprintf("SELECT count(*) FROM members WHERE queue = '%q'", queue_name);
/* queue count agents */
if (sub_action && !strcasecmp(sub_action, "agents")) {
if (argc-initial_argc > 2) {
status = argv[2 + initial_argc];
}
if (status) {
sql = switch_mprintf("SELECT count(*) FROM agents,tiers WHERE tiers.agent = agents.name AND tiers.queue = '%q' AND agents.status = '%q'", queue_name, status);
} else {
sql = switch_mprintf("SELECT count(*) FROM agents,tiers WHERE tiers.agent = agents.name AND tiers.queue = '%q'", queue_name);
}
/* queue count members */
} else if (sub_action && !strcasecmp(sub_action, "members")) {
sql = switch_mprintf("SELECT count(*) FROM members WHERE queue = '%q';", queue_name);
/* queue count tiers */
} else if (sub_action && !strcasecmp(sub_action, "tiers")) {
sql = switch_mprintf("SELECT count(*) FROM tiers WHERE queue = '%q';", queue_name);
} else {
stream->write_function(stream, "%s", "-ERR Invalid!\n");
goto done;
}
cc_execute_sql2str(NULL, NULL, sql, res, sizeof(res));
switch_safe_free(sql);
stream->write_function(stream, "%d\n", atoi(res));
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CALLCENTER_EVENT) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Queue", queue_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Action", "members-count");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CC-Count", res);
switch_event_fire(&event);
}
}
}
}
@@ -2789,10 +2920,10 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_callcenter_load)
switch_console_set_complete("add callcenter_config agent set ready_time");
switch_console_set_complete("add callcenter_config agent set reject_delay_time");
switch_console_set_complete("add callcenter_config agent set busy_delay_time");
switch_console_set_complete("add callcenter_config agent set no_answer_delay_time");
switch_console_set_complete("add callcenter_config agent get status");
switch_console_set_complete("add callcenter_config agent list");
switch_console_set_complete("add callcenter_config tier add");
switch_console_set_complete("add callcenter_config tier del");
switch_console_set_complete("add callcenter_config tier set state");
@@ -2804,7 +2935,13 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_callcenter_load)
switch_console_set_complete("add callcenter_config queue unload");
switch_console_set_complete("add callcenter_config queue reload");
switch_console_set_complete("add callcenter_config queue list");
switch_console_set_complete("add callcenter_config queue list agents");
switch_console_set_complete("add callcenter_config queue list members");
switch_console_set_complete("add callcenter_config queue list tiers");
switch_console_set_complete("add callcenter_config queue count");
switch_console_set_complete("add callcenter_config queue count agents");
switch_console_set_complete("add callcenter_config queue count members");
switch_console_set_complete("add callcenter_config queue count tiers");
/* indicate that the module should continue to be loaded */
return SWITCH_STATUS_SUCCESS;
@@ -37,6 +37,7 @@
*/
#include <switch.h>
#define DEFAULT_AGC_LEVEL 1100
#define CONFERENCE_UUID_VARIABLE "conference_uuid"
SWITCH_MODULE_LOAD_FUNCTION(mod_conference_load);
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_conference_shutdown);
@@ -564,7 +565,10 @@ static conference_member_t *conference_member_get(conference_obj_t *conference,
member = NULL;
}
switch_thread_rwlock_rdlock(member->rwlock);
if (member) {
switch_thread_rwlock_rdlock(member->rwlock);
}
switch_mutex_unlock(conference->member_mutex);
return member;
@@ -702,6 +706,7 @@ static switch_status_t conference_add_member(conference_obj_t *conference, confe
channel = switch_core_session_get_channel(member->session);
switch_channel_set_variable_printf(channel, "conference_member_id", "%d", member->id);
switch_channel_set_variable(channel, CONFERENCE_UUID_VARIABLE, conference->uuid_str);
if (conference->count > 1) {
if (conference->moh_sound && !switch_test_flag(conference, CFLAG_WAIT_MOD)) {
@@ -4625,6 +4630,7 @@ static switch_status_t conf_api_sub_transfer(conference_obj_t *conference, switc
/* move the member from the old conference to the new one */
lock_member(member);
switch_thread_rwlock_unlock(member->rwlock);
if (conference != new_conference) {
conference_del_member(conference, member);
@@ -4660,10 +4666,6 @@ static switch_status_t conf_api_sub_transfer(conference_obj_t *conference, switc
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "transfer");
switch_event_fire(&event);
}
if (member) {
switch_thread_rwlock_unlock(member->rwlock);
}
}
if (new_conference) {
+34
View File
@@ -0,0 +1,34 @@
# LDNS=ldns-1.6.9
# BASE=../../../..
# LDNS_DIR=$(switch_srcdir)/libs/$(LDNS)
# LDNS_BUILDDIR=$(switch_builddir)/libs/$(LDNS)
# LDNSLA=$(LDNS_BUILDDIR)/libldns.la
# include $(BASE)/build/modmake.rules
# LOCAL_LIBADD=$(LDNSLA)
BASE=../../../..
LDNS=ldns-1.6.9
LDNS_DIR=$(switch_srcdir)/libs/$(LDNS)
LDNS_BUILDDIR=$(switch_builddir)/libs/$(LDNS)
LOCAL_CFLAGS=-I$(LDNS_DIR) -I$(LDNS_DIR)/include
LDNS_LA=$(LDNS_BUILDDIR)/libldns.la
LOCAL_LIBADD=$(LDNS_LA)
include $(BASE)/build/modmake.rules
$(LDNS_DIR)/Makefile.in:
$(GETLIB) $(LDNS).tar.gz
$(LDNS_BUILDDIR)/Makefile: $(LDNS_DIR)/Makefile.in
mkdir -p $(LDNS_BUILDDIR)
cd $(LDNS_BUILDDIR) && $(DEFAULT_VARS) $(LDNS_DIR)/configure $(DEFAULT_ARGS) --srcdir=$(LDNS_DIR) --disable-gost --without-ssl --disable-sha2
$(TOUCH_TARGET)
$(LDNS_LA): $(LDNS_BUILDDIR)/Makefile
cd $(LDNS_BUILDDIR) && $(MAKE)
$(TOUCH_TARGET)
-13
View File
@@ -1,13 +0,0 @@
include $(top_srcdir)/build/modmake.rulesam
MODNAME=mod_enum
UDNS_DIR=$(switch_srcdir)/libs/udns
mod_enum_la_CFLAGS = -I$(UDNS_DIR) -DHAVE_POLL $(AM_CFLAGS)
mod_LTLIBRARIES = mod_enum.la
mod_enum_la_SOURCES = mod_enum.c
mod_enum_la_SOURCES += $(UDNS_DIR)/udns_dn.c $(UDNS_DIR)/udns_dntosp.c $(UDNS_DIR)/udns_parse.c $(UDNS_DIR)/udns_misc.c
mod_enum_la_SOURCES += $(UDNS_DIR)/udns_rr_a.c $(UDNS_DIR)/udns_rr_ptr.c $(UDNS_DIR)/udns_rr_mx.c $(UDNS_DIR)/udns_rr_txt.c $(UDNS_DIR)/udns_bl.c
mod_enum_la_SOURCES += $(UDNS_DIR)/udns_rr_srv.c $(UDNS_DIR)/udns_rr_naptr.c $(UDNS_DIR)/udns_codes.c $(UDNS_DIR)/udns_resolver.c
mod_enum_la_LIBADD = $(switch_builddir)/libfreeswitch.la
mod_enum_la_LDFLAGS = -avoid-version -module -no-undefined -shared
+235 -312
View File
@@ -30,11 +30,7 @@
*/
#include <switch.h>
#include <udns.h>
#ifndef WIN32
#define closesocket close
#endif
#include <ldns/ldns.h>
SWITCH_MODULE_LOAD_FUNCTION(mod_enum_load);
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_enum_shutdown);
@@ -49,19 +45,10 @@ struct enum_record {
char *route;
int supported;
struct enum_record *next;
struct enum_record *tail;
};
typedef struct enum_record enum_record_t;
struct query {
const char *name; /* original query string */
char *number;
unsigned char dn[DNS_MAXDN];
enum dns_type qtyp; /* type of the query */
enum_record_t *results;
int errs;
};
typedef struct query enum_query_t;
struct route {
char *service;
char *regex;
@@ -70,12 +57,11 @@ struct route {
};
typedef struct route enum_route_t;
static enum dns_class qcls = DNS_C_IN;
static switch_event_node_t *NODE = NULL;
static struct {
char *root;
char *server;
char *isn_root;
enum_route_t *route_order;
switch_memory_pool_t *pool;
@@ -84,6 +70,7 @@ static struct {
} globals;
SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_root, globals.root);
SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_server, globals.server);
SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_isn_root, globals.isn_root);
static void add_route(char *service, char *regex, char *replace)
@@ -125,6 +112,8 @@ static switch_status_t load_config(void)
const char *val = switch_xml_attr_soft(param, "value");
if (!strcasecmp(var, "default-root")) {
set_global_root(val);
} else if (!strcasecmp(var, "use-server")) {
set_global_server(val);
} else if (!strcasecmp(var, "auto-reload")) {
globals.auto_reload = switch_true(val);
} else if (!strcasecmp(var, "query-timeout")) {
@@ -168,11 +157,12 @@ static switch_status_t load_config(void)
return status;
}
static char *reverse_number(char *in, char *root)
static char *reverse_number(const char *in, const char *root)
{
switch_size_t len;
char *out = NULL;
char *y, *z;
const char *y;
char *z;
if (!(in && root)) {
return NULL;
@@ -198,59 +188,33 @@ static char *reverse_number(char *in, char *root)
return out;
}
static void dnserror(enum_query_t *q, int errnum)
{
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Unable to lookup %s record for %s: %s\n",
dns_typename(q->qtyp), dns_dntosp(q->dn), dns_strerror(errnum));
q->errs++;
}
static void add_result(enum_query_t *q, int order, int preference, char *service, char *route, int supported)
static void add_result(enum_record_t **results, int order, int preference, char *service, char *route, int supported)
{
enum_record_t *new_result, *rp, *prev = NULL;
enum_record_t *new_result;
new_result = malloc(sizeof(*new_result));
switch_assert(new_result);
memset(new_result, 0, sizeof(*new_result));
memset(new_result, 0, sizeof(*new_result));
new_result->order = order;
new_result->preference = preference;
new_result->service = strdup(service);
new_result->route = strdup(route);
new_result->supported = supported;
if (!q->results) {
q->results = new_result;
return;
}
rp = q->results;
while (rp && strcasecmp(rp->service, new_result->service)) {
prev = rp;
rp = rp->next;
}
while (rp && !strcasecmp(rp->service, new_result->service) && new_result->order > rp->order) {
prev = rp;
rp = rp->next;
}
while (rp && !strcasecmp(rp->service, new_result->service) && new_result->preference > rp->preference) {
prev = rp;
rp = rp->next;
}
if (prev) {
new_result->next = rp;
prev->next = new_result;
if (!*results) {
*results = new_result;
(*results)->tail = new_result;
} else {
new_result->next = rp;
q->results = new_result;
(*results)->tail->next = new_result;
(*results)->tail = new_result;
}
}
static void free_results(enum_record_t ** results)
{
enum_record_t *fp, *rp;
@@ -265,201 +229,234 @@ static void free_results(enum_record_t ** results)
*results = NULL;
}
static void parse_rr(const struct dns_parse *p, enum_query_t *q, struct dns_rr *rr)
static ldns_rdf *ldns_rdf_new_addr_frm_str(const char *str)
{
const unsigned char *pkt = p->dnsp_pkt;
const unsigned char *end = p->dnsp_end;
const unsigned char *dptr = rr->dnsrr_dptr;
const unsigned char *dend = rr->dnsrr_dend;
unsigned char *dn = rr->dnsrr_dn;
const unsigned char *c;
char flags;
int order;
int preference;
ldns_rdf *a;
ldns_str2rdf_a(&a, str);
if (!a) {
/* maybe ip6 */
ldns_str2rdf_aaaa(&a, str);
if (!a) {
return NULL;
}
}
return a;
}
#define strip_quotes(_s) if (*_s == '"') _s++; if (end_of(_s) == '"') end_of(_s) = '\0'
static void parse_naptr(const ldns_rr *naptr, const char *number, enum_record_t **results)
{
char *str = ldns_rr2str(naptr);
char *argv[11] = { 0 };
int i, argc;
char *pack[4] = { 0 };
int packc;
char *p;
int order = 10;
int preference = 100;
char *service = NULL;
char *regex = NULL;
char *replace = NULL;
char *ptr;
int argc = 0;
char *argv[4] = { 0 };
int n;
char string_arg[3][256] = { {0} };
char *packstr;
switch (rr->dnsrr_typ) {
case DNS_T_NAPTR: /* prio weight port targetDN */
c = dptr;
c += 4; /* order, pref */
for (n = 0; n < 3; ++n) {
if (c >= dend) {
goto xperr;
} else {
c += *c + 1;
}
}
if (dns_getdn(pkt, &c, end, dn, DNS_MAXDN) <= 0 || c != dend) {
goto xperr;
}
c = dptr;
order = dns_get16(c + 0);
preference = dns_get16(c + 2);
flags = (char) dns_get16(c + 4);
c += 4;
for (n = 0; n < 3; n++) {
uint32_t len = *c++, cpylen = len;
switch_assert(string_arg[n]);
if (len > sizeof(string_arg[n]) - 1) {
cpylen = sizeof(string_arg[n]) - 1;
}
strncpy(string_arg[n], (char *) c, cpylen);
*(string_arg[n] + len) = '\0';
c += len;
}
service = string_arg[1];
if ((argc = switch_separate_string(string_arg[2], '!', argv, (sizeof(argv) / sizeof(argv[0]))))) {
regex = argv[1];
replace = argv[2];
} else {
goto xperr;
}
for (ptr = replace; ptr && *ptr; ptr++) {
if (*ptr == '\\') {
*ptr = '$';
}
}
if (flags && service && regex && replace) {
switch_regex_t *re = NULL;
int proceed = 0, ovector[30];
char substituted[1024] = "";
char rbuf[1024] = "";
char *uri;
enum_route_t *route;
int supported = 0;
switch_regex_safe_free(re);
if ((proceed = switch_regex_perform(q->number, regex, &re, ovector, sizeof(ovector) / sizeof(ovector[0])))) {
if (strchr(regex, '(')) {
switch_perform_substitution(re, proceed, replace, q->number, substituted, sizeof(substituted), ovector);
uri = substituted;
} else {
uri = replace;
}
switch_mutex_lock(MUTEX);
for (route = globals.route_order; route; route = route->next) {
if (strcasecmp(service, route->service)) {
continue;
}
switch_regex_safe_free(re);
if ((proceed = switch_regex_perform(uri, route->regex, &re, ovector, sizeof(ovector) / sizeof(ovector[0])))) {
if (strchr(route->regex, '(')) {
switch_perform_substitution(re, proceed, route->replace, uri, rbuf, sizeof(rbuf), ovector);
uri = rbuf;
} else {
uri = route->replace;
}
supported++;
add_result(q, order, preference, service, uri, supported);
}
}
if (!supported) {
add_result(q, order, preference, service, uri, 0);
}
}
switch_mutex_unlock(MUTEX);
switch_regex_safe_free(re);
}
break;
default:
break;
char *regex, *replace;
if (zstr(str)) {
return;
}
return;
for (p = str; p && *p; p++) {
if (*p == '\t') *p = ' ';
if (*p == ' ' && *(p+1) == '.') *p = '\0';
}
xperr:
argc = switch_split(str, ' ', argv);
for (i = 0; i < argc; i++) {
if (i > 0) {
strip_quotes(argv[i]);
}
}
service = argv[7];
packstr = argv[8];
if (zstr(service) || zstr(packstr)) {
goto end;
}
if (!zstr(argv[4])) {
order = atoi(argv[4]);
}
if (!zstr(argv[5])) {
preference = atoi(argv[5]);
}
if ((packc = switch_split(packstr, '!', pack))) {
regex = pack[1];
replace = pack[2];
} else {
goto end;
}
for (p = replace; p && *p; p++) {
if (*p == '\\') {
*p = '$';
}
}
if (service && regex && replace) {
switch_regex_t *re = NULL, *re2 = NULL;
int proceed = 0, ovector[30];
char substituted[1024] = "";
char rbuf[1024] = "";
char *uri;
enum_route_t *route;
int supported = 0;
if ((proceed = switch_regex_perform(number, regex, &re, ovector, sizeof(ovector) / sizeof(ovector[0])))) {
if (strchr(regex, '(')) {
switch_perform_substitution(re, proceed, replace, number, substituted, sizeof(substituted), ovector);
uri = substituted;
} else {
uri = replace;
}
switch_mutex_lock(MUTEX);
for (route = globals.route_order; route; route = route->next) {
if (strcasecmp(service, route->service)) {
continue;
}
if ((proceed = switch_regex_perform(uri, route->regex, &re2, ovector, sizeof(ovector) / sizeof(ovector[0])))) {
if (strchr(route->regex, '(')) {
switch_perform_substitution(re2, proceed, route->replace, uri, rbuf, sizeof(rbuf), ovector);
uri = rbuf;
} else {
uri = route->replace;
}
supported++;
add_result(results, order, preference, service, uri, supported);
}
switch_regex_safe_free(re2);
}
switch_mutex_unlock(MUTEX);
if (!supported) {
add_result(results, order, preference, service, uri, 0);
}
switch_regex_safe_free(re);
}
}
end:
switch_safe_free(str);
return;
}
static void dnscb(struct dns_ctx *ctx, void *result, void *data)
switch_status_t ldns_lookup(const char *number, const char *root, const char *server_name, enum_record_t **results)
{
int r = dns_status(ctx);
enum_query_t *q = data;
struct dns_parse p;
struct dns_rr rr;
unsigned nrr;
unsigned char dn[DNS_MAXDN];
const unsigned char *pkt, *cur, *end, *qdn;
if (!result) {
dnserror(q, r);
return;
ldns_resolver *res = NULL;
ldns_rdf *domain = NULL;
ldns_pkt *p = NULL;
ldns_rr_list *naptr = NULL;
ldns_status s = LDNS_STATUS_ERR;
ldns_rdf *serv_rdf;
switch_status_t status = SWITCH_STATUS_FALSE;
char *name = NULL;
if (!(name = reverse_number(number, root))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Parse Error!\n");
goto end;
}
pkt = result;
end = pkt + r;
cur = dns_payload(pkt);
dns_getdn(pkt, &cur, end, dn, sizeof(dn));
dns_initparse(&p, NULL, pkt, cur, end);
p.dnsp_qcls = 0;
p.dnsp_qtyp = 0;
qdn = dn;
nrr = 0;
while ((r = dns_nextrr(&p, &rr)) > 0) {
if (!dns_dnequal(qdn, rr.dnsrr_dn))
continue;
if ((qcls == DNS_C_ANY || qcls == rr.dnsrr_cls) && (q->qtyp == DNS_T_ANY || q->qtyp == rr.dnsrr_typ))
++nrr;
else if (rr.dnsrr_typ == DNS_T_CNAME && !nrr) {
if (dns_getdn(pkt, &rr.dnsrr_dptr, end, p.dnsp_dnbuf, sizeof(p.dnsp_dnbuf)) <= 0 || rr.dnsrr_dptr != rr.dnsrr_dend) {
r = DNS_E_PROTOCOL;
break;
} else {
qdn = p.dnsp_dnbuf;
domain = ldns_dname_new_frm_str(name);
if (!domain) {
goto end;
}
if (!zstr(server_name)) {
res = ldns_resolver_new();
switch_assert(res);
if ((serv_rdf = ldns_rdf_new_addr_frm_str(server_name))) {
s = ldns_resolver_push_nameserver(res, serv_rdf);
ldns_rdf_deep_free(serv_rdf);
}
} else {
/* create a new resolver from /etc/resolv.conf */
s = ldns_resolver_new_frm_file(&res, NULL);
}
if (s != LDNS_STATUS_OK) {
goto end;
}
/* use the resolver to send a query for the naptr
* records of the domain given on the command line
*/
if ((p = ldns_resolver_query(res,
domain,
LDNS_RR_TYPE_NAPTR,
LDNS_RR_CLASS_IN,
LDNS_RD))) {
/* retrieve the NAPTR records from the answer section of that
* packet
*/
if ((naptr = ldns_pkt_rr_list_by_type(p, LDNS_RR_TYPE_NAPTR, LDNS_SECTION_ANSWER))) {
size_t i;
ldns_rr_list_sort(naptr);
for (i = 0; i < ldns_rr_list_rr_count(naptr); i++) {
parse_naptr(ldns_rr_list_rr(naptr, i), number, results);
}
//ldns_rr_list_print(stdout, naptr);
ldns_rr_list_deep_free(naptr);
status = SWITCH_STATUS_SUCCESS;
}
}
if (!r && !nrr)
r = DNS_E_NODATA;
if (r < 0) {
dnserror(q, r);
free(result);
return;
end:
switch_safe_free(name);
if (domain) {
ldns_rdf_deep_free(domain);
}
dns_rewind(&p, NULL);
p.dnsp_qtyp = q->qtyp;
p.dnsp_qcls = qcls;
while (dns_nextrr(&p, &rr)) {
parse_rr(&p, q, &rr);
if (p) {
ldns_pkt_free(p);
}
free(result);
if (res) {
ldns_resolver_deep_free(res);
}
return status;
}
static switch_status_t enum_lookup(char *root, char *in, enum_record_t ** results)
static switch_status_t enum_lookup(char *root, char *in, enum_record_t **results)
{
switch_status_t sstatus = SWITCH_STATUS_SUCCESS;
char *name = NULL;
enum_query_t query = { 0 };
enum dns_type l_qtyp = DNS_T_NAPTR;
int i = 0, abs = 0, j = 0;
dns_socket fd = (dns_socket) - 1;
fd_set fds;
struct timeval tv = { 0 };
time_t now = 0;
struct dns_ctx *nctx = NULL;
char *num, *mnum = NULL, *mroot = NULL, *p;
char *mnum = NULL, *mroot = NULL, *p;
char *server = NULL;
*results = NULL;
@@ -475,87 +472,14 @@ static switch_status_t enum_lookup(char *root, char *in, enum_record_t ** result
root = globals.root;
}
num = mnum;
if (!(name = reverse_number(num, root))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Parse Error!\n");
sstatus = SWITCH_STATUS_FALSE;
goto done;
#if 0
if (!(server = switch_core_get_variable("enum-server"))) {
server = globals.server;
}
if (!(nctx = dns_new(NULL))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Memory Error!\n");
sstatus = SWITCH_STATUS_MEMERR;
goto done;
}
fd = dns_open(nctx);
if (fd < 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FD Error!\n");
sstatus = SWITCH_STATUS_FALSE;
goto done;
}
dns_ptodn(name, (unsigned int) strlen(name), query.dn, sizeof(query.dn), &abs);
query.name = name;
query.number = num;
query.qtyp = l_qtyp;
if (abs) {
abs = DNS_NOSRCH;
}
if (!dns_submit_dn(nctx, query.dn, qcls, l_qtyp, abs, 0, dnscb, &query)) {
dnserror(&query, dns_status(nctx));
}
FD_ZERO(&fds);
now = 0;
while ((i = dns_timeouts(nctx, 1, now)) > 0) {
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4389 4127)
#endif
FD_SET(fd, &fds);
#ifdef _MSC_VER
#pragma warning(pop)
#endif
j += i;
ldns_lookup(mnum, root, server, results);
if (j > globals.timeout || query.results || query.errs) {
break;
}
tv.tv_sec = i;
tv.tv_usec = 0;
i = select((int) (fd + 1), &fds, 0, 0, &tv);
now = switch_epoch_time_now(NULL);
if (i > 0) {
dns_ioevent(nctx, now);
}
}
if (!query.results) {
sstatus = SWITCH_STATUS_FALSE;
}
*results = query.results;
query.results = NULL;
done:
if (fd > -1) {
closesocket(fd);
fd = (dns_socket) - 1;
}
if (nctx) {
dns_free(nctx);
}
switch_safe_free(name);
switch_safe_free(mnum);
switch_safe_free(mroot);
@@ -623,15 +547,17 @@ SWITCH_STANDARD_APP(enum_app_function)
dest = argv[0];
root = argv[1];
if (enum_lookup(root, dest, &results) == SWITCH_STATUS_SUCCESS) {
switch_event_header_t *hi;
if ((hi = switch_channel_variable_first(channel))) {
for (; hi; hi = hi->next) {
switch_event_t *vars;
if (switch_channel_get_variables(channel, &vars) == SWITCH_STATUS_SUCCESS) {
switch_event_header_t *hi;
for (hi = vars->headers; hi; hi = hi->next) {
char *vvar = hi->name;
if (vvar && !strncmp(vvar, "enum_", 5)) {
switch_channel_set_variable(channel, (char *) vvar, NULL);
}
}
switch_channel_variable_last(channel);
switch_event_destroy(&vars);
}
for (rp = results; rp; rp = rp->next) {
@@ -823,9 +749,6 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_enum_load)
return SWITCH_STATUS_TERM;
}
if (dns_init(0) < 0) {
return SWITCH_STATUS_FALSE;
}
memset(&globals, 0, sizeof(globals));
do_load();
+5
View File
@@ -0,0 +1,5 @@
BASE=../../../..
LOCAL_OBJS += load.o
include $(BASE)/build/modmake.rules
+173
View File
@@ -0,0 +1,173 @@
/* load.c
Free software by Richard W.E. Furse. Do with as you will. No
warranty. */
/*****************************************************************************/
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*****************************************************************************/
#include "ladspa.h"
#include "utils.h"
#include "inttypes.h"
#include "switch.h"
/*****************************************************************************/
/* This function provides a wrapping of dlopen(). When the filename is
not an absolute path (i.e. does not begin with / character), this
routine will search the LADSPA_PATH for the file. */
static void *dlopenLADSPA(const char *pcFilename, int iFlag)
{
char *pcBuffer;
const char *pcEnd;
const char *pcLADSPAPath;
const char *pcStart;
int iEndsInSO;
int iNeedSlash;
size_t iFilenameLength;
void *pvResult;
iFilenameLength = strlen(pcFilename);
pvResult = NULL;
if (pcFilename[0] == '/') {
/* The filename is absolute. Assume the user knows what he/she is
doing and simply dlopen() it. */
pvResult = dlopen(pcFilename, iFlag);
if (pvResult != NULL)
return pvResult;
} else {
/* If the filename is not absolute then we wish to check along the
LADSPA_PATH path to see if we can find the file there. We do
NOT call dlopen() directly as this would find plugins on the
LD_LIBRARY_PATH, whereas the LADSPA_PATH is the correct place
to search. */
pcLADSPAPath = getenv("LADSPA_PATH");
if (pcLADSPAPath) {
pcStart = pcLADSPAPath;
while (*pcStart != '\0') {
pcEnd = pcStart;
while (*pcEnd != ':' && *pcEnd != '\0')
pcEnd++;
pcBuffer = malloc(iFilenameLength + 2 + (pcEnd - pcStart));
if (pcEnd > pcStart)
strncpy(pcBuffer, pcStart, pcEnd - pcStart);
iNeedSlash = 0;
if (pcEnd > pcStart)
if (*(pcEnd - 1) != '/') {
iNeedSlash = 1;
pcBuffer[pcEnd - pcStart] = '/';
}
strcpy(pcBuffer + iNeedSlash + (pcEnd - pcStart), pcFilename);
pvResult = dlopen(pcBuffer, iFlag);
free(pcBuffer);
if (pvResult != NULL)
return pvResult;
pcStart = pcEnd;
if (*pcStart == ':')
pcStart++;
}
}
}
/* As a last ditch effort, check if filename does not end with
".so". In this case, add this suffix and recurse. */
iEndsInSO = 0;
if (iFilenameLength > 3)
iEndsInSO = (strcmp(pcFilename + iFilenameLength - 3, ".so") == 0);
if (!iEndsInSO) {
pcBuffer = malloc(iFilenameLength + 4);
strcpy(pcBuffer, pcFilename);
strcat(pcBuffer, ".so");
pvResult = dlopenLADSPA(pcBuffer, iFlag);
free(pcBuffer);
}
if (pvResult != NULL)
return pvResult;
/* If nothing has worked, then at least we can make sure we set the
correct error message - and this should correspond to a call to
dlopen() with the actual filename requested. The dlopen() manual
page does not specify whether the first or last error message
will be kept when multiple calls are made to dlopen(). We've
covered the former case - now we can handle the latter by calling
dlopen() again here. */
return dlopen(pcFilename, iFlag);
}
/*****************************************************************************/
void *loadLADSPAPluginLibrary(const char *pcPluginFilename)
{
void *pvPluginHandle;
pvPluginHandle = dlopenLADSPA(pcPluginFilename, RTLD_NOW);
if (!pvPluginHandle) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to load plugin \"%s\": %s\n", pcPluginFilename, dlerror());
}
return pvPluginHandle;
}
/*****************************************************************************/
void unloadLADSPAPluginLibrary(void *pvLADSPAPluginLibrary)
{
dlclose(pvLADSPAPluginLibrary);
}
/*****************************************************************************/
const LADSPA_Descriptor *findLADSPAPluginDescriptor(void *pvLADSPAPluginLibrary, const char *pcPluginLibraryFilename, const char *pcPluginLabel)
{
const LADSPA_Descriptor *psDescriptor;
LADSPA_Descriptor_Function pfDescriptorFunction;
unsigned long lPluginIndex;
dlerror();
pfDescriptorFunction = (LADSPA_Descriptor_Function) (intptr_t)dlsym(pvLADSPAPluginLibrary, "ladspa_descriptor");
if (!pfDescriptorFunction) {
const char *pcError = dlerror();
if (pcError) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
"Unable to find ladspa_descriptor() function in plugin "
"library file \"%s\": %s.\n" "Are you sure this is a LADSPA plugin file?\n", pcPluginLibraryFilename, pcError);
return NULL;
}
}
for (lPluginIndex = 0;; lPluginIndex++) {
psDescriptor = pfDescriptorFunction(lPluginIndex);
if (psDescriptor == NULL) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
"Unable to find label \"%s\" in plugin library file \"%s\".\n", pcPluginLabel, pcPluginLibraryFilename);
return NULL;
}
if (strcmp(psDescriptor->Label, pcPluginLabel) == 0)
return psDescriptor;
}
}
/*****************************************************************************/
/* EOF */
@@ -0,0 +1,674 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
*
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II <anthm@freeswitch.org>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Anthony Minessale II <anthm@freeswitch.org>
*
* mod_ladspa.c -- LADSPA
*
*/
#include <switch.h>
#include "ladspa.h"
#include "utils.h"
/* Prototypes */
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_ladspa_shutdown);
SWITCH_MODULE_RUNTIME_FUNCTION(mod_ladspa_runtime);
SWITCH_MODULE_LOAD_FUNCTION(mod_ladspa_load);
/* SWITCH_MODULE_DEFINITION(name, load, shutdown, runtime)
* Defines a switch_loadable_module_function_table_t and a static const char[] modname
*/
SWITCH_MODULE_DEFINITION(mod_ladspa, mod_ladspa_load, mod_ladspa_shutdown, NULL);
#define MAX_INDEX 256
typedef struct {
switch_core_session_t *session;
char *plugin_name;
char *label_name;
void *library_handle;
const LADSPA_Descriptor *ldesc;
LADSPA_Handle handle;
LADSPA_Data config[MAX_INDEX];
int num_idx;
char *str_config[MAX_INDEX];
int str_idx;
uint8_t has_config[MAX_INDEX];
int skip;
LADSPA_Data in_buf[SWITCH_RECOMMENDED_BUFFER_SIZE];
LADSPA_Data file_buf[SWITCH_RECOMMENDED_BUFFER_SIZE];
LADSPA_Data out_buf[SWITCH_RECOMMENDED_BUFFER_SIZE];
LADSPA_Data out_ports[MAX_INDEX];
switch_file_handle_t fh;
} switch_ladspa_t;
int check_range(const LADSPA_Descriptor *ldesc, int i, LADSPA_Data val)
{
if (ldesc->PortRangeHints[i].LowerBound && ldesc->PortRangeHints[i].UpperBound &&
(val < ldesc->PortRangeHints[i].LowerBound || val > ldesc->PortRangeHints[i].UpperBound)) {
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_ERROR, "Param %f out of bounds %f-%f\n",
val, ldesc->PortRangeHints[i].LowerBound, ldesc->PortRangeHints[i].UpperBound);
return 0;
}
return 1;
}
int find_default(const LADSPA_Descriptor *ldesc, int i, LADSPA_Data *ptr)
{
LADSPA_Data dftval = 0;
int fail = 0;
LADSPA_PortRangeHintDescriptor port_hint = ldesc->PortRangeHints[i].HintDescriptor;
switch (port_hint & LADSPA_HINT_DEFAULT_MASK) {
case LADSPA_HINT_DEFAULT_NONE:
break;
case LADSPA_HINT_DEFAULT_MINIMUM:
dftval = ldesc->PortRangeHints[i].LowerBound;
break;
case LADSPA_HINT_DEFAULT_LOW:
if (LADSPA_IS_HINT_LOGARITHMIC(port_hint)) {
dftval = exp(log(ldesc->PortRangeHints[i].LowerBound)
* 0.75 + log(ldesc->PortRangeHints[i].UpperBound)
* 0.25);
} else {
dftval = (ldesc->PortRangeHints[i].LowerBound * 0.75 + ldesc->PortRangeHints[i].UpperBound * 0.25);
}
break;
case LADSPA_HINT_DEFAULT_MIDDLE:
if (LADSPA_IS_HINT_LOGARITHMIC(port_hint)) {
dftval = sqrt(ldesc->PortRangeHints[i].LowerBound * ldesc->PortRangeHints[i].UpperBound);
} else {
dftval = 0.5 * (ldesc->PortRangeHints[i].LowerBound + ldesc->PortRangeHints[i].UpperBound);
}
break;
case LADSPA_HINT_DEFAULT_HIGH:
if (LADSPA_IS_HINT_LOGARITHMIC(port_hint)) {
dftval = exp(log(ldesc->PortRangeHints[i].LowerBound)
* 0.25 + log(ldesc->PortRangeHints[i].UpperBound)
* 0.75);
} else {
dftval = (ldesc->PortRangeHints[i].LowerBound * 0.25 + ldesc->PortRangeHints[i].UpperBound * 0.75);
}
break;
case LADSPA_HINT_DEFAULT_MAXIMUM:
dftval = ldesc->PortRangeHints[i].UpperBound;
break;
case LADSPA_HINT_DEFAULT_0:
dftval = 0;
break;
case LADSPA_HINT_DEFAULT_1:
dftval = 1;
break;
case LADSPA_HINT_DEFAULT_100:
dftval = 100;
break;
case LADSPA_HINT_DEFAULT_440:
dftval = 440;
break;
default:
fail = 1;
break;
}
if (!fail) {
*ptr = dftval;
}
return !fail;
}
static void dump_info(const LADSPA_Descriptor *ldesc)
{
int i = 0;
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Plugin Name: \"%s\"\n", ldesc->Name);
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Plugin Label: \"%s\"\n", ldesc->Label);
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Plugin Unique ID: %lu\n", ldesc->UniqueID);
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Maker: \"%s\"\n", ldesc->Maker);
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Copyright: \"%s\"\n", ldesc->Copyright);
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Must Run Real-Time: ");
if (LADSPA_IS_REALTIME(ldesc->Properties))
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Yes\n");
else
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "No\n");
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Has activate() Function: ");
if (ldesc->activate != NULL)
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Yes\n");
else
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "No\n");
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Has deactivate() Function: ");
if (ldesc->deactivate != NULL)
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Yes\n");
else
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "No\n");
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Has run_adding() Function: ");
if (ldesc->run_adding != NULL)
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Yes\n");
else
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "No\n");
if (ldesc->instantiate == NULL)
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "ERROR: PLUGIN HAS NO INSTANTIATE FUNCTION.\n");
if (ldesc->connect_port == NULL)
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "ERROR: PLUGIN HAS NO CONNECT_PORT FUNCTION.\n");
if (ldesc->run == NULL)
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "ERROR: PLUGIN HAS NO RUN FUNCTION.\n");
if (ldesc->run_adding != NULL && ldesc->set_run_adding_gain == NULL)
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "ERROR: PLUGIN HAS RUN_ADDING FUNCTION BUT " "NOT SET_RUN_ADDING_GAIN.\n");
if (ldesc->run_adding == NULL && ldesc->set_run_adding_gain != NULL)
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "ERROR: PLUGIN HAS SET_RUN_ADDING_GAIN FUNCTION BUT " "NOT RUN_ADDING.\n");
if (ldesc->cleanup == NULL)
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "ERROR: PLUGIN HAS NO CLEANUP FUNCTION.\n");
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Environment: ");
if (LADSPA_IS_HARD_RT_CAPABLE(ldesc->Properties))
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Normal or Hard Real-Time\n");
else
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Normal\n");
if (LADSPA_IS_INPLACE_BROKEN(ldesc->Properties))
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "This plugin cannot use in-place processing. " "It will not work with all hosts.\n");
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "Ports:");
if (ldesc->PortCount == 0)
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "\tERROR: PLUGIN HAS NO PORTS.\n");
for (i = 0; i < ldesc->PortCount; i++) {
LADSPA_Data dft = 0.0f;
int found = 0;
if (LADSPA_IS_PORT_CONTROL(ldesc->PortDescriptors[i])) {
found = find_default(ldesc, i, &dft);
}
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "\n \"%s\" ", ldesc->PortNames[i]);
if (LADSPA_IS_PORT_INPUT(ldesc->PortDescriptors[i])
&& LADSPA_IS_PORT_OUTPUT(ldesc->PortDescriptors[i]))
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "ERROR: INPUT AND OUTPUT");
else if (LADSPA_IS_PORT_INPUT(ldesc->PortDescriptors[i]))
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "input");
else if (LADSPA_IS_PORT_OUTPUT(ldesc->PortDescriptors[i]))
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "output");
else
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "ERROR: NEITHER INPUT NOR OUTPUT");
if (LADSPA_IS_PORT_CONTROL(ldesc->PortDescriptors[i])
&& LADSPA_IS_PORT_AUDIO(ldesc->PortDescriptors[i]))
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, ", ERROR: CONTROL AND AUDIO");
else if (LADSPA_IS_PORT_CONTROL(ldesc->PortDescriptors[i]))
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, ", control");
else if (LADSPA_IS_PORT_AUDIO(ldesc->PortDescriptors[i]))
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, ", audio");
else
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, ", ERROR: NEITHER CONTROL NOR AUDIO");
if (LADSPA_IS_PORT_CONTROL(ldesc->PortDescriptors[i])) {
if (found) {
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "\n RANGE: %f-%f DEFAULT: %f\n",
ldesc->PortRangeHints[i].LowerBound, ldesc->PortRangeHints[i].UpperBound, dft);
} else {
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "\n RANGE: %f-%f DEFAULT: none.\n",
ldesc->PortRangeHints[i].LowerBound, ldesc->PortRangeHints[i].UpperBound);
}
}
}
switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_DEBUG, "\n\n");
}
static switch_bool_t ladspa_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
{
switch_ladspa_t *pvt = (switch_ladspa_t *) user_data;
//switch_frame_t *frame = NULL;
switch_channel_t *channel = switch_core_session_get_channel(pvt->session);
switch (type) {
case SWITCH_ABC_TYPE_INIT:
{
switch_codec_implementation_t read_impl = { 0 };
LADSPA_PortDescriptor port_desc;
int i = 0, j = 0, k = 0, str_idx = 0;
switch_core_session_get_read_impl(pvt->session, &read_impl);
if (!(pvt->library_handle = loadLADSPAPluginLibrary(pvt->plugin_name))) {
return SWITCH_FALSE;
}
if (!(pvt->ldesc = findLADSPAPluginDescriptor(pvt->library_handle, pvt->plugin_name, pvt->label_name))) {
return SWITCH_FALSE;
}
pvt->handle = pvt->ldesc->instantiate(pvt->ldesc, read_impl.actual_samples_per_second);
dump_info(pvt->ldesc);
for (i = 0; i < pvt->ldesc->PortCount; i++) {
port_desc = pvt->ldesc->PortDescriptors[i];
if (LADSPA_IS_PORT_CONTROL(port_desc) && LADSPA_IS_PORT_INPUT(port_desc)) {
LADSPA_Data dft = 0.0f;
int found = find_default(pvt->ldesc, i, &dft);
if (found && !pvt->has_config[j]) {
pvt->config[j] = dft;
pvt->has_config[j] = 1;
}
if (pvt->has_config[j]) {
if (!check_range(pvt->ldesc, i, pvt->config[j])) {
pvt->config[j] = dft;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session), SWITCH_LOG_WARNING, "FALLING TO DEFAULT PARAM %d [%s] (%f)\n",
j+1,
pvt->ldesc->PortNames[i],
pvt->config[j]);
}
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session), SWITCH_LOG_DEBUG, "ADDING PARAM %d [%s] (%f)\n",
j+1,
pvt->ldesc->PortNames[i],
pvt->config[j]);
pvt->ldesc->connect_port(pvt->handle, i, &pvt->config[j++]);
usleep(10000);
}
}
if (LADSPA_IS_PORT_INPUT(port_desc) && LADSPA_IS_PORT_AUDIO(port_desc)) {
int mapped = 0;
if (pvt->str_idx && !zstr(pvt->str_config[str_idx])) {
if (!strcasecmp(pvt->str_config[str_idx], "none")) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session), SWITCH_LOG_DEBUG, "CONNECT NOTHING to port: %s\n",
pvt->ldesc->PortNames[i]
);
mapped = 1;
} else if (!strncasecmp(pvt->str_config[str_idx], "file:", 5)) {
char *file = pvt->str_config[str_idx] + 5;
if (switch_test_flag((&pvt->fh), SWITCH_FILE_OPEN)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session),
SWITCH_LOG_ERROR, "CAN'T CONNECT FILE [%s] File already mapped\n", file);
} else {
if (switch_core_file_open(&pvt->fh,
file,
read_impl.number_of_channels,
read_impl.actual_samples_per_second,
SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session), SWITCH_LOG_ERROR, "Cannot open file: %s\n", file);
return SWITCH_FALSE;
}
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session), SWITCH_LOG_DEBUG, "CONNECT FILE [%s] to port: %s\n",
file,
pvt->ldesc->PortNames[i]
);
pvt->ldesc->connect_port(pvt->handle, i, pvt->file_buf);
mapped = 1;
}
}
str_idx++;
}
if (!mapped) {
pvt->ldesc->connect_port(pvt->handle, i, pvt->in_buf);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session), SWITCH_LOG_DEBUG, "CONNECT CHANNEL AUDIO to port: %s\n",
pvt->ldesc->PortNames[i]
);
}
}
if (LADSPA_IS_PORT_OUTPUT(port_desc)) {
if (LADSPA_IS_PORT_AUDIO(port_desc)) {
pvt->ldesc->connect_port(pvt->handle, i, pvt->out_buf);
} else if (k < MAX_INDEX) {
pvt->ldesc->connect_port(pvt->handle, i, &pvt->out_ports[k++]);
}
}
}
}
break;
case SWITCH_ABC_TYPE_CLOSE:
{
if (switch_test_flag((&pvt->fh), SWITCH_FILE_OPEN)) {
switch_core_file_close(&pvt->fh);
}
if (pvt->handle && pvt->ldesc) {
pvt->ldesc->cleanup(pvt->handle);
}
if (pvt->library_handle) {
unloadLADSPAPluginLibrary(pvt->library_handle);
}
}
break;
case SWITCH_ABC_TYPE_WRITE_REPLACE:
case SWITCH_ABC_TYPE_READ_REPLACE:
{
switch_frame_t *rframe;
int16_t *slin, abuf[SWITCH_RECOMMENDED_BUFFER_SIZE] = { 0 };
switch_size_t olen = 0;
if (type == SWITCH_ABC_TYPE_READ_REPLACE) {
rframe = switch_core_media_bug_get_read_replace_frame(bug);
} else {
rframe = switch_core_media_bug_get_write_replace_frame(bug);
}
slin = rframe->data;
if (switch_channel_media_ready(channel)) {
switch_short_to_float(slin, pvt->in_buf, rframe->samples);
if (switch_test_flag((&pvt->fh), SWITCH_FILE_OPEN)) {
olen = rframe->samples;
if (switch_core_file_read(&pvt->fh, abuf, &olen) != SWITCH_STATUS_SUCCESS) {
switch_codec_implementation_t read_impl = { 0 };
char *file = switch_core_session_strdup(pvt->session, pvt->fh.file_path);
switch_core_session_get_read_impl(pvt->session, &read_impl);
switch_core_file_close(&pvt->fh);
if (switch_core_file_open(&pvt->fh,
file,
read_impl.number_of_channels,
read_impl.actual_samples_per_second,
SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, NULL) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session), SWITCH_LOG_ERROR, "Cannot open file: %s\n", file);
return SWITCH_FALSE;
}
olen = rframe->samples;
if (switch_core_file_read(&pvt->fh, abuf, &olen) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(pvt->session), SWITCH_LOG_ERROR, "Cannot READ file: %s\n", file);
return SWITCH_FALSE;
}
}
switch_short_to_float(abuf, pvt->file_buf, olen);
}
pvt->ldesc->run(pvt->handle, rframe->samples);
switch_float_to_short(pvt->out_buf, slin, rframe->samples);
}
if (type == SWITCH_ABC_TYPE_READ_REPLACE) {
switch_core_media_bug_set_read_replace_frame(bug, rframe);
} else {
switch_core_media_bug_set_write_replace_frame(bug, rframe);
}
if (pvt->skip && !--pvt->skip) {
return SWITCH_FALSE;
}
}
break;
case SWITCH_ABC_TYPE_WRITE:
default:
break;
}
return SWITCH_TRUE;
}
switch_status_t stop_ladspa_session(switch_core_session_t *session)
{
switch_media_bug_t *bug;
switch_channel_t *channel = switch_core_session_get_channel(session);
if ((bug = switch_channel_get_private(channel, "ladspa"))) {
switch_channel_set_private(channel, "ladspa", NULL);
switch_core_media_bug_remove(session, &bug);
return SWITCH_STATUS_SUCCESS;
}
return SWITCH_STATUS_FALSE;
}
switch_status_t ladspa_session(switch_core_session_t *session, const char *flags, const char *plugin_name, const char *label, const char *params)
{
switch_channel_t *channel = switch_core_session_get_channel(session);
switch_media_bug_t *bug;
switch_status_t status;
switch_ladspa_t *pvt = { 0 };
switch_codec_implementation_t read_impl = { 0 };
int i, bflags = SMBF_READ_REPLACE | SMBF_ANSWER_REQ;
char *pstr;
int argc;
char *argv[50];
char *dparams = NULL;
if (zstr(plugin_name)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "%s INVALID PLUGIN\n", switch_channel_get_name(channel));
return SWITCH_STATUS_FALSE;
}
if (zstr(flags)) {
flags = "r";
}
if (strchr(flags, 'w')) {
bflags = SMBF_WRITE_REPLACE;
}
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "FLAGS: %s PLUGIN: %s LABEL: %s PARAMS: %s\n",
flags, plugin_name, label, params);
switch_core_session_get_read_impl(session, &read_impl);
pvt = switch_core_session_alloc(session, sizeof(*pvt));
pvt->session = session;
if (!zstr(label)) {
pvt->label_name = switch_core_session_strdup(session, label);
} else {
char *p;
pvt->label_name = switch_core_session_strdup(session, plugin_name);
if ((p = strrchr(pvt->label_name, '.'))) {
*p = '\0';
}
}
if (strstr(plugin_name, ".so")) {
pvt->plugin_name = switch_core_session_strdup(session, plugin_name);
} else {
pvt->plugin_name = switch_core_session_sprintf(session, "%s.so", plugin_name);
}
dparams = switch_core_session_strdup(session, params);
argc = switch_split(dparams, ' ', argv);
for (i = 0; i < argc; i++) {
if (switch_is_number(argv[i])) {
if (pvt->num_idx < MAX_INDEX) {
pvt->config[pvt->num_idx] = atof(argv[i]);
pvt->has_config[pvt->num_idx] = 1;
pvt->num_idx++;
}
} else {
if (pvt->str_idx < MAX_INDEX) {
pvt->str_config[pvt->str_idx++] = switch_core_session_strdup(session, argv[i]);
}
}
}
if (switch_channel_pre_answer(channel) != SWITCH_STATUS_SUCCESS) {
return SWITCH_STATUS_FALSE;
}
pstr = switch_core_session_sprintf(session, "%s|%s|%s|%s", flags, plugin_name, label, params);
if ((status = switch_core_media_bug_add(session, "ladspa", pstr,
ladspa_callback, pvt, 0, bflags | SMBF_NO_PAUSE, &bug)) != SWITCH_STATUS_SUCCESS) {
return status;
}
switch_channel_set_private(channel, "ladspa", bug);
return SWITCH_STATUS_SUCCESS;
}
static void ladspa_parse(switch_core_session_t *session, const char *data)
{
char *argv[5] = { 0 };
int argc;
char *lbuf;
if (data) {
lbuf = strdup(data);
argc = switch_separate_string(lbuf, '|', argv, (sizeof(argv) / sizeof(argv[0])));
ladspa_session(session, argv[0], argv[1], argv[2], argv[3]);
free(lbuf);
}
}
#define APP_SYNTAX "<flags>|<plugin>|<label>|<params>"
SWITCH_STANDARD_APP(ladspa_run_function)
{
ladspa_parse(session, data);
}
#define API_SYNTAX "<uuid>|<flags>|<plugin>|<label>|<params>"
SWITCH_STANDARD_API(ladspa_api)
{
char *uuid = NULL;
char *data;
char *p;
switch_core_session_t *ksession = NULL;
if (!cmd) goto err;
data = strdup(cmd);
if ((p = strchr(data, ' '))) {
uuid = data;
*p++ = '\0';
if ((ksession = switch_core_session_locate(uuid))) {
ladspa_parse(ksession, p);
switch_core_session_rwunlock(ksession);
stream->write_function(stream, "+OK\n");
} else {
stream->write_function(stream, "-ERR non-existant UUID\n");
}
} else {
stream->write_function(stream, "-ERR Usage %s\n", API_SYNTAX);
}
free(data);
return SWITCH_STATUS_SUCCESS;
err:
stream->write_function(stream, "-ERR Operation Failed\n");
return SWITCH_STATUS_SUCCESS;
}
/* Macro expands to: switch_status_t mod_ladspa_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool) */
SWITCH_MODULE_LOAD_FUNCTION(mod_ladspa_load)
{
switch_application_interface_t *app_interface;
switch_api_interface_t *api_interface;
char *path = getenv("LADSPA_PATH");
if (zstr(path)) {
if (switch_directory_exists("/usr/lib64/ladspa/", pool) == SWITCH_STATUS_SUCCESS) {
putenv("LADSPA_PATH=/usr/lib64/ladspa/:/usr/local/lib/ladspa");
} else if (switch_directory_exists("/usr/lib/ladspa/", pool) == SWITCH_STATUS_SUCCESS) {
putenv("LADSPA_PATH=/usr/lib/ladspa/:/usr/local/lib/ladspa");
}
}
/* connect my internal structure to the blank pointer passed to me */
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
SWITCH_ADD_APP(app_interface, "ladspa_run", "ladspa_run", NULL, ladspa_run_function, APP_SYNTAX, SAF_NONE);
SWITCH_ADD_API(api_interface, "uuid_ladspa", "ladspa", ladspa_api, API_SYNTAX);
switch_console_set_complete("add uuid_ladspa ::console::list_uuid");
/* indicate that the module should continue to be loaded */
return SWITCH_STATUS_SUCCESS;
}
/*
Called when the system shuts down
Macro expands to: switch_status_t mod_ladspa_shutdown() */
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_ladspa_shutdown)
{
/* Cleanup dynamically allocated config settings */
return SWITCH_STATUS_SUCCESS;
}
/* For Emacs:
* Local Variables:
* mode:c
* indent-tabs-mode:t
* tab-width:4
* c-basic-offset:4
* End:
* For VIM:
* vim:set softtabstop=4 shiftwidth=4 tabstop=4
*/
+72
View File
@@ -0,0 +1,72 @@
/* utils.h
Free software by Richard W.E. Furse. Do with as you will. No
warranty. */
#ifndef LADSPA_SDK_LOAD_PLUGIN_LIB
#define LADSPA_SDK_LOAD_PLUGIN_LIB
/*****************************************************************************/
#include "ladspa.h"
/*****************************************************************************/
/* Functions in load.c: */
/* This function call takes a plugin library filename, searches for
the library along the LADSPA_PATH, loads it with dlopen() and
returns a plugin handle for use with findPluginDescriptor() or
unloadLADSPAPluginLibrary(). Errors are handled by writing a
message to stderr and calling exit(1). It is alright (although
inefficient) to call this more than once for the same file. */
void * loadLADSPAPluginLibrary(const char * pcPluginFilename);
/* This function unloads a LADSPA plugin library. */
void unloadLADSPAPluginLibrary(void * pvLADSPAPluginLibrary);
/* This function locates a LADSPA plugin within a plugin library
loaded with loadLADSPAPluginLibrary(). Errors are handled by
writing a message to stderr and calling exit(1). Note that the
plugin library filename is only included to help provide
informative error messages. */
const LADSPA_Descriptor *
findLADSPAPluginDescriptor(void * pvLADSPAPluginLibrary,
const char * pcPluginLibraryFilename,
const char * pcPluginLabel);
/*****************************************************************************/
/* Functions in search.c: */
/* Callback function for use with LADSPAPluginSearch(). The callback
function passes the filename (full path), a plugin handle (dlopen()
style) and a LADSPA_DescriptorFunction (from which
LADSPA_Descriptors can be acquired). */
typedef void LADSPAPluginSearchCallbackFunction
(const char * pcFullFilename,
void * pvPluginHandle,
LADSPA_Descriptor_Function fDescriptorFunction);
/* Search through the $(LADSPA_PATH) (or a default path) for any
LADSPA plugin libraries. Each plugin library is tested using
dlopen() and dlsym(,"ladspa_descriptor"). After loading each
library, the callback function is called to process it. This
function leaves items passed to the callback function open. */
void LADSPAPluginSearch(LADSPAPluginSearchCallbackFunction fCallbackFunction);
/*****************************************************************************/
/* Function in default.c: */
/* Find the default value for a port. Return 0 if a default is found
and -1 if not. */
int getLADSPADefault(const LADSPA_PortRangeHint * psPortRangeHint,
const unsigned long lSampleRate,
LADSPA_Data * pfResult);
/*****************************************************************************/
#endif
/* EOF */
@@ -2492,6 +2492,7 @@ static switch_status_t deliver_vm(vm_profile_t *profile,
if (copy) {
switch_file_copy(path, file_path, SWITCH_FPROT_FILE_SOURCE_PERMS, pool);
} else {
switch_safe_free(file_path);
file_path = (char *) path;
}
+7 -2
View File
@@ -3161,12 +3161,15 @@ static switch_status_t recog_asr_close(switch_asr_handle_t *ah, switch_asr_flag_
if (schannel != NULL && !switch_test_flag(ah, SWITCH_ASR_FLAG_CLOSED)) {
r = (recognizer_data_t *) schannel->data;
speech_channel_stop(schannel);
speech_channel_destroy(schannel);
switch_core_hash_destroy(&r->grammars);
switch_core_hash_destroy(&r->enabled_grammars);
switch_mutex_lock(schannel->mutex);
if (r->dtmf_generator) {
r->dtmf_generator_active = 0;
mpf_dtmf_generator_destroy(r->dtmf_generator);
}
switch_mutex_unlock(schannel->mutex);
speech_channel_destroy(schannel);
}
/* this lets FreeSWITCH's speech_thread know the handle is closed */
switch_set_flag(ah, SWITCH_ASR_FLAG_CLOSED);
@@ -3502,13 +3505,15 @@ static apt_bool_t recog_stream_read(mpf_audio_stream_t *stream, mpf_frame_t *fra
}
frame->type |= MEDIA_FRAME_TYPE_AUDIO;
}
switch_mutex_lock(schannel->mutex);
if (r->dtmf_generator_active) {
if (!mpf_dtmf_generator_put_frame(r->dtmf_generator, frame)) {
if (!mpf_dtmf_generator_sending(r->dtmf_generator))
r->dtmf_generator_active = 0;
}
}
switch_mutex_unlock(schannel->mutex);
return TRUE;
}
+1 -1
View File
@@ -1,7 +1,7 @@
include $(top_srcdir)/build/modmake.rulesam
MODNAME=mod_com_g729
VERSION=193
VERSION=194
if ISLINUX
+67 -22
View File
@@ -1373,6 +1373,9 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
if ((len = atoi(msg->string_arg))) {
qlen = len / (tech_pvt->read_impl.microseconds_per_packet / 1000);
if (qlen < 1) {
qlen = 3;
}
}
if (qlen) {
@@ -1393,6 +1396,9 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
}
if (qlen) {
if (maxqlen < qlen) {
maxqlen = qlen * 5;
}
if (switch_rtp_activate_jitter_buffer(tech_pvt->rtp_session, qlen, maxqlen,
tech_pvt->read_impl.samples_per_packet,
tech_pvt->read_impl.samples_per_second, max_drift) == SWITCH_STATUS_SUCCESS) {
@@ -1444,69 +1450,97 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
case SWITCH_MESSAGE_INDICATE_BRIDGE:
{
const char *var = switch_channel_get_variable(tech_pvt->channel, "sip_jitter_buffer_during_bridge");
sofia_glue_tech_track(tech_pvt->profile, session);
sofia_glue_tech_simplify(tech_pvt);
if (switch_false(var) && switch_rtp_ready(tech_pvt->rtp_session)) {
if (switch_rtp_ready(tech_pvt->rtp_session)) {
const char *val;
int ok = 0;
if (switch_channel_test_flag(tech_pvt->channel, CF_JITTERBUFFER) && switch_channel_test_cap_partner(tech_pvt->channel, CC_FS_RTP)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
"%s PAUSE Jitterbuffer\n", switch_channel_get_name(channel));
switch_rtp_pause_jitter_buffer(tech_pvt->rtp_session, SWITCH_TRUE);
if (!(val = switch_channel_get_variable(tech_pvt->channel, "sip_jitter_buffer_during_bridge")) || switch_false(val)) {
if (switch_channel_test_flag(tech_pvt->channel, CF_JITTERBUFFER) && switch_channel_test_cap_partner(tech_pvt->channel, CC_FS_RTP)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
"%s PAUSE Jitterbuffer\n", switch_channel_get_name(channel));
switch_rtp_pause_jitter_buffer(tech_pvt->rtp_session, SWITCH_TRUE);
sofia_set_flag(tech_pvt, TFLAG_JB_PAUSED);
}
}
if (sofia_test_flag(tech_pvt, TFLAG_PASS_RFC2833) && switch_channel_test_flag_partner(channel, CF_FS_RTP)) {
switch_rtp_set_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_PASS_RFC2833);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
"%s activate passthru 2833 mode.\n", switch_channel_get_name(channel));
}
if ((val = switch_channel_get_variable(channel, "rtp_autoflush_during_bridge"))) {
if ((val = switch_channel_get_variable(channel, "rtp_notimer_during_bridge"))) {
ok = switch_true(val);
} else {
ok = sofia_test_pflag(tech_pvt->profile, PFLAG_RTP_AUTOFLUSH_DURING_BRIDGE);
ok = sofia_test_pflag(tech_pvt->profile, PFLAG_RTP_NOTIMER_DURING_BRIDGE);
}
if (ok && !switch_rtp_test_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_USE_TIMER)) {
ok = 0;
}
if (ok) {
switch_rtp_clear_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_USE_TIMER);
switch_rtp_clear_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_NOBLOCK);
sofia_set_flag(tech_pvt, TFLAG_NOTIMER_DURING_BRIDGE);
}
if (ok && sofia_test_flag(tech_pvt, TFLAG_NOTIMER_DURING_BRIDGE)) {
/* these are not compat */
ok = 0;
} else {
if ((val = switch_channel_get_variable(channel, "rtp_autoflush_during_bridge"))) {
ok = switch_true(val);
} else {
ok = sofia_test_pflag(tech_pvt->profile, PFLAG_RTP_AUTOFLUSH_DURING_BRIDGE);
}
}
if (ok) {
rtp_flush_read_buffer(tech_pvt->rtp_session, SWITCH_RTP_FLUSH_STICK);
sofia_set_flag(tech_pvt, TFLAG_AUTOFLUSH_DURING_BRIDGE);
} else {
rtp_flush_read_buffer(tech_pvt->rtp_session, SWITCH_RTP_FLUSH_ONCE);
}
}
}
goto end;
case SWITCH_MESSAGE_INDICATE_UNBRIDGE:
if (switch_rtp_ready(tech_pvt->rtp_session)) {
const char *val;
int ok = 0;
sofia_glue_tech_track(tech_pvt->profile, session);
if (switch_channel_test_flag(tech_pvt->channel, CF_JITTERBUFFER)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
"%s RESUME Jitterbuffer\n", switch_channel_get_name(channel));
switch_rtp_pause_jitter_buffer(tech_pvt->rtp_session, SWITCH_FALSE);
if (sofia_test_flag(tech_pvt, TFLAG_JB_PAUSED)) {
sofia_clear_flag(tech_pvt, TFLAG_JB_PAUSED);
if (switch_channel_test_flag(tech_pvt->channel, CF_JITTERBUFFER)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
"%s RESUME Jitterbuffer\n", switch_channel_get_name(channel));
switch_rtp_pause_jitter_buffer(tech_pvt->rtp_session, SWITCH_FALSE);
}
}
if (switch_rtp_test_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_PASS_RFC2833)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s deactivate passthru 2833 mode.\n",
switch_channel_get_name(channel));
switch_rtp_clear_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_PASS_RFC2833);
}
if ((val = switch_channel_get_variable(channel, "rtp_autoflush_during_bridge"))) {
ok = switch_true(val);
} else {
ok = sofia_test_pflag(tech_pvt->profile, PFLAG_RTP_AUTOFLUSH_DURING_BRIDGE);
if (sofia_test_flag(tech_pvt, TFLAG_NOTIMER_DURING_BRIDGE)) {
switch_rtp_set_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_USE_TIMER);
switch_rtp_set_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_NOBLOCK);
sofia_clear_flag(tech_pvt, TFLAG_NOTIMER_DURING_BRIDGE);
}
if (ok) {
if (sofia_test_flag(tech_pvt, TFLAG_AUTOFLUSH_DURING_BRIDGE)) {
rtp_flush_read_buffer(tech_pvt->rtp_session, SWITCH_RTP_FLUSH_UNSTICK);
sofia_clear_flag(tech_pvt, TFLAG_AUTOFLUSH_DURING_BRIDGE);
} else {
rtp_flush_read_buffer(tech_pvt->rtp_session, SWITCH_RTP_FLUSH_ONCE);
}
@@ -1850,6 +1884,17 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
if (switch_stristr("update_display", tech_pvt->x_freeswitch_support_remote)) {
snprintf(message, sizeof(message), "X-FS-Display-Name: %s\nX-FS-Display-Number: %s\n", name, number);
if (switch_channel_test_flag(tech_pvt->channel, CF_LAZY_ATTENDED_TRANSFER)) {
snprintf(message + strlen(message), sizeof(message) - strlen(message), "X-FS-Lazy-Attended-Transfer: true\n");
switch_channel_clear_flag(tech_pvt->channel, CF_LAZY_ATTENDED_TRANSFER);
switch_channel_clear_flag(tech_pvt->channel, CF_ATTENDED_TRANSFER);
}
if (switch_channel_test_flag(tech_pvt->channel, CF_ATTENDED_TRANSFER)) {
snprintf(message + strlen(message), sizeof(message) - strlen(message), "X-FS-Attended-Transfer: true\n");
switch_channel_clear_flag(tech_pvt->channel, CF_ATTENDED_TRANSFER);
}
nua_info(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/update_display"),
TAG_IF(!zstr_buf(message), SIPTAG_HEADER_STR(message)),
TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)), TAG_END());
+9 -1
View File
@@ -230,6 +230,9 @@ typedef enum {
PFLAG_PRESENCE_ON_REGISTER,
PFLAG_PRESENCE_ON_FIRST_REGISTER,
PFLAG_NO_CONNECTION_REUSE,
PFLAG_RENEG_ON_HOLD,
PFLAG_RENEG_ON_REINVITE,
PFLAG_RTP_NOTIMER_DURING_BRIDGE,
/* No new flags below this line */
PFLAG_MAX
} PFLAGS;
@@ -288,6 +291,9 @@ typedef enum {
TFLAG_RECOVERING_BRIDGE,
TFLAG_T38_PASSTHRU,
TFLAG_RECOVERED,
TFLAG_AUTOFLUSH_DURING_BRIDGE,
TFLAG_NOTIMER_DURING_BRIDGE,
TFLAG_JB_PAUSED,
/* No new flags below this line */
TFLAG_MAX
} TFLAGS;
@@ -598,6 +604,8 @@ struct private_object {
int codec_order_last;
const switch_codec_implementation_t *codecs[SWITCH_MAX_CODECS];
int num_codecs;
const switch_codec_implementation_t *negotiated_codecs[SWITCH_MAX_CODECS];
int num_negotiated_codecs;
switch_codec_t read_codec;
switch_codec_t write_codec;
uint32_t codec_ms;
@@ -984,7 +992,7 @@ void sofia_glue_del_every_gateway(sofia_profile_t *profile);
void sofia_reg_send_reboot(sofia_profile_t *profile, const char *user, const char *host, const char *contact, const char *user_agent,
const char *network_ip);
void sofia_glue_restart_all_profiles(void);
void sofia_glue_toggle_hold(private_object_t *tech_pvt, int sendonly);
int sofia_glue_toggle_hold(private_object_t *tech_pvt, int sendonly);
const char *sofia_state_string(int state);
switch_status_t sofia_glue_tech_set_codec(private_object_t *tech_pvt, int force);
void sofia_wait_for_reply(struct private_object *tech_pvt, nua_event_t event, uint32_t timeout);
+67 -7
View File
@@ -637,7 +637,7 @@ void sofia_update_callee_id(switch_core_session_t *session, sofia_profile_t *pro
char *dup = NULL;
switch_event_t *event;
const char *val;
int fs = 0;
int fs = 0, lazy = 0, att = 0;
if (switch_true(switch_channel_get_variable(channel, SWITCH_IGNORE_DISPLAY_UPDATES_VARIABLE))) {
return;
@@ -656,6 +656,16 @@ void sofia_update_callee_id(switch_core_session_t *session, sofia_profile_t *pro
name = (char *) val;
fs++;
}
if ((val = sofia_glue_get_unknown_header(sip, "X-FS-Lazy-Attended-Transfer"))) {
lazy = switch_true(val);
fs++;
}
if ((val = sofia_glue_get_unknown_header(sip, "X-FS-Attended-Transfer"))) {
att = switch_true(val);
fs++;
}
if (!fs) {
if ((passerted = sip_p_asserted_identity(sip))) {
@@ -727,6 +737,10 @@ void sofia_update_callee_id(switch_core_session_t *session, sofia_profile_t *pro
caller_profile->callee_id_name = switch_sanitize_number(switch_core_strdup(caller_profile->pool, name));
caller_profile->callee_id_number = switch_sanitize_number(switch_core_strdup(caller_profile->pool, number));
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s Update Callee ID to \"%s\" <%s>\n", switch_channel_get_name(channel), name, number);
if (lazy || (att && !switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE))) {
switch_channel_flip_cid(channel);
}
}
if (send) {
@@ -2436,6 +2450,18 @@ switch_status_t reconfig_sofia(sofia_profile_t *profile)
} else {
sofia_clear_pflag(profile, PFLAG_IGNORE_183NOSDP);
}
} else if (!strcasecmp(var, "renegotiate-codec-on-hold")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_RENEG_ON_HOLD);
} else {
sofia_clear_pflag(profile, PFLAG_RENEG_ON_HOLD);
}
} else if (!strcasecmp(var, "renegotiate-codec-on-reinvite")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_RENEG_ON_REINVITE);
} else {
sofia_clear_pflag(profile, PFLAG_RENEG_ON_REINVITE);
}
} else if (!strcasecmp(var, "presence-probe-on-register")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_PRESENCE_PROBE_ON_REGISTER);
@@ -2519,6 +2545,12 @@ switch_status_t reconfig_sofia(sofia_profile_t *profile)
} else {
sofia_clear_pflag(profile, PFLAG_RTP_AUTOFLUSH_DURING_BRIDGE);
}
} else if (!strcasecmp(var, "rtp-notimer-during-bridge")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_RTP_NOTIMER_DURING_BRIDGE);
} else {
sofia_clear_pflag(profile, PFLAG_RTP_NOTIMER_DURING_BRIDGE);
}
} else if (!strcasecmp(var, "manual-redirect")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_MANUAL_REDIRECT);
@@ -3119,6 +3151,18 @@ switch_status_t config_sofia(int reload, char *profile_name)
} else {
sofia_clear_pflag(profile, PFLAG_IGNORE_183NOSDP);
}
} else if (!strcasecmp(var, "renegotiate-codec-on-hold")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_RENEG_ON_HOLD);
} else {
sofia_clear_pflag(profile, PFLAG_RENEG_ON_HOLD);
}
} else if (!strcasecmp(var, "renegotiate-codec-on-reinvite")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_RENEG_ON_REINVITE);
} else {
sofia_clear_pflag(profile, PFLAG_RENEG_ON_REINVITE);
}
} else if (!strcasecmp(var, "presence-probe-on-register")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_PRESENCE_PROBE_ON_REGISTER);
@@ -3190,6 +3234,12 @@ switch_status_t config_sofia(int reload, char *profile_name)
} else {
sofia_clear_pflag(profile, PFLAG_RTP_AUTOFLUSH_DURING_BRIDGE);
}
} else if (!strcasecmp(var, "rtp-notimer-during-bridge")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_RTP_NOTIMER_DURING_BRIDGE);
} else {
sofia_clear_pflag(profile, PFLAG_RTP_NOTIMER_DURING_BRIDGE);
}
} else if (!strcasecmp(var, "manual-redirect")) {
if (switch_true(val)) {
sofia_set_pflag(profile, PFLAG_MANUAL_REDIRECT);
@@ -4372,10 +4422,15 @@ static void sofia_handle_sip_r_invite(switch_core_session_t *session, int status
}
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Passing %d %s to other leg\n", status, phrase);
if (status == 200 && sofia_test_flag(tech_pvt, TFLAG_T38_PASSTHRU) && has_t38) {
if (sip->sip_payload && sip->sip_payload->pl_data) {
switch_t38_options_t *t38_options = sofia_glue_extract_t38_options(session, sip->sip_payload->pl_data);
if (status == 200 && sofia_test_flag(tech_pvt, TFLAG_T38_PASSTHRU) && has_t38 && sip->sip_payload && sip->sip_payload->pl_data) {
switch_t38_options_t *t38_options = sofia_glue_extract_t38_options(session, sip->sip_payload->pl_data);
if (!t38_options) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_WARNING, "%s Error parsing SDP:\n%s\n",
switch_channel_get_name(tech_pvt->channel), sip->sip_payload->pl_data);
goto end;
} else {
char *remote_host = switch_rtp_get_remote_host(tech_pvt->rtp_session);
switch_port_t remote_port = switch_rtp_get_remote_port(tech_pvt->rtp_session);
char tmp[32] = "";
@@ -5681,9 +5736,14 @@ void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Attended Transfer [%s][%s]\n",
switch_str_nil(br_a), switch_str_nil(br_b));
if ((profile->media_options & MEDIA_OPT_BYPASS_AFTER_ATT_XFER) && (tmp = switch_core_session_locate(br_b))) {
if ((tmp = switch_core_session_locate(br_b))) {
switch_channel_t *tchannel = switch_core_session_get_channel(tmp);
switch_channel_set_flag(tchannel, CF_BYPASS_MEDIA_AFTER_BRIDGE);
if ((profile->media_options & MEDIA_OPT_BYPASS_AFTER_ATT_XFER)) {
switch_channel_set_flag(tchannel, CF_BYPASS_MEDIA_AFTER_BRIDGE);
}
switch_channel_set_flag(tchannel, CF_ATTENDED_TRANSFER);
switch_core_session_rwunlock(tmp);
}
+77 -9
View File
@@ -2965,6 +2965,17 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f
flags |= SWITCH_RTP_FLAG_AUTO_CNG;
}
#if __BYTE_ORDER == __LITTLE_ENDIAN
if (!strcasecmp(tech_pvt->read_impl.iananame, "L16")) {
flags |= SWITCH_RTP_FLAG_BYTESWAP;
}
#endif
if ((flags & SWITCH_RTP_FLAG_BYTESWAP) && (val = switch_channel_get_variable(tech_pvt->channel, "rtp_disable_byteswap")) && switch_true(val)) {
flags &= ~SWITCH_RTP_FLAG_BYTESWAP;
}
if (tech_pvt->rtp_session && sofia_test_flag(tech_pvt, TFLAG_REINVITE)) {
//const char *ip = switch_channel_get_variable(tech_pvt->channel, SWITCH_LOCAL_MEDIA_IP_VARIABLE);
//const char *port = switch_channel_get_variable(tech_pvt->channel, SWITCH_LOCAL_MEDIA_PORT_VARIABLE);
@@ -2996,6 +3007,16 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f
if (switch_rtp_ready(tech_pvt->rtp_session)) {
switch_rtp_set_default_payload(tech_pvt->rtp_session, tech_pvt->agreed_pt);
if (tech_pvt->audio_recv_pt != tech_pvt->agreed_pt) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG,
"%s Set audio receive payload to %u\n", switch_channel_get_name(tech_pvt->channel), tech_pvt->audio_recv_pt);
switch_rtp_set_recv_pt(tech_pvt->rtp_session, tech_pvt->audio_recv_pt);
} else {
switch_rtp_set_recv_pt(tech_pvt->rtp_session, tech_pvt->agreed_pt);
}
}
}
@@ -3186,10 +3207,17 @@ switch_status_t sofia_glue_activate_rtp(private_object_t *tech_pvt, switch_rtp_f
qlen = jb_msec / (tech_pvt->read_impl.microseconds_per_packet / 1000);
if (qlen < 1) {
qlen = 3;
}
if (maxlen) {
maxqlen = maxlen / (tech_pvt->read_impl.microseconds_per_packet / 1000);
}
if (maxqlen < qlen) {
maxqlen = qlen * 5;
}
if (switch_rtp_activate_jitter_buffer(tech_pvt->rtp_session, qlen, maxqlen,
tech_pvt->read_impl.samples_per_packet,
tech_pvt->read_impl.samples_per_second, max_drift) == SWITCH_STATUS_SUCCESS) {
@@ -3749,8 +3777,10 @@ switch_status_t sofia_glue_tech_media(private_object_t *tech_pvt, const char *r_
return SWITCH_STATUS_FALSE;
}
void sofia_glue_toggle_hold(private_object_t *tech_pvt, int sendonly)
int sofia_glue_toggle_hold(private_object_t *tech_pvt, int sendonly)
{
int changed = 0;
if (sendonly && switch_channel_test_flag(tech_pvt->channel, CF_ANSWERED)) {
if (!sofia_test_flag(tech_pvt, TFLAG_SIP_HOLD)) {
const char *stream;
@@ -3769,6 +3799,7 @@ void sofia_glue_toggle_hold(private_object_t *tech_pvt, int sendonly)
switch_channel_set_flag(tech_pvt->channel, CF_LEG_HOLDING);
switch_channel_mark_hold(tech_pvt->channel, SWITCH_TRUE);
switch_channel_presence(tech_pvt->channel, "unknown", msg, NULL);
changed = 1;
if (tech_pvt->max_missed_hold_packets) {
switch_rtp_set_max_missed_packets(tech_pvt->rtp_session, tech_pvt->max_missed_hold_packets);
@@ -3795,6 +3826,7 @@ void sofia_glue_toggle_hold(private_object_t *tech_pvt, int sendonly)
sofia_set_flag(tech_pvt, TFLAG_SIP_HOLD);
switch_channel_set_flag(tech_pvt->channel, CF_LEG_HOLDING);
switch_channel_mark_hold(tech_pvt->channel, SWITCH_TRUE);
changed = 1;
}
sofia_clear_flag_locked(tech_pvt, TFLAG_HOLD_LOCK);
@@ -3828,8 +3860,11 @@ void sofia_glue_toggle_hold(private_object_t *tech_pvt, int sendonly)
switch_channel_clear_flag(tech_pvt->channel, CF_LEG_HOLDING);
switch_channel_mark_hold(tech_pvt->channel, SWITCH_FALSE);
switch_channel_presence(tech_pvt->channel, "unknown", "unhold", NULL);
changed = 1;
}
}
return changed;
}
void sofia_glue_copy_t38_options(switch_t38_options_t *t38_options, switch_core_session_t *session)
@@ -4154,6 +4189,14 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_s
int scrooge = 0;
sdp_parser_t *parser = NULL;
sdp_session_t *sdp;
int reneg = 1;
const switch_codec_implementation_t **codec_array;
int total_codecs;
codec_array = tech_pvt->codecs;
total_codecs = tech_pvt->num_codecs;
if (!(parser = sdp_parse(NULL, r_sdp, (int) strlen(r_sdp), 0))) {
return 0;
@@ -4254,10 +4297,30 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_s
if (!tech_pvt->hold_laps) {
tech_pvt->hold_laps++;
sofia_glue_toggle_hold(tech_pvt, sendonly);
if (sofia_glue_toggle_hold(tech_pvt, sendonly)) {
reneg = sofia_test_pflag(tech_pvt->profile, PFLAG_RENEG_ON_HOLD);
if ((val = switch_channel_get_variable(tech_pvt->channel, "sip_renegotiate_codec_on_hold"))) {
reneg = switch_true(val);
}
}
}
}
if (reneg) {
reneg = sofia_test_pflag(tech_pvt->profile, PFLAG_RENEG_ON_REINVITE);
if ((val = switch_channel_get_variable(tech_pvt->channel, "sip_renegotiate_codec_on_reinvite"))) {
reneg = switch_true(val);
}
}
if (!reneg && tech_pvt->num_negotiated_codecs) {
codec_array = tech_pvt->negotiated_codecs;
total_codecs = tech_pvt->num_negotiated_codecs;
}
for (m = sdp->sdp_media; m; m = m->m_next) {
sdp_connection_t *connection;
switch_core_session_t *other_session;
@@ -4351,6 +4414,7 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_s
goto done;
} else if (m->m_type == sdp_media_audio && m->m_port && !got_audio) {
sdp_rtpmap_t *map;
for (attr = m->m_attributes; attr; attr = attr->a_next) {
if (!strcasecmp(attr->a_name, "rtcp") && attr->a_value) {
@@ -4561,8 +4625,9 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_s
}
}
for (i = first; i < last && i < tech_pvt->num_codecs; i++) {
const switch_codec_implementation_t *imp = tech_pvt->codecs[i];
for (i = first; i < last && i < total_codecs; i++) {
const switch_codec_implementation_t *imp = codec_array[i];
uint32_t bit_rate = imp->bits_per_second;
uint32_t codec_rate = imp->samples_per_second;
if (imp->codec_type != SWITCH_CODEC_TYPE_AUDIO) {
@@ -4649,12 +4714,14 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_s
tech_pvt->rm_fmtp = switch_core_session_strdup(session, (char *) map->rm_fmtp);
tech_pvt->remote_sdp_audio_port = (switch_port_t) m->m_port;
tech_pvt->agreed_pt = (switch_payload_t) map->rm_pt;
tech_pvt->num_negotiated_codecs = 0;
tech_pvt->negotiated_codecs[tech_pvt->num_negotiated_codecs++] = mimp;
switch_snprintf(tmp, sizeof(tmp), "%d", tech_pvt->remote_sdp_audio_port);
switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE, tech_pvt->remote_sdp_audio_ip);
switch_channel_set_variable(tech_pvt->channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE, tmp);
tech_pvt->audio_recv_pt = map->rm_pt;
if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND && !sofia_test_flag(tech_pvt, TFLAG_REINVITE)) {
sofia_glue_get_offered_pt(tech_pvt, mimp, &tech_pvt->audio_recv_pt);
}
@@ -4690,7 +4757,7 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_s
}
if (!match && greedy && mine < tech_pvt->num_codecs) {
if (!match && greedy && mine < total_codecs) {
mine++;
skip = 0;
goto greed;
@@ -4729,8 +4796,8 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_s
rm_encoding = "";
}
for (i = 0; i < tech_pvt->num_codecs; i++) {
const switch_codec_implementation_t *imp = tech_pvt->codecs[i];
for (i = 0; i < total_codecs; i++) {
const switch_codec_implementation_t *imp = codec_array[i];
if (imp->codec_type != SWITCH_CODEC_TYPE_VIDEO) {
continue;
@@ -4792,8 +4859,9 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_s
done:
if (parser)
if (parser) {
sdp_parser_free(parser);
}
tech_pvt->cng_pt = cng_pt;
sofia_set_flag_locked(tech_pvt, TFLAG_SDP);
+1 -1
View File
@@ -2004,7 +2004,7 @@ static void sync_sla(sofia_profile_t *profile, const char *to_user, const char *
switch_core_hash_init(&sh->hash, sh->pool);
sql = switch_mprintf("select sip_from_user,sip_from_host,call_info,call_info_state,uuid from sip_dialogs "
"where hostname='%q' and ((sip_from_user='%q' and sip_from_host='%q') or presence_id='%q@%q')",
"where call_info_state is not null and hostname='%q' and ((sip_from_user='%q' and sip_from_host='%q') or presence_id='%q@%q')",
mod_sofia_globals.hostname, to_user, to_host, to_user, to_host);
+3 -3
View File
@@ -1124,8 +1124,8 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand
}
}
if ((v_contact_str = switch_event_get_header(*v_event, "sip-force-contact")) || auto_connectile) {
if ((!strcasecmp(v_contact_str, "NDLB-connectile-dysfunction-2.0")) || auto_connectile) {
if (auto_connectile || (v_contact_str = switch_event_get_header(*v_event, "sip-force-contact"))) {
if (auto_connectile || (!strcasecmp(v_contact_str, "NDLB-connectile-dysfunction-2.0"))) {
char *path_encoded;
size_t path_encoded_len;
char my_contact_str[1024];
@@ -1914,7 +1914,7 @@ void sofia_reg_handle_sip_r_challenge(int status,
} else if (gateway) {
switch_snprintf(authentication, sizeof(authentication), "%s:%s:%s:%s", scheme, realm, gateway->auth_username, gateway->register_password);
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "No Matching gateway found\n");
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot locate any authentication credentials to complete an authentication request for realm '%s'\n", realm);
goto cancel;
}
@@ -305,55 +305,60 @@ static void event_handler(switch_event_t *event)
}
}
if (send && l->filters && l->filters->headers) {
switch_event_header_t *hp;
const char *hval;
send = 0;
if (send) {
switch_mutex_lock(l->filter_mutex);
for (hp = l->filters->headers; hp; hp = hp->next) {
if ((hval = switch_event_get_header(event, hp->name))) {
const char *comp_to = hp->value;
int pos = 1, cmp = 0;
while (comp_to && *comp_to) {
if (*comp_to == '+') {
pos = 1;
} else if (*comp_to == '-') {
pos = 0;
} else if (*comp_to != ' ') {
break;
if (l->filters && l->filters->headers) {
switch_event_header_t *hp;
const char *hval;
send = 0;
for (hp = l->filters->headers; hp; hp = hp->next) {
if ((hval = switch_event_get_header(event, hp->name))) {
const char *comp_to = hp->value;
int pos = 1, cmp = 0;
while (comp_to && *comp_to) {
if (*comp_to == '+') {
pos = 1;
} else if (*comp_to == '-') {
pos = 0;
} else if (*comp_to != ' ') {
break;
}
comp_to++;
}
comp_to++;
}
if (send && pos) {
continue;
}
if (send && pos) {
continue;
}
if (!comp_to) {
continue;
}
if (!comp_to) {
continue;
}
if (*hp->value == '/') {
switch_regex_t *re = NULL;
int ovector[30];
cmp = !!switch_regex_perform(hval, comp_to, &re, ovector, sizeof(ovector) / sizeof(ovector[0]));
switch_regex_safe_free(re);
} else {
cmp = !strcasecmp(hval, comp_to);
}
if (cmp) {
if (pos) {
send = 1;
if (*hp->value == '/') {
switch_regex_t *re = NULL;
int ovector[30];
cmp = !!switch_regex_perform(hval, comp_to, &re, ovector, sizeof(ovector) / sizeof(ovector[0]));
switch_regex_safe_free(re);
} else {
send = 0;
break;
cmp = !strcasecmp(hval, comp_to);
}
if (cmp) {
if (pos) {
send = 1;
} else {
send = 0;
break;
}
}
}
}
}
switch_mutex_unlock(l->filter_mutex);
}
@@ -101,7 +101,6 @@ static int next_file(switch_file_handle_t *handle)
handle->seekable = context->fh.seekable;
handle->speed = context->fh.speed;
handle->interval = context->fh.interval;
handle->flags = context->fh.flags;
if (context->index == 0) {
context->samples = (handle->samplerate / 1000) * 250;
+9 -4
View File
@@ -3,6 +3,10 @@
#include "freeswitch_lua.h"
using namespace LUA;
extern "C" {
int docall(lua_State * L, int narg, int clear, int perror);
};
Session::Session():CoreSession()
{
cb_function = cb_arg = hangup_func_str = hangup_func_arg = NULL;
@@ -137,7 +141,7 @@ void Session::do_hangup_hook()
arg_count++;
}
lua_call(L, arg_count, 1);
docall(L, arg_count, 1, 1);
err = lua_tostring(L, -1);
if (!zstr(err)) {
@@ -273,7 +277,8 @@ switch_status_t Session::run_dtmf_callback(void *input, switch_input_type_t ityp
arg_count++;
}
lua_call(L, arg_count, 1);
docall(L, arg_count, 0, 1);
ret = lua_tostring(L, -1);
lua_pop(L, 1);
@@ -297,7 +302,7 @@ switch_status_t Session::run_dtmf_callback(void *input, switch_input_type_t ityp
arg_count++;
}
lua_call(L, arg_count, 1);
docall(L, arg_count, 1, 1);
ret = lua_tostring(L, -1);
lua_pop(L, 1);
@@ -374,7 +379,7 @@ int Dbh::query_callback(void *pArg, int argc, char **argv, char **cargv)
lua_settable(lua_fun->L, -3);
}
lua_call(lua_fun->L, 1, 1); /* 1 in, 1 out */
docall(lua_fun->L, 1, 1, 1); /* 1 in, 1 out */
if (lua_isnumber(lua_fun->L, -1)) {
if (lua_tonumber(lua_fun->L, -1) != 0) {
+17 -8
View File
@@ -80,7 +80,7 @@ static int traceback(lua_State * L)
return 1;
}
static int docall(lua_State * L, int narg, int clear)
int docall(lua_State * L, int narg, int clear, int perror)
{
int status;
int base = lua_gettop(L) - narg; /* function index */
@@ -92,13 +92,22 @@ static int docall(lua_State * L, int narg, int clear)
lua_remove(L, base); /* remove traceback function */
/* force a complete garbage collection in case of errors */
if (status != 0)
if (status != 0) {
lua_gc(L, LUA_GCCOLLECT, 0);
}
if (status && perror) {
const char *err = lua_tostring(L, -1);
if (!zstr(err)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s\n", err);
}
lua_pop(L, 1); /* pop error message from the stack */
}
return status;
}
static lua_State *lua_init(void)
{
lua_State *L = lua_open();
@@ -111,7 +120,7 @@ static lua_State *lua_init(void)
luaopen_freeswitch(L);
lua_gc(L, LUA_GCRESTART, 0);
lua_atpanic(L, panic);
error = luaL_loadbuffer(L, buff, strlen(buff), "line") || docall(L, 0, 1);
error = luaL_loadbuffer(L, buff, strlen(buff), "line") || docall(L, 0, 1, 0);
}
return L;
}
@@ -128,7 +137,7 @@ static int lua_parse_and_execute(lua_State * L, char *input_code)
if (*input_code == '~') {
char *buff = input_code + 1;
error = luaL_loadbuffer(L, buff, strlen(buff), "line") || docall(L, 0, 1); //lua_pcall(L, 0, 0, 0);
error = luaL_loadbuffer(L, buff, strlen(buff), "line") || docall(L, 0, 1, 0); //lua_pcall(L, 0, 0, 0);
} else {
char *args = strchr(input_code, ' ');
if (args) {
@@ -152,14 +161,14 @@ static int lua_parse_and_execute(lua_State * L, char *input_code)
}
if (code) {
error = luaL_loadbuffer(L, code, strlen(code), "line") || docall(L, 0, 1);
error = luaL_loadbuffer(L, code, strlen(code), "line") || docall(L, 0, 1, 0);
switch_safe_free(code);
}
} else {
// Force empty argv table
char *code = NULL;
code = switch_mprintf("argv = {[0]='%s'};", input_code);
error = luaL_loadbuffer(L, code, strlen(code), "line") || docall(L, 0, 1);
error = luaL_loadbuffer(L, code, strlen(code), "line") || docall(L, 0, 1, 0);
switch_safe_free(code);
}
@@ -171,7 +180,7 @@ static int lua_parse_and_execute(lua_State * L, char *input_code)
switch_assert(fdup);
file = fdup;
}
error = luaL_loadfile(L, file) || docall(L, 0, 1);
error = luaL_loadfile(L, file) || docall(L, 0, 1, 0);
switch_safe_free(fdup);
}
}
@@ -9315,6 +9315,16 @@ SWIGEXPORT int SWIGSTDCALL CSharp_set_high_priority() {
}
SWIGEXPORT int SWIGSTDCALL CSharp_set_normal_priority() {
int jresult ;
int32_t result;
result = (int32_t)set_normal_priority();
jresult = result;
return jresult;
}
SWIGEXPORT int SWIGSTDCALL CSharp_change_user_group(char * jarg1, char * jarg2) {
int jresult ;
char *arg1 = (char *) 0 ;
@@ -9638,6 +9648,14 @@ SWIGEXPORT void SWIGSTDCALL CSharp_switch_time_set_monotonic(int jarg1) {
}
SWIGEXPORT void SWIGSTDCALL CSharp_switch_time_set_timerfd(int jarg1) {
switch_bool_t arg1 ;
arg1 = (switch_bool_t)jarg1;
switch_time_set_timerfd(arg1);
}
SWIGEXPORT void SWIGSTDCALL CSharp_switch_time_set_nanosleep(int jarg1) {
switch_bool_t arg1 ;
@@ -23128,6 +23146,14 @@ SWIGEXPORT void SWIGSTDCALL CSharp_switch_channel_set_caller_extension(void * ja
}
SWIGEXPORT void SWIGSTDCALL CSharp_switch_channel_flip_cid(void * jarg1) {
switch_channel_t *arg1 = (switch_channel_t *) 0 ;
arg1 = (switch_channel_t *)jarg1;
switch_channel_flip_cid(arg1);
}
SWIGEXPORT void SWIGSTDCALL CSharp_switch_channel_sort_cid(void * jarg1, int jarg2) {
switch_channel_t *arg1 = (switch_channel_t *) 0 ;
switch_bool_t arg2 ;
@@ -9606,6 +9606,16 @@ SWIGEXPORT int SWIGSTDCALL CSharp_set_high_priority() {
}
SWIGEXPORT int SWIGSTDCALL CSharp_set_normal_priority() {
int jresult ;
int32_t result;
result = (int32_t)set_normal_priority();
jresult = result;
return jresult;
}
SWIGEXPORT int SWIGSTDCALL CSharp_change_user_group(char * jarg1, char * jarg2) {
int jresult ;
char *arg1 = (char *) 0 ;
@@ -9929,6 +9939,14 @@ SWIGEXPORT void SWIGSTDCALL CSharp_switch_time_set_monotonic(int jarg1) {
}
SWIGEXPORT void SWIGSTDCALL CSharp_switch_time_set_timerfd(int jarg1) {
switch_bool_t arg1 ;
arg1 = (switch_bool_t)jarg1;
switch_time_set_timerfd(arg1);
}
SWIGEXPORT void SWIGSTDCALL CSharp_switch_time_set_nanosleep(int jarg1) {
switch_bool_t arg1 ;
@@ -23791,6 +23809,14 @@ SWIGEXPORT void SWIGSTDCALL CSharp_switch_channel_set_caller_extension(void * ja
}
SWIGEXPORT void SWIGSTDCALL CSharp_switch_channel_flip_cid(void * jarg1) {
switch_channel_t *arg1 = (switch_channel_t *) 0 ;
arg1 = (switch_channel_t *)jarg1;
switch_channel_flip_cid(arg1);
}
SWIGEXPORT void SWIGSTDCALL CSharp_switch_channel_sort_cid(void * jarg1, int jarg2) {
switch_channel_t *arg1 = (switch_channel_t *) 0 ;
switch_bool_t arg2 ;
@@ -2134,6 +2134,11 @@ public class freeswitch {
return ret;
}
public static int set_normal_priority() {
int ret = freeswitchPINVOKE.set_normal_priority();
return ret;
}
public static int change_user_group(string user, string group) {
int ret = freeswitchPINVOKE.change_user_group(user, group);
return ret;
@@ -2275,6 +2280,10 @@ public class freeswitch {
freeswitchPINVOKE.switch_time_set_monotonic((int)enable);
}
public static void switch_time_set_timerfd(switch_bool_t enable) {
freeswitchPINVOKE.switch_time_set_timerfd((int)enable);
}
public static void switch_time_set_nanosleep(switch_bool_t enable) {
freeswitchPINVOKE.switch_time_set_nanosleep((int)enable);
}
@@ -3415,6 +3424,10 @@ public class freeswitch {
freeswitchPINVOKE.switch_channel_set_caller_extension(SWIGTYPE_p_switch_channel.getCPtr(channel), switch_caller_extension.getCPtr(caller_extension));
}
public static void switch_channel_flip_cid(SWIGTYPE_p_switch_channel channel) {
freeswitchPINVOKE.switch_channel_flip_cid(SWIGTYPE_p_switch_channel.getCPtr(channel));
}
public static void switch_channel_sort_cid(SWIGTYPE_p_switch_channel channel, switch_bool_t arg1) {
freeswitchPINVOKE.switch_channel_sort_cid(SWIGTYPE_p_switch_channel.getCPtr(channel), (int)arg1);
}
@@ -8068,6 +8081,9 @@ class freeswitchPINVOKE {
[DllImport("mod_managed", EntryPoint="CSharp_set_high_priority")]
public static extern int set_high_priority();
[DllImport("mod_managed", EntryPoint="CSharp_set_normal_priority")]
public static extern int set_normal_priority();
[DllImport("mod_managed", EntryPoint="CSharp_change_user_group")]
public static extern int change_user_group(string jarg1, string jarg2);
@@ -8155,6 +8171,9 @@ class freeswitchPINVOKE {
[DllImport("mod_managed", EntryPoint="CSharp_switch_time_set_monotonic")]
public static extern void switch_time_set_monotonic(int jarg1);
[DllImport("mod_managed", EntryPoint="CSharp_switch_time_set_timerfd")]
public static extern void switch_time_set_timerfd(int jarg1);
[DllImport("mod_managed", EntryPoint="CSharp_switch_time_set_nanosleep")]
public static extern void switch_time_set_nanosleep(int jarg1);
@@ -11500,6 +11519,9 @@ class freeswitchPINVOKE {
[DllImport("mod_managed", EntryPoint="CSharp_switch_channel_set_caller_extension")]
public static extern void switch_channel_set_caller_extension(HandleRef jarg1, HandleRef jarg2);
[DllImport("mod_managed", EntryPoint="CSharp_switch_channel_flip_cid")]
public static extern void switch_channel_flip_cid(HandleRef jarg1);
[DllImport("mod_managed", EntryPoint="CSharp_switch_channel_sort_cid")]
public static extern void switch_channel_sort_cid(HandleRef jarg1, int jarg2);
@@ -21716,6 +21738,8 @@ public enum switch_channel_flag_t {
CF_DIALPLAN,
CF_BLOCK_BROADCAST_UNTIL_MEDIA,
CF_CNG_PLC,
CF_ATTENDED_TRANSFER,
CF_LAZY_ATTENDED_TRANSFER,
CF_FLAG_MAX
}
@@ -28777,7 +28801,7 @@ namespace FreeSWITCH.Native {
SWITCH_RTP_FLAG_BREAK = (1 << 10),
SWITCH_RTP_FLAG_UDPTL = (1 << 11),
SWITCH_RTP_FLAG_DATAWAIT = (1 << 12),
SWITCH_RTP_FLAG_BUGGY_2833 = (1 << 13),
SWITCH_RTP_FLAG_BYTESWAP = (1 << 13),
SWITCH_RTP_FLAG_PASS_RFC2833 = (1 << 14),
SWITCH_RTP_FLAG_AUTO_CNG = (1 << 15),
SWITCH_RTP_FLAG_SECURE_SEND_RESET = (1 << 16),
+25 -1
View File
@@ -2124,6 +2124,11 @@ public class freeswitch {
return ret;
}
public static int set_normal_priority() {
int ret = freeswitchPINVOKE.set_normal_priority();
return ret;
}
public static int change_user_group(string user, string group) {
int ret = freeswitchPINVOKE.change_user_group(user, group);
return ret;
@@ -2265,6 +2270,10 @@ public class freeswitch {
freeswitchPINVOKE.switch_time_set_monotonic((int)enable);
}
public static void switch_time_set_timerfd(switch_bool_t enable) {
freeswitchPINVOKE.switch_time_set_timerfd((int)enable);
}
public static void switch_time_set_nanosleep(switch_bool_t enable) {
freeswitchPINVOKE.switch_time_set_nanosleep((int)enable);
}
@@ -3405,6 +3414,10 @@ public class freeswitch {
freeswitchPINVOKE.switch_channel_set_caller_extension(SWIGTYPE_p_switch_channel.getCPtr(channel), switch_caller_extension.getCPtr(caller_extension));
}
public static void switch_channel_flip_cid(SWIGTYPE_p_switch_channel channel) {
freeswitchPINVOKE.switch_channel_flip_cid(SWIGTYPE_p_switch_channel.getCPtr(channel));
}
public static void switch_channel_sort_cid(SWIGTYPE_p_switch_channel channel, switch_bool_t arg1) {
freeswitchPINVOKE.switch_channel_sort_cid(SWIGTYPE_p_switch_channel.getCPtr(channel), (int)arg1);
}
@@ -8054,6 +8067,9 @@ class freeswitchPINVOKE {
[DllImport("mod_managed", EntryPoint="CSharp_set_high_priority")]
public static extern int set_high_priority();
[DllImport("mod_managed", EntryPoint="CSharp_set_normal_priority")]
public static extern int set_normal_priority();
[DllImport("mod_managed", EntryPoint="CSharp_change_user_group")]
public static extern int change_user_group(string jarg1, string jarg2);
@@ -8141,6 +8157,9 @@ class freeswitchPINVOKE {
[DllImport("mod_managed", EntryPoint="CSharp_switch_time_set_monotonic")]
public static extern void switch_time_set_monotonic(int jarg1);
[DllImport("mod_managed", EntryPoint="CSharp_switch_time_set_timerfd")]
public static extern void switch_time_set_timerfd(int jarg1);
[DllImport("mod_managed", EntryPoint="CSharp_switch_time_set_nanosleep")]
public static extern void switch_time_set_nanosleep(int jarg1);
@@ -11486,6 +11505,9 @@ class freeswitchPINVOKE {
[DllImport("mod_managed", EntryPoint="CSharp_switch_channel_set_caller_extension")]
public static extern void switch_channel_set_caller_extension(HandleRef jarg1, HandleRef jarg2);
[DllImport("mod_managed", EntryPoint="CSharp_switch_channel_flip_cid")]
public static extern void switch_channel_flip_cid(HandleRef jarg1);
[DllImport("mod_managed", EntryPoint="CSharp_switch_channel_sort_cid")]
public static extern void switch_channel_sort_cid(HandleRef jarg1, int jarg2);
@@ -21664,6 +21686,8 @@ public enum switch_channel_flag_t {
CF_DIALPLAN,
CF_BLOCK_BROADCAST_UNTIL_MEDIA,
CF_CNG_PLC,
CF_ATTENDED_TRANSFER,
CF_LAZY_ATTENDED_TRANSFER,
CF_FLAG_MAX
}
@@ -28627,7 +28651,7 @@ namespace FreeSWITCH.Native {
SWITCH_RTP_FLAG_BREAK = (1 << 10),
SWITCH_RTP_FLAG_UDPTL = (1 << 11),
SWITCH_RTP_FLAG_DATAWAIT = (1 << 12),
SWITCH_RTP_FLAG_BUGGY_2833 = (1 << 13),
SWITCH_RTP_FLAG_BYTESWAP = (1 << 13),
SWITCH_RTP_FLAG_PASS_RFC2833 = (1 << 14),
SWITCH_RTP_FLAG_AUTO_CNG = (1 << 15),
SWITCH_RTP_FLAG_SECURE_SEND_RESET = (1 << 16),
@@ -240,7 +240,6 @@ void Session::unsetInputCallback(void)
cb_arg = NULL;
}
switch_channel_set_private(channel, "CoreSession", NULL);
args.input_callback = NULL;
ap = NULL;
+257
View File
@@ -0,0 +1,257 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II <anthm@freeswitch.org>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Timo Teräs <timo.teras@iki.fi>
*
*
* mod_timerfd.c -- Timer implementation using Linux timerfd
*
*/
#include <switch.h>
#include <sys/timerfd.h>
#include <sys/epoll.h>
SWITCH_MODULE_LOAD_FUNCTION(mod_timerfd_load);
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_timerfd_shutdown);
SWITCH_MODULE_RUNTIME_FUNCTION(mod_timerfd_runtime);
SWITCH_MODULE_DEFINITION(mod_timerfd, mod_timerfd_load, mod_timerfd_shutdown, mod_timerfd_runtime);
#define MAX_INTERVAL 2000 /* ms */
struct interval_timer {
int fd;
int users;
switch_size_t tick;
switch_mutex_t *mutex;
switch_thread_cond_t *cond;
};
typedef struct interval_timer interval_timer_t;
static switch_memory_pool_t *module_pool = NULL;
static switch_mutex_t *interval_timers_mutex;
static interval_timer_t interval_timers[MAX_INTERVAL + 1];
static int interval_poll_fd;
static switch_status_t timerfd_start_interval(interval_timer_t *it, int interval)
{
struct itimerspec val;
struct epoll_event e;
int fd;
it->users++;
if (it->users > 1)
return SWITCH_STATUS_SUCCESS;
it->tick = 0;
switch_mutex_init(&it->mutex, SWITCH_MUTEX_NESTED, module_pool);
switch_thread_cond_create(&it->cond, module_pool);
fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
if (fd < 0)
return SWITCH_STATUS_GENERR;
val.it_interval.tv_sec = interval / 1000;
val.it_interval.tv_nsec = (interval % 1000) * 1000000;
val.it_value.tv_sec = 0;
val.it_value.tv_nsec = 100000;
if (timerfd_settime(fd, 0, &val, NULL) < 0) {
close(fd);
return SWITCH_STATUS_GENERR;
}
e.events = EPOLLIN | EPOLLERR;
e.data.ptr = it;
if (epoll_ctl(interval_poll_fd, EPOLL_CTL_ADD, fd, &e) < 0) {
close(fd);
return SWITCH_STATUS_GENERR;
}
it->fd = fd;
return SWITCH_STATUS_SUCCESS;
}
static switch_status_t timerfd_stop_interval(interval_timer_t *it)
{
it->users--;
if (it->users > 0)
return SWITCH_STATUS_SUCCESS;
close(it->fd);
it->fd = -1;
return SWITCH_STATUS_SUCCESS;
}
static switch_status_t timerfd_init(switch_timer_t *timer)
{
interval_timer_t *it;
int rc;
if (timer->interval < 1 || timer->interval > MAX_INTERVAL)
return SWITCH_STATUS_GENERR;
it = &interval_timers[timer->interval];
switch_mutex_lock(interval_timers_mutex);
rc = timerfd_start_interval(it, timer->interval);
timer->private_info = it;
switch_mutex_unlock(interval_timers_mutex);
return rc;
}
static switch_status_t timerfd_step(switch_timer_t *timer)
{
timer->tick++;
timer->samplecount += timer->samples;
return SWITCH_STATUS_SUCCESS;
}
static switch_status_t timerfd_next(switch_timer_t *timer)
{
interval_timer_t *it = timer->private_info;
if ((int)(timer->tick - it->tick) < -1)
timer->tick = it->tick;
timerfd_step(timer);
switch_mutex_lock(it->mutex);
while ((int)(timer->tick - it->tick) > 0)
switch_thread_cond_wait(it->cond, it->mutex);
switch_mutex_unlock(it->mutex);
return SWITCH_STATUS_SUCCESS;
}
static switch_status_t timerfd_sync(switch_timer_t *timer)
{
interval_timer_t *it = timer->private_info;
timer->tick = it->tick;
return SWITCH_STATUS_SUCCESS;
}
static switch_status_t timerfd_check(switch_timer_t *timer, switch_bool_t step)
{
interval_timer_t *it = timer->private_info;
int diff = (int)(timer->tick - it->tick);
if (diff > 0) {
/* still pending */
timer->diff = diff;
return SWITCH_STATUS_FALSE;
} else {
/* timer pending */
timer->diff = 0;
if (step)
timerfd_step(timer);
return SWITCH_STATUS_SUCCESS;
}
}
static switch_status_t timerfd_destroy(switch_timer_t *timer)
{
interval_timer_t *it = timer->private_info;
int rc;
switch_mutex_lock(interval_timers_mutex);
rc = timerfd_stop_interval(it);
switch_mutex_unlock(interval_timers_mutex);
return rc;
}
SWITCH_MODULE_LOAD_FUNCTION(mod_timerfd_load)
{
switch_timer_interface_t *timer_interface;
module_pool = pool;
interval_poll_fd = epoll_create(16);
if (interval_poll_fd < 0)
return SWITCH_STATUS_GENERR;
switch_mutex_init(&interval_timers_mutex, SWITCH_MUTEX_NESTED, module_pool);
memset(interval_timers, 0, sizeof(interval_timers));
/* connect my internal structure to the blank pointer passed to me */
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
timer_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_TIMER_INTERFACE);
timer_interface->interface_name = "timerfd";
timer_interface->timer_init = timerfd_init;
timer_interface->timer_next = timerfd_next;
timer_interface->timer_step = timerfd_step;
timer_interface->timer_sync = timerfd_sync;
timer_interface->timer_check = timerfd_check;
timer_interface->timer_destroy = timerfd_destroy;
return SWITCH_STATUS_SUCCESS;
}
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_timerfd_shutdown)
{
close(interval_poll_fd);
return SWITCH_STATUS_SUCCESS;
}
SWITCH_MODULE_RUNTIME_FUNCTION(mod_timerfd_runtime)
{
struct epoll_event e[16];
interval_timer_t *it;
uint64_t u64;
int i, r;
do {
r = epoll_wait(interval_poll_fd, e, sizeof(e) / sizeof(e[0]), 1000);
if (r < 0)
break;
for (i = 0; i < r; i++) {
it = e[i].data.ptr;
if ((e[i].events & EPOLLIN) &&
read(it->fd, &u64, sizeof(u64)) == sizeof(u64)) {
switch_mutex_lock(it->mutex);
it->tick += u64;
switch_thread_cond_broadcast(it->cond);
switch_mutex_unlock(it->mutex);
}
}
} while (1);
return SWITCH_STATUS_TERM;
}
/* For Emacs:
* Local Variables:
* mode:c
* indent-tabs-mode:t
* tab-width:4
* c-basic-offset:4
* End:
* For VIM:
* vim:set softtabstop=4 shiftwidth=4 tabstop=4:
*/
+2 -2
View File
@@ -599,8 +599,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_xml_cdr_load)
}
if (globals.retries && globals.delay <= 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Retries set but delay 0 setting to 5000ms\n");
globals.delay = 5000;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Retries set but delay 0 setting to 5 seconds\n");
globals.delay = 5;
}
globals.retries++;