forked from Mirrors/freeswitch
Merge branch 'master' of git@git.freeswitch.org:freeswitch
This commit is contained in:
commit
484e0abe7a
@ -705,7 +705,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_h323", "src\mod\endpoin
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_distributor", "src\mod\applications\mod_distributor\mod_distributor.2010.vcxproj", "{5C2B4D88-3BEA-4FE0-90DF-FA9836099D5F}"
|
||||
EndProject
|
||||
Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "Setup", "Setup\Setup.wixproj", "{47213370-B933-487D-9F45-BCA26D7E2B6F}"
|
||||
Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "Setup", "w32\Setup\Setup.wixproj", "{47213370-B933-487D-9F45-BCA26D7E2B6F}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
|
@ -97,29 +97,6 @@ static struct {
|
||||
switch_event_node_t *node;
|
||||
} globals;
|
||||
|
||||
typedef enum {
|
||||
CALLER_CONTROL_MUTE,
|
||||
CALLER_CONTROL_MUTE_ON,
|
||||
CALLER_CONTROL_MUTE_OFF,
|
||||
CALLER_CONTROL_DEAF_MUTE,
|
||||
CALLER_CONTROL_ENERGY_UP,
|
||||
CALLER_CONTROL_ENERGY_EQU_CONF,
|
||||
CALLER_CONTROL_ENERGY_DN,
|
||||
CALLER_CONTROL_VOL_TALK_UP,
|
||||
CALLER_CONTROL_VOL_TALK_ZERO,
|
||||
CALLER_CONTROL_VOL_TALK_DN,
|
||||
CALLER_CONTROL_VOL_LISTEN_UP,
|
||||
CALLER_CONTROL_VOL_LISTEN_ZERO,
|
||||
CALLER_CONTROL_VOL_LISTEN_DN,
|
||||
CALLER_CONTROL_HANGUP,
|
||||
CALLER_CONTROL_MENU,
|
||||
CALLER_CONTROL_DIAL,
|
||||
CALLER_CONTROL_EVENT,
|
||||
CALLER_CONTROL_LOCK,
|
||||
CALLER_CONTROL_TRANSFER,
|
||||
CALLER_CONTROL_EXEC_APP
|
||||
} caller_control_t;
|
||||
|
||||
/* forward declaration for conference_obj and caller_control */
|
||||
struct conference_member;
|
||||
typedef struct conference_member conference_member_t;
|
||||
@ -133,17 +110,10 @@ typedef struct call_list call_list_t;
|
||||
|
||||
struct caller_control_actions;
|
||||
|
||||
typedef struct caller_control_fn_table {
|
||||
char *key;
|
||||
char *digits;
|
||||
caller_control_t action;
|
||||
void (*handler) (conference_member_t *, struct caller_control_actions *);
|
||||
} caller_control_fn_table_t;
|
||||
|
||||
typedef struct caller_control_actions {
|
||||
caller_control_fn_table_t *fndesc;
|
||||
char *binded_dtmf;
|
||||
void *data;
|
||||
char *data;
|
||||
char *expanded_data;
|
||||
} caller_control_action_t;
|
||||
|
||||
typedef struct caller_control_menu_info {
|
||||
@ -271,12 +241,12 @@ typedef struct conference_obj {
|
||||
uint32_t max_members;
|
||||
char *maxmember_sound;
|
||||
uint32_t announce_count;
|
||||
switch_ivr_digit_stream_parser_t *dtmf_parser;
|
||||
char *pin;
|
||||
char *pin_sound;
|
||||
char *bad_pin_sound;
|
||||
char *profile_name;
|
||||
char *domain;
|
||||
char *caller_controls;
|
||||
uint32_t flags;
|
||||
member_flag_t mflags;
|
||||
switch_call_cause_t bridge_hangup_cause;
|
||||
@ -362,8 +332,6 @@ struct conference_member {
|
||||
uint32_t resample_out_len;
|
||||
conference_file_node_t *fnode;
|
||||
conference_relationship_t *relationships;
|
||||
switch_ivr_digit_stream_parser_t *dtmf_parser;
|
||||
switch_ivr_digit_stream_t *digit_stream;
|
||||
switch_speech_handle_t lsh;
|
||||
switch_speech_handle_t *sh;
|
||||
uint32_t verbose_events;
|
||||
@ -371,6 +339,7 @@ struct conference_member {
|
||||
uint32_t avg_itt;
|
||||
uint32_t avg_tally;
|
||||
struct conference_member *next;
|
||||
switch_ivr_dmachine_t *dmachine;
|
||||
};
|
||||
|
||||
/* Record Node */
|
||||
@ -414,6 +383,7 @@ static void conference_send_all_dtmf(conference_member_t *member, conference_obj
|
||||
static switch_status_t conference_say(conference_obj_t *conference, const char *text, uint32_t leadin);
|
||||
static void conference_list(conference_obj_t *conference, switch_stream_handle_t *stream, char *delim);
|
||||
static conference_obj_t *conference_find(char *name);
|
||||
static void member_bind_controls(conference_member_t *member, const char *controls);
|
||||
|
||||
SWITCH_STANDARD_API(conf_api_main);
|
||||
|
||||
@ -656,6 +626,7 @@ static switch_status_t conference_add_member(conference_obj_t *conference, confe
|
||||
char msg[512]; /* conference count announcement */
|
||||
call_list_t *call_list = NULL;
|
||||
switch_channel_t *channel;
|
||||
const char *controls = NULL;
|
||||
|
||||
switch_assert(conference != NULL);
|
||||
switch_assert(member != NULL);
|
||||
@ -712,7 +683,7 @@ static switch_status_t conference_add_member(conference_obj_t *conference, confe
|
||||
conference_stop_file(conference, FILE_STOP_ASYNC);
|
||||
}
|
||||
|
||||
if (!switch_channel_test_app_flag_key("conf_silent", channel, CONF_SILENT_REQ)) {
|
||||
if (!switch_channel_test_app_flag_key("conf_silent", channel, CONF_SILENT_REQ) && !zstr(conference->enter_sound)) {
|
||||
conference_play_file(conference, conference->enter_sound, CONF_DEFAULT_LEADIN, switch_core_session_get_channel(member->session),
|
||||
switch_test_flag(conference, CFLAG_WAIT_MOD) ? 0 : 1);
|
||||
}
|
||||
@ -765,6 +736,24 @@ static switch_status_t conference_add_member(conference_obj_t *conference, confe
|
||||
}
|
||||
|
||||
switch_channel_clear_app_flag_key("conf_silent", channel, CONF_SILENT_REQ);
|
||||
|
||||
|
||||
switch_ivr_dmachine_create(&member->dmachine, "mod_conference", NULL, 500, 0, NULL, NULL, NULL);
|
||||
|
||||
controls = switch_channel_get_variable(channel, "conference_controls");
|
||||
|
||||
if (zstr(controls)) {
|
||||
controls = conference->caller_controls;
|
||||
}
|
||||
|
||||
if (zstr(controls)) {
|
||||
controls = "default";
|
||||
}
|
||||
|
||||
if (strcasecmp(controls, "none")) {
|
||||
member_bind_controls(member, controls);
|
||||
}
|
||||
|
||||
}
|
||||
unlock_member(member);
|
||||
switch_mutex_unlock(member->audio_out_mutex);
|
||||
@ -795,6 +784,8 @@ static switch_status_t conference_del_member(conference_obj_t *conference, confe
|
||||
member->sh = NULL;
|
||||
unlock_member(member);
|
||||
|
||||
switch_ivr_dmachine_destroy(&member->dmachine);
|
||||
|
||||
switch_mutex_lock(conference->mutex);
|
||||
switch_mutex_lock(conference->member_mutex);
|
||||
switch_mutex_lock(member->audio_in_mutex);
|
||||
@ -1462,8 +1453,6 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v
|
||||
switch_thread_rwlock_unlock(conference->rwlock);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Write Lock OFF\n");
|
||||
|
||||
switch_ivr_digit_stream_parser_destroy(conference->dtmf_parser);
|
||||
|
||||
if (conference->sh) {
|
||||
switch_speech_flag_t flags = SWITCH_SPEECH_FLAG_NONE;
|
||||
switch_core_speech_close(&conference->lsh, &flags);
|
||||
@ -1693,6 +1682,7 @@ static void conference_loop_fn_volume_talk_zero(conference_member_t *member, cal
|
||||
|
||||
switch_snprintf(msg, sizeof(msg), "Volume level %d", member->volume_out_level);
|
||||
conference_member_say(member, msg, 0);
|
||||
|
||||
}
|
||||
|
||||
static void conference_loop_fn_volume_talk_dn(conference_member_t *member, caller_control_action_t *action)
|
||||
@ -1801,7 +1791,7 @@ static void conference_loop_fn_event(conference_member_t *member, caller_control
|
||||
conference_add_event_member_data(member, event);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "dtmf");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "DTMF-Key", action->binded_dtmf);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Data", action->data);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Data", action->expanded_data);
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
}
|
||||
@ -1820,12 +1810,12 @@ static void conference_loop_fn_transfer(conference_member_t *member, caller_cont
|
||||
if (test_eflag(member->conference, EFLAG_DTMF) && switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
|
||||
conference_add_event_member_data(member, event);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "transfer");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Dialplan", action->data);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Dialplan", action->expanded_data);
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
switch_clear_flag_locked(member, MFLAG_RUNNING);
|
||||
|
||||
if ((mydata = switch_core_session_strdup(member->session, action->data))) {
|
||||
if ((mydata = switch_core_session_strdup(member->session, action->expanded_data))) {
|
||||
if ((argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0]))))) {
|
||||
if (argc > 0) {
|
||||
exten = argv[0];
|
||||
@ -1838,7 +1828,7 @@ static void conference_loop_fn_transfer(conference_member_t *member, caller_cont
|
||||
}
|
||||
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_ERROR, "Empty transfer string [%s]\n", (char *) action->data);
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_ERROR, "Empty transfer string [%s]\n", (char *) action->expanded_data);
|
||||
goto done;
|
||||
}
|
||||
} else {
|
||||
@ -1864,14 +1854,16 @@ static void conference_loop_fn_exec_app(conference_member_t *member, caller_cont
|
||||
switch_event_t *event = NULL;
|
||||
switch_channel_t *channel = NULL;
|
||||
|
||||
if (!action->expanded_data) return;
|
||||
|
||||
if (test_eflag(member->conference, EFLAG_DTMF) && switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
|
||||
conference_add_event_member_data(member, event);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "execute_app");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Application", action->data);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Application", action->expanded_data);
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
|
||||
if ((mydata = switch_core_session_strdup(member->session, action->data))) {
|
||||
if ((mydata = switch_core_session_strdup(member->session, action->expanded_data))) {
|
||||
if ((argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0]))))) {
|
||||
if (argc > 0) {
|
||||
app = argv[0];
|
||||
@ -1881,7 +1873,8 @@ static void conference_loop_fn_exec_app(conference_member_t *member, caller_cont
|
||||
}
|
||||
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_ERROR, "Empty execute app string [%s]\n", (char *) action->data);
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_ERROR, "Empty execute app string [%s]\n",
|
||||
(char *) action->expanded_data);
|
||||
goto done;
|
||||
}
|
||||
} else {
|
||||
@ -1893,6 +1886,7 @@ static void conference_loop_fn_exec_app(conference_member_t *member, caller_cont
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_ERROR, "Unable to find application.\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_DEBUG, "Execute app: %s, %s\n", app, arg);
|
||||
|
||||
channel = switch_core_session_get_channel(member->session);
|
||||
@ -1903,6 +1897,7 @@ static void conference_loop_fn_exec_app(conference_member_t *member, caller_cont
|
||||
switch_core_session_set_read_codec(member->session, &member->read_codec);
|
||||
switch_channel_clear_app_flag(channel, CF_APP_TAGGED);
|
||||
done:
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2307,29 +2302,6 @@ static void launch_conference_loop_input(conference_member_t *member, switch_mem
|
||||
switch_thread_create(&thread, thd_attr, conference_loop_input, member, pool);
|
||||
}
|
||||
|
||||
static caller_control_fn_table_t ccfntbl[] = {
|
||||
{"mute", "0", CALLER_CONTROL_MUTE, conference_loop_fn_mute_toggle},
|
||||
{"mute on", NULL, CALLER_CONTROL_MUTE_ON, conference_loop_fn_mute_on},
|
||||
{"mute off", NULL, CALLER_CONTROL_MUTE_OFF, conference_loop_fn_mute_off},
|
||||
{"deaf mute", "*", CALLER_CONTROL_DEAF_MUTE, conference_loop_fn_deafmute_toggle},
|
||||
{"energy up", "9", CALLER_CONTROL_ENERGY_UP, conference_loop_fn_energy_up},
|
||||
{"energy equ", "8", CALLER_CONTROL_ENERGY_EQU_CONF, conference_loop_fn_energy_equ_conf},
|
||||
{"energy dn", "7", CALLER_CONTROL_ENERGY_DN, conference_loop_fn_energy_dn},
|
||||
{"vol talk up", "3", CALLER_CONTROL_VOL_TALK_UP, conference_loop_fn_volume_talk_up},
|
||||
{"vol talk zero", "2", CALLER_CONTROL_VOL_TALK_ZERO, conference_loop_fn_volume_talk_zero},
|
||||
{"vol talk dn", "1", CALLER_CONTROL_VOL_TALK_DN, conference_loop_fn_volume_talk_dn},
|
||||
{"vol listen up", "6", CALLER_CONTROL_VOL_LISTEN_UP, conference_loop_fn_volume_listen_up},
|
||||
{"vol listen zero", "5", CALLER_CONTROL_VOL_LISTEN_ZERO, conference_loop_fn_volume_listen_zero},
|
||||
{"vol listen dn", "4", CALLER_CONTROL_VOL_LISTEN_DN, conference_loop_fn_volume_listen_dn},
|
||||
{"hangup", "#", CALLER_CONTROL_HANGUP, conference_loop_fn_hangup},
|
||||
{"event", NULL, CALLER_CONTROL_EVENT, conference_loop_fn_event},
|
||||
{"lock", NULL, CALLER_CONTROL_LOCK, conference_loop_fn_lock_toggle},
|
||||
{"transfer", NULL, CALLER_CONTROL_TRANSFER, conference_loop_fn_transfer},
|
||||
{"execute_application", NULL, CALLER_CONTROL_EXEC_APP, conference_loop_fn_exec_app}
|
||||
};
|
||||
|
||||
#define CCFNTBL_QTY (sizeof(ccfntbl)/sizeof(ccfntbl[0]))
|
||||
|
||||
/* marshall frames from the conference (or file or tts output) to the call leg */
|
||||
/* NB. this starts the input thread after some initial setup for the call leg */
|
||||
static void conference_loop_output(conference_member_t *member)
|
||||
@ -2400,13 +2372,6 @@ static void conference_loop_output(conference_member_t *member)
|
||||
/* Start the input thread */
|
||||
launch_conference_loop_input(member, switch_core_session_get_pool(member->session));
|
||||
|
||||
/* build a digit stream object */
|
||||
if (member->conference->dtmf_parser != NULL
|
||||
&& switch_ivr_digit_stream_new(member->conference->dtmf_parser, &member->digit_stream) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_ERROR,
|
||||
"Danger Will Robinson, there is no digit parser stream object\n");
|
||||
}
|
||||
|
||||
if ((call_list = switch_channel_get_private(channel, "_conference_autocall_list_"))) {
|
||||
const char *cid_name = switch_channel_get_variable(channel, "conference_auto_outcall_caller_id_name");
|
||||
const char *cid_num = switch_channel_get_variable(channel, "conference_auto_outcall_caller_id_number");
|
||||
@ -2457,9 +2422,7 @@ static void conference_loop_output(conference_member_t *member)
|
||||
while (switch_test_flag(member, MFLAG_RUNNING) && switch_test_flag(member, MFLAG_ITHREAD)
|
||||
&& switch_channel_ready(channel)) {
|
||||
char dtmf[128] = "";
|
||||
char *digit;
|
||||
switch_event_t *event;
|
||||
caller_control_action_t *caller_action = NULL;
|
||||
int use_timer = 0;
|
||||
switch_buffer_t *use_buffer = NULL;
|
||||
uint32_t mux_used = 0;
|
||||
@ -2513,40 +2476,13 @@ static void conference_loop_output(conference_member_t *member)
|
||||
|
||||
if (switch_test_flag(member, MFLAG_DIST_DTMF)) {
|
||||
conference_send_all_dtmf(member, member->conference, dtmf);
|
||||
} else {
|
||||
if (member->conference->dtmf_parser != NULL) {
|
||||
for (digit = dtmf; *digit && caller_action == NULL; digit++) {
|
||||
caller_action = (caller_control_action_t *)
|
||||
switch_ivr_digit_stream_parser_feed(member->conference->dtmf_parser, member->digit_stream, *digit);
|
||||
}
|
||||
}
|
||||
} else if (member->dmachine) {
|
||||
switch_ivr_dmachine_feed(member->dmachine, dtmf, NULL);
|
||||
}
|
||||
/* otherwise, clock the parser so that it can handle digit timeout detection */
|
||||
} else if (member->conference->dtmf_parser != NULL) {
|
||||
caller_action = (caller_control_action_t *) switch_ivr_digit_stream_parser_feed(member->conference->dtmf_parser, member->digit_stream, '\0');
|
||||
} else if (member->dmachine) {
|
||||
switch_ivr_dmachine_ping(member->dmachine, NULL);
|
||||
}
|
||||
|
||||
/* if a caller action has been detected, handle it */
|
||||
if (caller_action != NULL && caller_action->fndesc != NULL && caller_action->fndesc->handler != NULL) {
|
||||
char *param = NULL;
|
||||
|
||||
if (caller_action->fndesc->action != CALLER_CONTROL_MENU) {
|
||||
param = caller_action->data;
|
||||
}
|
||||
#ifdef INTENSE_DEBUG
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session),
|
||||
SWITCH_LOG_INFO,
|
||||
"executing caller control '%s' param '%s' on call '%u, %s\n",
|
||||
caller_action->fndesc->key, param ? param : "none", member->id, switch_channel_get_name(channel));
|
||||
#endif
|
||||
|
||||
caller_action->fndesc->handler(member, caller_action);
|
||||
|
||||
/* set up for next pass */
|
||||
caller_action = NULL;
|
||||
}
|
||||
|
||||
|
||||
use_buffer = NULL;
|
||||
mux_used = (uint32_t) switch_buffer_inuse(member->mux_buffer);
|
||||
|
||||
@ -2656,10 +2592,6 @@ static void conference_loop_output(conference_member_t *member)
|
||||
} /* Rinse ... Repeat */
|
||||
|
||||
|
||||
if (member->digit_stream != NULL) {
|
||||
switch_ivr_digit_stream_destroy(&member->digit_stream);
|
||||
}
|
||||
|
||||
switch_clear_flag_locked(member, MFLAG_RUNNING);
|
||||
switch_core_timer_destroy(&timer);
|
||||
|
||||
@ -2942,6 +2874,10 @@ static switch_status_t conference_play_file(conference_obj_t *conference, char *
|
||||
|
||||
switch_assert(conference != NULL);
|
||||
|
||||
if (zstr(file)) {
|
||||
return SWITCH_STATUS_NOTFOUND;
|
||||
}
|
||||
|
||||
switch_mutex_lock(conference->mutex);
|
||||
switch_mutex_lock(conference->member_mutex);
|
||||
count = conference->count;
|
||||
@ -4375,8 +4311,9 @@ static switch_status_t conf_api_sub_transfer(conference_obj_t *conference, switc
|
||||
if ((profiles = switch_xml_child(cfg, "profiles"))) {
|
||||
xml_cfg.profile = switch_xml_find_child(profiles, "profile", "name", profile_name);
|
||||
}
|
||||
|
||||
xml_cfg.controls = switch_xml_child(cfg, "caller-controls");
|
||||
|
||||
/* Create the conference object. */
|
||||
new_conference = conference_new(conf_name, xml_cfg, pool);
|
||||
|
||||
/* Release the config registry handle */
|
||||
if (cxml) {
|
||||
@ -4384,9 +4321,6 @@ static switch_status_t conf_api_sub_transfer(conference_obj_t *conference, switc
|
||||
cxml = NULL;
|
||||
}
|
||||
|
||||
/* Create the conference object. */
|
||||
new_conference = conference_new(conf_name, xml_cfg, pool);
|
||||
|
||||
if (!new_conference) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n");
|
||||
if (pool != NULL) {
|
||||
@ -5455,8 +5389,6 @@ SWITCH_STANDARD_APP(conference_function)
|
||||
xml_cfg.profile = switch_xml_find_child(profiles, "profile", "name", profile_name);
|
||||
}
|
||||
|
||||
xml_cfg.controls = switch_xml_child(cfg, "caller-controls");
|
||||
|
||||
/* if this is a bridging call, and it's not a duplicate, build a */
|
||||
/* conference object, and skip pin handling, and locked checking */
|
||||
|
||||
@ -5788,9 +5720,6 @@ SWITCH_STANDARD_APP(conference_function)
|
||||
switch_buffer_destroy(&member.resample_buffer);
|
||||
switch_buffer_destroy(&member.audio_buffer);
|
||||
switch_buffer_destroy(&member.mux_buffer);
|
||||
if (conference && member.dtmf_parser != conference->dtmf_parser) {
|
||||
switch_ivr_digit_stream_parser_destroy(member.dtmf_parser);
|
||||
}
|
||||
|
||||
if (conference) {
|
||||
switch_mutex_lock(conference->mutex);
|
||||
@ -5939,88 +5868,6 @@ static switch_status_t chat_send(const char *proto, const char *from, const char
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static switch_status_t conf_default_controls(conference_obj_t *conference)
|
||||
{
|
||||
switch_status_t status = SWITCH_STATUS_FALSE;
|
||||
uint32_t i;
|
||||
caller_control_action_t *action;
|
||||
|
||||
switch_assert(conference != NULL);
|
||||
|
||||
for (i = 0, status = SWITCH_STATUS_SUCCESS; status == SWITCH_STATUS_SUCCESS && i < CCFNTBL_QTY; i++) {
|
||||
if (!zstr(ccfntbl[i].digits)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
|
||||
"Installing default caller control action '%s' bound to '%s'.\n", ccfntbl[i].key, ccfntbl[i].digits);
|
||||
action = (caller_control_action_t *) switch_core_alloc(conference->pool, sizeof(caller_control_action_t));
|
||||
if (action != NULL) {
|
||||
action->fndesc = &ccfntbl[i];
|
||||
action->data = NULL;
|
||||
status = switch_ivr_digit_stream_parser_set_event(conference->dtmf_parser, ccfntbl[i].digits, action);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
|
||||
"unable to alloc memory for caller control binding '%s' to '%s'\n", ccfntbl[i].key, ccfntbl[i].digits);
|
||||
status = SWITCH_STATUS_MEMERR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static switch_status_t conference_new_install_caller_controls_custom(conference_obj_t *conference, switch_xml_t xml_controls, switch_xml_t xml_menus)
|
||||
{
|
||||
switch_status_t status = SWITCH_STATUS_FALSE;
|
||||
switch_xml_t xml_kvp;
|
||||
|
||||
switch_assert(conference != NULL);
|
||||
|
||||
if (!xml_controls) {
|
||||
return status;
|
||||
}
|
||||
|
||||
/* parse the controls tree for caller control digit strings */
|
||||
for (xml_kvp = switch_xml_child(xml_controls, "control"); xml_kvp; xml_kvp = xml_kvp->next) {
|
||||
char *key = (char *) switch_xml_attr(xml_kvp, "action");
|
||||
char *val = (char *) switch_xml_attr(xml_kvp, "digits");
|
||||
char *data = (char *) switch_xml_attr_soft(xml_kvp, "data");
|
||||
|
||||
if (!zstr(key) && !zstr(val)) {
|
||||
uint32_t i;
|
||||
|
||||
/* scan through all of the valid actions, and if found, */
|
||||
/* set the new caller control action digit string, then */
|
||||
/* stop scanning the table, and go to the next xml kvp. */
|
||||
for (i = 0, status = SWITCH_STATUS_NOOP; i < CCFNTBL_QTY && status == SWITCH_STATUS_NOOP; i++) {
|
||||
|
||||
if (strcasecmp(ccfntbl[i].key, key) == 0) {
|
||||
|
||||
caller_control_action_t *action;
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Installing caller control action '%s' bound to '%s'.\n", key, val);
|
||||
action = (caller_control_action_t *) switch_core_alloc(conference->pool, sizeof(caller_control_action_t));
|
||||
if (action != NULL) {
|
||||
action->fndesc = &ccfntbl[i];
|
||||
action->data = (void *) switch_core_strdup(conference->pool, data);
|
||||
action->binded_dtmf = switch_core_strdup(conference->pool, val);
|
||||
status = switch_ivr_digit_stream_parser_set_event(conference->dtmf_parser, val, action);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
|
||||
"unable to alloc memory for caller control binding '%s' to '%s'\n", ccfntbl[i].key, ccfntbl[i].digits);
|
||||
status = SWITCH_STATUS_MEMERR;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (status == SWITCH_STATUS_NOOP) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid caller control action name '%s'.\n", key);
|
||||
}
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid caller control config entry pair action = '%s' digits = '%s'\n", key, val);
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static conference_obj_t *conference_find(char *name)
|
||||
{
|
||||
conference_obj_t *conference;
|
||||
@ -6263,7 +6110,8 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_m
|
||||
conference->comfort_noise_level = comfort_noise_level;
|
||||
conference->caller_id_name = switch_core_strdup(conference->pool, caller_id_name);
|
||||
conference->caller_id_number = switch_core_strdup(conference->pool, caller_id_number);
|
||||
|
||||
conference->caller_controls = switch_core_strdup(conference->pool, caller_controls);
|
||||
|
||||
|
||||
if (!zstr(perpetual_sound)) {
|
||||
conference->perpetual_sound = switch_core_strdup(conference->pool, perpetual_sound);
|
||||
@ -6387,7 +6235,6 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_m
|
||||
}
|
||||
conference->rate = rate;
|
||||
conference->interval = interval;
|
||||
conference->dtmf_parser = NULL;
|
||||
|
||||
conference->eflags = 0xFFFFFFFF;
|
||||
if (!zstr(suppress_events)) {
|
||||
@ -6405,27 +6252,6 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_m
|
||||
conference->verbose_events = 1;
|
||||
}
|
||||
|
||||
/* caller control configuration chores */
|
||||
if (switch_ivr_digit_stream_parser_new(conference->pool, &conference->dtmf_parser) == SWITCH_STATUS_SUCCESS) {
|
||||
|
||||
/* if no controls, or default controls specified, install default */
|
||||
if (caller_controls == NULL || *caller_controls == '\0' || strcasecmp(caller_controls, "default") == 0) {
|
||||
status = conf_default_controls(conference);
|
||||
} else if (strcasecmp(caller_controls, "none") != 0) {
|
||||
/* try to build caller control if the group has been specified and != "none" */
|
||||
switch_xml_t xml_controls = switch_xml_find_child(cfg.controls, "group", "name", caller_controls);
|
||||
status = conference_new_install_caller_controls_custom(conference, xml_controls, NULL);
|
||||
|
||||
if (status != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unable to install caller controls group '%s'\n", caller_controls);
|
||||
}
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "No caller controls installed.\n");
|
||||
}
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unable to allocate caller control digit parser.\n");
|
||||
}
|
||||
|
||||
/* Activate the conference mutex for exclusivity */
|
||||
switch_mutex_init(&conference->mutex, SWITCH_MUTEX_NESTED, conference->pool);
|
||||
switch_mutex_init(&conference->flag_mutex, SWITCH_MUTEX_NESTED, conference->pool);
|
||||
@ -6540,6 +6366,145 @@ static void send_presence(switch_event_types_t id)
|
||||
}
|
||||
}
|
||||
|
||||
typedef void (*conf_key_callback_t) (conference_member_t *, struct caller_control_actions *);
|
||||
|
||||
typedef struct {
|
||||
conference_member_t *member;
|
||||
caller_control_action_t action;
|
||||
conf_key_callback_t handler;
|
||||
} key_binding_t;
|
||||
|
||||
|
||||
static switch_status_t dmachine_dispatcher(switch_ivr_dmachine_match_t *match)
|
||||
{
|
||||
key_binding_t *binding = match->user_data;
|
||||
switch_channel_t *channel;
|
||||
|
||||
if (!binding) return SWITCH_STATUS_FALSE;
|
||||
|
||||
channel = switch_core_session_get_channel(binding->member->session);
|
||||
switch_channel_set_variable(channel, "conference_last_matching_digits", match->match_digits);
|
||||
|
||||
if (binding->action.data) {
|
||||
binding->action.expanded_data = switch_channel_expand_variables(channel, binding->action.data);
|
||||
}
|
||||
|
||||
binding->handler(binding->member, &binding->action);
|
||||
|
||||
if (binding->action.expanded_data != binding->action.data) {
|
||||
free(binding->action.expanded_data);
|
||||
binding->action.expanded_data = NULL;
|
||||
}
|
||||
|
||||
switch_set_flag_locked(binding->member, MFLAG_FLUSH_BUFFER);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static void do_binding(conference_member_t *member, conf_key_callback_t handler, const char *digits, const char *data)
|
||||
{
|
||||
key_binding_t *binding;
|
||||
|
||||
binding = switch_core_alloc(member->pool, sizeof(*binding));
|
||||
binding->member = member;
|
||||
|
||||
binding->action.binded_dtmf = switch_core_strdup(member->pool, digits);
|
||||
|
||||
if (data) {
|
||||
binding->action.data = switch_core_strdup(member->pool, data);
|
||||
}
|
||||
|
||||
binding->handler = handler;
|
||||
switch_ivr_dmachine_bind(member->dmachine, "conf", digits, 0, dmachine_dispatcher, binding);
|
||||
|
||||
}
|
||||
|
||||
struct _mapping {
|
||||
const char *name;
|
||||
conf_key_callback_t handler;
|
||||
};
|
||||
|
||||
static struct _mapping control_mappings[] = {
|
||||
{"mute", conference_loop_fn_mute_toggle},
|
||||
{"mute on", conference_loop_fn_mute_on},
|
||||
{"mute off", conference_loop_fn_mute_off},
|
||||
{"deaf mute", conference_loop_fn_deafmute_toggle},
|
||||
{"energy up", conference_loop_fn_energy_up},
|
||||
{"energy equ", conference_loop_fn_energy_equ_conf},
|
||||
{"energy dn", conference_loop_fn_energy_dn},
|
||||
{"vol talk up", conference_loop_fn_volume_talk_up},
|
||||
{"vol talk zero", conference_loop_fn_volume_talk_zero},
|
||||
{"vol talk dn", conference_loop_fn_volume_talk_dn},
|
||||
{"vol listen up", conference_loop_fn_volume_listen_up},
|
||||
{"vol listen zero", conference_loop_fn_volume_listen_zero},
|
||||
{"vol listen dn", conference_loop_fn_volume_listen_dn},
|
||||
{"hangup", conference_loop_fn_hangup},
|
||||
{"event", conference_loop_fn_event},
|
||||
{"lock", conference_loop_fn_lock_toggle},
|
||||
{"transfer", conference_loop_fn_transfer},
|
||||
{"execute_application", conference_loop_fn_exec_app}
|
||||
};
|
||||
#define MAPPING_LEN (sizeof(control_mappings)/sizeof(control_mappings[0]))
|
||||
|
||||
static void member_bind_controls(conference_member_t *member, const char *controls)
|
||||
{
|
||||
switch_xml_t cxml, cfg, xgroups, xcontrol;
|
||||
switch_event_t *params;
|
||||
int i;
|
||||
|
||||
switch_event_create(¶ms, SWITCH_EVENT_REQUEST_PARAMS);
|
||||
switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "Conf-Name", member->conference->name);
|
||||
switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "Action", "request-controls");
|
||||
switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "Controls", controls);
|
||||
|
||||
if (!(cxml = switch_xml_open_cfg(global_cf_name, &cfg, params))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", global_cf_name);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!(xgroups = switch_xml_child(cfg, "caller-controls"))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't find caller-controls in %s\n", global_cf_name);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!(xgroups = switch_xml_find_child(xgroups, "group", "name", controls))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't find caller-controls in %s\n", global_cf_name);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
||||
for (xcontrol = switch_xml_child(xgroups, "control"); xcontrol; xcontrol = xcontrol->next) {
|
||||
const char *key = switch_xml_attr(xcontrol, "action");
|
||||
const char *digits = switch_xml_attr(xcontrol, "digits");
|
||||
const char *data = switch_xml_attr_soft(xcontrol, "data");
|
||||
|
||||
if (zstr(key) || zstr(digits)) continue;
|
||||
|
||||
for(i = 0; i < MAPPING_LEN; i++) {
|
||||
if (!strcasecmp(key, control_mappings[i].name)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s binding '%s' to '%s'\n",
|
||||
switch_core_session_get_name(member->session), digits, key);
|
||||
|
||||
do_binding(member, control_mappings[i].handler, digits, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
|
||||
/* Release the config registry handle */
|
||||
if (cxml) {
|
||||
switch_xml_free(cxml);
|
||||
cxml = NULL;
|
||||
}
|
||||
|
||||
if (params) switch_event_destroy(¶ms);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* Called by FreeSWITCH when the module loads */
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_conference_load)
|
||||
{
|
||||
|
@ -223,11 +223,11 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_dmachine_bind(switch_ivr_dmachine_t *
|
||||
}
|
||||
|
||||
if (binding->is_regex) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Digit parser %s: binding realm: %s regex: %s key: %.4d callback: %p data: %p\n",
|
||||
dmachine->name, realm, digits, key, (void *)(intptr_t) callback, user_data);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Digit parser %s: binding %s/%s/%d callback: %p data: %p\n",
|
||||
dmachine->name, digits, realm, key, (void *)(intptr_t) callback, user_data);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Digit parser %s: binding realm %s digits: %4s key: %.4d callback: %p data: %p\n",
|
||||
dmachine->name, realm, digits, key, (void *)(intptr_t) callback, user_data);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Digit parser %s: binding %s/%s/%d callback: %p data: %p\n",
|
||||
dmachine->name, digits, realm, key, (void *)(intptr_t) callback, user_data);
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
@ -244,60 +244,61 @@ typedef enum {
|
||||
static dm_match_t switch_ivr_dmachine_check_match(switch_ivr_dmachine_t *dmachine, switch_bool_t is_timeout)
|
||||
{
|
||||
dm_match_t best = DM_MATCH_NONE;
|
||||
switch_ivr_dmachine_binding_t *bp, *exact_bp = NULL;
|
||||
int exact_count = 0, partial_count = 0, both_count = 0;
|
||||
switch_ivr_dmachine_binding_t *bp, *exact_bp = NULL, *partial_bp = NULL, *both_bp = NULL, *r_bp = NULL;
|
||||
|
||||
|
||||
if (!dmachine->cur_digit_len || !dmachine->realm) goto end;
|
||||
|
||||
for(bp = dmachine->realm->binding_list; bp; bp = bp->next) {
|
||||
|
||||
if (bp->is_regex) {
|
||||
switch_status_t r_status = switch_regex_match(dmachine->digits, bp->digits);
|
||||
|
||||
if (r_status == SWITCH_STATUS_SUCCESS) {
|
||||
if (is_timeout) {
|
||||
best = DM_MATCH_EXACT;
|
||||
exact_count++;
|
||||
exact_bp = bp;
|
||||
break;
|
||||
}
|
||||
|
||||
best = DM_MATCH_PARTIAL;
|
||||
partial_count++;
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
|
||||
if (!exact_bp && !strcmp(bp->digits, dmachine->digits)) {
|
||||
exact_bp = bp;
|
||||
best = DM_MATCH_EXACT;
|
||||
exact_count++;
|
||||
continue;
|
||||
exact_bp = bp;
|
||||
}
|
||||
|
||||
if (!strncmp(dmachine->digits, bp->digits, strlen(dmachine->digits))) {
|
||||
if (best == DM_MATCH_EXACT) {
|
||||
if (is_timeout) {
|
||||
best = DM_MATCH_EXACT;
|
||||
exact_count++;
|
||||
exact_bp = bp;
|
||||
} else {
|
||||
best = DM_MATCH_BOTH;
|
||||
both_count++;
|
||||
}
|
||||
if (!(both_bp && partial_bp) && !strncmp(dmachine->digits, bp->digits, strlen(dmachine->digits))) {
|
||||
if (exact_bp) {
|
||||
best = DM_MATCH_BOTH;
|
||||
both_bp = bp;
|
||||
} else {
|
||||
best = DM_MATCH_PARTIAL;
|
||||
partial_count++;
|
||||
partial_bp = bp;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (both_bp && exact_bp && partial_bp) break;
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
|
||||
if (is_timeout) {
|
||||
if (both_bp) {
|
||||
r_bp = both_bp;
|
||||
} else if (partial_bp) {
|
||||
r_bp = partial_bp;
|
||||
}
|
||||
}
|
||||
|
||||
if (best == DM_MATCH_EXACT && exact_bp) {
|
||||
r_bp = exact_bp;
|
||||
}
|
||||
|
||||
if (!both_count && exact_bp) {
|
||||
dmachine->last_matching_binding = exact_bp;
|
||||
|
||||
if (r_bp) {
|
||||
dmachine->last_matching_binding = r_bp;
|
||||
switch_set_string(dmachine->last_matching_digits, dmachine->digits);
|
||||
best = DM_MATCH_EXACT;
|
||||
}
|
||||
@ -343,7 +344,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_dmachine_ping(switch_ivr_dmachine_t *
|
||||
switch_bool_t is_timeout = switch_ivr_dmachine_check_timeout(dmachine);
|
||||
dm_match_t is_match = switch_ivr_dmachine_check_match(dmachine, is_timeout);
|
||||
switch_status_t r;
|
||||
|
||||
int clear = 0;
|
||||
|
||||
if (zstr(dmachine->digits) && !is_timeout) {
|
||||
r = SWITCH_STATUS_SUCCESS;
|
||||
} else if (dmachine->cur_digit_len > dmachine->max_digit_len) {
|
||||
@ -362,7 +364,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_dmachine_ping(switch_ivr_dmachine_t *
|
||||
dmachine->is_match = 1;
|
||||
|
||||
dmachine->match.type = DM_MATCH_POSITIVE;
|
||||
|
||||
|
||||
if (dmachine->last_matching_binding->callback) {
|
||||
dmachine->last_matching_binding->callback(&dmachine->match);
|
||||
}
|
||||
@ -371,10 +373,10 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_dmachine_ping(switch_ivr_dmachine_t *
|
||||
dmachine->match.user_data = dmachine->user_data;
|
||||
dmachine->match_callback(&dmachine->match);
|
||||
}
|
||||
|
||||
clear++;
|
||||
} else if (is_timeout) {
|
||||
r = SWITCH_STATUS_TIMEOUT;
|
||||
} else if (dmachine->cur_digit_len == dmachine->max_digit_len) {
|
||||
} else if (is_match == DM_MATCH_NONE && dmachine->cur_digit_len == dmachine->max_digit_len) {
|
||||
r = SWITCH_STATUS_NOTFOUND;
|
||||
} else {
|
||||
r = SWITCH_STATUS_SUCCESS;
|
||||
@ -390,9 +392,11 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_dmachine_ping(switch_ivr_dmachine_t *
|
||||
dmachine->match.user_data = dmachine->user_data;
|
||||
dmachine->nonmatch_callback(&dmachine->match);
|
||||
}
|
||||
|
||||
clear++;
|
||||
}
|
||||
|
||||
if (r != SWITCH_STATUS_SUCCESS) {
|
||||
if (clear) {
|
||||
switch_ivr_dmachine_clear(dmachine);
|
||||
}
|
||||
|
||||
@ -414,6 +418,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_dmachine_feed(switch_ivr_dmachine_t *
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_ivr_dmachine_clear(switch_ivr_dmachine_t *dmachine)
|
||||
{
|
||||
|
||||
memset(dmachine->digits, 0, sizeof(dmachine->digits));
|
||||
dmachine->cur_digit_len = 0;
|
||||
dmachine->last_digit_time = 0;
|
||||
|
Loading…
Reference in New Issue
Block a user