minor refactor

This commit is contained in:
Anthony Minessale 2013-10-24 23:59:41 +05:00
parent 328997fb77
commit 3089eee77c
1 changed files with 431 additions and 5 deletions

View File

@ -100,6 +100,7 @@ static struct {
uint32_t id_pool;
int32_t running;
uint32_t threads;
switch_event_channel_id_t event_channel_id;
} globals;
/* forward declaration for conference_obj and caller_control */
@ -115,6 +116,7 @@ typedef struct conference_cdr_node_s {
uint32_t flags;
uint32_t id;
conference_member_t *member;
switch_event_t *var_event;
struct conference_cdr_node_s *next;
} conference_cdr_node_t;
@ -204,7 +206,9 @@ typedef enum {
CFLAG_ENDCONF_FORCED = (1 << 16),
CFLAG_RFC4579 = (1 << 17),
CFLAG_FLOOR_CHANGE = (1 << 18),
CFLAG_VID_FLOOR_LOCK = (1 << 19)
CFLAG_VID_FLOOR_LOCK = (1 << 19),
CFLAG_JSON_EVENTS = (1 << 20),
CFLAG_LIVEARRAY_SYNC = (1 << 21)
} conf_flag_t;
typedef enum {
@ -300,6 +304,8 @@ typedef struct conference_record {
/* Conference Object */
typedef struct conference_obj {
char *name;
char *la_name;
char *la_event_channel;
char *desc;
char *timer_name;
char *tts_engine;
@ -338,6 +344,7 @@ typedef struct conference_obj {
char *domain;
char *caller_controls;
char *moderator_controls;
switch_live_array_t *la;
uint32_t flags;
member_flag_t mflags;
switch_call_cause_t bridge_hangup_cause;
@ -466,6 +473,8 @@ struct conference_member {
char *kicked_sound;
switch_queue_t *dtmf_queue;
switch_thread_t *input_thread;
cJSON *json;
cJSON *status_field;
};
typedef enum {
@ -564,6 +573,9 @@ static switch_status_t conf_api_sub_clear_vid_floor(conference_obj_t *conference
static void conference_cdr_del(conference_member_t *member)
{
if (member->channel) {
switch_channel_get_variables(member->channel, &member->cdr_node->var_event);
}
member->cdr_node->leave_time = switch_epoch_time_now(NULL);
member->cdr_node->flags = member->flags;
member->cdr_node->member = NULL;
@ -1086,6 +1098,218 @@ static void conference_cdr_render(conference_obj_t *conference)
switch_xml_free(cdr);
}
static cJSON *conference_json_render(conference_obj_t *conference, cJSON *req)
{
char tmp[30];
const char *domain; const char *name;
char *dup_domain = NULL;
char *uri;
conference_cdr_node_t *np;
char *tmpp = tmp;
cJSON *json = cJSON_CreateObject(), *jusers = NULL, *jold_users = NULL, *juser = NULL, *jvars = NULL;
switch_assert(json);
switch_mutex_lock(conference->mutex);
switch_snprintf(tmp, sizeof(tmp), "%u", conference->doc_version);
conference->doc_version++;
switch_mutex_unlock(conference->mutex);
if (!(name = conference->name)) {
name = "conference";
}
if (!(domain = conference->domain)) {
dup_domain = switch_core_get_domain(SWITCH_TRUE);
if (!(domain = dup_domain)) {
domain = "cluecon.com";
}
}
uri = switch_mprintf("%s@%s", name, domain);
json_add_child_string(json, "entity", uri);
json_add_child_string(json, "conferenceDescription", conference->desc ? conference->desc : "FreeSWITCH Conference");
json_add_child_string(json, "conferenceState", "active");
switch_snprintf(tmp, sizeof(tmp), "%u", conference->count);
json_add_child_string(json, "userCount", tmp);
jusers = json_add_child_array(json, "users");
jold_users = json_add_child_array(json, "oldUsers");
switch_mutex_lock(conference->member_mutex);
for (np = conference->cdr_nodes; np; np = np->next) {
char *user_uri = NULL;
switch_channel_t *channel = NULL;
switch_time_exp_t tm;
switch_size_t retsize;
const char *fmt = "%Y-%m-%dT%H:%M:%S%z";
char *p;
if (np->record_path || !np->cp) {
continue;
}
//if (!np->cp || (np->member && !np->member->session) || np->leave_time) { /* for now we'll remove participants when they leave */
//continue;
//}
if (np->member && np->member->session) {
channel = switch_core_session_get_channel(np->member->session);
}
juser = cJSON_CreateObject();
if (channel) {
const char *uri = switch_channel_get_variable_dup(channel, "conference_invite_uri", SWITCH_FALSE, -1);
if (uri) {
user_uri = strdup(uri);
}
}
if (np->cp) {
if (!user_uri) {
user_uri = switch_mprintf("%s@%s", np->cp->caller_id_number, domain);
}
json_add_child_string(juser, "entity", user_uri);
json_add_child_string(juser, "displayText", np->cp->caller_id_name);
}
//if (np->record_path) {
//json_add_child_string(juser, "recordingPATH", np->record_path);
//}
json_add_child_string(juser, "status", np->leave_time ? "disconnected" : "connected");
switch_time_exp_lt(&tm, (switch_time_t) conference->start_time * 1000000);
switch_strftime_nocheck(tmp, &retsize, sizeof(tmp), fmt, &tm);
p = end_of_p(tmpp) -1;
snprintf(p, 4, ":00");
json_add_child_string(juser, "joinTime", tmpp);
snprintf(tmp, sizeof(tmp), "%u", np->id);
json_add_child_string(juser, "memberId", tmp);
jvars = cJSON_CreateObject();
if (!np->member && np->var_event) {
switch_json_add_presence_data_cols(np->var_event, jvars, "PD-");
} else if (np->member) {
const char *var;
const char *prefix = NULL;
switch_event_t *var_event = NULL;
switch_event_header_t *hp;
int all = 0;
switch_channel_get_variables(channel, &var_event);
if ((prefix = switch_event_get_header(var_event, "json_conf_var_prefix"))) {
all = strcasecmp(prefix, "__all__");
} else {
prefix = "json_";
}
for(hp = var_event->headers; hp; hp = hp->next) {
if (all || !strncasecmp(hp->name, prefix, strlen(prefix))) {
json_add_child_string(jvars, hp->name, hp->value);
}
}
switch_json_add_presence_data_cols(var_event, jvars, "PD-");
switch_event_destroy(&var_event);
if ((var = switch_channel_get_variable(channel, "rtp_use_ssrc"))) {
json_add_child_string(juser, "rtpAudioSSRC", var);
}
json_add_child_string(juser, "rtpAudioDirection", switch_channel_test_flag(channel, CF_HOLD) ? "sendonly" : "sendrecv");
if (switch_channel_test_flag(channel, CF_VIDEO)) {
if ((var = switch_channel_get_variable(channel, "rtp_use_video_ssrc"))) {
json_add_child_string(juser, "rtpVideoSSRC", var);
}
json_add_child_string(juser, "rtpVideoDirection", switch_channel_test_flag(channel, CF_HOLD) ? "sendonly" : "sendrecv");
}
}
if (jvars) {
json_add_child_obj(juser, "variables", jvars);
}
cJSON_AddItemToArray(np->leave_time ? jold_users : jusers, juser);
switch_safe_free(user_uri);
}
switch_mutex_unlock(conference->member_mutex);
switch_safe_free(dup_domain);
switch_safe_free(uri);
return json;
}
static void conference_la_event_channel_handler(const char *event_channel, cJSON *json, const char *key, switch_event_channel_id_t id)
{
switch_live_array_parse_json(json, globals.event_channel_id);
}
static void conference_event_channel_handler(const char *event_channel, cJSON *json, const char *key, switch_event_channel_id_t id)
{
char *domain = NULL, *name = NULL;
conference_obj_t *conference = NULL;
cJSON *data, *reply = NULL, *conf_desc = NULL;
const char *action = NULL;
if ((data = cJSON_GetObjectItem(json, "data"))) {
action = cJSON_GetObjectCstr(data, "action");
}
if (!action) action = "";
reply = cJSON_Duplicate(json, 1);
cJSON_DeleteItemFromObject(reply, "data");
if ((name = strchr(event_channel, '.'))) {
char *tmp = strdup(name + 1);
switch_assert(tmp);
name = tmp;
if ((domain = strchr(name, '@'))) {
*domain++ = '\0';
}
}
if (!strcasecmp(action, "bootstrap")) {
if (!zstr(name) && (conference = conference_find(name, domain))) {
conf_desc = conference_json_render(conference, json);
} else {
conf_desc = cJSON_CreateObject();
json_add_child_string(conf_desc, "conferenceDescription", "FreeSWITCH Conference");
json_add_child_string(conf_desc, "conferenceState", "inactive");
json_add_child_array(conf_desc, "users");
json_add_child_array(conf_desc, "oldUsers");
}
} else {
conf_desc = cJSON_CreateObject();
json_add_child_string(conf_desc, "error", "Invalid action");
}
json_add_child_string(conf_desc, "action", "conferenceDescription");
cJSON_AddItemToObject(reply, "data", conf_desc);
switch_event_channel_broadcast(event_channel, &reply, modname, globals.event_channel_id);
}
static switch_status_t conference_add_event_data(conference_obj_t *conference, switch_event_t *event)
@ -1340,6 +1564,42 @@ static switch_status_t member_del_relationship(conference_member_t *member, uint
return status;
}
static void send_json_event(conference_obj_t *conference)
{
cJSON *event, *conf_desc = NULL;
char *name = NULL, *domain = NULL, *dup_domain = NULL;
char *event_channel = NULL;
if (!switch_test_flag(conference, CFLAG_JSON_EVENTS)) {
return;
}
conf_desc = conference_json_render(conference, NULL);
if (!(name = conference->name)) {
name = "conference";
}
if (!(domain = conference->domain)) {
dup_domain = switch_core_get_domain(SWITCH_TRUE);
if (!(domain = dup_domain)) {
domain = "cluecon.com";
}
}
event_channel = switch_mprintf("conference.%q@%q", name, domain);
event = cJSON_CreateObject();
json_add_child_string(event, "eventChannel", event_channel);
cJSON_AddItemToObject(event, "data", conf_desc);
switch_event_channel_broadcast(event_channel, &event, modname, globals.event_channel_id);
switch_safe_free(dup_domain);
switch_safe_free(event_channel);
}
static void send_rfc_event(conference_obj_t *conference)
{
switch_event_t *event;
@ -1422,6 +1682,73 @@ static void send_conference_notify(conference_obj_t *conference, const char *sta
}
static void member_update_status_field(conference_member_t *member)
{
char *str, *vstr = "", display[128] = "";
if (!member->conference->la) {
return;
}
switch_live_array_lock(member->conference->la);
if (!switch_test_flag(member, MFLAG_CAN_SPEAK)) {
str = "MUTE";
} else if (switch_channel_test_flag(member->channel, CF_HOLD)) {
str = "HOLD";
} else if (member == member->conference->floor_holder) {
if (switch_test_flag(member, MFLAG_TALKING)) {
str = "TALKING (FLOOR)";
} else {
str = "FLOOR";
}
} else if (switch_test_flag(member, MFLAG_TALKING)) {
str = "TALKING";
} else {
str = "ACTIVE";
}
if (switch_channel_test_flag(member->channel, CF_VIDEO)) {
vstr = " VIDEO";
if (member == member->conference->video_floor_holder) {
vstr = " VIDEO (FLOOR)";
}
}
switch_snprintf(display, sizeof(display), "%s%s", str, vstr);
free(member->status_field->valuestring);
member->status_field->valuestring = strdup(display);
switch_live_array_add(member->conference->la, switch_core_session_get_uuid(member->session), -1, &member->json, SWITCH_FALSE);
switch_live_array_unlock(member->conference->la);
}
static void adv_la(conference_obj_t *conference, conference_member_t *member, switch_bool_t join)
{
if (conference && conference->la && member->session) {
cJSON *msg, *data;
const char *uuid = switch_core_session_get_uuid(member->session);
const char *cookie = switch_channel_get_variable(member->channel, "event_channel_cookie");
msg = cJSON_CreateObject();
data = json_add_child_obj(msg, "pvtData", NULL);
cJSON_AddItemToObject(msg, "eventChannel", cJSON_CreateString(uuid));
cJSON_AddItemToObject(msg, "eventType", cJSON_CreateString("channelPvtData"));
cJSON_AddItemToObject(data, "action", cJSON_CreateString(join ? "conference-liveArray-join" : "conference-liveArray-part"));
cJSON_AddItemToObject(data, "laChannel", cJSON_CreateString(conference->la_event_channel));
cJSON_AddItemToObject(data, "laName", cJSON_CreateString(conference->la_name));
if (cookie) {
switch_event_channel_permission_modify(cookie, conference->la_event_channel, join);
}
switch_event_channel_broadcast(uuid, &msg, modname, globals.event_channel_id);
}
}
/* Gain exclusive access and add the member to the list */
static switch_status_t conference_add_member(conference_obj_t *conference, conference_member_t *member)
@ -1585,7 +1912,29 @@ static switch_status_t conference_add_member(conference_obj_t *conference, confe
switch_mutex_unlock(member->audio_out_mutex);
switch_mutex_unlock(member->audio_in_mutex);
if (conference->la && member->channel) {
member->json = cJSON_CreateArray();
cJSON_AddItemToArray(member->json, cJSON_CreateStringPrintf("%0.8d", member->id));
cJSON_AddItemToArray(member->json, cJSON_CreateString(switch_channel_get_variable(member->channel, "caller_id_number")));
cJSON_AddItemToArray(member->json, cJSON_CreateString(switch_channel_get_variable(member->channel, "caller_id_name")));
cJSON_AddItemToArray(member->json, cJSON_CreateStringPrintf("%s@%s",
switch_channel_get_variable(member->channel, "original_read_codec"),
switch_channel_get_variable(member->channel, "original_read_rate")
));
member->status_field = cJSON_CreateString("");
cJSON_AddItemToArray(member->json, member->status_field);
member_update_status_field(member);
//switch_live_array_add_alias(conference->la, switch_core_session_get_uuid(member->session), "conference");
adv_la(conference, member, SWITCH_TRUE);
switch_live_array_add(conference->la, switch_core_session_get_uuid(member->session), -1, &member->json, SWITCH_FALSE);
}
send_rfc_event(conference);
send_json_event(conference);
switch_mutex_unlock(conference->mutex);
status = SWITCH_STATUS_SUCCESS;
@ -1637,12 +1986,14 @@ static void conference_set_video_floor_holder(conference_obj_t *conference, conf
//switch_channel_set_flag(member->channel, CF_VIDEO_PASSIVE);
switch_core_session_refresh_video(member->session);
conference->video_floor_holder = member;
member_update_status_field(member);
} else {
conference->video_floor_holder = NULL;
}
if (old_member) {
old_id = old_member->id;
member_update_status_field(old_member);
//switch_channel_clear_flag(old_member->channel, CF_VIDEO_PASSIVE);
}
@ -1714,6 +2065,7 @@ static void conference_set_floor_holder(conference_obj_t *conference, conference
switch_channel_get_name(member->channel));
conference->floor_holder = member;
member_update_status_field(member);
} else {
conference->floor_holder = NULL;
}
@ -1721,6 +2073,7 @@ static void conference_set_floor_holder(conference_obj_t *conference, conference
if (old_member) {
old_id = old_member->id;
member_update_status_field(old_member);
}
switch_set_flag(conference, CFLAG_FLOOR_CHANGE);
@ -1881,8 +2234,14 @@ static switch_status_t conference_del_member(conference_obj_t *conference, confe
switch_mutex_unlock(member->audio_in_mutex);
if (conference->la && member->session) {
switch_live_array_del(conference->la, switch_core_session_get_uuid(member->session));
//switch_live_array_clear_alias(conference->la, switch_core_session_get_uuid(member->session), "conference");
adv_la(conference, member, SWITCH_FALSE);
}
send_rfc_event(conference);
send_json_event(conference);
switch_mutex_unlock(conference->mutex);
status = SWITCH_STATUS_SUCCESS;
@ -2062,6 +2421,11 @@ static void *SWITCH_THREAD_FUNC conference_video_thread_run(switch_thread_t *thr
return NULL;
}
static void conference_command_handler(switch_live_array_t *la, const char *cmd, const char *sessid, cJSON *jla, void *user_data)
{
}
/* Main monitor thread (1 per distinct conference room) */
static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, void *obj)
{
@ -2079,6 +2443,7 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v
int32_t z = 0;
int member_score_sum = 0;
int divisor = 0;
conference_cdr_node_t *np;
if (!(divisor = conference->rate / 8000)) {
divisor = 1;
@ -2108,6 +2473,26 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "conference-create");
switch_event_fire(&event);
if (switch_test_flag(conference, CFLAG_LIVEARRAY_SYNC)) {
char *p;
if (strchr(conference->name, '@')) {
conference->la_event_channel = switch_core_sprintf(conference->pool, "conference-liveArray.%s", conference->name);
} else {
conference->la_event_channel = switch_core_sprintf(conference->pool, "conference-liveArray.%s@%s", conference->name, conference->domain);
}
conference->la_name = switch_core_strdup(conference->pool, conference->name);
if ((p = strchr(conference->la_name, '@'))) {
*p = '\0';
}
switch_live_array_create(conference->la_event_channel, conference->la_name, globals.event_channel_id, &conference->la);
switch_live_array_set_user_data(conference->la, conference);
switch_live_array_set_command_handler(conference->la, conference_command_handler);
}
while (globals.running && !switch_test_flag(conference, CFLAG_DESTRUCT)) {
switch_size_t file_sample_len = samples;
switch_size_t file_data_len = samples * 2;
@ -2505,6 +2890,14 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v
switch_mutex_lock(conference->mutex);
conference_stop_file(conference, FILE_STOP_ASYNC);
conference_stop_file(conference, FILE_STOP_ALL);
for (np = conference->cdr_nodes; np; np = np->next) {
if (np->var_event) {
switch_event_destroy(&np->var_event);
}
}
/* Close Unused Handles */
if (conference->fnode) {
conference_file_node_t *fnode, *cur;
@ -2596,6 +2989,10 @@ 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");
if (conference->la) {
switch_live_array_destroy(&conference->la);
}
if (conference->sh) {
switch_speech_flag_t flags = SWITCH_SPEECH_FLAG_NONE;
switch_core_speech_close(&conference->lsh, &flags);
@ -3241,7 +3638,6 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v
break;
}
/* if we have caller digits, feed them to the parser to find an action */
if (switch_channel_has_dtmf(channel)) {
char dtmf[128] = "";
@ -3251,7 +3647,12 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v
if (switch_test_flag(member, MFLAG_DIST_DTMF)) {
conference_send_all_dtmf(member, member->conference, dtmf);
} else if (member->dmachine) {
switch_ivr_dmachine_feed(member->dmachine, dtmf, NULL);
char *p;
char str[2] = "";
for (p = dtmf; p && *p; p++) {
str[0] = *p;
switch_ivr_dmachine_feed(member->dmachine, str, NULL);
}
}
} else if (member->dmachine) {
switch_ivr_dmachine_ping(member->dmachine, NULL);
@ -3280,6 +3681,7 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v
if (++hangover_hits >= hangover) {
hangover_hits = hangunder_hits = 0;
switch_clear_flag_locked(member, MFLAG_TALKING);
member_update_status_field(member);
check_agc_levels(member);
clear_avg(member);
member->score_iir = 0;
@ -3398,7 +3800,7 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v
if (!switch_test_flag(member, MFLAG_TALKING)) {
switch_set_flag_locked(member, MFLAG_TALKING);
member_update_status_field(member);
if (test_eflag(member->conference, EFLAG_START_TALKING) && switch_test_flag(member, MFLAG_CAN_SPEAK) &&
switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
conference_add_event_member_data(member, event);
@ -3435,6 +3837,7 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v
if (++hangover_hits >= hangover) {
hangover_hits = hangunder_hits = 0;
switch_clear_flag_locked(member, MFLAG_TALKING);
member_update_status_field(member);
check_agc_levels(member);
clear_avg(member);
@ -3763,6 +4166,15 @@ static void conference_loop_output(conference_member_t *member)
switch_mutex_lock(member->write_mutex);
if (switch_channel_test_flag(member->channel, CF_CONFERENCE_ADV)) {
if (member->conference->la) {
adv_la(member->conference, member, SWITCH_TRUE);
}
switch_channel_clear_flag(member->channel, CF_CONFERENCE_ADV);
}
if (switch_core_session_dequeue_event(member->session, &event, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) {
if (event->event_id == SWITCH_EVENT_MESSAGE) {
char *from = switch_event_get_header(event, "from");
@ -4864,6 +5276,8 @@ static switch_status_t conf_api_sub_mute(conference_member_t *member, switch_str
switch_event_fire(&event);
}
member_update_status_field(member);
return SWITCH_STATUS_SUCCESS;
}
@ -4948,6 +5362,8 @@ static switch_status_t conf_api_sub_unmute(conference_member_t *member, switch_s
switch_event_fire(&event);
}
member_update_status_field(member);
return SWITCH_STATUS_SUCCESS;
}
@ -7260,6 +7676,10 @@ static void set_cflags(const char *flags, uint32_t *f)
*f |= CFLAG_VIDEO_BRIDGE;
} else if (!strcasecmp(argv[i], "audio-always")) {
*f |= CFLAG_AUDIO_ALWAYS;
} else if (!strcasecmp(argv[i], "json-events")) {
*f |= CFLAG_JSON_EVENTS;
} else if (!strcasecmp(argv[i], "livearray-sync")) {
*f |= CFLAG_LIVEARRAY_SYNC;
} else if (!strcasecmp(argv[i], "rfc-4579")) {
*f |= CFLAG_RFC4579;
}
@ -9308,6 +9728,9 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_conference_load)
switch_console_add_complete_func("::conference::list_conferences", list_conferences);
switch_event_channel_bind("conference", conference_event_channel_handler, &globals.event_channel_id);
switch_event_channel_bind("conference-liveArray", conference_la_event_channel_handler, &globals.event_channel_id);
/* build api interface help ".syntax" field string */
p = strdup("");
for (i = 0; i < CONFFUNCAPISIZE; i++) {
@ -9389,6 +9812,9 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_conference_shutdown)
/* signal all threads to shutdown */
globals.running = 0;
switch_event_channel_unbind(NULL, conference_event_channel_handler);
switch_event_channel_unbind(NULL, conference_la_event_channel_handler);
switch_console_del_complete_func("::conference::list_conferences");
/* wait for all threads */