switch_mutex_t *audio_in_mutex;
switch_mutex_t *audio_out_mutex;
switch_mutex_t *read_mutex;
+ switch_thread_rwlock_t *rwlock;
switch_codec_implementation_t read_impl;
switch_codec_implementation_t orig_read_impl;
switch_codec_t read_codec;
char *pname;
void_fn_t pfnapicmd;
conference_fntype_t fntype;
+ char *pcommand;
char *psyntax;
} api_command_t;
member = NULL;
}
+ switch_thread_rwlock_rdlock(member->rwlock);
switch_mutex_unlock(conference->member_mutex);
return member;
switch_assert(conference != NULL);
switch_assert(member != NULL);
+ switch_thread_rwlock_wrlock(member->rwlock);
+
lock_member(member);
member_fnode = member->fnode;
member_sh = member->sh;
last = imember;
}
+ switch_thread_rwlock_unlock(member->rwlock);
+
/* Close Unused Handles */
if (member_fnode) {
conference_file_node_t *fnode, *cur;
switch_mutex_init(&member->audio_in_mutex, SWITCH_MUTEX_NESTED, rec->pool);
switch_mutex_init(&member->audio_out_mutex, SWITCH_MUTEX_NESTED, rec->pool);
switch_mutex_init(&member->read_mutex, SWITCH_MUTEX_NESTED, rec->pool);
+ switch_thread_rwlock_create(&member->rwlock, rec->pool);
/* Setup an audio buffer for the incoming audio */
if (switch_buffer_create_dynamic(&member->audio_buffer, CONF_DBLOCK_SIZE, CONF_DBUFFER_SIZE, 0) != SWITCH_STATUS_SUCCESS) {
switch_mutex_unlock(conference->member_mutex);
}
+
+static switch_status_t list_conferences(const char *line, const char *cursor, switch_console_callback_match_t **matches)
+{
+ switch_console_callback_match_t *my_matches = NULL;
+ switch_status_t status = SWITCH_STATUS_FALSE;
+ switch_hash_index_t *hi;
+ void *val;
+ const void *vvar;
+
+ switch_mutex_lock(globals.hash_mutex);
+ for (hi = switch_hash_first(NULL, globals.conference_hash); hi; hi = switch_hash_next(hi)) {
+ switch_hash_this(hi, &vvar, NULL, &val);
+ switch_console_push_match(&my_matches, (const char *) vvar);
+ }
+ switch_mutex_unlock(globals.hash_mutex);
+
+ if (my_matches) {
+ *matches = my_matches;
+ status = SWITCH_STATUS_SUCCESS;
+ }
+
+ return status;
+}
+
static void conference_list_pretty(conference_obj_t *conference, switch_stream_handle_t *stream)
{
conference_member_t *member = NULL;
} else {
stream->write_function(stream, "(play) File: %s not found.\n", argv[2] ? argv[2] : "(unspecified)");
}
+ switch_thread_rwlock_unlock(member->rwlock);
ret_status = SWITCH_STATUS_SUCCESS;
} else {
stream->write_function(stream, "Member: %u not found.\n", id);
char *start_text = NULL;
char *workspace = NULL;
uint32_t id = 0;
- conference_member_t *member;
+ conference_member_t *member = NULL;
switch_event_t *event;
if (zstr(text)) {
ret_status = SWITCH_STATUS_SUCCESS;
done:
+
+ if (member) {
+ switch_thread_rwlock_unlock(member->rwlock);
+ }
+
switch_safe_free(workspace);
switch_safe_free(expanded);
return ret_status;
if ((member = conference_member_get(conference, id))) {
uint32_t stopped = conference_member_stop_file(member, async ? FILE_STOP_ASYNC : current ? FILE_STOP_CURRENT : FILE_STOP_ALL);
stream->write_function(stream, "Stopped %u files.\n", stopped);
+ switch_thread_rwlock_unlock(member->rwlock);
} else {
stream->write_function(stream, "Member: %u not found.\n", id);
}
if ((member = conference_member_get(conference, id))) {
member_del_relationship(member, oid);
stream->write_function(stream, "relationship %u->%u cleared.\n", id, oid);
+ switch_thread_rwlock_unlock(member->rwlock);
} else {
stream->write_function(stream, "relationship %u->%u not found.\n", id, oid);
}
uint32_t id = atoi(argv[2]);
uint32_t oid = atoi(argv[3]);
- if ((member = conference_member_get(conference, id))
- && (other_member = conference_member_get(conference, oid))) {
+ if ((member = conference_member_get(conference, id))) {
+ other_member = conference_member_get(conference, oid);
+ }
+
+ if (member && other_member) {
conference_relationship_t *rel = NULL;
+
if ((rel = member_get_relationship(member, other_member))) {
rel->flags = 0;
} else {
} else {
stream->write_function(stream, "relationship %u->%u not found.\n", id, oid);
}
+
+ if (member) {
+ switch_thread_rwlock_unlock(member->rwlock);
+ }
+
+ if (other_member) {
+ switch_thread_rwlock_unlock(other_member->rwlock);
+ }
}
return SWITCH_STATUS_SUCCESS;
/* Setup a memory pool to use. */
if (switch_core_new_memory_pool(&pool) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Pool Failure\n");
+ switch_thread_rwlock_unlock(member->rwlock);
goto done;
}
/* Open the config from the xml registry */
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);
+ switch_thread_rwlock_unlock(member->rwlock);
goto done;
}
if (pool != NULL) {
switch_core_destroy_memory_pool(&pool);
}
+ switch_thread_rwlock_unlock(member->rwlock);
goto done;
}
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) {
/* API Interface Function sub-commands */
/* Entries in this list should be kept in sync with the enum above */
static api_command_t conf_api_sub_commands[] = {
- {"list", (void_fn_t) & conf_api_sub_list, CONF_API_SUB_ARGS_SPLIT, "<confname> list [delim <string>]"},
- {"xml_list", (void_fn_t) & conf_api_sub_xml_list, CONF_API_SUB_ARGS_SPLIT, "<confname> xml_list"},
- {"energy", (void_fn_t) & conf_api_sub_energy, CONF_API_SUB_MEMBER_TARGET,
- "<confname> energy <member_id|all|last> [<newval>]"},
- {"volume_in", (void_fn_t) & conf_api_sub_volume_in, CONF_API_SUB_MEMBER_TARGET,
- "<confname> volume_in <member_id|all|last> [<newval>]"},
- {"volume_out", (void_fn_t) & conf_api_sub_volume_out, CONF_API_SUB_MEMBER_TARGET,
- "<confname> volume_out <member_id|all|last> [<newval>]"},
- {"play", (void_fn_t) & conf_api_sub_play, CONF_API_SUB_ARGS_SPLIT, "<confname> play <file_path> [async|<member_id>]"},
- {"say", (void_fn_t) & conf_api_sub_say, CONF_API_SUB_ARGS_AS_ONE, "<confname> say <text>"},
- {"saymember", (void_fn_t) & conf_api_sub_saymember, CONF_API_SUB_ARGS_AS_ONE,
- "<confname> saymember <member_id> <text>"},
- {"stop", (void_fn_t) & conf_api_sub_stop, CONF_API_SUB_ARGS_SPLIT,
- "<confname> stop <[current|all|async|last]> [<member_id>]"},
- {"dtmf", (void_fn_t) & conf_api_sub_dtmf, CONF_API_SUB_MEMBER_TARGET,
- "<confname> dtmf <[member_id|all|last]> <digits>"},
- {"kick", (void_fn_t) & conf_api_sub_kick, CONF_API_SUB_MEMBER_TARGET, "<confname> kick <[member_id|all|last]>"},
- {"mute", (void_fn_t) & conf_api_sub_mute, CONF_API_SUB_MEMBER_TARGET, "<confname> mute <[member_id|all]|last>"},
- {"unmute", (void_fn_t) & conf_api_sub_unmute, CONF_API_SUB_MEMBER_TARGET, "<confname> unmute <[member_id|all]|last>"},
- {"deaf", (void_fn_t) & conf_api_sub_deaf, CONF_API_SUB_MEMBER_TARGET, "<confname> deaf <[member_id|all]|last>"},
- {"undeaf", (void_fn_t) & conf_api_sub_undeaf, CONF_API_SUB_MEMBER_TARGET, "<confname> undeaf <[member_id|all]|last>"},
- {"relate", (void_fn_t) & conf_api_sub_relate, CONF_API_SUB_ARGS_SPLIT, "<confname> relate <member_id> <other_member_id> [nospeak|nohear|clear]"},
- {"lock", (void_fn_t) & conf_api_sub_lock, CONF_API_SUB_ARGS_SPLIT, "<confname> lock"},
- {"unlock", (void_fn_t) & conf_api_sub_unlock, CONF_API_SUB_ARGS_SPLIT, "<confname> unlock"},
- {"agc", (void_fn_t) & conf_api_sub_agc, CONF_API_SUB_ARGS_SPLIT, "<confname> agc"},
- {"dial", (void_fn_t) & conf_api_sub_dial, CONF_API_SUB_ARGS_SPLIT,
- "<confname> dial <endpoint_module_name>/<destination> <callerid number> <callerid name>"},
- {"bgdial", (void_fn_t) & conf_api_sub_bgdial, CONF_API_SUB_ARGS_SPLIT,
- "<confname> bgdial <endpoint_module_name>/<destination> <callerid number> <callerid name>"},
- {"transfer", (void_fn_t) & conf_api_sub_transfer, CONF_API_SUB_ARGS_SPLIT,
- "<confname> transfer <conference_name> <member id> [...<member id>]"},
- {"record", (void_fn_t) & conf_api_sub_record, CONF_API_SUB_ARGS_SPLIT, "<confname> record <filename>"},
- {"norecord", (void_fn_t) & conf_api_sub_norecord, CONF_API_SUB_ARGS_SPLIT, "<confname> norecord <[filename|all]>"},
- {"pin", (void_fn_t) & conf_api_sub_pin, CONF_API_SUB_ARGS_SPLIT, "<confname> pin <pin#>"},
- {"nopin", (void_fn_t) & conf_api_sub_pin, CONF_API_SUB_ARGS_SPLIT, "<confname> nopin"},
+ {"list", (void_fn_t) & conf_api_sub_list, CONF_API_SUB_ARGS_SPLIT, "list", "[delim <string>]"},
+ {"xml_list", (void_fn_t) & conf_api_sub_xml_list, CONF_API_SUB_ARGS_SPLIT, "xml_list", ""},
+ {"energy", (void_fn_t) & conf_api_sub_energy, CONF_API_SUB_MEMBER_TARGET, "energy", "<member_id|all|last> [<newval>]"},
+ {"volume_in", (void_fn_t) & conf_api_sub_volume_in, CONF_API_SUB_MEMBER_TARGET, "volume_in", "<member_id|all|last> [<newval>]"},
+ {"volume_out", (void_fn_t) & conf_api_sub_volume_out, CONF_API_SUB_MEMBER_TARGET, "volume_out", "<member_id|all|last> [<newval>]"},
+ {"play", (void_fn_t) & conf_api_sub_play, CONF_API_SUB_ARGS_SPLIT, "play", "<file_path> [async|<member_id>]"},
+ {"say", (void_fn_t) & conf_api_sub_say, CONF_API_SUB_ARGS_AS_ONE, "say", "<text>"},
+ {"saymember", (void_fn_t) & conf_api_sub_saymember, CONF_API_SUB_ARGS_AS_ONE, "saymember", "<member_id> <text>"},
+ {"stop", (void_fn_t) & conf_api_sub_stop, CONF_API_SUB_ARGS_SPLIT, "stop", "<[current|all|async|last]> [<member_id>]"},
+ {"dtmf", (void_fn_t) & conf_api_sub_dtmf, CONF_API_SUB_MEMBER_TARGET, "dtmf", "<[member_id|all|last]> <digits>"},
+ {"kick", (void_fn_t) & conf_api_sub_kick, CONF_API_SUB_MEMBER_TARGET, "kick", "<[member_id|all|last]>"},
+ {"mute", (void_fn_t) & conf_api_sub_mute, CONF_API_SUB_MEMBER_TARGET, "mute", "<[member_id|all]|last>"},
+ {"unmute", (void_fn_t) & conf_api_sub_unmute, CONF_API_SUB_MEMBER_TARGET, "unmute", "<[member_id|all]|last>"},
+ {"deaf", (void_fn_t) & conf_api_sub_deaf, CONF_API_SUB_MEMBER_TARGET, "deaf", "<[member_id|all]|last>"},
+ {"undeaf", (void_fn_t) & conf_api_sub_undeaf, CONF_API_SUB_MEMBER_TARGET, "undeaf", "<[member_id|all]|last>"},
+ {"relate", (void_fn_t) & conf_api_sub_relate, CONF_API_SUB_ARGS_SPLIT, "relate", "<member_id> <other_member_id> [nospeak|nohear|clear]"},
+ {"lock", (void_fn_t) & conf_api_sub_lock, CONF_API_SUB_ARGS_SPLIT, "lock", ""},
+ {"unlock", (void_fn_t) & conf_api_sub_unlock, CONF_API_SUB_ARGS_SPLIT, "unlock", ""},
+ {"agc", (void_fn_t) & conf_api_sub_agc, CONF_API_SUB_ARGS_SPLIT, "agc", ""},
+ {"dial", (void_fn_t) & conf_api_sub_dial, CONF_API_SUB_ARGS_SPLIT, "dial", "<endpoint_module_name>/<destination> <callerid number> <callerid name>"},
+ {"bgdial", (void_fn_t) & conf_api_sub_bgdial, CONF_API_SUB_ARGS_SPLIT, "bgdial", "<endpoint_module_name>/<destination> <callerid number> <callerid name>"},
+ {"transfer", (void_fn_t) & conf_api_sub_transfer, CONF_API_SUB_ARGS_SPLIT, "transfer", "<conference_name> <member id> [...<member id>]"},
+ {"record", (void_fn_t) & conf_api_sub_record, CONF_API_SUB_ARGS_SPLIT, "record", "<filename>"},
+ {"norecord", (void_fn_t) & conf_api_sub_norecord, CONF_API_SUB_ARGS_SPLIT, "norecord", "<[filename|all]>"},
+ {"pin", (void_fn_t) & conf_api_sub_pin, CONF_API_SUB_ARGS_SPLIT, "pin", "<pin#>"},
+ {"nopin", (void_fn_t) & conf_api_sub_pin, CONF_API_SUB_ARGS_SPLIT, "nopin", ""},
};
#define CONFFUNCAPISIZE (sizeof(conf_api_sub_commands)/sizeof(conf_api_sub_commands[0]))
if (pfn(conference, stream, argc, argv) != SWITCH_STATUS_SUCCESS) {
/* command returned error, so show syntax usage */
- stream->write_function(stream, conf_api_sub_commands[i].psyntax);
+ stream->write_function(stream, "%s %s", conf_api_sub_commands[i].pcommand, conf_api_sub_commands[i].psyntax);
}
}
break;
if (member != NULL) {
pfn(member, stream, argv[argn + 2]);
+ switch_thread_rwlock_unlock(member->rwlock);
} else {
stream->write_function(stream, "Non-Existant ID %u\n", id);
}
} else {
- stream->write_function(stream, conf_api_sub_commands[i].psyntax);
+ stream->write_function(stream, "%s %s", conf_api_sub_commands[i].pcommand, conf_api_sub_commands[i].psyntax);
}
}
break;
/* call the command handler */
if (pfn(conference, stream, modified_cmdline) != SWITCH_STATUS_SUCCESS) {
/* command returned error, so show syntax usage */
- stream->write_function(stream, conf_api_sub_commands[i].psyntax);
+ stream->write_function(stream, "%s %s", conf_api_sub_commands[i].pcommand, conf_api_sub_commands[i].psyntax);
}
}
break;
} else if (argv[1] && strcasecmp(argv[1], "dial") == 0) {
if (conf_api_sub_dial(NULL, stream, argc, argv) != SWITCH_STATUS_SUCCESS) {
/* command returned error, so show syntax usage */
- stream->write_function(stream, conf_api_sub_commands[CONF_API_COMMAND_DIAL].psyntax);
+ stream->write_function(stream, "%s %s", conf_api_sub_commands[CONF_API_COMMAND_DIAL].pcommand,
+ conf_api_sub_commands[CONF_API_COMMAND_DIAL].psyntax);
}
} else if (argv[1] && strcasecmp(argv[1], "bgdial") == 0) {
if (conf_api_sub_bgdial(NULL, stream, argc, argv) != SWITCH_STATUS_SUCCESS) {
/* command returned error, so show syntax usage */
- stream->write_function(stream, conf_api_sub_commands[CONF_API_COMMAND_BGDIAL].psyntax);
+ stream->write_function(stream, "%s %s", conf_api_sub_commands[CONF_API_COMMAND_BGDIAL].pcommand,
+ conf_api_sub_commands[CONF_API_COMMAND_BGDIAL].psyntax);
}
} else {
stream->write_function(stream, "Conference %s not found\n", argv[0]);
}
} else {
- stream->write_function(stream, "No parameters specified.\nTry 'help conference'\n");
+ int i;
+
+ for (i = 0; i < CONFFUNCAPISIZE; i++) {
+ stream->write_function(stream, "<conf name> %s %s\n", conf_api_sub_commands[i].pcommand, conf_api_sub_commands[i].psyntax);
+ }
}
done:
switch_mutex_init(&member.read_mutex, SWITCH_MUTEX_NESTED, member.pool);
switch_mutex_init(&member.audio_in_mutex, SWITCH_MUTEX_NESTED, member.pool);
switch_mutex_init(&member.audio_out_mutex, SWITCH_MUTEX_NESTED, member.pool);
+ switch_thread_rwlock_create(&member.rwlock, member.pool);
/* Install our Signed Linear codec so we get the audio in that format */
switch_core_session_set_read_codec(member.session, &member.read_codec);
switch_api_interface_t *api_interface;
switch_application_interface_t *app_interface;
switch_status_t status = SWITCH_STATUS_SUCCESS;
+ char cmd_str[256];
memset(&globals, 0, sizeof(globals));
/* Connect my internal structure to the blank pointer passed to me */
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
+ switch_console_add_complete_func("::conference::list_conferences", list_conferences);
+
+
/* build api interface help ".syntax" field string */
p = strdup("");
for (i = 0; i < CONFFUNCAPISIZE; i++) {
- nl = strlen(conf_api_sub_commands[i].psyntax) + 4;
+ nl = strlen(conf_api_sub_commands[i].pcommand) + strlen(conf_api_sub_commands[i].psyntax) + 5;
+
+ switch_snprintf(cmd_str, sizeof(cmd_str), "add conference ::conference::list_conferences %s", conf_api_sub_commands[i].pcommand);
+
+ switch_console_set_complete(cmd_str);
+
if (p != NULL) {
ol = strlen(p);
}
if (tmp != NULL) {
p = tmp;
strcat(p, "\t\t");
- strcat(p, conf_api_sub_commands[i].psyntax);
+ strcat(p, conf_api_sub_commands[i].pcommand);
+ if (!zstr(conf_api_sub_commands[i].psyntax)) {
+ strcat(p, " ");
+ strcat(p, conf_api_sub_commands[i].psyntax);
+ }
if (i < CONFFUNCAPISIZE - 1) {
strcat(p, "\n");
}
SWITCH_ADD_APP(app_interface, global_app_name, global_app_name, NULL, conference_function, NULL, SAF_NONE);
SWITCH_ADD_APP(app_interface, "conference_set_auto_outcall", "conference_set_auto_outcall", NULL, conference_auto_function, NULL, SAF_NONE);
SWITCH_ADD_CHAT(chat_interface, CONF_CHAT_PROTO, chat_send);
+
send_presence(SWITCH_EVENT_PRESENCE_IN);
/* signal all threads to shutdown */
globals.running = 0;
+ switch_console_del_complete_func("::conference::list_conferences");
+
/* wait for all threads */
while (globals.threads) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Waiting for %d threads\n", globals.threads);