Author: knhor Date: Wed Nov 8 00:51:04 2006 New Revision: 3281 Modified: freeswitch/branches/knhor/trunk/src/mod/applications/mod_conference/mod_conference.c Log: do clean up. add comments Modified: freeswitch/branches/knhor/trunk/src/mod/applications/mod_conference/mod_conference.c ============================================================================== --- freeswitch/branches/knhor/trunk/src/mod/applications/mod_conference/mod_conference.c (original) +++ freeswitch/branches/knhor/trunk/src/mod/applications/mod_conference/mod_conference.c Wed Nov 8 00:51:04 2006 @@ -206,7 +206,6 @@ typedef struct api_command { char *pname; void *pfnapicmd; -// int (*pfnapicmd)(); int fntype; char *psyntax; } api_command_t; @@ -225,7 +224,7 @@ static switch_status_t conference_play_file(conference_obj_t *conference, char *file, uint32_t leadin); static switch_status_t conference_say(conference_obj_t *conference, char *text, uint32_t leadin); static void conference_list(conference_obj_t *conference, switch_stream_handle_t *stream, char *delim); -static switch_status_t conf_function(char *buf, switch_core_session_t *session, switch_stream_handle_t *stream); +static switch_status_t conf_api_main(char *buf, switch_core_session_t *session, switch_stream_handle_t *stream); static switch_status_t audio_bridge_on_ring(switch_core_session_t *session); static switch_status_t conference_outcall(conference_obj_t *conference, switch_core_session_t *session, @@ -254,16 +253,16 @@ switch_stream_handle_t *stream, conf_api_member_cmd_t pfncallback, void *data); -static int conference_function_api_mute(conference_member_t *member, +static int conf_api_sub_mute(conference_member_t *member, switch_stream_handle_t *stream, void *data); -static int conference_function_api_unmute(conference_member_t *member, +static int conf_api_sub_unmute(conference_member_t *member, switch_stream_handle_t *stream, void *data); -static int conference_function_api_deaf(conference_member_t *member, +static int conf_api_sub_deaf(conference_member_t *member, switch_stream_handle_t *stream, void *data); -static int conference_function_api_undeaf(conference_member_t *member, +static int conf_api_sub_undeaf(conference_member_t *member, switch_stream_handle_t *stream, void *data); @@ -312,12 +311,12 @@ return rel; } +// traverse the conference member list for the specified member id and return it's pointer static conference_member_t *conference_member_get(conference_obj_t *conference, uint32_t id) { conference_member_t *member = NULL; for(member = conference->members; member; member = member->next) { - if (switch_test_flag(member, MFLAG_NOCHANNEL)) { continue; } @@ -330,6 +329,7 @@ return member; } +// stop the specified recording static int conference_record_stop(conference_obj_t *conference, char *path) { conference_member_t *member = NULL; @@ -403,7 +403,6 @@ member->energy_level = conference->energy_level; conference->members = member; - if (!switch_test_flag(member, MFLAG_NOCHANNEL)) { conference->count++; if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) { @@ -415,7 +414,6 @@ switch_event_fire(&event); } - if (conference->enter_sound) { conference_play_file(conference, conference->enter_sound, CONF_DEFAULT_LEADIN); } @@ -471,7 +469,6 @@ last = imember; } - member->conference = NULL; if (!switch_test_flag(member, MFLAG_NOCHANNEL)) { @@ -512,10 +509,7 @@ switch_mutex_unlock(member->audio_in_mutex); switch_mutex_unlock(conference->member_mutex); switch_mutex_unlock(conference->mutex); - - switch_thread_rwlock_unlock(conference->rwlock); - } /* Main monitor thread (1 per distinct conference room) */ @@ -777,54 +771,22 @@ static void conference_loop_fn_mute_toggle(conference_member_t *member) { - char msg[512]; - if (switch_test_flag(member, MFLAG_CAN_SPEAK)) { -// switch_clear_flag_locked(member, MFLAG_CAN_SPEAK | MFLAG_CAN_HEAR); - conference_function_api_mute(member, NULL, NULL); - conference_function_api_deaf(member, NULL, NULL); - if (member->conference->muted_sound) { - conference_member_play_file(member, member->conference->muted_sound, 0); - } else { - snprintf(msg, sizeof(msg), "Muted"); - conference_member_say(member->conference, member, msg, 0); - } + conf_api_sub_mute(member, NULL, NULL); + conf_api_sub_deaf(member, NULL, NULL); } else { -// switch_set_flag_locked(member, MFLAG_CAN_SPEAK); - conference_function_api_unmute(member, NULL, NULL); - if (member->conference->unmuted_sound) { - conference_member_play_file(member, member->conference->unmuted_sound, 0); - } else { - snprintf(msg, sizeof(msg), "Un-Muted"); - conference_member_say(member->conference, member, msg, 0); - } + conf_api_sub_unmute(member, NULL, NULL); } } static void conference_loop_fn_deafmute_toggle(conference_member_t *member) { - char msg[512]; - if (switch_test_flag(member, MFLAG_CAN_SPEAK)) { -// switch_clear_flag_locked(member, MFLAG_CAN_SPEAK|MFLAG_CAN_HEAR); - conference_function_api_mute(member, NULL, NULL); - conference_function_api_deaf(member, NULL, NULL); - if (member->conference->muted_sound) { - conference_member_play_file(member, member->conference->muted_sound, 0); - } else { - snprintf(msg, sizeof(msg), "Muted"); - conference_member_say(member->conference, member, msg, 0); - } + conf_api_sub_mute(member, NULL, NULL); + conf_api_sub_deaf(member, NULL, NULL); } else { -// switch_set_flag_locked(member, MFLAG_CAN_SPEAK|MFLAG_CAN_HEAR); - conference_function_api_unmute(member, NULL, NULL); - conference_function_api_undeaf(member, NULL, NULL); - if (member->conference->unmuted_sound) { - conference_member_play_file(member, member->conference->unmuted_sound, 0); - } else { - snprintf(msg, sizeof(msg), "UN-Muted"); - conference_member_say(member->conference, member, msg, 0); - } + conf_api_sub_unmute(member, NULL, NULL); + conf_api_sub_undeaf(member, NULL, NULL); } } @@ -942,6 +904,19 @@ switch_clear_flag_locked(member, MFLAG_RUNNING); } +/* Create a thread for the conference and launch it */ +static void launch_input_thread(conference_member_t *member, switch_memory_pool_t *pool) +{ + switch_thread_t *thread; + switch_threadattr_t *thd_attr = NULL; + + switch_threadattr_create(&thd_attr, pool); + switch_threadattr_detach_set(thd_attr, 1); + switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE); + switch_set_flag_locked(member, MFLAG_ITHREAD); + switch_thread_create(&thread, thd_attr, input_thread_run, member, pool); +} + /* Sub-Routine called by a channel inside a conference */ static void conference_loop(conference_member_t *member) { @@ -1010,7 +985,6 @@ } if (switch_channel_test_flag(channel, CF_OUTBOUND)) { - // test to see if outbound channel has answered if (switch_channel_test_flag(channel, CF_ANSWERED) && !switch_test_flag(member->conference, CFLAG_ANSWERED)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Outbound conference channel answered, setting CFLAG_ANSWERED"); switch_set_flag(member->conference, CFLAG_ANSWERED); @@ -1032,7 +1006,7 @@ // determines the operation that is being requested // To disable the function for the user, make the control // string digit something that can't be dialed... ie. a space - // The control string should have at least 12 characters in it + // The control string MUST have 12 characters in it pcontroldigit = strchr(member->conference->caller_dtmf_control,*digit); if(pcontroldigit != NULL) { @@ -1144,7 +1118,6 @@ } else { switch_buffer_t *use_buffer = NULL; uint32_t mux_used = (uint32_t)switch_buffer_inuse(member->mux_buffer); - //uint32_t res_used = member->mux_resampler ? switch_buffer_inuse(member->resample_buffer) : 0; if (mux_used) { /* Flush the output buffer and write all the data (presumably muxed) back to the channel */ @@ -1648,35 +1621,8 @@ switch_mutex_unlock(conference->member_mutex); } -static void conference_list_pretty(conference_obj_t *conference, switch_stream_handle_t *stream) +static int conf_api_sub_mute(conference_member_t *member, switch_stream_handle_t *stream, void *data) { - conference_member_t *member = NULL; - - switch_mutex_lock(conference->member_mutex); - stream->write_function(stream, "<pre>Current Callers:\n"); - - for (member = conference->members; member; member = member->next) { - switch_channel_t *channel; - switch_caller_profile_t *profile; - - if (switch_test_flag(member, MFLAG_NOCHANNEL)) { - continue; - } - channel = switch_core_session_get_channel(member->session); - profile = switch_channel_get_caller_profile(channel); - - - stream->write_function(stream, "*) %s (%s)\n", - profile->caller_id_name, - profile->caller_id_number - ); - - } - switch_mutex_unlock(conference->member_mutex); -} - -static int conference_function_api_mute(conference_member_t *member, switch_stream_handle_t *stream, void *data) -{ int err = 0; if (member != NULL) { @@ -1685,6 +1631,11 @@ switch_clear_flag_locked(member, MFLAG_CAN_SPEAK); if (member->conference->muted_sound) { conference_member_play_file(member, member->conference->muted_sound, 0); + } else { + char msg[512]; + + snprintf(msg, sizeof(msg), "Muted"); + conference_member_say(member->conference, member, msg, 0); } if(stream != NULL) { stream->write_function(stream, "OK mute %u\n", member->id); @@ -1705,7 +1656,7 @@ return err; } -static int conference_function_api_unmute(conference_member_t *member, switch_stream_handle_t *stream, void *data) +static int conf_api_sub_unmute(conference_member_t *member, switch_stream_handle_t *stream, void *data) { int err = 0; @@ -1718,6 +1669,11 @@ } if (member->conference->unmuted_sound) { conference_member_play_file(member, member->conference->unmuted_sound, 0); + } else { + char msg[512]; + + snprintf(msg, sizeof(msg), "Un-Muted"); + conference_member_say(member->conference, member, msg, 0); } if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) { switch_channel_t *channel = switch_core_session_get_channel(member->session); @@ -1735,7 +1691,7 @@ return err; } -static int conference_function_api_deaf(conference_member_t *member, switch_stream_handle_t *stream, void *data) +static int conf_api_sub_deaf(conference_member_t *member, switch_stream_handle_t *stream, void *data) { int err = 0; @@ -1762,7 +1718,7 @@ return err; } -static int conference_function_api_undeaf(conference_member_t *member, switch_stream_handle_t *stream, void *data) +static int conf_api_sub_undeaf(conference_member_t *member, switch_stream_handle_t *stream, void *data) { int err = 0; @@ -1789,7 +1745,7 @@ return err; } -static int conference_function_api_kick(conference_member_t *member, switch_stream_handle_t *stream, void *data) +static int conf_api_sub_kick(conference_member_t *member, switch_stream_handle_t *stream, void *data) { int err = 0; @@ -1821,7 +1777,7 @@ return err; } -static int conference_function_api_energy(conference_member_t *member, switch_stream_handle_t *stream, void *data) +static int conf_api_sub_energy(conference_member_t *member, switch_stream_handle_t *stream, void *data) { int err = 0; @@ -1858,7 +1814,7 @@ return err; } -static int conference_function_api_volume_in(conference_member_t *member, switch_stream_handle_t *stream, void *data) +static int conf_api_sub_volume_in(conference_member_t *member, switch_stream_handle_t *stream, void *data) { int err = 0; @@ -1895,7 +1851,7 @@ return err; } -static int conference_function_api_volume_out(conference_member_t *member, switch_stream_handle_t *stream, void *data) +static int conf_api_sub_volume_out(conference_member_t *member, switch_stream_handle_t *stream, void *data) { int err = 0; @@ -1933,9 +1889,8 @@ return err; } -static int conference_function_api_list(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char**argv) +static int conf_api_sub_list(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char**argv) { -//static void conference_list(conference_obj_t *conference, switch_stream_handle_t *stream, char *delim) switch_hash_index_t *hi; void *val; char *d = ";"; @@ -1963,13 +1918,12 @@ stream->write_function(stream, "Conference %s (%u members)\n", conference->name, conference->count); conference_list(conference, stream, d); -// stream->write_function(stream, "\n"); } return 0; } -static int conference_function_api_play(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char**argv) +static int conf_api_sub_play(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char**argv) { switch_event_t *event; @@ -2010,7 +1964,7 @@ return 0; } -static int conference_function_api_say(conference_obj_t *conference, switch_stream_handle_t *stream, char *text) +static int conf_api_sub_say(conference_obj_t *conference, switch_stream_handle_t *stream, char *text) { int err = 0; @@ -2036,7 +1990,7 @@ return err; } -static int conference_function_api_saymember(conference_obj_t *conference, switch_stream_handle_t *stream, char *text) +static int conf_api_sub_saymember(conference_obj_t *conference, switch_stream_handle_t *stream, char *text) { int err = 0; @@ -2080,7 +2034,7 @@ return err; } -static int conference_function_api_stop(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char**argv) +static int conf_api_sub_stop(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char**argv) { uint8_t current = 0, all = 0; int err = 0; @@ -2112,11 +2066,10 @@ return err; } -static int conference_function_api_relate(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char**argv) +static int conf_api_sub_relate(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char**argv) { int err = 0; - char *relate_usage = "Usage relate <id> <id> [nospeak|nohear|clear]\n"; if (argc > 4) { uint8_t nospeak = 0, nohear = 0, clear = 0; nospeak = strstr(argv[4], "nospeak") ? 1 : 0; @@ -2127,7 +2080,7 @@ } if (!(clear || nospeak || nohear)) { - stream->write_function(stream, relate_usage); + err = 1; goto done; } @@ -2181,16 +2134,15 @@ switch_mutex_unlock(conference->mutex); } - } else { - stream->write_function(stream, relate_usage); + err = 1; } done: return err; } -static int conference_function_api_lock(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char**argv) +static int conf_api_sub_lock(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char**argv) { switch_event_t *event; @@ -2205,7 +2157,7 @@ return 0; } -static int conference_function_api_unlock(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char**argv) +static int conf_api_sub_unlock(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char**argv) { switch_event_t *event; @@ -2220,7 +2172,7 @@ return 0; } -static int conference_function_api_dial(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char**argv) +static int conf_api_sub_dial(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char**argv) { int err = 0; @@ -2234,7 +2186,7 @@ return err; } -static int conference_function_api_transfer(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char**argv) +static int conf_api_sub_transfer(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char**argv) { int err = 0; @@ -2254,6 +2206,7 @@ channel = switch_core_session_get_channel(member->session); + // build a new conference if it doesn't exist if (!(new_conference = (conference_obj_t *) switch_core_hash_find(globals.conference_hash, argv[3]))) { switch_memory_pool_t *pool; char *conf_name; @@ -2280,7 +2233,6 @@ } } - // Release the config registry handle if (cxml) { switch_xml_free(cxml); @@ -2290,7 +2242,6 @@ // Create the conference object. new_conference = conference_new(conf_name, profile, pool); - if (!new_conference) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n"); goto done; @@ -2306,10 +2257,13 @@ launch_conference_thread(new_conference); } + // move the member from the old conference to the new one conference_del_member(member->last_conference, member); conference_add_member(new_conference, member); + stream->write_function(stream, "OK Member %u sent to conference %s.\n", id, argv[3]); + // tell them what happened if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) { switch_channel_event_set_data(channel, event); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Member-ID", "%u", member->id); @@ -2318,7 +2272,6 @@ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Action", "transfer"); switch_event_fire(&event); } - } else { err = 1; } @@ -2326,19 +2279,23 @@ return err; } -static int conference_function_api_record(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char**argv) +static int conf_api_sub_record(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char**argv) { + int err = 0; + if (argc > 2) { launch_conference_record_thread(conference, argv[2]); } else { - stream->write_function(stream, "usage record <filename>\n"); + err = 1; } - return 0; + return err; } -static int conference_function_api_norecord(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char**argv) +static int conf_api_sub_norecord(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char**argv) { + int err = 0; + if (argc > 2) { int all = (strcasecmp(argv[2], "all") == 0 ); @@ -2346,40 +2303,40 @@ stream->write_function(stream, "non-existant recording '%s'\n", argv[2]); } } else { - stream->write_function(stream, "usage norecord <[filename | all]>\n"); + err = 1; } - return 0; + return err; } /* API Interface Function sub-commands */ -static api_command_t conf_function_api_commands[] = { - {"list", &conference_function_api_list, 0, "<confname> list [delim <string>]"}, - {"energy", &conference_function_api_energy, 1, "<confname> energy <member_id|all> [<newval>]"}, - {"volume in", &conference_function_api_volume_in, 1, "<confname> volume_in <member_id|all> [<newval>]"}, - {"volume out", &conference_function_api_volume_out, 1, "<confname> volume_out <member_id|all> [<newval>]"}, - {"play", &conference_function_api_play, 0, "<confname> play <file_path> [<member_id>]"}, - {"say", &conference_function_api_say, 2, "<confname> say <text>"}, - {"saymember", &conference_function_api_saymember, 2, "<confname> saymember <member_id><text>"}, - {"stop", &conference_function_api_stop, 1, "<confname> stop <[current|all]> [<member_id>]"}, - {"kick", &conference_function_api_kick, 1, "<confname> kick <[member_id|all]>"}, - {"mute", &conference_function_api_mute, 1, "<confname> mute <[member_id|all]>"}, - {"unmute", &conference_function_api_unmute, 1, "<confname> unmute <[member_id|all]>"}, - {"deaf", &conference_function_api_deaf, 1, "<confname> deaf <[member_id|all]>"}, - {"undeaf", &conference_function_api_undeaf, 1, "<confname> undef <[member_id|all]>"}, - {"relate", &conference_function_api_relate, 0, "<confname> relate <member_id> <other_member_id> [nospeak|nohear|clear]"}, - {"lock", &conference_function_api_lock, 0, "<confname> lock"}, - {"unlock", &conference_function_api_unlock, 0, "<confname> unlock"}, - {"dial", &conference_function_api_dial, 0, "<confname> dial <endpoint_module_name>/<destination>"}, - {"transfer", &conference_function_api_transfer, 0, "<confname> transfer <member_id> <conference_name>"}, - {"record", &conference_function_api_record, 0, "<confname> record <filename>"}, - {"norecord", &conference_function_api_norecord, 0, "<confname> norecord <[filename|all]>"}, +static api_command_t conf_api_sub_commands[] = { + {"list", &conf_api_sub_list, 0, "<confname> list [delim <string>]"}, + {"energy", &conf_api_sub_energy, 1, "<confname> energy <member_id|all> [<newval>]"}, + {"volume in", &conf_api_sub_volume_in, 1, "<confname> volume_in <member_id|all> [<newval>]"}, + {"volume out", &conf_api_sub_volume_out, 1, "<confname> volume_out <member_id|all> [<newval>]"}, + {"play", &conf_api_sub_play, 0, "<confname> play <file_path> [<member_id>]"}, + {"say", &conf_api_sub_say, 2, "<confname> say <text>"}, + {"saymember", &conf_api_sub_saymember, 2, "<confname> saymember <member_id><text>"}, + {"stop", &conf_api_sub_stop, 1, "<confname> stop <[current|all]> [<member_id>]"}, + {"kick", &conf_api_sub_kick, 1, "<confname> kick <[member_id|all]>"}, + {"mute", &conf_api_sub_mute, 1, "<confname> mute <[member_id|all]>"}, + {"unmute", &conf_api_sub_unmute, 1, "<confname> unmute <[member_id|all]>"}, + {"deaf", &conf_api_sub_deaf, 1, "<confname> deaf <[member_id|all]>"}, + {"undeaf", &conf_api_sub_undeaf, 1, "<confname> undef <[member_id|all]>"}, + {"relate", &conf_api_sub_relate, 0, "<confname> relate <member_id> <other_member_id> [nospeak|nohear|clear]"}, + {"lock", &conf_api_sub_lock, 0, "<confname> lock"}, + {"unlock", &conf_api_sub_unlock, 0, "<confname> unlock"}, + {"dial", &conf_api_sub_dial, 0, "<confname> dial <endpoint_module_name>/<destination>"}, + {"transfer", &conf_api_sub_transfer, 0, "<confname> transfer <member_id> <conference_name>"}, + {"record", &conf_api_sub_record, 0, "<confname> record <filename>"}, + {"norecord", &conf_api_sub_norecord, 0, "<confname> norecord <[filename|all]>"}, }; -#define CONFFUNCAPISIZE (sizeof(conf_function_api_commands)/sizeof(conf_function_api_commands[0])) +#define CONFFUNCAPISIZE (sizeof(conf_api_sub_commands)/sizeof(conf_api_sub_commands[0])) /* API Interface Function */ -static switch_status_t conf_function(char *buf, switch_core_session_t *session, switch_stream_handle_t *stream) +static switch_status_t conf_api_main(char *buf, switch_core_session_t *session, switch_stream_handle_t *stream) { char *lbuf = NULL; switch_status_t status = SWITCH_STATUS_SUCCESS; @@ -2405,7 +2362,7 @@ memset(argv,0,sizeof(argv)); argc = switch_separate_string(lbuf, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); - // find a command to execute + // try to find a command to execute if (argc) { int i,found=0; uint32_t cnum = atoi(argv[0]); @@ -2414,16 +2371,17 @@ if(cnum == 0 || (cnum != 0 && conference != NULL)) { int argn = (cnum != 0 ? 1 : 0); + // loop through the command table to find a match for (i=0; i<CONFFUNCAPISIZE && !found; i++) { - if (strcasecmp(argv[argn],conf_function_api_commands[i].pname) == 0) { + if (strcasecmp(argv[argn],conf_api_sub_commands[i].pname) == 0) { found = 1; - switch(conf_function_api_commands[i].fntype) { + switch(conf_api_sub_commands[i].fntype) { case 0: // commands that we've broken the command line into arguments for - { conf_api_args_cmd_t pfn = (conf_api_args_cmd_t)conf_function_api_commands[i].pfnapicmd; + { conf_api_args_cmd_t pfn = (conf_api_args_cmd_t)conf_api_sub_commands[i].pfnapicmd; if (pfn(conference, stream, argc, &argv[0]) != 0) { // command returned error, so show syntax usage - stream->write_function(stream,conf_function_api_commands[i].psyntax); + stream->write_function(stream,conf_api_sub_commands[i].psyntax); } } break; @@ -2433,16 +2391,16 @@ int all = ( id == 0 && strcasecmp(argv[argn+1], "all") == 0 ); if(all) { - conference_member_itterator(conference, stream, conf_function_api_commands[i].pfnapicmd, argv[argn+2]); + conference_member_itterator(conference, stream, conf_api_sub_commands[i].pfnapicmd, argv[argn+2]); } else { - conf_api_member_cmd_t pfn = (conf_api_member_cmd_t)conf_function_api_commands[i].pfnapicmd; + conf_api_member_cmd_t pfn = (conf_api_member_cmd_t)conf_api_sub_commands[i].pfnapicmd; conference_member_t *member = conference_member_get(conference, id); if (member != NULL) { pfn(conference_member_get(conference, id), stream, argv[argn+2]); } else { if (id == 0) { - stream->write_function(stream,conf_function_api_commands[i].psyntax); + stream->write_function(stream,conf_api_sub_commands[i].psyntax); } else { stream->write_function(stream, "Non-Existant ID %u\n", id); } @@ -2451,26 +2409,27 @@ } break; case 2: // commands that deals with all text after command - { conf_api_text_cmd_t pfn = (conf_api_text_cmd_t)conf_function_api_commands[i].pfnapicmd; - char *pstr = lbuf+strlen(conf_function_api_commands[i].pname)+1; + { conf_api_text_cmd_t pfn = (conf_api_text_cmd_t)conf_api_sub_commands[i].pfnapicmd; + char *pstr = lbuf+strlen(conf_api_sub_commands[i].pname)+1; // advance past all leading white space after command while(*pstr == ' ' || *pstr == '\t') { pstr++; } + // call the command handler if (pfn(conference, stream, pstr) != 0) { // command returned error, so show syntax usage - stream->write_function(stream,conf_function_api_commands[i].psyntax); + stream->write_function(stream,conf_api_sub_commands[i].psyntax); } } break; } } } + // no command found if(!found) { stream->write_function(stream, "Confernece command '%s' not found.\nTry 'help conference'\n", argv[argn]); -// stream->write_function(stream,(char *)conf_api_interface.syntax); } } else { stream->write_function(stream,"No Conference called %s found.\n",argv[0]); @@ -2478,7 +2437,6 @@ } else { stream->write_function(stream, "Command not specified.\nTry 'help conference'\n"); -// stream->write_function(stream,(char *)conf_api_interface.syntax); } } @@ -2487,9 +2445,9 @@ } return status; - } +// outbound call bridge progress call state callback handler static switch_status_t audio_bridge_on_ring(switch_core_session_t *session) { switch_channel_t *channel = NULL; @@ -2501,6 +2459,7 @@ /* put the channel in a passive state so we can loop audio to it */ switch_channel_set_state(channel, CS_TRANSMIT); + return SWITCH_STATUS_FALSE; } @@ -2514,6 +2473,7 @@ /*.on_hold */ NULL, }; +// generate an outbound call from the conference static switch_status_t conference_outcall(conference_obj_t *conference, switch_core_session_t *session, char *bridgeto, @@ -2540,6 +2500,7 @@ } + // establish an outbound call leg if (switch_ivr_originate(session, &peer_session, &cause, @@ -2557,10 +2518,10 @@ goto done; } - peer_channel = switch_core_session_get_channel(peer_session); assert(peer_channel != NULL); + // make sure the conference still exists if (!switch_test_flag(conference, CFLAG_RUNNING)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Conference is gone now, nevermind..\n"); if (caller_channel) { @@ -2574,13 +2535,17 @@ switch_channel_answer(caller_channel); } + // if the outbound call leg is ready if (switch_channel_test_flag(peer_channel, CF_ANSWERED) || switch_channel_test_flag(peer_channel, CF_EARLY_MEDIA)) { switch_caller_extension_t *extension = NULL; + + // build an extension name object if ((extension = switch_caller_extension_new(peer_session, conference->name, conference->name)) == 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "memory error!\n"); status = SWITCH_STATUS_MEMERR; goto done; } + /* add them to the conference */ if (flags) { snprintf(appdata, sizeof(appdata), "%s +flags{%s}", conference->name, flags); @@ -2591,7 +2556,6 @@ switch_channel_set_caller_extension(peer_channel, extension); switch_channel_set_state(peer_channel, CS_EXECUTE); - } else { switch_channel_hangup(peer_channel, SWITCH_CAUSE_NO_ANSWER); status = SWITCH_STATUS_FALSE; @@ -2609,6 +2573,7 @@ uint32_t x = 0; switch_status_t status = SWITCH_STATUS_SUCCESS; + // generate some space infront of the file to be played for (x = 0; x < leadin; x++) { switch_frame_t *read_frame; switch_status_t status = switch_core_session_read_frame(session, &read_frame, 1000, 0); @@ -2618,6 +2583,7 @@ } } + // if all is well, really play the file if (status == SWITCH_STATUS_SUCCESS) { status = switch_ivr_play_file(session, NULL, path, NULL, NULL, NULL, 0); } @@ -2661,7 +2627,7 @@ return; } - + // Start the conference muted or deaf ? if ((flags_str=strstr(mydata, flags_prefix))) { char *p; @@ -2678,6 +2644,7 @@ } } + // is this a bridging conference ? if (!strncasecmp(mydata, bridge_prefix, strlen(bridge_prefix))) { isbr = 1; mydata += strlen(bridge_prefix); @@ -2709,6 +2676,8 @@ } } + // if this is a bridging call, and it's not a duplicate, build a + // conference object, and skip pin handling, and locked checking if (isbr) { char *uuid = switch_core_session_get_uuid(session); @@ -2743,14 +2712,13 @@ launch_conference_thread(conference); } else { - /* Figure out what conference to call. */ + // if the conference exists, get the pointer to it if ((conference = (conference_obj_t *) switch_core_hash_find(globals.conference_hash, conf_name))) { freepool = pool; + // couldn't find the conference, create one } else { - /* Create the conference object. */ conference = conference_new(conf_name, profile, pool); - if (!conference) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n"); goto done; @@ -2768,9 +2736,9 @@ /* Start the conference thread for this conference */ launch_conference_thread(conference); - } + // deal with conference pins if (conference->pin) { char term = '\0'; char pin[80] = ""; @@ -2800,6 +2768,7 @@ } } + // don't allow more callers if the conference is locked if (switch_test_flag(conference, CFLAG_LOCKED)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Conference %s is locked.\n", conf_name); if (conference->locked_sound) { @@ -2817,6 +2786,7 @@ cxml = NULL; } + // if we're using "bridge:" make an outbound call and bridge it in if (!switch_strlen_zero(bridgeto) && strcasecmp(bridgeto, "none")) { if (conference_outcall(conference, session, bridgeto, 60, NULL, NULL, NULL) != SWITCH_STATUS_SUCCESS) { goto done; @@ -2903,8 +2873,6 @@ goto codec_done1; } - - /* Prepare MUTEXS */ member.id = next_member_id(); member.pool = pool; @@ -3054,6 +3022,8 @@ energy_level = member->energy_level; + // if the member can speak, compute the audio energy level and + // generate events when the level crosses the threshold if (switch_test_flag(member, MFLAG_CAN_SPEAK) && energy_level) { uint32_t energy = 0, i = 0, samples = 0, j = 0, score = 0; int16_t *data; @@ -3143,19 +3113,6 @@ return NULL; } -/* Create a thread for the conference and launch it */ -static void launch_input_thread(conference_member_t *member, switch_memory_pool_t *pool) -{ - switch_thread_t *thread; - switch_threadattr_t *thd_attr = NULL; - - switch_threadattr_create(&thd_attr, pool); - switch_threadattr_detach_set(thd_attr, 1); - switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE); - switch_set_flag_locked(member, MFLAG_ITHREAD); - switch_thread_create(&thread, thd_attr, input_thread_run, member, pool); -} - static const switch_application_interface_t conference_application_interface = { /*.interface_name */ global_app_name, /*.application_function */ conference_function, @@ -3166,11 +3123,38 @@ static switch_api_interface_t conf_api_interface = { /*.interface_name */ "conference", /*.desc */ "Conference module commands", - /*.function */ conf_function, + /*.function */ conf_api_main, /*.syntax */ // see switch_module_load /*.next */ }; +static void chat_list_pretty(conference_obj_t *conference, switch_stream_handle_t *stream) +{ + conference_member_t *member = NULL; + + switch_mutex_lock(conference->member_mutex); + stream->write_function(stream, "<pre>Current Callers:\n"); + + for (member = conference->members; member; member = member->next) { + switch_channel_t *channel; + switch_caller_profile_t *profile; + + if (switch_test_flag(member, MFLAG_NOCHANNEL)) { + continue; + } + channel = switch_core_session_get_channel(member->session); + profile = switch_channel_get_caller_profile(channel); + + + stream->write_function(stream, "*) %s (%s)\n", + profile->caller_id_name, + profile->caller_id_number + ); + + } + switch_mutex_unlock(conference->member_mutex); +} + static switch_status_t chat_send(char *proto, char *from, char *to, char *subject, char *body, char *hint) { char name[512] = "", *p; @@ -3190,7 +3174,6 @@ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invaid Chat Interface [%s]!\n", proto); } - if ((p = strchr(to, '@'))) { switch_copy_string(name, to, ++p-to); } else { @@ -3205,7 +3188,7 @@ SWITCH_STANDARD_STREAM(stream); if (strstr(body, "list")) { - conference_list_pretty(conference, &stream); + chat_list_pretty(conference, &stream); } else { stream.write_function(&stream, "The only command we have so far is 'list'.\nGet coding or go press PayPal!!\n"); } @@ -3213,15 +3196,12 @@ ci->chat_send(CONF_CHAT_PROTO, to, from, "", stream.data, NULL); switch_safe_free(stream.data); - - return SWITCH_STATUS_SUCCESS; } static const switch_chat_interface_t conference_chat_interface = { /*.name */ CONF_CHAT_PROTO, /*.chat_send */ chat_send, - }; static switch_loadable_module_interface_t conference_module_interface = { @@ -3268,12 +3248,13 @@ uint32_t rate = 8000, interval = 20; switch_status_t status; - /* Conference Name */ + // Validate the conference name if (switch_strlen_zero(name)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Record! no name.\n"); return NULL; } + // parse the profile tree for config values for (param = switch_xml_child(profile, "param"); param; param = param->next) { char *var = (char *) switch_xml_attr_soft(param, "name"); char *val = (char *) switch_xml_attr_soft(param, "value"); @@ -3386,7 +3367,7 @@ return NULL; } - /* Initilize the object with some settings */ + // initialize the conference object with settings from the specified profile conference->pool = pool; conference->timer_name = switch_core_strdup(conference->pool, timer_name); conference->tts_engine = switch_core_strdup(conference->pool, tts_engine); @@ -3399,7 +3380,7 @@ // determines the operation that is being requested // To disable the function for the user, make the control // string digit something that can't be dialed... ie. a space - // The control string should have at least 12 characters in it + // The control string MUST have 12 characters in it if(strlen(caller_dtmf_control) < 12) { char dbuf[13]; @@ -3497,13 +3478,13 @@ // build api interface help ".syntax" field string p=strdup("list\n"); for (i=0; i<CONFFUNCAPISIZE; i++) { - nl=strlen(conf_function_api_commands[i].psyntax)+4; + nl=strlen(conf_api_sub_commands[i].psyntax)+4; if(p != NULL) ol = strlen(p); p = realloc(p,ol+nl); if(p != NULL) { strcat(p,"\t\t"); - strcat(p,conf_function_api_commands[i].psyntax); + strcat(p,conf_api_sub_commands[i].psyntax); if(i<CONFFUNCAPISIZE-1) strcat(p,"\n"); } @@ -3516,6 +3497,7 @@ /* Connect my internal structure to the blank pointer passed to me */ *module_interface = &conference_module_interface; + // create/register custom event message type if (switch_event_reserve_subclass(CONF_EVENT_MAINT) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!", CONF_EVENT_MAINT); return SWITCH_STATUS_TERM; @@ -3543,7 +3525,9 @@ if (globals.running) { + // signal all threads to shutdown globals.running = 0; + // wait for all threads while (globals.threads) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Waiting for %d threads\n", globals.threads); switch_yield(100000);