2015-07-15 09:50:17 -07:00
|
|
|
/*
|
|
|
|
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
|
|
|
* Copyright (C) 2005-2014, Anthony Minessale II <anthm@freeswitch.org>
|
|
|
|
*
|
|
|
|
* Version: MPL 1.1
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
|
|
* the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/MPL/
|
|
|
|
*
|
2015-07-16 17:42:21 -07:00
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
2015-07-15 09:50:17 -07:00
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
|
|
|
*
|
|
|
|
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is
|
|
|
|
* Anthony Minessale II <anthm@freeswitch.org>
|
|
|
|
* Portions created by the Initial Developer are Copyright (C)
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
2015-07-16 17:42:21 -07:00
|
|
|
*
|
2015-07-15 09:50:17 -07:00
|
|
|
* Anthony Minessale II <anthm@freeswitch.org>
|
|
|
|
* Neal Horman <neal at wanlink dot com>
|
|
|
|
* Bret McDanel <trixter at 0xdecafbad dot com>
|
|
|
|
* Dale Thatcher <freeswitch at dalethatcher dot com>
|
|
|
|
* Chris Danielson <chris at maxpowersoft dot com>
|
|
|
|
* Rupa Schomaker <rupa@rupa.com>
|
|
|
|
* David Weekly <david@weekly.org>
|
|
|
|
* Joao Mesquita <jmesquita@gmail.com>
|
|
|
|
* Raymond Chandler <intralanman@freeswitch.org>
|
|
|
|
* Seven Du <dujinfang@gmail.com>
|
|
|
|
* Emmanuel Schmidbauer <e.schmidbauer@gmail.com>
|
|
|
|
* William King <william.king@quentustech.com>
|
|
|
|
*
|
|
|
|
* mod_conference.c -- Software Conference Bridge
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
#include <mod_conference.h>
|
|
|
|
|
|
|
|
|
2015-11-24 20:33:07 +00:00
|
|
|
static inline switch_bool_t conference_cdr_test_mflag(conference_cdr_node_t *np, member_flag_t mflag)
|
2015-07-15 09:50:17 -07:00
|
|
|
{
|
|
|
|
return !!np->mflags[mflag];
|
|
|
|
}
|
|
|
|
|
2015-07-16 16:58:39 -07:00
|
|
|
const char *conference_cdr_audio_flow(conference_member_t *member)
|
2015-07-15 09:50:17 -07:00
|
|
|
{
|
|
|
|
const char *flow = "sendrecv";
|
|
|
|
|
2015-07-16 16:58:39 -07:00
|
|
|
if (!conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK)) {
|
2015-07-15 09:50:17 -07:00
|
|
|
flow = "recvonly";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (member->channel && switch_channel_test_flag(member->channel, CF_HOLD)) {
|
2015-07-16 16:58:39 -07:00
|
|
|
flow = conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK) ? "sendonly" : "inactive";
|
2015-07-15 09:50:17 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return flow;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-07-16 16:58:39 -07:00
|
|
|
char *conference_cdr_rfc4579_render(conference_obj_t *conference, switch_event_t *event, switch_event_t *revent)
|
2015-07-15 09:50:17 -07:00
|
|
|
{
|
|
|
|
switch_xml_t xml, x_tag, x_tag1, x_tag2, x_tag3, x_tag4;
|
|
|
|
char tmp[30];
|
|
|
|
const char *domain; const char *name;
|
|
|
|
char *dup_domain = NULL;
|
|
|
|
char *uri;
|
|
|
|
int off = 0, off1 = 0, off2 = 0, off3 = 0, off4 = 0;
|
2015-07-16 16:58:39 -07:00
|
|
|
conference_cdr_node_t *np;
|
2015-07-15 09:50:17 -07:00
|
|
|
char *tmpp = tmp;
|
|
|
|
char *xml_text = NULL;
|
|
|
|
|
|
|
|
if (!(xml = switch_xml_new("conference-info"))) {
|
|
|
|
abort();
|
|
|
|
}
|
2015-07-16 17:42:21 -07:00
|
|
|
|
2015-07-15 09:50:17 -07:00
|
|
|
switch_mutex_lock(conference->mutex);
|
|
|
|
switch_snprintf(tmp, sizeof(tmp), "%u", conference->doc_version);
|
|
|
|
conference->doc_version++;
|
|
|
|
switch_mutex_unlock(conference->mutex);
|
|
|
|
|
|
|
|
if (!event || !(name = switch_event_get_header(event, "conference-name"))) {
|
|
|
|
if (!(name = conference->name)) {
|
|
|
|
name = "conference";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!event || !(domain = switch_event_get_header(event, "conference-domain"))) {
|
|
|
|
if (!(domain = conference->domain)) {
|
|
|
|
dup_domain = switch_core_get_domain(SWITCH_TRUE);
|
|
|
|
if (!(domain = dup_domain)) {
|
|
|
|
domain = "cluecon.com";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-07-16 17:42:21 -07:00
|
|
|
|
2015-07-15 09:50:17 -07:00
|
|
|
switch_xml_set_attr_d(xml, "version", tmpp);
|
|
|
|
|
|
|
|
switch_xml_set_attr_d(xml, "state", "full");
|
|
|
|
switch_xml_set_attr_d(xml, "xmlns", "urn:ietf:params:xml:ns:conference-info");
|
2015-07-16 17:42:21 -07:00
|
|
|
|
2015-07-15 09:50:17 -07:00
|
|
|
|
|
|
|
uri = switch_mprintf("sip:%s@%s", name, domain);
|
|
|
|
switch_xml_set_attr_d(xml, "entity", uri);
|
|
|
|
|
|
|
|
if (!(x_tag = switch_xml_add_child_d(xml, "conference-description", off++))) {
|
|
|
|
abort();
|
|
|
|
}
|
2015-07-16 17:42:21 -07:00
|
|
|
|
2015-07-15 09:50:17 -07:00
|
|
|
if (!(x_tag1 = switch_xml_add_child_d(x_tag, "display-text", off1++))) {
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
switch_xml_set_txt_d(x_tag1, conference->desc ? conference->desc : "FreeSWITCH Conference");
|
|
|
|
|
|
|
|
|
|
|
|
if (!(x_tag1 = switch_xml_add_child_d(x_tag, "conf-uris", off1++))) {
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(x_tag2 = switch_xml_add_child_d(x_tag1, "entry", off2++))) {
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(x_tag3 = switch_xml_add_child_d(x_tag2, "uri", off3++))) {
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
switch_xml_set_txt_d(x_tag3, uri);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!(x_tag = switch_xml_add_child_d(xml, "conference-state", off++))) {
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
if (!(x_tag1 = switch_xml_add_child_d(x_tag, "user-count", off1++))) {
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
switch_snprintf(tmp, sizeof(tmp), "%u", conference->count);
|
2015-07-16 17:42:21 -07:00
|
|
|
switch_xml_set_txt_d(x_tag1, tmpp);
|
2015-07-15 09:50:17 -07:00
|
|
|
|
|
|
|
#if 0
|
|
|
|
if (conference->count == 0) {
|
|
|
|
switch_event_add_header(revent, SWITCH_STACK_BOTTOM, "notfound", "true");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (!(x_tag1 = switch_xml_add_child_d(x_tag, "active", off1++))) {
|
|
|
|
abort();
|
|
|
|
}
|
2015-07-16 17:42:21 -07:00
|
|
|
switch_xml_set_txt_d(x_tag1, "true");
|
|
|
|
|
2015-07-15 09:50:17 -07:00
|
|
|
off1 = off2 = off3 = off4 = 0;
|
|
|
|
|
|
|
|
if (!(x_tag = switch_xml_add_child_d(xml, "users", off++))) {
|
|
|
|
abort();
|
|
|
|
}
|
2015-07-16 17:42:21 -07:00
|
|
|
|
2015-07-15 09:50:17 -07:00
|
|
|
switch_mutex_lock(conference->member_mutex);
|
2015-07-16 17:42:21 -07:00
|
|
|
|
2015-07-15 09:50:17 -07:00
|
|
|
for (np = conference->cdr_nodes; np; np = np->next) {
|
|
|
|
char *user_uri = NULL;
|
|
|
|
switch_channel_t *channel = NULL;
|
2015-07-16 17:42:21 -07:00
|
|
|
|
2015-07-15 09:50:17 -07:00
|
|
|
if (!np->cp || (np->member && !np->member->session) || np->leave_time) { /* for now we'll remove participants when the leave */
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (np->member && np->member->session) {
|
|
|
|
channel = switch_core_session_get_channel(np->member->session);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(x_tag1 = switch_xml_add_child_d(x_tag, "user", off1++))) {
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (channel) {
|
|
|
|
const char *uri = switch_channel_get_variable_dup(channel, "conference_invite_uri", SWITCH_FALSE, -1);
|
|
|
|
|
|
|
|
if (uri) {
|
|
|
|
user_uri = strdup(uri);
|
|
|
|
}
|
|
|
|
}
|
2015-07-16 17:42:21 -07:00
|
|
|
|
2015-07-15 09:50:17 -07:00
|
|
|
if (!user_uri) {
|
|
|
|
user_uri = switch_mprintf("sip:%s@%s", np->cp->caller_id_number, domain);
|
|
|
|
}
|
2015-07-16 17:42:21 -07:00
|
|
|
|
|
|
|
|
2015-07-15 09:50:17 -07:00
|
|
|
switch_xml_set_attr_d(x_tag1, "state", "full");
|
|
|
|
switch_xml_set_attr_d(x_tag1, "entity", user_uri);
|
|
|
|
|
|
|
|
if (!(x_tag2 = switch_xml_add_child_d(x_tag1, "display-text", off2++))) {
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
switch_xml_set_txt_d(x_tag2, np->cp->caller_id_name);
|
2015-07-16 17:42:21 -07:00
|
|
|
|
2015-07-15 09:50:17 -07:00
|
|
|
|
|
|
|
if (!(x_tag2 = switch_xml_add_child_d(x_tag1, "endpoint", off2++))) {
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
switch_xml_set_attr_d(x_tag2, "entity", user_uri);
|
2015-07-16 17:42:21 -07:00
|
|
|
|
2015-07-15 09:50:17 -07:00
|
|
|
if (!(x_tag3 = switch_xml_add_child_d(x_tag2, "display-text", off3++))) {
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
switch_xml_set_txt_d(x_tag3, np->cp->caller_id_name);
|
|
|
|
|
|
|
|
|
|
|
|
if (!(x_tag3 = switch_xml_add_child_d(x_tag2, "status", off3++))) {
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
switch_xml_set_txt_d(x_tag3, np->leave_time ? "disconnected" : "connected");
|
|
|
|
|
|
|
|
|
|
|
|
if (!(x_tag3 = switch_xml_add_child_d(x_tag2, "joining-info", off3++))) {
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
if (!(x_tag4 = switch_xml_add_child_d(x_tag3, "when", off4++))) {
|
|
|
|
abort();
|
|
|
|
} else {
|
|
|
|
switch_time_exp_t tm;
|
|
|
|
switch_size_t retsize;
|
|
|
|
const char *fmt = "%Y-%m-%dT%H:%M:%S%z";
|
|
|
|
char *p;
|
|
|
|
|
|
|
|
switch_time_exp_lt(&tm, (switch_time_t) conference->start_time * 1000000);
|
2015-07-16 17:42:21 -07:00
|
|
|
switch_strftime_nocheck(tmp, &retsize, sizeof(tmp), fmt, &tm);
|
2015-07-15 09:50:17 -07:00
|
|
|
p = end_of_p(tmpp) -1;
|
|
|
|
snprintf(p, 4, ":00");
|
|
|
|
|
|
|
|
|
|
|
|
switch_xml_set_txt_d(x_tag4, tmpp);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2015-07-16 17:42:21 -07:00
|
|
|
|
|
|
|
/** ok so this is in the rfc but not the xsd
|
|
|
|
if (!(x_tag3 = switch_xml_add_child_d(x_tag2, "joining-method", off3++))) {
|
2015-07-15 09:50:17 -07:00
|
|
|
abort();
|
2015-07-16 17:42:21 -07:00
|
|
|
}
|
|
|
|
switch_xml_set_txt_d(x_tag3, np->cp->direction == SWITCH_CALL_DIRECTION_INBOUND ? "dialed-in" : "dialed-out");
|
2015-07-15 09:50:17 -07:00
|
|
|
*/
|
|
|
|
|
|
|
|
if (np->member) {
|
|
|
|
const char *var;
|
|
|
|
//char buf[1024];
|
|
|
|
|
2015-07-16 16:58:39 -07:00
|
|
|
//switch_snprintf(buf, sizeof(buf), "conference_%s_%s_%s", conference->name, conference->domain, np->cp->caller_id_number);
|
2015-07-15 09:50:17 -07:00
|
|
|
//switch_channel_set_variable(channel, "conference_call_key", buf);
|
|
|
|
|
|
|
|
if (!(x_tag3 = switch_xml_add_child_d(x_tag2, "media", off3++))) {
|
|
|
|
abort();
|
|
|
|
}
|
2015-07-16 17:42:21 -07:00
|
|
|
|
2015-07-15 09:50:17 -07:00
|
|
|
snprintf(tmp, sizeof(tmp), "%ua", np->member->id);
|
|
|
|
switch_xml_set_attr_d(x_tag3, "id", tmpp);
|
|
|
|
|
|
|
|
|
|
|
|
if (!(x_tag4 = switch_xml_add_child_d(x_tag3, "type", off4++))) {
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
switch_xml_set_txt_d(x_tag4, "audio");
|
|
|
|
|
|
|
|
if ((var = switch_channel_get_variable(channel, "rtp_use_ssrc"))) {
|
|
|
|
if (!(x_tag4 = switch_xml_add_child_d(x_tag3, "src-id", off4++))) {
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
switch_xml_set_txt_d(x_tag4, var);
|
|
|
|
}
|
2015-07-16 17:42:21 -07:00
|
|
|
|
2015-07-15 09:50:17 -07:00
|
|
|
if (!(x_tag4 = switch_xml_add_child_d(x_tag3, "status", off4++))) {
|
|
|
|
abort();
|
|
|
|
}
|
2015-07-16 16:58:39 -07:00
|
|
|
switch_xml_set_txt_d(x_tag4, conference_cdr_audio_flow(np->member));
|
2015-07-16 17:42:21 -07:00
|
|
|
|
|
|
|
|
2015-07-15 09:50:17 -07:00
|
|
|
if (switch_channel_test_flag(channel, CF_VIDEO)) {
|
|
|
|
off4 = 0;
|
|
|
|
|
|
|
|
if (!(x_tag3 = switch_xml_add_child_d(x_tag2, "media", off3++))) {
|
|
|
|
abort();
|
|
|
|
}
|
2015-07-16 17:42:21 -07:00
|
|
|
|
2015-07-15 09:50:17 -07:00
|
|
|
snprintf(tmp, sizeof(tmp), "%uv", np->member->id);
|
|
|
|
switch_xml_set_attr_d(x_tag3, "id", tmpp);
|
|
|
|
|
|
|
|
|
|
|
|
if (!(x_tag4 = switch_xml_add_child_d(x_tag3, "type", off4++))) {
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
switch_xml_set_txt_d(x_tag4, "video");
|
|
|
|
|
|
|
|
if ((var = switch_channel_get_variable(channel, "rtp_use_video_ssrc"))) {
|
|
|
|
if (!(x_tag4 = switch_xml_add_child_d(x_tag3, "src-id", off4++))) {
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
switch_xml_set_txt_d(x_tag4, var);
|
|
|
|
}
|
2015-07-16 17:42:21 -07:00
|
|
|
|
2015-07-15 09:50:17 -07:00
|
|
|
if (!(x_tag4 = switch_xml_add_child_d(x_tag3, "status", off4++))) {
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
switch_xml_set_txt_d(x_tag4, switch_channel_test_flag(channel, CF_HOLD) ? "sendonly" : "sendrecv");
|
2015-07-16 17:42:21 -07:00
|
|
|
|
2015-07-15 09:50:17 -07:00
|
|
|
}
|
|
|
|
}
|
2015-07-16 17:42:21 -07:00
|
|
|
|
2015-07-15 09:50:17 -07:00
|
|
|
switch_safe_free(user_uri);
|
|
|
|
}
|
|
|
|
|
|
|
|
switch_mutex_unlock(conference->member_mutex);
|
|
|
|
|
|
|
|
off1 = off2 = off3 = off4 = 0;
|
|
|
|
|
|
|
|
xml_text = switch_xml_toxml(xml, SWITCH_TRUE);
|
|
|
|
switch_xml_free(xml);
|
2015-07-16 17:42:21 -07:00
|
|
|
|
2015-07-15 09:50:17 -07:00
|
|
|
switch_safe_free(dup_domain);
|
2015-07-16 17:42:21 -07:00
|
|
|
switch_safe_free(uri);
|
2015-07-15 09:50:17 -07:00
|
|
|
|
|
|
|
return xml_text;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-07-16 16:58:39 -07:00
|
|
|
cJSON *conference_cdr_json_render(conference_obj_t *conference, cJSON *req)
|
2015-07-15 09:50:17 -07:00
|
|
|
{
|
|
|
|
char tmp[30];
|
|
|
|
const char *domain; const char *name;
|
|
|
|
char *dup_domain = NULL;
|
|
|
|
char *uri;
|
2015-07-16 16:58:39 -07:00
|
|
|
conference_cdr_node_t *np;
|
2015-07-15 09:50:17 -07:00
|
|
|
char *tmpp = tmp;
|
|
|
|
cJSON *json = cJSON_CreateObject(), *jusers = NULL, *jold_users = NULL, *juser = NULL, *jvars = NULL;
|
|
|
|
|
|
|
|
switch_assert(json);
|
2015-07-16 17:42:21 -07:00
|
|
|
|
2015-07-15 09:50:17 -07:00
|
|
|
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";
|
|
|
|
}
|
|
|
|
}
|
2015-07-16 17:42:21 -07:00
|
|
|
|
2015-07-15 09:50:17 -07:00
|
|
|
|
|
|
|
uri = switch_mprintf("%s@%s", name, domain);
|
2015-07-16 17:42:21 -07:00
|
|
|
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");
|
2015-07-15 09:50:17 -07:00
|
|
|
switch_snprintf(tmp, sizeof(tmp), "%u", conference->count);
|
2015-07-16 17:42:21 -07:00
|
|
|
json_add_child_string(json, "userCount", tmp);
|
|
|
|
|
2015-07-15 09:50:17 -07:00
|
|
|
jusers = json_add_child_array(json, "users");
|
|
|
|
jold_users = json_add_child_array(json, "oldUsers");
|
2015-07-16 17:42:21 -07:00
|
|
|
|
2015-07-15 09:50:17 -07:00
|
|
|
switch_mutex_lock(conference->member_mutex);
|
2015-07-16 17:42:21 -07:00
|
|
|
|
2015-07-15 09:50:17 -07:00
|
|
|
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;
|
2015-07-16 17:42:21 -07:00
|
|
|
|
2015-07-15 09:50:17 -07:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2015-07-16 17:42:21 -07:00
|
|
|
|
2015-07-15 09:50:17 -07:00
|
|
|
if (np->cp) {
|
|
|
|
|
|
|
|
if (!user_uri) {
|
|
|
|
user_uri = switch_mprintf("%s@%s", np->cp->caller_id_number, domain);
|
|
|
|
}
|
2015-07-16 17:42:21 -07:00
|
|
|
|
2015-07-15 09:50:17 -07:00
|
|
|
json_add_child_string(juser, "entity", user_uri);
|
|
|
|
json_add_child_string(juser, "displayText", np->cp->caller_id_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
//if (np->record_path) {
|
2015-07-16 17:42:21 -07:00
|
|
|
//json_add_child_string(juser, "recordingPATH", np->record_path);
|
2015-07-15 09:50:17 -07:00
|
|
|
//}
|
|
|
|
|
|
|
|
json_add_child_string(juser, "status", np->leave_time ? "disconnected" : "connected");
|
|
|
|
|
|
|
|
switch_time_exp_lt(&tm, (switch_time_t) conference->start_time * 1000000);
|
2015-07-16 17:42:21 -07:00
|
|
|
switch_strftime_nocheck(tmp, &retsize, sizeof(tmp), fmt, &tm);
|
2015-07-15 09:50:17 -07:00
|
|
|
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);
|
|
|
|
|
2015-07-16 16:58:39 -07:00
|
|
|
if ((prefix = switch_event_get_header(var_event, "json_conference_var_prefix"))) {
|
2015-07-15 09:50:17 -07:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2015-07-16 17:42:21 -07:00
|
|
|
|
2015-07-15 09:50:17 -07:00
|
|
|
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);
|
|
|
|
}
|
2015-07-16 17:42:21 -07:00
|
|
|
|
2015-07-16 16:58:39 -07:00
|
|
|
json_add_child_string(juser, "rtpAudioDirection", conference_cdr_audio_flow(np->member));
|
2015-07-16 17:42:21 -07:00
|
|
|
|
|
|
|
|
2015-07-15 09:50:17 -07:00
|
|
|
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);
|
|
|
|
}
|
2015-07-16 17:42:21 -07:00
|
|
|
|
2015-07-15 09:50:17 -07:00
|
|
|
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);
|
2015-07-16 17:42:21 -07:00
|
|
|
|
2015-07-15 09:50:17 -07:00
|
|
|
switch_safe_free(user_uri);
|
|
|
|
}
|
|
|
|
|
|
|
|
switch_mutex_unlock(conference->member_mutex);
|
|
|
|
|
|
|
|
switch_safe_free(dup_domain);
|
2015-07-16 17:42:21 -07:00
|
|
|
switch_safe_free(uri);
|
2015-07-15 09:50:17 -07:00
|
|
|
|
|
|
|
return json;
|
|
|
|
}
|
|
|
|
|
2015-07-16 16:58:39 -07:00
|
|
|
void conference_cdr_del(conference_member_t *member)
|
2015-07-15 09:50:17 -07:00
|
|
|
{
|
2015-08-27 15:19:57 -04:00
|
|
|
if (!member->cdr_node) return;
|
|
|
|
|
2015-07-15 09:50:17 -07:00
|
|
|
if (member->channel) {
|
|
|
|
switch_channel_get_variables(member->channel, &member->cdr_node->var_event);
|
|
|
|
}
|
|
|
|
if (member->cdr_node) {
|
|
|
|
member->cdr_node->leave_time = switch_epoch_time_now(NULL);
|
|
|
|
memcpy(member->cdr_node->mflags, member->flags, sizeof(member->flags));
|
|
|
|
member->cdr_node->member = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-07-16 16:58:39 -07:00
|
|
|
void conference_cdr_add(conference_member_t *member)
|
2015-07-15 09:50:17 -07:00
|
|
|
{
|
2015-07-16 16:58:39 -07:00
|
|
|
conference_cdr_node_t *np;
|
2015-07-15 09:50:17 -07:00
|
|
|
switch_caller_profile_t *cp;
|
|
|
|
switch_channel_t *channel;
|
|
|
|
|
2015-08-27 15:19:57 -04:00
|
|
|
if (zstr(member->conference->log_dir) && (member->conference->cdr_event_mode == CDRE_NONE)) return;
|
|
|
|
|
2015-07-15 09:50:17 -07:00
|
|
|
np = switch_core_alloc(member->conference->pool, sizeof(*np));
|
|
|
|
|
|
|
|
np->next = member->conference->cdr_nodes;
|
|
|
|
member->conference->cdr_nodes = member->cdr_node = np;
|
|
|
|
member->cdr_node->join_time = switch_epoch_time_now(NULL);
|
|
|
|
member->cdr_node->member = member;
|
|
|
|
|
|
|
|
if (!member->session) {
|
|
|
|
member->cdr_node->record_path = switch_core_strdup(member->conference->pool, member->rec_path);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
channel = switch_core_session_get_channel(member->session);
|
|
|
|
|
|
|
|
if (!(cp = switch_channel_get_caller_profile(channel))) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
member->cdr_node->cp = switch_caller_profile_dup(member->conference->pool, cp);
|
|
|
|
|
|
|
|
member->cdr_node->id = member->id;
|
|
|
|
|
2015-07-16 17:42:21 -07:00
|
|
|
|
|
|
|
|
2015-07-15 09:50:17 -07:00
|
|
|
}
|
|
|
|
|
2015-07-16 16:58:39 -07:00
|
|
|
void conference_cdr_rejected(conference_obj_t *conference, switch_channel_t *channel, cdr_reject_reason_t reason)
|
2015-07-15 09:50:17 -07:00
|
|
|
{
|
2015-07-16 16:58:39 -07:00
|
|
|
conference_cdr_reject_t *rp;
|
2015-07-15 09:50:17 -07:00
|
|
|
switch_caller_profile_t *cp;
|
|
|
|
|
2015-08-27 15:19:57 -04:00
|
|
|
if (zstr(conference->log_dir) && (conference->cdr_event_mode == CDRE_NONE)) return;
|
|
|
|
|
2015-07-15 09:50:17 -07:00
|
|
|
rp = switch_core_alloc(conference->pool, sizeof(*rp));
|
|
|
|
|
|
|
|
rp->next = conference->cdr_rejected;
|
|
|
|
conference->cdr_rejected = rp;
|
|
|
|
rp->reason = reason;
|
|
|
|
rp->reject_time = switch_epoch_time_now(NULL);
|
|
|
|
|
|
|
|
if (!(cp = switch_channel_get_caller_profile(channel))) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
rp->cp = switch_caller_profile_dup(conference->pool, cp);
|
|
|
|
}
|
|
|
|
|
2015-07-16 16:58:39 -07:00
|
|
|
void conference_cdr_render(conference_obj_t *conference)
|
2015-07-15 09:50:17 -07:00
|
|
|
{
|
|
|
|
switch_xml_t cdr, x_ptr, x_member, x_members, x_conference, x_cp, x_flags, x_tag, x_rejected, x_attempt;
|
2015-07-16 16:58:39 -07:00
|
|
|
conference_cdr_node_t *np;
|
|
|
|
conference_cdr_reject_t *rp;
|
|
|
|
int cdr_off = 0, conference_off = 0;
|
2015-07-15 09:50:17 -07:00
|
|
|
char str[512];
|
|
|
|
char *path = NULL, *xml_text;
|
|
|
|
int fd;
|
|
|
|
|
|
|
|
if (zstr(conference->log_dir) && (conference->cdr_event_mode == CDRE_NONE)) return;
|
|
|
|
|
|
|
|
if (!conference->cdr_nodes && !conference->cdr_rejected) return;
|
|
|
|
|
|
|
|
if (!(cdr = switch_xml_new("cdr"))) {
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(x_conference = switch_xml_add_child_d(cdr, "conference", cdr_off++))) {
|
|
|
|
abort();
|
|
|
|
}
|
2015-07-16 17:42:21 -07:00
|
|
|
|
2015-07-16 16:58:39 -07:00
|
|
|
if (!(x_ptr = switch_xml_add_child_d(x_conference, "name", conference_off++))) {
|
2015-07-15 09:50:17 -07:00
|
|
|
abort();
|
|
|
|
}
|
|
|
|
switch_xml_set_txt_d(x_ptr, conference->name);
|
2015-07-16 17:42:21 -07:00
|
|
|
|
2015-07-16 16:58:39 -07:00
|
|
|
if (!(x_ptr = switch_xml_add_child_d(x_conference, "hostname", conference_off++))) {
|
2015-07-15 09:50:17 -07:00
|
|
|
abort();
|
|
|
|
}
|
|
|
|
switch_xml_set_txt_d(x_ptr, switch_core_get_hostname());
|
2015-07-16 17:42:21 -07:00
|
|
|
|
2015-07-16 16:58:39 -07:00
|
|
|
if (!(x_ptr = switch_xml_add_child_d(x_conference, "rate", conference_off++))) {
|
2015-07-15 09:50:17 -07:00
|
|
|
abort();
|
|
|
|
}
|
|
|
|
switch_snprintf(str, sizeof(str), "%d", conference->rate);
|
|
|
|
switch_xml_set_txt_d(x_ptr, str);
|
2015-07-16 17:42:21 -07:00
|
|
|
|
2015-07-16 16:58:39 -07:00
|
|
|
if (!(x_ptr = switch_xml_add_child_d(x_conference, "interval", conference_off++))) {
|
2015-07-15 09:50:17 -07:00
|
|
|
abort();
|
|
|
|
}
|
|
|
|
switch_snprintf(str, sizeof(str), "%d", conference->interval);
|
|
|
|
switch_xml_set_txt_d(x_ptr, str);
|
2015-07-16 17:42:21 -07:00
|
|
|
|
|
|
|
|
2015-07-16 16:58:39 -07:00
|
|
|
if (!(x_ptr = switch_xml_add_child_d(x_conference, "start_time", conference_off++))) {
|
2015-07-15 09:50:17 -07:00
|
|
|
abort();
|
|
|
|
}
|
|
|
|
switch_xml_set_attr_d(x_ptr, "type", "UNIX-epoch");
|
|
|
|
switch_snprintf(str, sizeof(str), "%ld", (long)conference->start_time);
|
|
|
|
switch_xml_set_txt_d(x_ptr, str);
|
2015-07-16 17:42:21 -07:00
|
|
|
|
|
|
|
|
2015-07-16 16:58:39 -07:00
|
|
|
if (!(x_ptr = switch_xml_add_child_d(x_conference, "end_time", conference_off++))) {
|
2015-07-15 09:50:17 -07:00
|
|
|
abort();
|
|
|
|
}
|
2015-07-16 16:58:39 -07:00
|
|
|
switch_xml_set_attr_d(x_ptr, "endconference_forced", conference_utils_test_flag(conference, CFLAG_ENDCONF_FORCED) ? "true" : "false");
|
2015-07-15 09:50:17 -07:00
|
|
|
switch_xml_set_attr_d(x_ptr, "type", "UNIX-epoch");
|
|
|
|
switch_snprintf(str, sizeof(str), "%ld", (long)conference->end_time);
|
|
|
|
switch_xml_set_txt_d(x_ptr, str);
|
|
|
|
|
|
|
|
|
|
|
|
|
2015-07-16 16:58:39 -07:00
|
|
|
if (!(x_members = switch_xml_add_child_d(x_conference, "members", conference_off++))) {
|
2015-07-15 09:50:17 -07:00
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
for (np = conference->cdr_nodes; np; np = np->next) {
|
|
|
|
int member_off = 0;
|
|
|
|
int flag_off = 0;
|
|
|
|
|
|
|
|
|
2015-07-16 16:58:39 -07:00
|
|
|
if (!(x_member = switch_xml_add_child_d(x_members, "member", conference_off++))) {
|
2015-07-15 09:50:17 -07:00
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
switch_xml_set_attr_d(x_member, "type", np->cp ? "caller" : "recording_node");
|
2015-07-16 17:42:21 -07:00
|
|
|
|
2015-07-15 09:50:17 -07:00
|
|
|
if (!(x_ptr = switch_xml_add_child_d(x_member, "join_time", member_off++))) {
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
switch_xml_set_attr_d(x_ptr, "type", "UNIX-epoch");
|
|
|
|
switch_snprintf(str, sizeof(str), "%ld", (long) np->join_time);
|
|
|
|
switch_xml_set_txt_d(x_ptr, str);
|
|
|
|
|
|
|
|
|
|
|
|
if (!(x_ptr = switch_xml_add_child_d(x_member, "leave_time", member_off++))) {
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
switch_xml_set_attr_d(x_ptr, "type", "UNIX-epoch");
|
|
|
|
switch_snprintf(str, sizeof(str), "%ld", (long) np->leave_time);
|
|
|
|
switch_xml_set_txt_d(x_ptr, str);
|
|
|
|
|
|
|
|
if (np->cp) {
|
|
|
|
x_flags = switch_xml_add_child_d(x_member, "flags", member_off++);
|
|
|
|
switch_assert(x_flags);
|
|
|
|
|
|
|
|
x_tag = switch_xml_add_child_d(x_flags, "is_moderator", flag_off++);
|
2015-07-16 16:58:39 -07:00
|
|
|
switch_xml_set_txt_d(x_tag, conference_cdr_test_mflag(np, MFLAG_MOD) ? "true" : "false");
|
2015-07-15 09:50:17 -07:00
|
|
|
|
|
|
|
x_tag = switch_xml_add_child_d(x_flags, "end_conference", flag_off++);
|
2015-07-16 16:58:39 -07:00
|
|
|
switch_xml_set_txt_d(x_tag, conference_cdr_test_mflag(np, MFLAG_ENDCONF) ? "true" : "false");
|
2015-07-15 09:50:17 -07:00
|
|
|
|
|
|
|
x_tag = switch_xml_add_child_d(x_flags, "was_kicked", flag_off++);
|
2015-07-16 16:58:39 -07:00
|
|
|
switch_xml_set_txt_d(x_tag, conference_cdr_test_mflag(np, MFLAG_KICKED) ? "true" : "false");
|
2015-07-15 09:50:17 -07:00
|
|
|
|
|
|
|
x_tag = switch_xml_add_child_d(x_flags, "is_ghost", flag_off++);
|
2015-07-16 16:58:39 -07:00
|
|
|
switch_xml_set_txt_d(x_tag, conference_cdr_test_mflag(np, MFLAG_GHOST) ? "true" : "false");
|
2015-07-15 09:50:17 -07:00
|
|
|
|
|
|
|
if (!(x_cp = switch_xml_add_child_d(x_member, "caller_profile", member_off++))) {
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
switch_ivr_set_xml_profile_data(x_cp, np->cp, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!zstr(np->record_path)) {
|
|
|
|
if (!(x_ptr = switch_xml_add_child_d(x_member, "record_path", member_off++))) {
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
switch_xml_set_txt_d(x_ptr, np->record_path);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2015-07-16 16:58:39 -07:00
|
|
|
if (!(x_rejected = switch_xml_add_child_d(x_conference, "rejected", conference_off++))) {
|
2015-07-15 09:50:17 -07:00
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
for (rp = conference->cdr_rejected; rp; rp = rp->next) {
|
|
|
|
int attempt_off = 0;
|
|
|
|
int tag_off = 0;
|
|
|
|
|
|
|
|
if (!(x_attempt = switch_xml_add_child_d(x_rejected, "attempt", attempt_off++))) {
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(x_ptr = switch_xml_add_child_d(x_attempt, "reason", tag_off++))) {
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
if (rp->reason == CDRR_LOCKED) {
|
|
|
|
switch_xml_set_txt_d(x_ptr, "conference_locked");
|
|
|
|
} else if (rp->reason == CDRR_MAXMEMBERS) {
|
|
|
|
switch_xml_set_txt_d(x_ptr, "max_members_reached");
|
2015-07-16 17:42:21 -07:00
|
|
|
} else if (rp->reason == CDRR_PIN) {
|
2015-07-15 09:50:17 -07:00
|
|
|
switch_xml_set_txt_d(x_ptr, "invalid_pin");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(x_ptr = switch_xml_add_child_d(x_attempt, "reject_time", tag_off++))) {
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
switch_xml_set_attr_d(x_ptr, "type", "UNIX-epoch");
|
|
|
|
switch_snprintf(str, sizeof(str), "%ld", (long) rp->reject_time);
|
|
|
|
switch_xml_set_txt_d(x_ptr, str);
|
|
|
|
|
|
|
|
if (rp->cp) {
|
|
|
|
if (!(x_cp = switch_xml_add_child_d(x_attempt, "caller_profile", attempt_off++))) {
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
switch_ivr_set_xml_profile_data(x_cp, rp->cp, 0);
|
|
|
|
}
|
|
|
|
}
|
2015-07-16 17:42:21 -07:00
|
|
|
|
2015-07-15 09:50:17 -07:00
|
|
|
xml_text = switch_xml_toxml(cdr, SWITCH_TRUE);
|
|
|
|
|
2015-07-16 17:42:21 -07:00
|
|
|
|
2015-07-15 09:50:17 -07:00
|
|
|
if (!zstr(conference->log_dir)) {
|
|
|
|
path = switch_mprintf("%s%s%s.cdr.xml", conference->log_dir, SWITCH_PATH_SEPARATOR, conference->uuid_str);
|
2015-07-16 17:42:21 -07:00
|
|
|
|
2015-07-15 09:50:17 -07:00
|
|
|
|
|
|
|
|
|
|
|
#ifdef _MSC_VER
|
|
|
|
if ((fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)) > -1) {
|
|
|
|
#else
|
2015-07-16 17:42:21 -07:00
|
|
|
if ((fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) > -1) {
|
2015-07-15 09:50:17 -07:00
|
|
|
#endif
|
2015-07-16 17:42:21 -07:00
|
|
|
int wrote;
|
|
|
|
wrote = write(fd, xml_text, (unsigned) strlen(xml_text));
|
|
|
|
wrote++;
|
|
|
|
close(fd);
|
|
|
|
fd = -1;
|
2015-07-15 09:50:17 -07:00
|
|
|
} else {
|
2015-07-16 17:42:21 -07:00
|
|
|
char ebuf[512] = { 0 };
|
|
|
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error writing [%s][%s]\n",
|
|
|
|
path, switch_strerror_r(errno, ebuf, sizeof(ebuf)));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (conference->cdr_event_mode != CDRE_NONE) {
|
|
|
|
switch_event_t *event;
|
|
|
|
|
|
|
|
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_CDR) == SWITCH_STATUS_SUCCESS)
|
|
|
|
// if (switch_event_create(&event, SWITCH_EVENT_CDR) == SWITCH_STATUS_SUCCESS)
|
|
|
|
{
|
|
|
|
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CDR-Source", CONF_EVENT_CDR);
|
|
|
|
if (conference->cdr_event_mode == CDRE_AS_CONTENT) {
|
|
|
|
switch_event_set_body(event, xml_text);
|
|
|
|
} else {
|
|
|
|
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CDR-Path", path);
|
|
|
|
}
|
|
|
|
switch_event_fire(&event);
|
|
|
|
} else {
|
|
|
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not create CDR event");
|
|
|
|
}
|
2015-07-15 09:50:17 -07:00
|
|
|
}
|
|
|
|
}
|
2015-07-16 17:42:21 -07:00
|
|
|
|
|
|
|
switch_safe_free(path);
|
|
|
|
switch_safe_free(xml_text);
|
|
|
|
switch_xml_free(cdr);
|
2015-07-15 09:50:17 -07:00
|
|
|
}
|
|
|
|
|
2015-07-16 17:42:21 -07:00
|
|
|
/* For Emacs:
|
|
|
|
* Local Variables:
|
|
|
|
* mode:c
|
|
|
|
* indent-tabs-mode:t
|
|
|
|
* tab-width:4
|
|
|
|
* c-basic-offset:4
|
|
|
|
* End:
|
|
|
|
* For VIM:
|
|
|
|
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
|
|
|
|
*/
|