]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
FS-9958: [freeswitch-core,mod_local_stream] Add agc object and use it in mod_local_st...
authorAnthony Minessale <anthm@freeswitch.org>
Wed, 18 Jan 2017 19:19:41 +0000 (13:19 -0600)
committerAnthony Minessale <anthm@freeswitch.org>
Wed, 18 Jan 2017 19:19:47 +0000 (13:19 -0600)
src/include/switch_resample.h
src/include/switch_types.h
src/mod/formats/mod_local_stream/mod_local_stream.c
src/switch_resample.c

index b3fb436c86033412535b7dff6023cd8a4a0cdc89..252f156ed73a5128fad5fffb843614e0109dbe87 100644 (file)
@@ -177,7 +177,10 @@ 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(switch_status_t) switch_agc_create(switch_agc_t **agcP, uint32_t energy_avg, uint32_t margin, uint32_t change_factor, uint32_t period_len);
+SWITCH_DECLARE(void) switch_agc_destroy(switch_agc_t **agcP);
+SWITCH_DECLARE(switch_status_t) switch_agc_feed(switch_agc_t *agc, int16_t *data, uint32_t samples, uint32_t channels);
+SWITCH_DECLARE(void) switch_agc_set_energy_avg(switch_agc_t *agc, uint32_t energy_avg);
 SWITCH_END_EXTERN_C
 #endif
 /* For Emacs:
index b2f91735a5508eb7ec2c1f902f8795359e85bcc9..0bcb1202843696e371e460d26d5bb8820295ab81 100644 (file)
@@ -2658,6 +2658,7 @@ typedef enum {
 
 struct switch_rtp_text_factory_s;
 typedef struct switch_rtp_text_factory_s  switch_rtp_text_factory_t;
+typedef struct switch_agc_s switch_agc_t;
 
 SWITCH_END_EXTERN_C
 #endif
index 3dcb6bf65e8187f331977257a9779845d074e3ef..5ab74f49503bddad58b0855bbf321898c67376a6 100644 (file)
@@ -93,6 +93,9 @@ struct local_stream_source {
        char *timer_name;
        local_stream_context_t *context_list;
        int total;
+       int vol;
+       switch_agc_t *agc;
+       int energy_avg;
        int first;
        switch_dir_t *dir_handle;
        switch_mutex_t *mutex;
@@ -571,6 +574,13 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void
                                                }
                                                
                                                if (source->total) {
+
+                                                       if (source->energy_avg && source->agc) {
+                                                               switch_agc_feed(source->agc, (int16_t *)source->abuf, olen, source->channels);
+                                                       } else if (source->vol) {
+                                                               switch_change_sln_volume_granular((int16_t *)source->abuf, olen * source->channels, source->vol);
+                                                       }
+
                                                        switch_buffer_write(audio_buffer, source->abuf, olen * 2 * source->channels);
                                                } else {
                                                        switch_buffer_zero(audio_buffer);
@@ -720,6 +730,15 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void
                                                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
                                                                                                          "Interval must be multiple of 10 and less than %d, Using default of 20\n", SWITCH_MAX_INTERVAL);
                                                                }
+                                                       } else if (!strcasecmp(var, "volume")) {
+                                                               source->vol = atoi(val);
+                                                               switch_normalize_volume_granular(source->vol);
+                                                       } else if (!strcasecmp(var, "auto-volume")) {
+                                                               source->energy_avg = atoi(val);
+
+                                                               if (!(source->energy_avg > -1 && source->energy_avg <= 20000)) {
+                                                                       source->energy_avg = 0;
+                                                               }
                                                        }
                                                        if (source->chime_max) {
                                                                source->chime_max *= source->rate;
@@ -773,6 +792,10 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void
        switch_core_hash_delete(globals.source_hash, source->name);
        switch_mutex_unlock(globals.mutex);
 
+       if (source->agc) {
+               switch_agc_destroy(&source->agc);
+       }
+
        switch_thread_rwlock_wrlock(source->rwlock);
        switch_thread_rwlock_unlock(source->rwlock);
 
@@ -1247,6 +1270,16 @@ static void launch_thread(const char *name, const char *path, switch_xml_t direc
                        if (source->text_opacity < 0 && source->text_opacity > 100) {
                                source->text_opacity = 0;
                        }
+               } else if (!strcasecmp(var, "volume")) {
+                       source->vol = atoi(val);
+                       switch_normalize_volume_granular(source->vol);
+               } else if (!strcasecmp(var, "auto-volume")) {
+                       source->energy_avg = atoi(val);
+                       
+                       if (!(source->energy_avg > -1 && source->energy_avg <= 20000)) {
+                               source->energy_avg = 0;
+                       }
+
                }
        }
 
@@ -1330,6 +1363,34 @@ SWITCH_STANDARD_API(local_stream_function)
                        stream->write_function(stream, "+OK hup stream: %s", source->name);
                        switch_thread_rwlock_unlock(source->rwlock);
                }
+       } else if (!strcasecmp(argv[0], "vol") && local_stream_name) {
+               if ((source = get_source(local_stream_name))) {
+                       if (argv[2]) {
+                               if (!strncasecmp(argv[2], "auto:", 5)) {
+                                       source->energy_avg = atoi(argv[2] + 5);
+                                       if (!(source->energy_avg > -1 && source->energy_avg <= 20000)) {
+                                               source->energy_avg = 0;
+                                               stream->write_function(stream, "-ERR invalid auto-volume level for  stream: %s\n", source->name);
+                                       } else {
+                                               if (!source->agc) {
+                                                       switch_agc_create(&source->agc, source->energy_avg, 500, 3, (1000 / source->interval) * 2);
+                                               } else {
+                                                       switch_agc_set_energy_avg(source->agc, source->energy_avg);
+                                               }
+                                       }
+                               } else {
+                                       source->vol = atoi(argv[2]);
+                                       switch_normalize_volume_granular(source->vol);
+                               }
+                       }
+
+                       if (source->energy_avg) {
+                               stream->write_function(stream, "+OK Auto-Volume stream: %s is %d", source->name, source->energy_avg);
+                       } else {
+                               stream->write_function(stream, "+OK vol stream: %s is %d", source->name, source->vol);
+                       }
+                       switch_thread_rwlock_unlock(source->rwlock);
+               }
        } else if (!strcasecmp(argv[0], "stop") && local_stream_name) {
                if ((source = get_source(local_stream_name))) {
                        source->stopped = 1;
index d9f041b55fd964616df1774ad05b3aa41b6cb889..db099cd26476c76501b08e08d64c6410d10dfe44 100644 (file)
@@ -399,6 +399,126 @@ SWITCH_DECLARE(void) switch_change_sln_volume(int16_t *data, uint32_t samples, i
        }
 }
 
+struct switch_agc_s {
+       switch_memory_pool_t *pool;
+       uint32_t energy_avg;
+       uint32_t margin;
+       uint32_t change_factor;
+
+       int vol;
+       uint32_t score;
+       uint32_t score_count;
+       uint32_t score_sum;
+       uint32_t score_avg;
+       uint32_t score_over;
+       uint32_t score_under;
+       uint32_t period_len;
+};
+
+
+
+SWITCH_DECLARE(switch_status_t) switch_agc_create(switch_agc_t **agcP, uint32_t energy_avg, uint32_t margin, uint32_t change_factor, uint32_t period_len)
+{
+       switch_agc_t *agc;
+       switch_memory_pool_t *pool;
+
+       switch_assert(agcP);
+
+       switch_core_new_memory_pool(&pool);
+       
+       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;
+
+       *agcP = agc;
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_DECLARE(void) switch_agc_destroy(switch_agc_t **agcP)
+{
+       switch_agc_t *agc;
+
+       switch_assert(agcP);
+
+       agc = *agcP;
+       *agcP = NULL;
+
+       if (agc) {
+               switch_memory_pool_t *pool = agc->pool;
+               switch_core_destroy_memory_pool(&pool);
+       }
+}
+
+SWITCH_DECLARE(void) switch_agc_set_energy_avg(switch_agc_t *agc, uint32_t energy_avg)
+{
+       switch_assert(agc);
+
+       agc->energy_avg = energy_avg;
+}
+
+SWITCH_DECLARE(switch_status_t) switch_agc_feed(switch_agc_t *agc, int16_t *data, uint32_t samples, uint32_t channels)
+{
+       
+       if (!channels) channels = 1;
+
+       if (agc->vol) {
+               switch_change_sln_volume_granular(data, samples * channels, agc->vol);
+       }
+                                                       
+       if (agc->energy_avg) {
+               uint32_t energy = 0;
+               int i;
+
+               for (i = 0; i < samples * channels; i++) {
+                       energy += abs(data[i]);
+               }
+
+               agc->score = energy / samples * channels;
+               agc->score_sum += agc->score;
+               agc->score_count++;
+                                                               
+               if (agc->score_count > agc->period_len) {
+                                                                       
+                       agc->score_avg = (int)((double)agc->score_sum / agc->score_count);
+                       agc->score_count = 0;
+                       agc->score_sum = 0;
+                                                                       
+                       if (agc->score_avg > agc->energy_avg + agc->margin) {
+                               agc->score_over++;
+                       } else {
+                               agc->score_over = 0;
+                       }
+
+                       if (agc->score_avg < agc->energy_avg - agc->margin) {
+                               agc->score_under++;
+                       } else {
+                               agc->score_under = 0;
+                       }
+
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "AVG %d over: %d under: %d\n", agc->score_avg, agc->score_over, agc->score_under);
+
+                       if (agc->score_over > agc->change_factor) {
+                               agc->vol--;
+                               switch_normalize_volume_granular(agc->vol);
+                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "VOL DOWN %d\n", agc->vol);
+                       } else if (agc->score_under > agc->change_factor) {
+                               agc->vol++;
+                               switch_normalize_volume_granular(agc->vol);
+                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "VOL UP %d\n", agc->vol);
+                       }
+
+               }
+
+       }
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
+
 /* For Emacs:
  * Local Variables:
  * mode:c