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:
Anthony Minessale II 2017-03-09 11:59:33 -06:00
commit abcb7f83a1
9 changed files with 671 additions and 260 deletions

View File

@ -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);

View File

@ -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

View File

@ -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);
}

View File

@ -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);
}
}
}

View File

@ -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) {

View File

@ -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")) {

View File

@ -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;
}

View File

@ -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);

View File

@ -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;