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