Merge pull request #1220 in FS/freeswitch from bugfix/FS-9922-auto-energy-level to master
* commit '51dd5e87a7df7cb8d952a9e8d0548c810086b9b4': FS-9922: [mod_conference] Auto Energy Level #resolve
This commit is contained in:
commit
abcb7f83a1
|
@ -177,6 +177,8 @@ SWITCH_DECLARE(void) switch_mux_channels(int16_t *data, switch_size_t samples, u
|
|||
|
||||
#define switch_resample_calc_buffer_size(_to, _from, _srclen) ((uint32_t)(((float)_to / (float)_from) * (float)_srclen) * 2)
|
||||
|
||||
SWITCH_DECLARE(void) switch_agc_set(switch_agc_t *agc, uint32_t energy_avg,
|
||||
uint32_t low_energy_point, uint32_t margin, uint32_t change_factor, uint32_t period_len);
|
||||
SWITCH_DECLARE(switch_status_t) switch_agc_create(switch_agc_t **agcP, uint32_t energy_avg,
|
||||
uint32_t low_energy_point, uint32_t margin, uint32_t change_factor, uint32_t period_len);
|
||||
SWITCH_DECLARE(void) switch_agc_destroy(switch_agc_t **agcP);
|
||||
|
|
|
@ -47,6 +47,9 @@ api_command_t conference_api_sub_commands[] = {
|
|||
{"xml_list", (void_fn_t) & conference_api_sub_xml_list, CONF_API_SUB_ARGS_SPLIT, "xml_list", ""},
|
||||
{"json_list", (void_fn_t) & conference_api_sub_json_list, CONF_API_SUB_ARGS_SPLIT, "json_list", "[compact]"},
|
||||
{"energy", (void_fn_t) & conference_api_sub_energy, CONF_API_SUB_MEMBER_TARGET, "energy", "<member_id|all|last|non_moderator> [<newval>]"},
|
||||
{"auto-energy", (void_fn_t) & conference_api_sub_auto_energy, CONF_API_SUB_MEMBER_TARGET, "auto-energy", "<member_id|all|last|non_moderator> [<newval>]"},
|
||||
{"max-energy", (void_fn_t) & conference_api_sub_max_energy, CONF_API_SUB_MEMBER_TARGET, "max-energy", "<member_id|all|last|non_moderator> [<newval>]"},
|
||||
{"agc", (void_fn_t) & conference_api_sub_agc, CONF_API_SUB_MEMBER_TARGET, "agc", "<member_id|all|last|non_moderator> [<newval>]"},
|
||||
{"vid-canvas", (void_fn_t) & conference_api_sub_canvas, CONF_API_SUB_MEMBER_TARGET, "vid-canvas", "<member_id|all|last|non_moderator> [<newval>]"},
|
||||
{"vid-watching-canvas", (void_fn_t) & conference_api_sub_watching_canvas, CONF_API_SUB_MEMBER_TARGET, "vid-watching-canvas", "<member_id|all|last|non_moderator> [<newval>]"},
|
||||
{"vid-layer", (void_fn_t) & conference_api_sub_layer, CONF_API_SUB_MEMBER_TARGET, "vid-layer", "<member_id|all|last|non_moderator> [<newval>]"},
|
||||
|
@ -78,7 +81,6 @@ api_command_t conference_api_sub_commands[] = {
|
|||
{"relate", (void_fn_t) & conference_api_sub_relate, CONF_API_SUB_ARGS_SPLIT, "relate", "<member_id>[,<member_id>] <other_member_id>[,<other_member_id>] [nospeak|nohear|clear]"},
|
||||
{"lock", (void_fn_t) & conference_api_sub_lock, CONF_API_SUB_ARGS_SPLIT, "lock", ""},
|
||||
{"unlock", (void_fn_t) & conference_api_sub_unlock, CONF_API_SUB_ARGS_SPLIT, "unlock", ""},
|
||||
{"agc", (void_fn_t) & conference_api_sub_agc, CONF_API_SUB_ARGS_SPLIT, "agc", ""},
|
||||
{"dial", (void_fn_t) & conference_api_sub_dial, CONF_API_SUB_ARGS_SPLIT, "dial", "<endpoint_module_name>/<destination> <callerid number> <callerid name>"},
|
||||
{"bgdial", (void_fn_t) & conference_api_sub_bgdial, CONF_API_SUB_ARGS_SPLIT, "bgdial", "<endpoint_module_name>/<destination> <callerid number> <callerid name>"},
|
||||
{"transfer", (void_fn_t) & conference_api_sub_transfer, CONF_API_SUB_ARGS_SPLIT, "transfer", "<conference_name> <member id> [...<member id>]"},
|
||||
|
@ -291,53 +293,6 @@ switch_status_t conference_api_sub_syntax(char **syntax)
|
|||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
switch_status_t conference_api_sub_agc(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv)
|
||||
{
|
||||
int level;
|
||||
int on = 0;
|
||||
|
||||
if (argc == 2) {
|
||||
stream->write_function(stream, "+OK CURRENT AGC LEVEL IS %d\n", conference->agc_level);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
if (!(on = !strcasecmp(argv[2], "on"))) {
|
||||
stream->write_function(stream, "+OK AGC DISABLED\n");
|
||||
conference->agc_level = 0;
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (argc > 3) {
|
||||
level = atoi(argv[3]);
|
||||
} else {
|
||||
level = DEFAULT_AGC_LEVEL;
|
||||
}
|
||||
|
||||
if (level > conference->energy_level) {
|
||||
conference->avg_score = 0;
|
||||
conference->avg_itt = 0;
|
||||
conference->avg_tally = 0;
|
||||
conference->agc_level = level;
|
||||
|
||||
if (stream) {
|
||||
stream->write_function(stream, "OK AGC ENABLED %d\n", conference->agc_level);
|
||||
}
|
||||
|
||||
} else {
|
||||
if (stream) {
|
||||
stream->write_function(stream, "-ERR invalid level\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
|
||||
}
|
||||
|
||||
switch_status_t conference_api_sub_mute(conference_member_t *member, switch_stream_handle_t *stream, void *data)
|
||||
{
|
||||
switch_event_t *event;
|
||||
|
@ -911,6 +866,13 @@ switch_status_t conference_api_sub_energy(conference_member_t *member, switch_st
|
|||
if (stream != NULL) {
|
||||
stream->write_function(stream, "Energy %u = %d\n", member->id, member->energy_level);
|
||||
}
|
||||
|
||||
if (member->auto_energy_level && member->energy_level > member->auto_energy_level) {
|
||||
member->auto_energy_level = 0;
|
||||
stream->write_function(stream, "Auto-Energy level exceeded, Auto-Energy mode disabled\n", SWITCH_VA_NONE);
|
||||
}
|
||||
|
||||
|
||||
if (test_eflag(member->conference, EFLAG_ENERGY_LEVEL_MEMBER) &&
|
||||
data && switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
|
||||
conference_member_add_event_data(member, event);
|
||||
|
@ -922,6 +884,232 @@ switch_status_t conference_api_sub_energy(conference_member_t *member, switch_st
|
|||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
void conference_api_set_agc(conference_member_t *member, const char *data)
|
||||
{
|
||||
int tmp = 0;
|
||||
char *argv[4] = { 0 };
|
||||
char *conf;
|
||||
|
||||
if (data) {
|
||||
conf = switch_core_strdup(member->pool, data);
|
||||
switch_split(conf, ':', argv);
|
||||
} else {
|
||||
member->agc_level = member->conference->agc_level;
|
||||
member->agc_low_energy_level = member->conference->agc_low_energy_level;
|
||||
member->agc_change_factor = member->conference->agc_change_factor;
|
||||
member->agc_margin = member->conference->agc_margin;
|
||||
member->agc_period_len = member->conference->agc_period_len;
|
||||
}
|
||||
|
||||
if (argv[0]) {
|
||||
tmp = atoi(argv[0]);
|
||||
|
||||
if (tmp > 0) {
|
||||
member->agc_level = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
if (argv[1]) {
|
||||
tmp = atoi(argv[1]);
|
||||
|
||||
if (tmp > 0) {
|
||||
member->agc_low_energy_level = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (argv[2]) {
|
||||
tmp = atoi(argv[2]);
|
||||
|
||||
if (tmp > 0) {
|
||||
member->agc_change_factor = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (argv[2]) {
|
||||
tmp = atoi(argv[0]);
|
||||
|
||||
if (tmp > 0) {
|
||||
member->agc_period_len = (1000 / member->conference->interval) * tmp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!member->agc) {
|
||||
switch_agc_create(&member->agc, member->agc_level, member->agc_low_energy_level, member->agc_margin,
|
||||
member->agc_change_factor, member->agc_period_len);
|
||||
} else {
|
||||
switch_agc_set(member->agc, member->agc_level, member->agc_low_energy_level, member->agc_margin,
|
||||
member->agc_change_factor, member->agc_period_len);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
switch_status_t conference_api_sub_agc(conference_member_t *member, switch_stream_handle_t *stream, void *data)
|
||||
{
|
||||
switch_event_t *event;
|
||||
|
||||
if (member == NULL) {
|
||||
return SWITCH_STATUS_GENERR;
|
||||
}
|
||||
|
||||
if (data) {
|
||||
lock_member(member);
|
||||
if (!strcasecmp(data, "up")) {
|
||||
member->agc_level += 200;
|
||||
if (member->agc_level > 1800) {
|
||||
member->agc_level = 1800;
|
||||
}
|
||||
} else if (!strcasecmp(data, "down")) {
|
||||
member->agc_level -= 200;
|
||||
if (member->agc_level < 0) {
|
||||
member->agc_level = 0;
|
||||
}
|
||||
} else {
|
||||
conference_api_set_agc(member, (char *)data);
|
||||
}
|
||||
unlock_member(member);
|
||||
}
|
||||
if (stream != NULL) {
|
||||
stream->write_function(stream, "Agc %u = %d\n", member->id, member->agc_level);
|
||||
}
|
||||
|
||||
|
||||
// if (test_eflag(member->conference, EFLAG_AGC_LEVEL_MEMBER) &&
|
||||
if (data && switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
|
||||
conference_member_add_event_data(member, event);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "agc-level-member");
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Agc-Level", "%d", member->agc_level);
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
switch_status_t conference_api_sub_auto_energy(conference_member_t *member, switch_stream_handle_t *stream, void *data)
|
||||
{
|
||||
switch_event_t *event;
|
||||
|
||||
if (member == NULL) {
|
||||
return SWITCH_STATUS_GENERR;
|
||||
}
|
||||
|
||||
if (data) {
|
||||
lock_member(member);
|
||||
if (!strcasecmp(data, "up")) {
|
||||
member->auto_energy_level += 200;
|
||||
if (member->auto_energy_level > 1800) {
|
||||
member->auto_energy_level = 1800;
|
||||
}
|
||||
} else if (!strcasecmp(data, "down")) {
|
||||
member->auto_energy_level -= 200;
|
||||
if (member->auto_energy_level < 0) {
|
||||
member->auto_energy_level = 0;
|
||||
}
|
||||
} else {
|
||||
member->auto_energy_level = atoi((char *) data);
|
||||
}
|
||||
unlock_member(member);
|
||||
}
|
||||
if (stream != NULL) {
|
||||
stream->write_function(stream, "%u = Auto-Energy: %d Energy: %d\n", member->id, member->auto_energy_level, member->energy_level);
|
||||
}
|
||||
|
||||
if (!member->energy_level) {
|
||||
member->energy_level = member->auto_energy_level / 2;
|
||||
}
|
||||
|
||||
|
||||
if (test_eflag(member->conference, EFLAG_ENERGY_LEVEL_MEMBER) &&
|
||||
data && switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
|
||||
conference_member_add_event_data(member, event);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "auto-energy-level-member");
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Auto-Energy-Level", "%d", member->auto_energy_level);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Energy-Level", "%d", member->energy_level);
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
switch_status_t conference_api_sub_max_energy(conference_member_t *member, switch_stream_handle_t *stream, void *data)
|
||||
{
|
||||
switch_event_t *event;
|
||||
|
||||
if (member == NULL) {
|
||||
return SWITCH_STATUS_GENERR;
|
||||
}
|
||||
|
||||
if (data) {
|
||||
lock_member(member);
|
||||
if (!strcasecmp(data, "up")) {
|
||||
member->max_energy_level += 200;
|
||||
if (member->max_energy_level > 1800) {
|
||||
member->max_energy_level = 1800;
|
||||
}
|
||||
} else if (!strcasecmp(data, "down")) {
|
||||
member->max_energy_level -= 200;
|
||||
if (member->max_energy_level < 0) {
|
||||
member->max_energy_level = 0;
|
||||
}
|
||||
} else {
|
||||
member->max_energy_level = atoi((char *) data);
|
||||
}
|
||||
unlock_member(member);
|
||||
}
|
||||
|
||||
if (member->max_energy_level && member->max_energy_level < member->energy_level) {
|
||||
member->max_energy_level = 0;
|
||||
stream->write_function(stream, "-ERR %u Max-Energy cannot exceed energy level.\n", member->id);
|
||||
} else if (data) {
|
||||
char *p, *q;
|
||||
if ((p = strchr(data, ':'))) {
|
||||
p++;
|
||||
if (*p) {
|
||||
int tmp = atoi(p);
|
||||
if (tmp >= 0) {
|
||||
member->burst_mute_count = tmp / member->conference->interval;
|
||||
}
|
||||
|
||||
if ((q = strchr(p, ':'))) {
|
||||
q++;
|
||||
if (*q) {
|
||||
int tmp = atoi(q);
|
||||
|
||||
if (tmp >= 0) {
|
||||
member->max_energy_hit_trigger = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (stream != NULL) {
|
||||
stream->write_function(stream, "%u = Max-Energy: %d Energy: %d Max-Energy-Mute: %dms Max-Energy-Hit-Trigger %d\n",
|
||||
member->id, member->energy_level, member->max_energy_level, member->burst_mute_count * member->conference->interval, member->max_energy_hit_trigger);
|
||||
}
|
||||
|
||||
|
||||
if (test_eflag(member->conference, EFLAG_ENERGY_LEVEL_MEMBER) &&
|
||||
data && switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
|
||||
conference_member_add_event_data(member, event);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "max-energy-level-member");
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Max-Energy-Level", "%d", member->max_energy_level);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Max-Energy-Mute", "%d", member->burst_mute_count * member->conference->interval);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Max-Energy-Hit-Trigger", "%d", member->max_energy_hit_trigger);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Energy-Level", "%d", member->max_energy_level);
|
||||
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
switch_status_t conference_api_sub_auto_position(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv)
|
||||
{
|
||||
#ifdef OPENAL_POSITIONING
|
||||
|
|
|
@ -490,7 +490,6 @@ void conference_cdr_del(conference_member_t *member)
|
|||
{
|
||||
switch_mutex_lock(member->conference->member_mutex);
|
||||
if (member->cdr_node) {
|
||||
|
||||
if (member->channel) {
|
||||
switch_channel_get_variables(member->channel, &member->cdr_node->var_event);
|
||||
}
|
||||
|
|
|
@ -296,6 +296,15 @@ void conference_loop_energy_up(conference_member_t *member, caller_control_actio
|
|||
member->energy_level = 1800;
|
||||
}
|
||||
|
||||
if (member->auto_energy_level && member->energy_level > member->auto_energy_level) {
|
||||
member->auto_energy_level = 0;
|
||||
}
|
||||
|
||||
if (member->max_energy_level && member->max_energy_level > member->max_energy_level) {
|
||||
member->max_energy_level = 0;
|
||||
}
|
||||
|
||||
|
||||
if (test_eflag(member->conference, EFLAG_ENERGY_LEVEL) &&
|
||||
switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
|
||||
conference_member_add_event_data(member, event);
|
||||
|
@ -328,6 +337,15 @@ void conference_loop_energy_equ_conf(conference_member_t *member, caller_control
|
|||
|
||||
member->energy_level = member->conference->energy_level;
|
||||
|
||||
|
||||
if (member->auto_energy_level && member->energy_level > member->auto_energy_level) {
|
||||
member->auto_energy_level = 0;
|
||||
}
|
||||
|
||||
if (member->max_energy_level && member->max_energy_level > member->max_energy_level) {
|
||||
member->max_energy_level = 0;
|
||||
}
|
||||
|
||||
if (test_eflag(member->conference, EFLAG_ENERGY_LEVEL) &&
|
||||
switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
|
||||
conference_member_add_event_data(member, event);
|
||||
|
@ -359,6 +377,14 @@ void conference_loop_energy_dn(conference_member_t *member, caller_control_actio
|
|||
if (member->energy_level < 0) {
|
||||
member->energy_level = 0;
|
||||
}
|
||||
|
||||
if (member->auto_energy_level && member->energy_level > member->auto_energy_level) {
|
||||
member->auto_energy_level = 0;
|
||||
}
|
||||
|
||||
if (member->max_energy_level && member->max_energy_level > member->max_energy_level) {
|
||||
member->max_energy_level = 0;
|
||||
}
|
||||
|
||||
if (test_eflag(member->conference, EFLAG_ENERGY_LEVEL) &&
|
||||
switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
|
||||
|
@ -690,6 +716,70 @@ void conference_loop_hangup(conference_member_t *member, caller_control_action_t
|
|||
conference_utils_member_clear_flag_locked(member, MFLAG_RUNNING);
|
||||
}
|
||||
|
||||
static void stop_talking_handler(conference_member_t *member)
|
||||
{
|
||||
switch_event_t *event;
|
||||
double avg = 0, avg2 = 0, gcp = 0, ngcp = 0, pct = 0;
|
||||
|
||||
member->auto_energy_track = 0;
|
||||
|
||||
if (member->score_count && member->talking_count) {
|
||||
int duration_ms = member->talking_count * member->conference->interval;
|
||||
avg = (double)member->score_delta_accum / member->score_count;
|
||||
avg2 = (double)member->score_accum / member->score_count;
|
||||
|
||||
|
||||
if (!member->nogate_count) member->nogate_count = 1;
|
||||
if (!member->gate_count) member->gate_count = 1;
|
||||
|
||||
pct = ((float)member->nogate_count / (float)member->gate_count) * 100;
|
||||
gcp = ((double)member->gate_count / member->talking_count) * 100;
|
||||
ngcp = ((double)member->nogate_count / member->talking_count) * 100;
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG2, "SCORE AVG %f/%f %d GC %d NGC %d GC %% %f NGC %% %f DIFF %f EL %d MS %d PCT %f\n",
|
||||
avg2, avg, member->score_count, member->gate_count,
|
||||
member->nogate_count,
|
||||
gcp, ngcp, gcp - ngcp, member->energy_level, duration_ms, pct);
|
||||
|
||||
|
||||
if (member->auto_energy_level) {
|
||||
if (duration_ms > 2000 && pct > 1) {
|
||||
int new_level = (int)(avg2 *.75);
|
||||
if (new_level > member->auto_energy_level) {
|
||||
new_level = member->auto_energy_level;
|
||||
}
|
||||
member->energy_level = new_level;
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG2, "SET ENERGY %d\n", new_level);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
member->gate_open = 0;
|
||||
member->nogate_count = 0;
|
||||
member->gate_count = 0;
|
||||
|
||||
if (test_eflag(member->conference, EFLAG_STOP_TALKING) &&
|
||||
switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
|
||||
conference_member_add_event_data(member, event);
|
||||
if (avg) {
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "talking-gate-hits", "%u", member->score_count);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "talking-total-packets", "%u", member->talking_count);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "talking-duration-ms", "%u", member->talking_count * member->conference->interval);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "talking-average-energy", "%f", avg2);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "talking-delta-average", "%f", avg);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "talking-hit-on-percent", "%f", gcp);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "talking-non-hit-ratio", "%f", pct);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "talking-hit-off-percent", "%f", ngcp);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "talking-hit-off-differential", "%f", gcp - ngcp);
|
||||
}
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "stop-talking");
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/* marshall frames from the call leg to the conference thread for muxing to other call legs */
|
||||
void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, void *obj)
|
||||
{
|
||||
|
@ -805,54 +895,35 @@ void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, void *ob
|
|||
}
|
||||
|
||||
if (switch_test_flag(read_frame, SFF_CNG)) {
|
||||
if (member->conference->agc_level) {
|
||||
member->nt_tally++;
|
||||
}
|
||||
|
||||
if (hangunder_hits) {
|
||||
hangunder_hits--;
|
||||
}
|
||||
if (conference_utils_member_test_flag(member, MFLAG_TALKING)) {
|
||||
if (++hangover_hits >= hangover) {
|
||||
hangover_hits = hangunder_hits = 0;
|
||||
if (member->nogate_count < hangover) {
|
||||
member->nogate_count = 0;
|
||||
} else {
|
||||
member->nogate_count -= hangover;
|
||||
}
|
||||
conference_utils_member_clear_flag_locked(member, MFLAG_TALKING);
|
||||
conference_member_update_status_field(member);
|
||||
conference_member_check_agc_levels(member);
|
||||
conference_member_clear_avg(member);
|
||||
member->score_iir = 0;
|
||||
member->floor_packets = 0;
|
||||
|
||||
if (test_eflag(member->conference, EFLAG_STOP_TALKING) &&
|
||||
switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
|
||||
conference_member_add_event_data(member, event);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "stop-talking");
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
stop_talking_handler(member);
|
||||
}
|
||||
}
|
||||
|
||||
goto do_continue;
|
||||
}
|
||||
|
||||
if (member->nt_tally > (int32_t)(member->read_impl.actual_samples_per_second / member->read_impl.samples_per_packet) * 3) {
|
||||
member->agc_volume_in_level = 0;
|
||||
conference_member_clear_avg(member);
|
||||
}
|
||||
|
||||
/* Check for input volume adjustments */
|
||||
if (!member->conference->agc_level) {
|
||||
member->conference->agc_level = 0;
|
||||
conference_member_clear_avg(member);
|
||||
}
|
||||
|
||||
|
||||
/* if the member can speak, compute the audio energy level and */
|
||||
/* generate events when the level crosses the threshold */
|
||||
if ((conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK) || conference_utils_member_test_flag(member, MFLAG_MUTE_DETECT))) {
|
||||
uint32_t energy = 0, i = 0, samples = 0, j = 0;
|
||||
int16_t *data;
|
||||
int agc_period = (member->read_impl.actual_samples_per_second / member->read_impl.samples_per_packet) / 4;
|
||||
|
||||
int gate_check = 0;
|
||||
|
||||
data = read_frame->data;
|
||||
member->score = 0;
|
||||
|
@ -861,14 +932,14 @@ void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, void *ob
|
|||
switch_change_sln_volume(read_frame->data, (read_frame->datalen / 2) * member->conference->channels, member->volume_in_level);
|
||||
}
|
||||
|
||||
if (member->agc_volume_in_level) {
|
||||
switch_change_sln_volume_granular(read_frame->data, (read_frame->datalen / 2) * member->conference->channels, member->agc_volume_in_level);
|
||||
if (member->agc) {
|
||||
switch_agc_feed(member->agc, (int16_t *)read_frame->data, (read_frame->datalen / 2) * member->conference->channels, 1);
|
||||
}
|
||||
|
||||
if ((samples = read_frame->datalen / sizeof(*data) / member->read_impl.number_of_channels)) {
|
||||
if ((samples = read_frame->datalen / sizeof(*data))) {
|
||||
for (i = 0; i < samples; i++) {
|
||||
energy += abs(data[j]);
|
||||
j += member->read_impl.number_of_channels;
|
||||
j++;
|
||||
}
|
||||
|
||||
member->score = energy / samples;
|
||||
|
@ -878,57 +949,146 @@ void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, void *ob
|
|||
member->vol_period--;
|
||||
}
|
||||
|
||||
if (member->conference->agc_level && member->score &&
|
||||
conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK) &&
|
||||
conference_member_noise_gate_check(member)
|
||||
) {
|
||||
int last_shift = abs((int)(member->last_score - member->score));
|
||||
|
||||
if (member->score && member->last_score && last_shift > 900) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG7,
|
||||
"AGC %s:%d drop anomalous shift of %d\n",
|
||||
member->conference->name,
|
||||
member->id, last_shift);
|
||||
|
||||
} else {
|
||||
member->avg_tally += member->score;
|
||||
member->avg_itt++;
|
||||
if (!member->avg_itt) member->avg_itt++;
|
||||
member->avg_score = member->avg_tally / member->avg_itt;
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG7,
|
||||
"AGC %s:%d diff:%d level:%d cur:%d avg:%d vol:%d\n",
|
||||
member->conference->name,
|
||||
member->id, member->conference->agc_level - member->avg_score, member->conference->agc_level,
|
||||
member->score, member->avg_score, member->agc_volume_in_level);
|
||||
|
||||
if (++member->agc_concur >= agc_period) {
|
||||
if (!member->vol_period) {
|
||||
conference_member_check_agc_levels(member);
|
||||
}
|
||||
member->agc_concur = 0;
|
||||
}
|
||||
} else {
|
||||
member->nt_tally++;
|
||||
}
|
||||
gate_check = conference_member_noise_gate_check(member);
|
||||
|
||||
member->score_iir = (int) (((1.0 - SCORE_DECAY) * (float) member->score) + (SCORE_DECAY * (float) member->score_iir));
|
||||
|
||||
if (member->score_iir > SCORE_MAX_IIR) {
|
||||
member->score_iir = SCORE_MAX_IIR;
|
||||
}
|
||||
|
||||
if (member->auto_energy_level && !conference_utils_member_test_flag(member, MFLAG_TALKING)) {
|
||||
if (++member->auto_energy_track >= (1000 / member->conference->interval * member->conference->auto_energy_sec)) {
|
||||
if (member->energy_level > member->conference->energy_level) {
|
||||
int new_level = member->energy_level - 100;
|
||||
|
||||
if (new_level < member->conference->energy_level) {
|
||||
new_level = member->conference->energy_level;
|
||||
}
|
||||
member->energy_level = new_level;
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG2, "ENERGY DOWN %d\n", member->energy_level);
|
||||
}
|
||||
member->auto_energy_track = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (conference_member_noise_gate_check(member)) {
|
||||
gate_check = conference_member_noise_gate_check(member);
|
||||
|
||||
if (conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK)) {
|
||||
if (member->max_energy_level) {
|
||||
if (member->score > member->max_energy_level && ++member->max_energy_hits > member->max_energy_hit_trigger) {
|
||||
member->mute_counter = member->burst_mute_count;
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG2, "MAX ENERGY HIT!\n");
|
||||
} else if (!member->mute_counter && member->score > (int)((double)member->max_energy_level * .75)) {
|
||||
int dec = 1;
|
||||
|
||||
if (member->score_count > 3) {
|
||||
dec = 2;
|
||||
} else if (member->score_count > 6) {
|
||||
dec = 3;
|
||||
} else if (member->score_count > 9) {
|
||||
dec = 4;
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG2, "MAX ENERGY THRESHOLD! -%d\n", dec);
|
||||
switch_change_sln_volume(read_frame->data, (read_frame->datalen / 2) * member->conference->channels, -1 * dec);
|
||||
}
|
||||
}
|
||||
|
||||
if (member->mute_counter > 0) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG2, "MAX ENERGY DECAY %d\n", member->mute_counter);
|
||||
member->mute_counter--;
|
||||
switch_generate_sln_silence(read_frame->data, (read_frame->datalen / 2), member->conference->channels, 1400 * (member->conference->rate / 8000));
|
||||
if (member->mute_counter == 0) {
|
||||
member->max_energy_hits = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (conference_utils_member_test_flag(member, MFLAG_TALKING)) {
|
||||
member->talking_count++;
|
||||
|
||||
if (gate_check) {
|
||||
int gate_count = 0, nogate_count = 0;
|
||||
double pct;
|
||||
member->score_accum += member->score;
|
||||
member->score_delta_accum += abs(member->score - member->last_score);
|
||||
member->score_count++;
|
||||
member->score_avg = member->score_accum / member->score_count;
|
||||
|
||||
member->gate_count++;
|
||||
member->gate_open = 1;
|
||||
|
||||
gate_count = member->gate_count;
|
||||
nogate_count = member->nogate_count;
|
||||
|
||||
if (!gate_count) {
|
||||
pct = 0;
|
||||
} else {
|
||||
pct = ((float)nogate_count / (float)gate_count) * 100;
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG2, "TRACK %d %d %d/%d %f\n",
|
||||
member->score,
|
||||
member->score_avg,
|
||||
gate_count, nogate_count, pct);
|
||||
|
||||
|
||||
} else {
|
||||
member->nogate_count++;
|
||||
member->gate_open = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (conference_utils_member_test_flag(member, MFLAG_TALK_DATA_EVENTS)) {
|
||||
if (++member->talk_track >= (1000 / member->conference->interval * 10)) {
|
||||
uint32_t diff = 0;
|
||||
double avg = 0;
|
||||
switch_event_t *event;
|
||||
|
||||
if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
|
||||
conference_member_add_event_data(member, event);
|
||||
|
||||
|
||||
if (member->first_talk_detect) {
|
||||
|
||||
if (!member->talk_detects) {
|
||||
member->talk_detects = 1;
|
||||
}
|
||||
|
||||
diff = (uint32_t) (switch_micro_time_now() - member->first_talk_detect) / 1000;
|
||||
avg = (double)diff / member->talk_detects;
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "talk-detects", "%d", member->talk_detects);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "talk-detect-duration", "%d", diff);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "talk-detect-avg", "%f", avg);
|
||||
} else {
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "talk-detects", "%d", 0);
|
||||
}
|
||||
|
||||
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "talk-report");
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
|
||||
if (!conference_utils_member_test_flag(member, MFLAG_TALKING)) {
|
||||
member->first_talk_detect = 0;
|
||||
member->talk_detects = 0;
|
||||
} else {
|
||||
member->talk_detects = 1;
|
||||
}
|
||||
|
||||
member->talk_track = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (gate_check) {
|
||||
uint32_t diff = member->score - member->energy_level;
|
||||
if (hangover_hits) {
|
||||
hangover_hits--;
|
||||
}
|
||||
|
||||
if (member->conference->agc_level) {
|
||||
member->nt_tally = 0;
|
||||
}
|
||||
|
||||
if (member == member->conference->floor_holder) {
|
||||
member->floor_packets++;
|
||||
}
|
||||
|
@ -943,6 +1103,17 @@ void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, void *ob
|
|||
conference_member_update_status_field(member);
|
||||
member->floor_packets = 0;
|
||||
|
||||
|
||||
if (!member->first_talk_detect) {
|
||||
member->first_talk_detect = switch_micro_time_now();
|
||||
}
|
||||
|
||||
member->talk_detects++;
|
||||
member->score_delta_accum = 0;
|
||||
member->score_accum = 0;
|
||||
member->score_count = 0;
|
||||
member->talking_count = 0;
|
||||
|
||||
if (test_eflag(member->conference, EFLAG_START_TALKING) && conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK) &&
|
||||
switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
|
||||
conference_member_add_event_data(member, event);
|
||||
|
@ -970,25 +1141,20 @@ void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, void *ob
|
|||
hangunder_hits--;
|
||||
}
|
||||
|
||||
if (member->conference->agc_level) {
|
||||
member->nt_tally++;
|
||||
}
|
||||
|
||||
if (conference_utils_member_test_flag(member, MFLAG_TALKING) && conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK)) {
|
||||
switch_event_t *event;
|
||||
if (++hangover_hits >= hangover) {
|
||||
hangover_hits = hangunder_hits = 0;
|
||||
|
||||
if (member->nogate_count < hangover) {
|
||||
member->nogate_count = 0;
|
||||
} else {
|
||||
member->nogate_count -= hangover;
|
||||
}
|
||||
|
||||
conference_utils_member_clear_flag_locked(member, MFLAG_TALKING);
|
||||
conference_member_update_status_field(member);
|
||||
conference_member_check_agc_levels(member);
|
||||
conference_member_clear_avg(member);
|
||||
|
||||
if (test_eflag(member->conference, EFLAG_STOP_TALKING) &&
|
||||
switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
|
||||
conference_member_add_event_data(member, event);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "stop-talking");
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
stop_talking_handler(member);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,34 +43,11 @@
|
|||
|
||||
int conference_member_noise_gate_check(conference_member_t *member)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
|
||||
if (member->conference->agc_level && member->agc_volume_in_level != 0) {
|
||||
int target_score = 0;
|
||||
|
||||
target_score = (member->energy_level + (25 * member->agc_volume_in_level));
|
||||
|
||||
if (target_score < 0) target_score = 0;
|
||||
|
||||
r = (int)member->score > target_score;
|
||||
|
||||
} else {
|
||||
r = (int32_t)member->score > member->energy_level;
|
||||
}
|
||||
int r = (int32_t)member->score > member->energy_level;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void conference_member_clear_avg(conference_member_t *member)
|
||||
{
|
||||
|
||||
member->avg_score = 0;
|
||||
member->avg_itt = 0;
|
||||
member->avg_tally = 0;
|
||||
member->agc_concur = 0;
|
||||
}
|
||||
|
||||
void conference_member_do_binding(conference_member_t *member, conference_key_callback_t handler, const char *digits, const char *data)
|
||||
{
|
||||
key_binding_t *binding;
|
||||
|
@ -455,33 +432,6 @@ conference_member_t *conference_member_get_by_var(conference_obj_t *conference,
|
|||
return member;
|
||||
}
|
||||
|
||||
void conference_member_check_agc_levels(conference_member_t *member)
|
||||
{
|
||||
int x = 0;
|
||||
|
||||
if (!member->avg_score) return;
|
||||
|
||||
if ((int)member->avg_score < member->conference->agc_level - 100) {
|
||||
member->agc_volume_in_level++;
|
||||
switch_normalize_volume_granular(member->agc_volume_in_level);
|
||||
x = 1;
|
||||
} else if ((int)member->avg_score > member->conference->agc_level + 100) {
|
||||
member->agc_volume_in_level--;
|
||||
switch_normalize_volume_granular(member->agc_volume_in_level);
|
||||
x = -1;
|
||||
}
|
||||
|
||||
if (x) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG7,
|
||||
"AGC %s:%d diff:%d level:%d cur:%d avg:%d vol:%d %s\n",
|
||||
member->conference->name,
|
||||
member->id, member->conference->agc_level - member->avg_score, member->conference->agc_level,
|
||||
member->score, member->avg_score, member->agc_volume_in_level, x > 0 ? "+++" : "---");
|
||||
|
||||
conference_member_clear_avg(member);
|
||||
}
|
||||
}
|
||||
|
||||
void conference_member_check_channels(switch_frame_t *frame, conference_member_t *member, switch_bool_t in)
|
||||
{
|
||||
if (member->conference->channels != member->read_impl.number_of_channels || conference_utils_member_test_flag(member, MFLAG_POSITIONAL)) {
|
||||
|
@ -701,6 +651,10 @@ switch_status_t conference_member_add(conference_obj_t *conference, conference_m
|
|||
member->conference = conference;
|
||||
member->next = conference->members;
|
||||
member->energy_level = conference->energy_level;
|
||||
member->auto_energy_level = conference->auto_energy_level;
|
||||
member->max_energy_level = conference->max_energy_level;
|
||||
member->max_energy_hit_trigger = conference->max_energy_hit_trigger;
|
||||
member->burst_mute_count = conference->burst_mute_count;;
|
||||
member->score_iir = 0;
|
||||
member->verbose_events = conference->verbose_events;
|
||||
member->video_layer_id = -1;
|
||||
|
@ -713,6 +667,7 @@ switch_status_t conference_member_add(conference_obj_t *conference, conference_m
|
|||
switch_mutex_unlock(conference->member_mutex);
|
||||
conference_cdr_add(member);
|
||||
|
||||
conference_api_set_agc(member, NULL);
|
||||
|
||||
if (!conference_utils_member_test_flag(member, MFLAG_NOCHANNEL)) {
|
||||
|
||||
|
@ -1125,6 +1080,10 @@ switch_status_t conference_member_del(conference_obj_t *conference, conference_m
|
|||
conference_member_del_relationship(member, 0);
|
||||
|
||||
conference_cdr_del(member);
|
||||
|
||||
if (member->agc) {
|
||||
switch_agc_destroy(&member->agc);
|
||||
}
|
||||
|
||||
#ifdef OPENAL_POSITIONING
|
||||
if (member->al && member->al->device) {
|
||||
|
|
|
@ -130,6 +130,8 @@ void conference_utils_set_mflags(const char *flags, member_flag_t *f)
|
|||
f[MFLAG_ENDCONF] = 1;
|
||||
} else if (!strcasecmp(argv[i], "mintwo")) {
|
||||
f[MFLAG_MINTWO] = 1;
|
||||
} else if (!strcasecmp(argv[i], "talk-data-events")) {
|
||||
f[MFLAG_TALK_DATA_EVENTS] = 1;
|
||||
} else if (!strcasecmp(argv[i], "video-bridge")) {
|
||||
f[MFLAG_VIDEO_BRIDGE] = 1;
|
||||
} else if (!strcasecmp(argv[i], "ghost")) {
|
||||
|
|
|
@ -137,10 +137,8 @@ void conference_list(conference_obj_t *conference, switch_stream_handle_t *strea
|
|||
count++;
|
||||
}
|
||||
|
||||
stream->write_function(stream, "%s%d%s%d%s%d%s%d\n", delim,
|
||||
stream->write_function(stream, "%s%d%s%d%s%d\n", delim,
|
||||
member->volume_in_level,
|
||||
delim,
|
||||
member->agc_volume_in_level,
|
||||
delim, member->volume_out_level, delim, member->energy_level);
|
||||
}
|
||||
|
||||
|
@ -205,7 +203,6 @@ void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, void *ob
|
|||
int16_t *bptr;
|
||||
uint32_t x = 0;
|
||||
int32_t z = 0;
|
||||
int member_score_sum = 0;
|
||||
int divisor = 0;
|
||||
conference_cdr_node_t *np;
|
||||
|
||||
|
@ -234,7 +231,6 @@ void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, void *ob
|
|||
switch_size_t file_sample_len = samples;
|
||||
switch_size_t file_data_len = samples * 2 * conference->channels;
|
||||
int has_file_data = 0, members_with_video = 0, members_with_avatar = 0, members_seeing_video = 0;
|
||||
uint32_t conference_energy = 0;
|
||||
int nomoh = 0;
|
||||
conference_member_t *floor_holder;
|
||||
switch_status_t moh_status = SWITCH_STATUS_SUCCESS;
|
||||
|
@ -553,7 +549,6 @@ void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, void *ob
|
|||
}
|
||||
}
|
||||
|
||||
member_score_sum = 0;
|
||||
conference->mux_loop_count = 0;
|
||||
conference->member_loop_count = 0;
|
||||
|
||||
|
@ -566,34 +561,12 @@ void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, void *ob
|
|||
continue;
|
||||
}
|
||||
|
||||
if (conference->agc_level) {
|
||||
if (conference_utils_member_test_flag(omember, MFLAG_TALKING) && conference_utils_member_test_flag(omember, MFLAG_CAN_SPEAK)) {
|
||||
member_score_sum += omember->score;
|
||||
conference->mux_loop_count++;
|
||||
}
|
||||
}
|
||||
|
||||
bptr = (int16_t *) omember->frame;
|
||||
for (x = 0; x < omember->read / 2; x++) {
|
||||
main_frame[x] += (int32_t) bptr[x];
|
||||
}
|
||||
}
|
||||
|
||||
if (conference->agc_level && conference->member_loop_count) {
|
||||
conference_energy = 0;
|
||||
|
||||
for (x = 0; x < bytes / 2; x++) {
|
||||
z = abs(main_frame[x]);
|
||||
switch_normalize_to_16bit(z);
|
||||
conference_energy += (int16_t) z;
|
||||
}
|
||||
|
||||
conference->score = conference_energy / ((bytes / 2) / divisor) / conference->member_loop_count;
|
||||
conference->avg_tally += conference->score;
|
||||
conference->avg_score = conference->avg_tally / ++conference->avg_itt;
|
||||
if (!conference->avg_itt) conference->avg_tally = conference->score;
|
||||
}
|
||||
|
||||
/* Create write frame once per member who is not deaf for each sample in the main frame
|
||||
check if our audio is involved and if so, subtract it from the sample so we don't hear ourselves.
|
||||
Since main frame was 32 bit int, we did not lose any detail, now that we have to convert to 16 bit we can
|
||||
|
@ -671,7 +644,7 @@ void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, void *ob
|
|||
int16_t write_frame[SWITCH_RECOMMENDED_BUFFER_SIZE] = { 0 };
|
||||
|
||||
if (conference->comfort_noise_level) {
|
||||
switch_generate_sln_silence(write_frame, samples, conference->channels, conference->comfort_noise_level);
|
||||
switch_generate_sln_silence(write_frame, samples, conference->channels, conference->comfort_noise_level * (conference->rate / 8000));
|
||||
} else {
|
||||
memset(write_frame, 255, bytes);
|
||||
}
|
||||
|
@ -1186,12 +1159,6 @@ void conference_xlist(conference_obj_t *conference, switch_xml_t x_conference, i
|
|||
switch_snprintf(i, sizeof(i), "%d", switch_epoch_time_now(NULL) - conference->run_time);
|
||||
switch_xml_set_attr_d(x_conference, "run_time", ival);
|
||||
|
||||
if (conference->agc_level) {
|
||||
char tmp[30] = "";
|
||||
switch_snprintf(tmp, sizeof(tmp), "%d", conference->agc_level);
|
||||
switch_xml_set_attr_d_buf(x_conference, "agc", tmp);
|
||||
}
|
||||
|
||||
x_members = switch_xml_add_child_d(x_conference, "members", 0);
|
||||
switch_assert(x_members);
|
||||
|
||||
|
@ -1298,13 +1265,6 @@ void conference_xlist(conference_obj_t *conference, switch_xml_t x_conference, i
|
|||
|
||||
switch_snprintf(tmp, sizeof(tmp), "%d", member->volume_out_level);
|
||||
add_x_tag(x_member, "output-volume", tmp, toff++);
|
||||
|
||||
switch_snprintf(tmp, sizeof(tmp), "%d", member->agc_volume_in_level ? member->agc_volume_in_level : member->volume_in_level);
|
||||
add_x_tag(x_member, "input-volume", tmp, toff++);
|
||||
|
||||
switch_snprintf(tmp, sizeof(tmp), "%d", member->agc_volume_in_level);
|
||||
add_x_tag(x_member, "auto-adjusted-input-volume", tmp, toff++);
|
||||
|
||||
}
|
||||
|
||||
switch_mutex_unlock(conference->member_mutex);
|
||||
|
@ -1353,10 +1313,6 @@ void conference_jlist(conference_obj_t *conference, cJSON *json_conferences)
|
|||
cJSON_AddNumberToObject(json_conference, "max_members", conference->max_members);
|
||||
}
|
||||
|
||||
if (conference->agc_level) {
|
||||
cJSON_AddNumberToObject(json_conference, "agc", conference->agc_level);
|
||||
}
|
||||
|
||||
cJSON_AddItemToObject(json_conference, "members", json_conference_members = cJSON_CreateArray());
|
||||
switch_mutex_lock(conference->member_mutex);
|
||||
for (member = conference->members; member; member = member->next) {
|
||||
|
@ -1393,8 +1349,7 @@ void conference_jlist(conference_obj_t *conference, cJSON *json_conferences)
|
|||
cJSON_AddNumberToObject(json_conference_member, "volume_in", member->volume_in_level);
|
||||
cJSON_AddNumberToObject(json_conference_member, "volume_out", member->volume_out_level);
|
||||
cJSON_AddNumberToObject(json_conference_member, "output-volume", member->volume_out_level);
|
||||
cJSON_AddNumberToObject(json_conference_member, "input-volume", member->agc_volume_in_level ? member->agc_volume_in_level : member->volume_in_level);
|
||||
cJSON_AddNumberToObject(json_conference_member, "auto-adjusted-input-volume", member->agc_volume_in_level);
|
||||
cJSON_AddNumberToObject(json_conference_member, "input-volume", member->volume_in_level);
|
||||
ADDBOOL(json_conference_member_flags, "can_hear", conference_utils_member_test_flag(member, MFLAG_CAN_HEAR));
|
||||
ADDBOOL(json_conference_member_flags, "can_speak", conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK));
|
||||
ADDBOOL(json_conference_member_flags, "mute_detect", conference_utils_member_test_flag(member, MFLAG_MUTE_DETECT));
|
||||
|
@ -2613,7 +2568,16 @@ conference_obj_t *conference_new(char *name, conference_xml_cfg_t cfg, switch_co
|
|||
char *pin_sound = NULL;
|
||||
char *bad_pin_sound = NULL;
|
||||
char *energy_level = NULL;
|
||||
char *auto_gain_level = NULL;
|
||||
char *auto_energy_level = NULL;
|
||||
char *max_energy_level = NULL;
|
||||
char *max_energy_hit_trigger = NULL;
|
||||
char *max_energy_level_mute_ms = NULL;
|
||||
char *auto_energy_sec = NULL;
|
||||
char *agc_level = NULL;
|
||||
char *agc_low_energy_level = NULL;
|
||||
char *agc_margin = NULL;
|
||||
char *agc_change_factor = NULL;
|
||||
char *agc_period_len = NULL;
|
||||
char *caller_id_name = NULL;
|
||||
char *caller_id_number = NULL;
|
||||
char *caller_controls = NULL;
|
||||
|
@ -2672,6 +2636,7 @@ conference_obj_t *conference_new(char *name, conference_xml_cfg_t cfg, switch_co
|
|||
int scale_h264_canvas_height = 0;
|
||||
int scale_h264_canvas_fps_divisor = 0;
|
||||
char *scale_h264_canvas_bandwidth = NULL;
|
||||
int tmp;
|
||||
|
||||
/* Validate the conference name */
|
||||
if (zstr(name)) {
|
||||
|
@ -2876,8 +2841,26 @@ conference_obj_t *conference_new(char *name, conference_xml_cfg_t cfg, switch_co
|
|||
bad_pin_sound = val;
|
||||
} else if (!strcasecmp(var, "energy-level") && !zstr(val)) {
|
||||
energy_level = val;
|
||||
} else if (!strcasecmp(var, "auto-energy-level") && !zstr(val)) {
|
||||
auto_energy_level = val;
|
||||
} else if (!strcasecmp(var, "max-energy-level") && !zstr(val)) {
|
||||
max_energy_level = val;
|
||||
} else if (!strcasecmp(var, "max-energy-hit-trigger") && !zstr(val)) {
|
||||
max_energy_hit_trigger = val;
|
||||
} else if (!strcasecmp(var, "max-energy-level-mute-ms") && !zstr(val)) {
|
||||
max_energy_level_mute_ms = val;
|
||||
} else if (!strcasecmp(var, "auto-energy-seconds") && !zstr(val)) {
|
||||
auto_energy_sec = val;
|
||||
} else if (!strcasecmp(var, "auto-gain-level") && !zstr(val)) {
|
||||
auto_gain_level = val;
|
||||
agc_level = val;
|
||||
} else if (!strcasecmp(var, "auto-gain-low-energy-level") && !zstr(val)) {
|
||||
agc_low_energy_level = val;
|
||||
} else if (!strcasecmp(var, "auto-gain-margin") && !zstr(val)) {
|
||||
agc_margin = val;
|
||||
} else if (!strcasecmp(var, "auto-gain-change-factor") && !zstr(val)) {
|
||||
agc_change_factor = val;
|
||||
} else if (!strcasecmp(var, "auto-gain-period-len") && !zstr(val)) {
|
||||
agc_period_len = val;
|
||||
} else if (!strcasecmp(var, "caller-id-name") && !zstr(val)) {
|
||||
caller_id_name = val;
|
||||
} else if (!strcasecmp(var, "caller-id-number") && !zstr(val)) {
|
||||
|
@ -3348,17 +3331,54 @@ conference_obj_t *conference_new(char *name, conference_xml_cfg_t cfg, switch_co
|
|||
}
|
||||
}
|
||||
|
||||
if (!zstr(auto_gain_level)) {
|
||||
int level = 0;
|
||||
if (!zstr(max_energy_level_mute_ms)) {
|
||||
int mute_ms = atoi(max_energy_level_mute_ms);
|
||||
|
||||
if (switch_true(auto_gain_level) && !switch_is_number(auto_gain_level)) {
|
||||
level = DEFAULT_AGC_LEVEL;
|
||||
} else {
|
||||
level = atoi(auto_gain_level);
|
||||
if (mute_ms > 0) {
|
||||
conference->burst_mute_count = mute_ms / conference->interval;
|
||||
}
|
||||
}
|
||||
|
||||
conference->max_energy_hit_trigger = 5;
|
||||
|
||||
if (!zstr(max_energy_level)) {
|
||||
conference->max_energy_hit_trigger = atoi(max_energy_hit_trigger);
|
||||
if (conference->max_energy_hit_trigger < 0) {
|
||||
conference->max_energy_hit_trigger = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!zstr(max_energy_level)) {
|
||||
conference->max_energy_level = atoi(max_energy_level);
|
||||
if (conference->max_energy_level < 0) {
|
||||
conference->max_energy_level = 0;
|
||||
}
|
||||
|
||||
if (level > 0 && level > conference->energy_level) {
|
||||
conference->agc_level = level;
|
||||
|
||||
if (conference->energy_level && conference->max_energy_level < conference->energy_level) {
|
||||
conference->max_energy_level = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!zstr(auto_energy_sec)) {
|
||||
conference->auto_energy_sec = atoi(auto_energy_sec);
|
||||
if (conference->auto_energy_sec < 0) {
|
||||
conference->auto_energy_sec = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!conference->auto_energy_sec) {
|
||||
conference->auto_energy_sec = 5;
|
||||
}
|
||||
|
||||
if (!zstr(auto_energy_level)) {
|
||||
conference->auto_energy_level = atoi(auto_energy_level);
|
||||
if (conference->auto_energy_level < 0) {
|
||||
conference->auto_energy_level = 0;
|
||||
}
|
||||
|
||||
if (!conference->energy_level) {
|
||||
conference->energy_level = conference->auto_energy_level / 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3391,6 +3411,49 @@ conference_obj_t *conference_new(char *name, conference_xml_cfg_t cfg, switch_co
|
|||
conference->ivr_dtmf_timeout = ivr_dtmf_timeout;
|
||||
conference->ivr_input_timeout = ivr_input_timeout;
|
||||
|
||||
|
||||
conference->agc_level = 0;
|
||||
conference->agc_low_energy_level = 0;
|
||||
conference->agc_margin = 500;
|
||||
conference->agc_change_factor = 3;
|
||||
conference->agc_period_len = (1000 / conference->interval) * 2;
|
||||
|
||||
|
||||
if (agc_level) {
|
||||
tmp = atoi(agc_level);
|
||||
if (tmp > 0) {
|
||||
conference->agc_level = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
if (agc_low_energy_level) {
|
||||
tmp = atoi(agc_low_energy_level);
|
||||
if (tmp > 0) {
|
||||
conference->agc_low_energy_level = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
if (agc_margin) {
|
||||
tmp = atoi(agc_margin);
|
||||
if (tmp > 0) {
|
||||
conference->agc_margin = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
if (agc_change_factor) {
|
||||
tmp = atoi(agc_change_factor);
|
||||
if (tmp > 0) {
|
||||
conference->agc_change_factor = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
if (agc_period_len) {
|
||||
tmp = atoi(agc_period_len);
|
||||
if (tmp > 0) {
|
||||
conference->agc_period_len = (1000 / conference->interval) * tmp;
|
||||
}
|
||||
}
|
||||
|
||||
if (video_auto_floor_msec) {
|
||||
conference->video_floor_packets = video_auto_floor_msec / conference->interval;
|
||||
}
|
||||
|
|
|
@ -212,6 +212,7 @@ typedef enum {
|
|||
MFLAG_ROTATE_VIDEO,
|
||||
MFLAG_INDICATE_DEAF,
|
||||
MFLAG_INDICATE_UNDEAF,
|
||||
MFLAG_TALK_DATA_EVENTS,
|
||||
///////////////////////////
|
||||
MFLAG_MAX
|
||||
} member_flag_t;
|
||||
|
@ -652,6 +653,16 @@ typedef struct conference_obj {
|
|||
switch_thread_rwlock_t *rwlock;
|
||||
uint32_t count;
|
||||
int32_t energy_level;
|
||||
int32_t auto_energy_level;
|
||||
int32_t max_energy_level;
|
||||
uint32_t agc_level;
|
||||
uint32_t agc_low_energy_level;
|
||||
uint32_t agc_margin;
|
||||
uint32_t agc_change_factor;
|
||||
uint32_t agc_period_len;
|
||||
uint32_t max_energy_hit_trigger;
|
||||
uint32_t auto_energy_sec;
|
||||
uint32_t burst_mute_count;
|
||||
uint8_t min;
|
||||
switch_speech_handle_t lsh;
|
||||
switch_speech_handle_t *sh;
|
||||
|
@ -677,11 +688,6 @@ typedef struct conference_obj {
|
|||
uint32_t score;
|
||||
int mux_loop_count;
|
||||
int member_loop_count;
|
||||
int agc_level;
|
||||
|
||||
uint32_t avg_score;
|
||||
uint32_t avg_itt;
|
||||
uint32_t avg_tally;
|
||||
switch_time_t run_time;
|
||||
char *uuid_str;
|
||||
uint32_t originating;
|
||||
|
@ -762,14 +768,35 @@ struct conference_member {
|
|||
uint32_t read;
|
||||
uint32_t vol_period;
|
||||
int32_t energy_level;
|
||||
int32_t agc_volume_in_level;
|
||||
int32_t auto_energy_level;
|
||||
int32_t max_energy_level;
|
||||
uint32_t agc_level;
|
||||
uint32_t agc_low_energy_level;
|
||||
uint32_t agc_margin;
|
||||
uint32_t agc_change_factor;
|
||||
uint32_t agc_period_len;
|
||||
switch_agc_t *agc;
|
||||
uint32_t mute_counter;
|
||||
uint32_t burst_mute_count;
|
||||
uint32_t score_avg;
|
||||
uint32_t max_energy_hits;
|
||||
uint32_t max_energy_hit_trigger;
|
||||
int32_t volume_in_level;
|
||||
int32_t volume_out_level;
|
||||
int32_t agc_concur;
|
||||
int32_t nt_tally;
|
||||
switch_time_t join_time;
|
||||
switch_time_t last_talking;
|
||||
time_t last_talking;
|
||||
switch_time_t first_talk_detect;
|
||||
uint32_t talk_detects;
|
||||
uint32_t auto_energy_track;
|
||||
uint32_t talk_track;
|
||||
uint32_t score_count;
|
||||
uint32_t score_accum;
|
||||
uint32_t score_delta_accum;
|
||||
uint32_t native_rate;
|
||||
uint32_t gate_open;
|
||||
uint32_t gate_count;
|
||||
uint32_t nogate_count;
|
||||
uint32_t talking_count;
|
||||
switch_audio_resampler_t *read_resampler;
|
||||
int16_t *resample_out;
|
||||
uint32_t resample_out_len;
|
||||
|
@ -778,9 +805,6 @@ struct conference_member {
|
|||
switch_speech_handle_t lsh;
|
||||
switch_speech_handle_t *sh;
|
||||
uint32_t verbose_events;
|
||||
uint32_t avg_score;
|
||||
uint32_t avg_itt;
|
||||
uint32_t avg_tally;
|
||||
struct conference_member *next;
|
||||
switch_ivr_dmachine_t *dmachine;
|
||||
conference_cdr_node_t *cdr_node;
|
||||
|
@ -1030,8 +1054,7 @@ switch_status_t conference_text_thread_callback(switch_core_session_t *session,
|
|||
void *SWITCH_THREAD_FUNC conference_video_muxing_write_thread_run(switch_thread_t *thread, void *obj);
|
||||
void conference_video_launch_layer_thread(conference_member_t *member);
|
||||
void conference_video_wake_layer_thread(conference_member_t *member);
|
||||
void conference_member_check_agc_levels(conference_member_t *member);
|
||||
void conference_member_clear_avg(conference_member_t *member);
|
||||
|
||||
int conference_member_noise_gate_check(conference_member_t *member);
|
||||
void conference_member_check_channels(switch_frame_t *frame, conference_member_t *member, switch_bool_t in);
|
||||
|
||||
|
@ -1065,6 +1088,7 @@ void conference_video_canvas_set_fnode_layer(mcu_canvas_t *canvas, conference_fi
|
|||
void conference_list(conference_obj_t *conference, switch_stream_handle_t *stream, char *delim);
|
||||
const char *conference_utils_combine_flag_var(switch_core_session_t *session, const char *var_name);
|
||||
int conference_loop_mapping_len();
|
||||
void conference_api_set_agc(conference_member_t *member, const char *data);
|
||||
|
||||
switch_status_t conference_outcall(conference_obj_t *conference,
|
||||
char *conference_name,
|
||||
|
@ -1136,7 +1160,6 @@ switch_status_t conference_api_sub_play_status(conference_obj_t *conference, swi
|
|||
switch_status_t conference_api_sub_play(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv);
|
||||
switch_status_t conference_api_sub_say(conference_obj_t *conference, switch_stream_handle_t *stream, const char *text);
|
||||
switch_status_t conference_api_sub_dial(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv);
|
||||
switch_status_t conference_api_sub_agc(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv);
|
||||
switch_status_t conference_api_sub_bgdial(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv);
|
||||
switch_status_t conference_api_sub_auto_position(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv);
|
||||
switch_status_t conference_api_sub_saymember(conference_obj_t *conference, switch_stream_handle_t *stream, const char *text);
|
||||
|
@ -1172,6 +1195,9 @@ switch_status_t conference_api_sub_list(conference_obj_t *conference, switch_str
|
|||
switch_status_t conference_api_sub_xml_list(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv);
|
||||
switch_status_t conference_api_sub_json_list(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv);
|
||||
switch_status_t conference_api_sub_energy(conference_member_t *member, switch_stream_handle_t *stream, void *data);
|
||||
switch_status_t conference_api_sub_auto_energy(conference_member_t *member, switch_stream_handle_t *stream, void *data);
|
||||
switch_status_t conference_api_sub_agc(conference_member_t *member, switch_stream_handle_t *stream, void *data);
|
||||
switch_status_t conference_api_sub_max_energy(conference_member_t *member, switch_stream_handle_t *stream, void *data);
|
||||
switch_status_t conference_api_sub_watching_canvas(conference_member_t *member, switch_stream_handle_t *stream, void *data);
|
||||
switch_status_t conference_api_sub_canvas(conference_member_t *member, switch_stream_handle_t *stream, void *data);
|
||||
switch_status_t conference_api_sub_layer(conference_member_t *member, switch_stream_handle_t *stream, void *data);
|
||||
|
|
|
@ -417,6 +417,15 @@ struct switch_agc_s {
|
|||
};
|
||||
|
||||
|
||||
SWITCH_DECLARE(void) switch_agc_set(switch_agc_t *agc, uint32_t energy_avg,
|
||||
uint32_t low_energy_point, uint32_t margin, uint32_t change_factor, uint32_t period_len)
|
||||
{
|
||||
agc->energy_avg = energy_avg;
|
||||
agc->margin = margin;
|
||||
agc->change_factor = change_factor;
|
||||
agc->period_len = period_len;
|
||||
agc->low_energy_point = low_energy_point;
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_agc_create(switch_agc_t **agcP, uint32_t energy_avg,
|
||||
uint32_t low_energy_point, uint32_t margin, uint32_t change_factor, uint32_t period_len)
|
||||
|
@ -430,11 +439,8 @@ SWITCH_DECLARE(switch_status_t) switch_agc_create(switch_agc_t **agcP, uint32_t
|
|||
|
||||
agc = switch_core_alloc(pool, sizeof(*agc));
|
||||
agc->pool = pool;
|
||||
agc->energy_avg = energy_avg;
|
||||
agc->margin = margin;
|
||||
agc->change_factor = change_factor;
|
||||
agc->period_len = period_len;
|
||||
agc->low_energy_point = low_energy_point;
|
||||
|
||||
switch_agc_set(agc, energy_avg, low_energy_point, margin, change_factor, period_len);
|
||||
|
||||
*agcP = agc;
|
||||
|
||||
|
|
Loading…
Reference in New Issue