From 180e3d4ab1943361610ca241d150565aad8d16fd Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Sun, 20 Feb 2011 14:37:23 -0600 Subject: [PATCH] agc tweaks --- src/include/switch_resample.h | 9 ++ .../mod_conference/mod_conference.c | 84 +++++++++++++------ src/switch_resample.c | 37 ++++++++ 3 files changed, 104 insertions(+), 26 deletions(-) diff --git a/src/include/switch_resample.h b/src/include/switch_resample.h index b38e094dd6..3dff620c4b 100644 --- a/src/include/switch_resample.h +++ b/src/include/switch_resample.h @@ -39,6 +39,7 @@ */ #define switch_normalize_volume(x) if (x > 4) x = 4; if (x < -4) x = -4; +#define switch_normalize_volume_granular(x) if (x > 12) x = 12; if (x < -12) x = -12; #ifndef SWITCH_RESAMPLE_H #define SWITCH_RESAMPLE_H @@ -158,6 +159,14 @@ SWITCH_DECLARE(void) switch_generate_sln_silence(int16_t *data, uint32_t samples \param vol the volume factor -4 -> 4 */ SWITCH_DECLARE(void) switch_change_sln_volume(int16_t *data, uint32_t samples, int32_t vol); + +/*! + \brief Change the volume of a signed linear audio frame with more granularity + \param data the audio data + \param samples the number of 2 byte samples + \param vol the volume factor -12 -> 12 + */ +SWITCH_DECLARE(void) switch_change_sln_volume_granular(int16_t *data, uint32_t samples, int32_t vol); ///\} SWITCH_DECLARE(uint32_t) switch_merge_sln(int16_t *data, uint32_t samples, int16_t *other_data, uint32_t other_samples); diff --git a/src/mod/applications/mod_conference/mod_conference.c b/src/mod/applications/mod_conference/mod_conference.c index 5eeae5c781..8a3f53e17a 100644 --- a/src/mod/applications/mod_conference/mod_conference.c +++ b/src/mod/applications/mod_conference/mod_conference.c @@ -318,6 +318,7 @@ struct conference_member { switch_mutex_t *audio_in_mutex; switch_mutex_t *audio_out_mutex; switch_mutex_t *read_mutex; + switch_codec_implementation_t read_impl; switch_codec_implementation_t orig_read_impl; switch_codec_t read_codec; switch_codec_t write_codec; @@ -1942,14 +1943,37 @@ static void conference_loop_fn_hangup(conference_member_t *member, caller_contro switch_clear_flag_locked(member, MFLAG_RUNNING); } +static void check_agc_levels(conference_member_t *member) +{ + if (!member->avg_score) return; + + if (member->avg_score < member->conference->agc_level - 200) { + member->agc_volume_in_level++; + switch_normalize_volume_granular(member->agc_volume_in_level); + } else if (member->avg_score > member->conference->agc_level + 200) { + member->agc_volume_in_level--; + switch_normalize_volume_granular(member->agc_volume_in_level); + } + //} else { + //member->vol_period = (member->read_impl.actual_samples_per_second / member->read_impl.samples_per_packet) * 5; + //} +} + static void clear_avg(conference_member_t *member) { - member->agc_volume_in_level = 0; + if (member->agc_volume_in_level < -5) { + member->agc_volume_in_level = 0; + } + + if (member->conference->agc_level) { + check_agc_levels(member); + } + member->avg_score = 0; member->avg_itt = 0; member->avg_tally = 0; - member->nt_tally = 0; + member->agc_concur = 0; } @@ -1962,7 +1986,6 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v switch_status_t status; switch_frame_t *read_frame = NULL; uint32_t hangover = 40, hangunder = 5, hangover_hits = 0, hangunder_hits = 0, energy_level = 0, diff_level = 400; - switch_codec_implementation_t read_impl = { 0 }; switch_core_session_t *session = member->session; int check_floor_change; @@ -1972,7 +1995,7 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v channel = switch_core_session_get_channel(session); - switch_core_session_get_read_impl(session, &read_impl); + switch_core_session_get_read_impl(session, &member->read_impl); /* As long as we have a valid read, feed that data into an input buffer where the conference thread will take it and mux it with any audio from other channels. */ @@ -1997,6 +2020,10 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v } if (switch_test_flag(read_frame, SFF_CNG)) { + if (member->conference->agc_level) { + member->nt_tally++; + } + if (hangunder_hits) { hangunder_hits--; } @@ -2017,6 +2044,11 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v goto do_continue; } + + if (member->nt_tally > (member->read_impl.actual_samples_per_second / member->read_impl.samples_per_packet) * 3) { + member->agc_volume_in_level = 0; + clear_avg(member); + } /* Check for input volume adjustments */ if (!member->conference->agc_level) { @@ -2031,30 +2063,29 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v uint32_t energy = 0, i = 0, samples = 0, j = 0; int16_t *data; int divisor = 0; - int agc_period = (read_impl.actual_samples_per_second / read_impl.samples_per_packet) / 2; - int combined_vol = 0; + int agc_period = (member->read_impl.actual_samples_per_second / member->read_impl.samples_per_packet) / 4; + data = read_frame->data; - if (!(divisor = read_impl.actual_samples_per_second / 8000)) { + if (!(divisor = member->read_impl.actual_samples_per_second / 8000)) { divisor = 1; } member->score = 0; - combined_vol = member->agc_volume_in_level; - if (member->conference->agc_level) { - combined_vol += member->agc_volume_in_level; + if (member->volume_in_level) { + switch_change_sln_volume(read_frame->data, read_frame->datalen / 2, member->volume_in_level); } - if (combined_vol) { - switch_change_sln_volume(read_frame->data, read_frame->datalen / 2, combined_vol); + if (member->agc_volume_in_level) { + switch_change_sln_volume_granular(read_frame->data, read_frame->datalen / 2, member->agc_volume_in_level); } if ((samples = read_frame->datalen / sizeof(*data))) { for (i = 0; i < samples; i++) { energy += abs(data[j]); - j += read_impl.number_of_channels; + j += member->read_impl.number_of_channels; } member->score = energy / (samples / divisor); } @@ -2082,22 +2113,14 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v - if (++member->nt_tally >= agc_period) { + if (++member->agc_concur >= agc_period) { if (!member->vol_period) { - if (member->avg_score < member->conference->agc_level) { - member->agc_volume_in_level++; - switch_normalize_volume(member->agc_volume_in_level); - member->vol_period = (read_impl.actual_samples_per_second / read_impl.samples_per_packet) * 2; - } - - if (member->avg_score > member->conference->agc_level) { - member->agc_volume_in_level--; - switch_normalize_volume(member->agc_volume_in_level); - member->vol_period = (read_impl.actual_samples_per_second / read_impl.samples_per_packet) * 2; - } + check_agc_levels(member); } - member->nt_tally = 0; + member->agc_concur = 0; } + } else { + member->nt_tally++; } member->score_iir = (int) (((1.0 - SCORE_DECAY) * (float) member->score) + (SCORE_DECAY * (float) member->score_iir)); @@ -2112,6 +2135,10 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v hangover_hits--; } + if (member->conference->agc_level) { + member->nt_tally = 0; + } + if (diff >= diff_level || ++hangunder_hits >= hangunder) { check_floor_change = 1; @@ -2147,6 +2174,11 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v if (hangunder_hits) { hangunder_hits--; } + + if (member->conference->agc_level) { + member->nt_tally++; + } + if (switch_test_flag(member, MFLAG_TALKING) && switch_test_flag(member, MFLAG_CAN_SPEAK)) { switch_event_t *event; if (++hangover_hits >= hangover) { diff --git a/src/switch_resample.c b/src/switch_resample.c index 10c633c01a..64656b6c61 100644 --- a/src/switch_resample.c +++ b/src/switch_resample.c @@ -269,6 +269,43 @@ SWITCH_DECLARE(void) switch_mux_channels(int16_t *data, switch_size_t samples, u } +SWITCH_DECLARE(void) switch_change_sln_volume_granular(int16_t *data, uint32_t samples, int32_t vol) +{ + double newrate = 0; + double pos[12] = {1.25, 1.50, 1.75, 2.0, 2.25, 2.50, 2.75, 3.0, 3.25, 3.50, 3.75, 4.0}; + double neg[12] = {.917, .834, .751, .668, .585, .502, .419, .336, .253, .017, .087, .004}; + double *chart; + uint32_t i; + + if (vol == 0) return; + + switch_normalize_volume_granular(vol); + + if (vol > 0) { + chart = pos; + } else { + chart = neg; + } + + i = abs(vol) - 1; + + switch_assert(i < 12); + + newrate = chart[i]; + + if (newrate) { + int32_t tmp; + uint32_t x; + int16_t *fp = data; + + for (x = 0; x < samples; x++) { + tmp = (int32_t) fp[x] * newrate; + switch_normalize_to_16bit(tmp); + fp[x] = (int16_t) tmp; + } + } +} + SWITCH_DECLARE(void) switch_change_sln_volume(int16_t *data, uint32_t samples, int32_t vol) { double newrate = 0;