#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);
{"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>]"},
{"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>]"},
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;
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);
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
{
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);
}
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);
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);
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) {
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)
{
}
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;
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;
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;
- }
+ gate_check = conference_member_noise_gate_check(member);
- 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);
+ member->score_iir = (int) (((1.0 - SCORE_DECAY) * (float) member->score) + (SCORE_DECAY * (float) member->score_iir));
- if (++member->agc_concur >= agc_period) {
- if (!member->vol_period) {
- conference_member_check_agc_levels(member);
+ 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->agc_concur = 0;
+ member->auto_energy_track = 0;
}
- } else {
- member->nt_tally++;
}
- member->score_iir = (int) (((1.0 - SCORE_DECAY) * (float) member->score) + (SCORE_DECAY * (float) member->score_iir));
+ 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;
+ }
- if (member->score_iir > SCORE_MAX_IIR) {
- member->score_iir = SCORE_MAX_IIR;
+ 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 (conference_member_noise_gate_check(member)) {
+
+ 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++;
}
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);
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);
}
}
}
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;
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)) {
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;
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)) {
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) {
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")) {
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);
}
int16_t *bptr;
uint32_t x = 0;
int32_t z = 0;
- int member_score_sum = 0;
int divisor = 0;
conference_cdr_node_t *np;
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;
}
}
- member_score_sum = 0;
conference->mux_loop_count = 0;
conference->member_loop_count = 0;
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
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);
}
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);
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);
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) {
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));
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;
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)) {
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)) {
}
}
- 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 (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 (level > 0 && level > conference->energy_level) {
- conference->agc_level = level;
+ 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;
}
}
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;
}
MFLAG_ROTATE_VIDEO,
MFLAG_INDICATE_DEAF,
MFLAG_INDICATE_UNDEAF,
+ MFLAG_TALK_DATA_EVENTS,
///////////////////////////
MFLAG_MAX
} member_flag_t;
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;
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;
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;
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;
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);
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,
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);
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);
};
+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)
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;