add some device-state mechinism to FS to allow tracking of device-specific states where they may have more than one call from the same device
This commit is contained in:
parent
b4ed2f55bf
commit
4240526ce3
|
@ -143,6 +143,8 @@ static const char *EVENT_NAMES[] = {
|
|||
"CONFERENCE_DATA",
|
||||
"CALL_SETUP_REQ",
|
||||
"CALL_SETUP_RESULT",
|
||||
"CALL_DETAIL",
|
||||
"DEVICE_STATE",
|
||||
"ALL"
|
||||
};
|
||||
|
||||
|
|
|
@ -132,6 +132,8 @@ typedef enum {
|
|||
ESL_EVENT_CONFERENCE_DATA,
|
||||
ESL_EVENT_CALL_SETUP_REQ,
|
||||
ESL_EVENT_CALL_SETUP_RESULT,
|
||||
ESL_EVENT_CALL_DETAIL,
|
||||
ESL_EVENT_DEVICE_STATE,
|
||||
ESL_EVENT_ALL
|
||||
} esl_event_types_t;
|
||||
|
||||
|
|
|
@ -659,7 +659,16 @@ SWITCH_DECLARE(void) switch_channel_state_thread_lock(switch_channel_t *channel)
|
|||
SWITCH_DECLARE(void) switch_channel_state_thread_unlock(switch_channel_t *channel);
|
||||
SWITCH_DECLARE(switch_status_t) switch_channel_state_thread_trylock(switch_channel_t *channel);
|
||||
SWITCH_DECLARE(void) switch_channel_handle_cause(switch_channel_t *channel, switch_call_cause_t cause);
|
||||
|
||||
SWITCH_DECLARE(void) switch_channel_global_init(switch_memory_pool_t *pool);
|
||||
SWITCH_DECLARE(void) switch_channel_global_uninit(void);
|
||||
SWITCH_DECLARE(const char *) switch_channel_set_device_id(switch_channel_t *channel, const char *device_id);
|
||||
SWITCH_DECLARE(void) switch_channel_clear_device_record(switch_channel_t *channel);
|
||||
SWITCH_DECLARE(switch_device_record_t *) switch_channel_get_device_record(switch_channel_t *channel);
|
||||
SWITCH_DECLARE(void) switch_channel_release_device_record(switch_device_record_t **dcdrp);
|
||||
SWITCH_DECLARE(switch_status_t) switch_channel_bind_device_state_handler(switch_device_state_function_t function, void *user_data);
|
||||
SWITCH_DECLARE(switch_status_t) switch_channel_unbind_device_state_handler(switch_device_state_function_t function);
|
||||
SWITCH_DECLARE(const char *) switch_channel_device_state2str(switch_device_state_t device_state);
|
||||
|
||||
SWITCH_END_EXTERN_C
|
||||
#endif
|
||||
/* For Emacs:
|
||||
|
|
|
@ -61,6 +61,11 @@ struct switch_app_log {
|
|||
struct switch_app_log *next;
|
||||
};
|
||||
|
||||
typedef struct switch_thread_data_s {
|
||||
switch_thread_start_t func;
|
||||
void *obj;
|
||||
int alloc;
|
||||
} switch_thread_data_t;
|
||||
|
||||
typedef struct switch_hold_record_s {
|
||||
switch_time_t on;
|
||||
|
@ -69,12 +74,42 @@ typedef struct switch_hold_record_s {
|
|||
struct switch_hold_record_s *next;
|
||||
} switch_hold_record_t;
|
||||
|
||||
typedef struct device_uuid_node_s {
|
||||
char *uuid;
|
||||
switch_xml_t xml_cdr;
|
||||
switch_event_t *event;
|
||||
switch_channel_callstate_t callstate;
|
||||
switch_hold_record_t *hold_record;
|
||||
switch_caller_profile_t *hup_profile;
|
||||
struct switch_device_record_s *parent;
|
||||
struct device_uuid_node_s *next;
|
||||
} switch_device_node_t;
|
||||
|
||||
typedef struct switch_thread_data_s {
|
||||
switch_thread_start_t func;
|
||||
void *obj;
|
||||
int alloc;
|
||||
} switch_thread_data_t;
|
||||
typedef struct switch_device_stats_s {
|
||||
uint32_t total;
|
||||
uint32_t offhook;
|
||||
uint32_t active;
|
||||
uint32_t held;
|
||||
uint32_t hup;
|
||||
} switch_device_stats_t;
|
||||
|
||||
|
||||
typedef struct switch_device_record_s {
|
||||
char *device_id;
|
||||
char *uuid;
|
||||
int refs;
|
||||
switch_device_stats_t stats;
|
||||
switch_device_state_t state;
|
||||
switch_device_state_t last_state;
|
||||
switch_time_t active_start;
|
||||
switch_time_t active_stop;
|
||||
struct device_uuid_node_s *uuid_list;
|
||||
struct device_uuid_node_s *uuid_tail;
|
||||
switch_mutex_t *mutex;
|
||||
switch_memory_pool_t *pool;
|
||||
} switch_device_record_t;
|
||||
|
||||
typedef void(*switch_device_state_function_t)(switch_core_session_t *session, switch_channel_callstate_t callstate, switch_device_record_t *drec);
|
||||
|
||||
|
||||
#define DTLS_SRTP_FNAME "dtls-srtp"
|
||||
|
|
|
@ -1111,9 +1111,19 @@ typedef enum {
|
|||
CCS_EARLY,
|
||||
CCS_ACTIVE,
|
||||
CCS_HELD,
|
||||
CCS_HANGUP
|
||||
CCS_HANGUP,
|
||||
CCS_UNHOLD
|
||||
} switch_channel_callstate_t;
|
||||
|
||||
typedef enum {
|
||||
SDS_DOWN,
|
||||
SDS_ACTIVE,
|
||||
SDS_ACTIVE_MULTI,
|
||||
SDS_HELD,
|
||||
SDS_HANGUP
|
||||
} switch_device_state_t;
|
||||
|
||||
|
||||
/*!
|
||||
\enum switch_channel_state_t
|
||||
\brief Channel States (these are the defaults, CS_SOFT_EXECUTE, CS_EXCHANGE_MEDIA, and CS_CONSUME_MEDIA are often overridden by specific apps)
|
||||
|
@ -1279,6 +1289,8 @@ typedef enum {
|
|||
CF_ZRTP_PASSTHRU,
|
||||
CF_ZRTP_HASH,
|
||||
CF_CHANNEL_SWAP,
|
||||
CF_DEVICE_LEG,
|
||||
CF_FINAL_DEVICE_LEG,
|
||||
CF_PICKUP,
|
||||
CF_CONFIRM_BLIND_TRANSFER,
|
||||
CF_NO_PRESENCE,
|
||||
|
@ -1751,6 +1763,8 @@ typedef enum {
|
|||
SWITCH_EVENT_CONFERENCE_DATA,
|
||||
SWITCH_EVENT_CALL_SETUP_REQ,
|
||||
SWITCH_EVENT_CALL_SETUP_RESULT,
|
||||
SWITCH_EVENT_CALL_DETAIL,
|
||||
SWITCH_EVENT_DEVICE_STATE,
|
||||
SWITCH_EVENT_ALL
|
||||
} switch_event_types_t;
|
||||
|
||||
|
|
|
@ -214,6 +214,28 @@ SWITCH_STANDARD_API(skel_function)
|
|||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static void mycb(switch_core_session_t *session, switch_channel_callstate_t callstate, switch_device_record_t *drec)
|
||||
{
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_CRIT,
|
||||
"%s device: %s\nState: %s Dev State: %s/%s Total:%u Offhook:%u Active:%u Held:%u Hungup:%u Dur: %u %s\n",
|
||||
switch_channel_get_name(channel),
|
||||
drec->device_id,
|
||||
switch_channel_callstate2str(callstate),
|
||||
switch_channel_device_state2str(drec->last_state),
|
||||
switch_channel_device_state2str(drec->state),
|
||||
drec->stats.total,
|
||||
drec->stats.offhook,
|
||||
drec->stats.active,
|
||||
drec->stats.held,
|
||||
drec->stats.hup,
|
||||
drec->active_stop ? (uint32_t)(drec->active_stop - drec->active_start) / 1000 : 0,
|
||||
switch_channel_test_flag(channel, CF_FINAL_DEVICE_LEG) ? "FINAL LEG" : "");
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Macro expands to: switch_status_t mod_skel_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool) */
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_skel_load)
|
||||
{
|
||||
|
@ -227,6 +249,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_skel_load)
|
|||
|
||||
SWITCH_ADD_API(api_interface, "skel", "Skel API", skel_function, "syntax");
|
||||
|
||||
switch_channel_bind_device_state_handler(mycb, NULL);
|
||||
|
||||
/* indicate that the module should continue to be loaded */
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
@ -237,6 +261,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_skel_load)
|
|||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_skel_shutdown)
|
||||
{
|
||||
/* Cleanup dynamically allocated config settings */
|
||||
switch_channel_unbind_device_state_handler(mycb);
|
||||
switch_xml_config_cleanup(instructions);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -5091,7 +5091,7 @@ SWITCH_STANDARD_APP(sofia_sla_function)
|
|||
{
|
||||
private_object_t *tech_pvt;
|
||||
switch_core_session_t *bargee_session;
|
||||
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
if (zstr(data)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Usage: <uuid>\n");
|
||||
return;
|
||||
|
@ -5101,8 +5101,7 @@ SWITCH_STANDARD_APP(sofia_sla_function)
|
|||
if (bargee_session == session) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "BARGE: %s (cannot barge on myself)\n", (char *) data);
|
||||
} else {
|
||||
switch_channel_t *channel;
|
||||
|
||||
|
||||
if (switch_core_session_check_interface(bargee_session, sofia_endpoint_interface)) {
|
||||
tech_pvt = switch_core_session_get_private(bargee_session);
|
||||
switch_channel_clear_flag(tech_pvt->channel, CF_SLA_BARGING);
|
||||
|
@ -5115,13 +5114,13 @@ SWITCH_STANDARD_APP(sofia_sla_function)
|
|||
switch_channel_set_flag(tech_pvt->channel, CF_SLA_BARGING);
|
||||
}
|
||||
|
||||
channel = switch_core_session_get_channel(session);
|
||||
switch_channel_set_variable(channel, "sip_barging_uuid", (char *)data);
|
||||
|
||||
}
|
||||
|
||||
switch_core_session_rwunlock(bargee_session);
|
||||
}
|
||||
|
||||
switch_channel_execute_on(channel, "execute_on_sip_barge");
|
||||
|
||||
switch_ivr_eavesdrop_session(session, data, NULL, ED_MUX_READ | ED_MUX_WRITE | ED_COPY_DISPLAY);
|
||||
}
|
||||
|
|
|
@ -40,6 +40,19 @@ struct switch_cause_table {
|
|||
switch_call_cause_t cause;
|
||||
};
|
||||
|
||||
typedef struct switch_device_state_binding_s {
|
||||
switch_device_state_function_t function;
|
||||
void *user_data;
|
||||
struct switch_device_state_binding_s *next;
|
||||
} switch_device_state_binding_t;
|
||||
|
||||
static struct {
|
||||
switch_memory_pool_t *pool;
|
||||
switch_hash_t *device_hash;
|
||||
switch_mutex_t *device_mutex;
|
||||
switch_device_state_binding_t *device_bindings;
|
||||
} globals;
|
||||
|
||||
static struct switch_cause_table CAUSE_CHART[] = {
|
||||
{"NONE", SWITCH_CAUSE_NONE},
|
||||
{"UNALLOCATED_NUMBER", SWITCH_CAUSE_UNALLOCATED_NUMBER},
|
||||
|
@ -128,7 +141,7 @@ struct switch_channel {
|
|||
switch_call_direction_t direction;
|
||||
switch_queue_t *dtmf_queue;
|
||||
switch_queue_t *dtmf_log_queue;
|
||||
switch_mutex_t *dtmf_mutex;
|
||||
switch_mutex_t*dtmf_mutex;
|
||||
switch_mutex_t *flag_mutex;
|
||||
switch_mutex_t *state_mutex;
|
||||
switch_mutex_t *thread_mutex;
|
||||
|
@ -159,8 +172,13 @@ struct switch_channel {
|
|||
switch_event_t *api_list;
|
||||
switch_event_t *var_list;
|
||||
switch_hold_record_t *hold_record;
|
||||
switch_device_node_t *device_node;
|
||||
char *device_id;
|
||||
};
|
||||
|
||||
static void process_device_hup(switch_channel_t *channel);
|
||||
static void switch_channel_check_device_state(switch_channel_t *channel, switch_channel_callstate_t callstate);
|
||||
|
||||
SWITCH_DECLARE(switch_hold_record_t *) switch_channel_get_hold_record(switch_channel_t *channel)
|
||||
{
|
||||
return channel->hold_record;
|
||||
|
@ -223,6 +241,20 @@ static struct switch_callstate_table CALLSTATE_CHART[] = {
|
|||
{"ACTIVE", CCS_ACTIVE},
|
||||
{"HELD", CCS_HELD},
|
||||
{"HANGUP", CCS_HANGUP},
|
||||
{"UNHOLD", CCS_UNHOLD},
|
||||
{NULL, 0}
|
||||
};
|
||||
|
||||
struct switch_device_state_table {
|
||||
const char *name;
|
||||
switch_device_state_t device_state;
|
||||
};
|
||||
static struct switch_device_state_table DEVICE_STATE_CHART[] = {
|
||||
{"DOWN", SDS_DOWN},
|
||||
{"ACTIVE", SDS_ACTIVE},
|
||||
{"ACTIVE_MULTI", SDS_ACTIVE_MULTI},
|
||||
{"HELD", SDS_HELD},
|
||||
{"HANGUP", SDS_HANGUP},
|
||||
{NULL, 0}
|
||||
};
|
||||
|
||||
|
@ -236,7 +268,9 @@ SWITCH_DECLARE(void) switch_channel_perform_set_callstate(switch_channel_t *chan
|
|||
if (o_callstate == callstate) return;
|
||||
|
||||
channel->callstate = callstate;
|
||||
|
||||
if (channel->device_node) {
|
||||
channel->device_node->callstate = callstate;
|
||||
}
|
||||
switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, switch_channel_get_uuid(channel), SWITCH_LOG_DEBUG,
|
||||
"(%s) Callstate Change %s -> %s\n", channel->name,
|
||||
switch_channel_callstate2str(o_callstate), switch_channel_callstate2str(callstate));
|
||||
|
@ -270,6 +304,21 @@ SWITCH_DECLARE(const char *) switch_channel_callstate2str(switch_channel_callsta
|
|||
return str;
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(const char *) switch_channel_device_state2str(switch_device_state_t device_state)
|
||||
{
|
||||
uint8_t x;
|
||||
const char *str = "UNKNOWN";
|
||||
|
||||
for (x = 0; x < (sizeof(DEVICE_STATE_CHART) / sizeof(struct switch_cause_table)) - 1; x++) {
|
||||
if (DEVICE_STATE_CHART[x].device_state == device_state) {
|
||||
str = DEVICE_STATE_CHART[x].name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
SWITCH_DECLARE(switch_channel_callstate_t) switch_channel_str2callstate(const char *str)
|
||||
{
|
||||
|
@ -994,6 +1043,18 @@ SWITCH_DECLARE(switch_status_t) switch_channel_set_profile_var(switch_channel_t
|
|||
|
||||
switch_mutex_lock(channel->profile_mutex);
|
||||
|
||||
|
||||
if (!strcasecmp(name, "device_id") && !zstr(val)) {
|
||||
const char *device_id;
|
||||
if (!(device_id = switch_channel_set_device_id(channel, val))) {
|
||||
/* one time setting */
|
||||
switch_mutex_unlock(channel->profile_mutex);
|
||||
return status;
|
||||
}
|
||||
|
||||
val = device_id;
|
||||
}
|
||||
|
||||
if (!zstr(val)) {
|
||||
v = switch_core_strdup(channel->caller_profile->pool, val);
|
||||
} else {
|
||||
|
@ -1041,7 +1102,7 @@ SWITCH_DECLARE(switch_status_t) switch_channel_set_profile_var(switch_channel_t
|
|||
} else {
|
||||
profile_node_t *pn, *n = switch_core_alloc(channel->caller_profile->pool, sizeof(*n));
|
||||
int var_found;
|
||||
|
||||
|
||||
n->var = switch_core_strdup(channel->caller_profile->pool, name);
|
||||
n->val = v;
|
||||
|
||||
|
@ -1680,6 +1741,7 @@ SWITCH_DECLARE(void) switch_channel_set_flag_value(switch_channel_t *channel, sw
|
|||
const char *brto = switch_channel_get_partner_uuid(channel);
|
||||
|
||||
switch_channel_set_callstate(channel, CCS_HELD);
|
||||
switch_channel_check_device_state(channel, CCS_HELD);
|
||||
switch_mutex_lock(channel->profile_mutex);
|
||||
channel->caller_profile->times->last_hold = switch_time_now();
|
||||
|
||||
|
@ -1839,6 +1901,7 @@ SWITCH_DECLARE(void) switch_channel_clear_flag(switch_channel_t *channel, switch
|
|||
|
||||
if (ACTIVE) {
|
||||
switch_channel_set_callstate(channel, CCS_ACTIVE);
|
||||
switch_channel_check_device_state(channel, CCS_UNHOLD);
|
||||
switch_mutex_lock(channel->profile_mutex);
|
||||
if (channel->caller_profile->times->last_hold) {
|
||||
channel->caller_profile->times->hold_accum += (switch_time_now() - channel->caller_profile->times->last_hold);
|
||||
|
@ -3034,8 +3097,8 @@ SWITCH_DECLARE(switch_channel_state_t) switch_channel_perform_hangup(switch_chan
|
|||
channel->state = CS_HANGUP;
|
||||
switch_mutex_unlock(channel->state_mutex);
|
||||
|
||||
|
||||
|
||||
process_device_hup(channel);
|
||||
|
||||
channel->hangup_cause = hangup_cause;
|
||||
switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, switch_channel_get_uuid(channel), SWITCH_LOG_NOTICE, "Hangup %s [%s] [%s]\n",
|
||||
channel->name, state_names[last_state], switch_channel_cause2str(channel->hangup_cause));
|
||||
|
@ -4512,6 +4575,394 @@ SWITCH_DECLARE(void) switch_channel_handle_cause(switch_channel_t *channel, swit
|
|||
}
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(void) switch_channel_global_init(switch_memory_pool_t *pool)
|
||||
{
|
||||
memset(&globals, 0, sizeof(globals));
|
||||
globals.pool = pool;
|
||||
|
||||
switch_mutex_init(&globals.device_mutex, SWITCH_MUTEX_NESTED, pool);
|
||||
switch_core_hash_init(&globals.device_hash, globals.pool);
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(void) switch_channel_global_uninit(void)
|
||||
{
|
||||
switch_core_hash_destroy(&globals.device_hash);
|
||||
}
|
||||
|
||||
|
||||
static void fetch_device_stats(switch_device_record_t *drec)
|
||||
{
|
||||
switch_device_node_t *np;
|
||||
|
||||
memset(&drec->stats, 0, sizeof(switch_device_stats_t));
|
||||
|
||||
switch_mutex_lock(drec->mutex);
|
||||
for(np = drec->uuid_list; np; np = np->next) {
|
||||
drec->stats.total++;
|
||||
|
||||
if (!np->hup_profile) {
|
||||
drec->stats.offhook++;
|
||||
|
||||
if (np->callstate == CCS_HELD) {
|
||||
drec->stats.held++;
|
||||
} else {
|
||||
drec->stats.active++;
|
||||
}
|
||||
} else {
|
||||
drec->stats.hup++;
|
||||
}
|
||||
}
|
||||
switch_mutex_unlock(drec->mutex);
|
||||
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(void) switch_channel_clear_device_record(switch_channel_t *channel)
|
||||
{
|
||||
switch_memory_pool_t *pool;
|
||||
int sanity = 100;
|
||||
switch_device_node_t *np;
|
||||
switch_event_t *event;
|
||||
|
||||
if (!channel->device_node || !switch_channel_test_flag(channel, CF_FINAL_DEVICE_LEG)) {
|
||||
return;
|
||||
}
|
||||
|
||||
while(--sanity && channel->device_node->parent->refs) {
|
||||
switch_yield(100000);
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG, "Destroying device cdr %s on device [%s]\n",
|
||||
channel->device_node->parent->uuid,
|
||||
channel->device_node->parent->device_id);
|
||||
|
||||
if (switch_event_create(&event, SWITCH_EVENT_CALL_DETAIL) == SWITCH_STATUS_SUCCESS) {
|
||||
int x = 0;
|
||||
char prefix[80] = "";
|
||||
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "type", "device");
|
||||
|
||||
switch_mutex_lock(channel->device_node->parent->mutex);
|
||||
for(np = channel->device_node->parent->uuid_list; np; np = np->next) {
|
||||
switch_snprintf(prefix, sizeof(prefix), "Call-%d", ++x);
|
||||
switch_caller_profile_event_set_data(np->hup_profile, prefix, event);
|
||||
}
|
||||
switch_mutex_unlock(channel->device_node->parent->mutex);
|
||||
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
|
||||
switch_mutex_lock(channel->device_node->parent->mutex);
|
||||
for(np = channel->device_node->parent->uuid_list; np; np = np->next) {
|
||||
if (np->xml_cdr) {
|
||||
switch_xml_free(np->xml_cdr);
|
||||
}
|
||||
if (np->event) {
|
||||
switch_event_destroy(&np->event);
|
||||
}
|
||||
}
|
||||
switch_mutex_unlock(channel->device_node->parent->mutex);
|
||||
|
||||
pool = channel->device_node->parent->pool;
|
||||
|
||||
switch_mutex_lock(globals.device_mutex);
|
||||
switch_core_destroy_memory_pool(&pool);
|
||||
|
||||
switch_mutex_unlock(globals.device_mutex);
|
||||
|
||||
|
||||
}
|
||||
|
||||
static void process_device_hup(switch_channel_t *channel)
|
||||
{
|
||||
switch_hold_record_t *hr, *newhr, *last = NULL;
|
||||
|
||||
if (!channel->device_node) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch_mutex_lock(globals.device_mutex);
|
||||
channel->device_node->hup_profile = switch_caller_profile_dup(channel->device_node->parent->pool, channel->caller_profile);
|
||||
fetch_device_stats(channel->device_node->parent);
|
||||
|
||||
switch_ivr_generate_xml_cdr(channel->session, &channel->device_node->xml_cdr);
|
||||
if (switch_event_create(&channel->device_node->event, SWITCH_EVENT_CALL_DETAIL) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_channel_event_set_extended_data(channel, channel->device_node->event);
|
||||
}
|
||||
|
||||
for (hr = channel->hold_record; hr; hr = hr->next) {
|
||||
newhr = switch_core_alloc(channel->device_node->parent->pool, sizeof(*newhr));
|
||||
newhr->on = hr->on;
|
||||
newhr->off = hr->off;
|
||||
|
||||
if (hr->uuid) {
|
||||
newhr->uuid = switch_core_strdup(channel->device_node->parent->pool, hr->uuid);
|
||||
}
|
||||
|
||||
if (!channel->device_node->hold_record) {
|
||||
channel->device_node->hold_record = newhr;
|
||||
} else {
|
||||
last->next = newhr;
|
||||
}
|
||||
|
||||
last = newhr;
|
||||
}
|
||||
|
||||
if (!channel->device_node->parent->stats.offhook) { /* this is final call */
|
||||
|
||||
switch_core_hash_delete(globals.device_hash, channel->device_node->parent->device_id);
|
||||
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG, "Processing last call from device [%s]\n",
|
||||
channel->device_node->parent->device_id);
|
||||
switch_channel_set_flag(channel, CF_FINAL_DEVICE_LEG);
|
||||
}
|
||||
|
||||
switch_channel_check_device_state(channel, CCS_HANGUP);
|
||||
|
||||
channel->device_node->parent->refs--;
|
||||
|
||||
switch_mutex_unlock(globals.device_mutex);
|
||||
|
||||
}
|
||||
|
||||
static void switch_channel_check_device_state(switch_channel_t *channel, switch_channel_callstate_t callstate)
|
||||
{
|
||||
switch_device_record_t *drec = NULL;
|
||||
switch_device_state_binding_t *ptr = NULL;
|
||||
switch_event_t *event = NULL;
|
||||
|
||||
if (!channel->device_node) {
|
||||
return;
|
||||
}
|
||||
|
||||
drec = channel->device_node->parent;
|
||||
|
||||
switch_mutex_lock(globals.device_mutex);
|
||||
switch_mutex_lock(drec->mutex);
|
||||
|
||||
fetch_device_stats(drec);
|
||||
|
||||
if (drec->stats.offhook == 0) {
|
||||
drec->state = SDS_HANGUP;
|
||||
} else {
|
||||
if (drec->stats.active == 0 && drec->stats.held > 0) {
|
||||
drec->state = SDS_HELD;
|
||||
} else if (drec->stats.active == 1) {
|
||||
drec->state = SDS_ACTIVE;
|
||||
} else {
|
||||
drec->state = SDS_ACTIVE_MULTI;
|
||||
}
|
||||
}
|
||||
|
||||
switch(drec->state) {
|
||||
case SDS_ACTIVE:
|
||||
case SDS_ACTIVE_MULTI:
|
||||
if (drec->last_state != SDS_HELD && drec->active_start) {
|
||||
drec->active_stop = switch_micro_time_now();
|
||||
} else if (!drec->active_start) {
|
||||
drec->active_start = switch_micro_time_now();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (drec->last_state != SDS_HELD) {
|
||||
drec->active_stop = switch_micro_time_now();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (switch_event_create(&event, SWITCH_EVENT_DEVICE_STATE) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Last-Device-State", switch_channel_device_state2str(drec->last_state));
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Device-State", switch_channel_device_state2str(drec->state));
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Device-Call-State", switch_channel_callstate2str(callstate));
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Device-Total-Legs", "%u", drec->stats.total);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Device-Legs-Offhook", "%u", drec->stats.offhook);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Device-Legs-Active", "%u", drec->stats.active);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Device-Legs-Held", "%u", drec->stats.held);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Device-Legs-Hup", "%u", drec->stats.hup);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Device-Talk-Time-Start-Uepoch", "%"SWITCH_TIME_T_FMT, drec->active_start);
|
||||
if (drec->active_stop) {
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Device-Talk-Time-Stop-Uepoch", "%"SWITCH_TIME_T_FMT, drec->active_stop);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Device-Talk-Time-Milliseconds", "%u", (uint32_t)(drec->active_stop - drec->active_start) / 1000);
|
||||
}
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG1,
|
||||
"%s device: %s\nState: %s Dev State: %s/%s Total:%u Offhook:%u Active:%u Held:%u Hungup:%u Dur: %u %s\n",
|
||||
switch_channel_get_name(channel),
|
||||
drec->device_id,
|
||||
switch_channel_callstate2str(callstate),
|
||||
switch_channel_device_state2str(drec->last_state),
|
||||
switch_channel_device_state2str(drec->state),
|
||||
drec->stats.total,
|
||||
drec->stats.offhook,
|
||||
drec->stats.active,
|
||||
drec->stats.held,
|
||||
drec->stats.hup,
|
||||
drec->active_stop ? (uint32_t)(drec->active_stop - drec->active_start) / 1000 : 0,
|
||||
switch_channel_test_flag(channel, CF_FINAL_DEVICE_LEG) ? "FINAL LEG" : "");
|
||||
|
||||
for (ptr = globals.device_bindings; ptr; ptr = ptr->next) {
|
||||
ptr->function(channel->session, callstate, drec);
|
||||
}
|
||||
|
||||
if (drec->active_stop) {
|
||||
drec->active_start = drec->active_stop = 0;
|
||||
if (drec->state == SDS_ACTIVE || drec->state == SDS_ACTIVE_MULTI) {
|
||||
drec->active_start = switch_micro_time_now();
|
||||
}
|
||||
}
|
||||
|
||||
drec->last_state = drec->state;
|
||||
|
||||
switch_mutex_unlock(drec->mutex);
|
||||
switch_mutex_unlock(globals.device_mutex);
|
||||
|
||||
|
||||
if (event) {
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* assumed to be called under a lock */
|
||||
static void add_uuid(switch_device_record_t *drec, switch_channel_t *channel)
|
||||
{
|
||||
switch_device_node_t *node;
|
||||
|
||||
switch_assert(drec);
|
||||
|
||||
switch_channel_set_flag(channel, CF_DEVICE_LEG);
|
||||
node = switch_core_alloc(drec->pool, sizeof(*node));
|
||||
|
||||
node->uuid = switch_core_strdup(drec->pool, switch_core_session_get_uuid(channel->session));
|
||||
node->parent = drec;
|
||||
channel->device_node = node;
|
||||
|
||||
if (!drec->uuid_list) {
|
||||
drec->uuid_list = node;
|
||||
drec->uuid = node->uuid;
|
||||
} else {
|
||||
drec->uuid_tail->next = node;
|
||||
}
|
||||
|
||||
drec->uuid_tail = node;
|
||||
drec->refs++;
|
||||
}
|
||||
|
||||
static switch_status_t create_device_record(switch_device_record_t **drecp, const char *device_id)
|
||||
{
|
||||
switch_device_record_t *drec;
|
||||
switch_memory_pool_t *pool;
|
||||
|
||||
switch_assert(drecp);
|
||||
|
||||
switch_core_new_memory_pool(&pool);
|
||||
drec = switch_core_alloc(pool, sizeof(*drec));
|
||||
drec->pool = pool;
|
||||
drec->device_id = switch_core_strdup(drec->pool, device_id);
|
||||
switch_mutex_init(&drec->mutex, SWITCH_MUTEX_NESTED, drec->pool);
|
||||
|
||||
*drecp = drec;
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
SWITCH_DECLARE(const char *) switch_channel_set_device_id(switch_channel_t *channel, const char *device_id)
|
||||
{
|
||||
switch_device_record_t *drec;
|
||||
|
||||
if (channel->device_node) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
channel->device_id = switch_core_session_strdup(channel->session, device_id);
|
||||
|
||||
switch_mutex_lock(globals.device_mutex);
|
||||
|
||||
if (!(drec = switch_core_hash_find(globals.device_hash, channel->device_id))) {
|
||||
create_device_record(&drec, channel->device_id);
|
||||
switch_core_hash_insert(globals.device_hash, drec->device_id, drec);
|
||||
}
|
||||
|
||||
add_uuid(drec, channel);
|
||||
|
||||
switch_mutex_unlock(globals.device_mutex);
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG, "Setting DEVICE ID to [%s]\n", device_id);
|
||||
|
||||
switch_channel_check_device_state(channel, CCS_ACTIVE);
|
||||
|
||||
return device_id;
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(switch_device_record_t *) switch_channel_get_device_record(switch_channel_t *channel)
|
||||
{
|
||||
if (channel->device_node) {
|
||||
switch_mutex_lock(channel->device_node->parent->mutex);
|
||||
return channel->device_node->parent;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(void) switch_channel_release_device_record(switch_device_record_t **drecp)
|
||||
{
|
||||
if (drecp && *drecp) {
|
||||
switch_mutex_unlock((*drecp)->mutex);
|
||||
*drecp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_channel_bind_device_state_handler(switch_device_state_function_t function, void *user_data)
|
||||
{
|
||||
switch_device_state_binding_t *binding = NULL, *ptr = NULL;
|
||||
assert(function != NULL);
|
||||
|
||||
if (!(binding = (switch_device_state_binding_t *) switch_core_alloc(globals.pool, sizeof(*binding)))) {
|
||||
return SWITCH_STATUS_MEMERR;
|
||||
}
|
||||
|
||||
binding->function = function;
|
||||
binding->user_data = user_data;
|
||||
|
||||
switch_mutex_lock(globals.device_mutex);
|
||||
for (ptr = globals.device_bindings; ptr && ptr->next; ptr = ptr->next);
|
||||
|
||||
if (ptr) {
|
||||
ptr->next = binding;
|
||||
} else {
|
||||
globals.device_bindings = binding;
|
||||
}
|
||||
|
||||
switch_mutex_unlock(globals.device_mutex);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_channel_unbind_device_state_handler(switch_device_state_function_t function)
|
||||
{
|
||||
switch_device_state_binding_t *ptr, *last = NULL;
|
||||
switch_status_t status = SWITCH_STATUS_FALSE;
|
||||
|
||||
switch_mutex_lock(globals.device_mutex);
|
||||
for (ptr = globals.device_bindings; ptr; ptr = ptr->next) {
|
||||
if (ptr->function == function) {
|
||||
status = SWITCH_STATUS_SUCCESS;
|
||||
|
||||
if (last) {
|
||||
last->next = ptr->next;
|
||||
} else {
|
||||
globals.device_bindings = ptr->next;
|
||||
last = NULL;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
last = ptr;
|
||||
}
|
||||
switch_mutex_unlock(globals.device_mutex);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
|
|
|
@ -1657,6 +1657,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_init(switch_core_flag_t flags, switc
|
|||
|
||||
switch_console_init(runtime.memory_pool);
|
||||
switch_event_init(runtime.memory_pool);
|
||||
switch_channel_global_init(runtime.memory_pool);
|
||||
|
||||
if (switch_xml_init(runtime.memory_pool, err) != SWITCH_STATUS_SUCCESS) {
|
||||
apr_terminate();
|
||||
|
@ -2566,6 +2567,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_destroy(void)
|
|||
switch_xml_destroy();
|
||||
switch_core_session_uninit();
|
||||
switch_console_shutdown();
|
||||
switch_channel_global_uninit();
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Closing Event Engine.\n");
|
||||
switch_event_shutdown();
|
||||
|
|
|
@ -577,6 +577,8 @@ SWITCH_DECLARE(void) switch_core_session_destroy_state(switch_core_session_t *se
|
|||
|
||||
STATE_MACRO(destroy, "DESTROY");
|
||||
|
||||
switch_channel_clear_device_record(session->channel);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -198,6 +198,8 @@ static char *EVENT_NAMES[] = {
|
|||
"CONFERENCE_DATA",
|
||||
"CALL_SETUP_REQ",
|
||||
"CALL_SETUP_RESULT",
|
||||
"CALL_DETAIL",
|
||||
"DEVICE_STATE",
|
||||
"ALL"
|
||||
};
|
||||
|
||||
|
|
|
@ -2689,6 +2689,11 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
|
|||
}
|
||||
|
||||
|
||||
if (local_var_event) {
|
||||
const char *device_id = switch_event_get_header(local_var_event, "device_id");
|
||||
switch_channel_set_profile_var(originate_status[i].peer_channel, "device_id", device_id);
|
||||
}
|
||||
|
||||
if ((lc = switch_event_get_header(var_event, "local_var_clobber"))) {
|
||||
local_clobber = switch_true(lc);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue