Index: apps/app_meetme.c =================================================================== --- apps/app_meetme.c (revision 169716) +++ apps/app_meetme.c (working copy) @@ -441,6 +441,8 @@ #define MEETME_DELAYDETECTTALK 300 #define MEETME_DELAYDETECTENDTALK 1000 +/* 100 frames = 2 seconds */ +#define MEETME_GAINFRAMES 100 #define AST_FRAME_BITS 32 @@ -520,6 +522,8 @@ CONFFLAG_DURATION_LIMIT = (1 << 30), /*! Do not write any audio to this channel until the state is up. */ CONFFLAG_NO_AUDIO_UNTIL_UP = (1 << 31), + /*! Maintains gain of each user and throws MeetmeGain events */ + CONFFLAG_MONITORGAIN = (1 << 32), }; enum { @@ -542,6 +546,7 @@ AST_APP_OPTION('E', CONFFLAG_EMPTYNOPIN ), AST_APP_OPTION('e', CONFFLAG_EMPTY ), AST_APP_OPTION('F', CONFFLAG_PASS_DTMF ), + AST_APP_OPTION('g', CONFFLAG_MONITORGAIN), AST_APP_OPTION('i', CONFFLAG_INTROUSER ), AST_APP_OPTION('I', CONFFLAG_INTROUSERNOREVIEW ), AST_APP_OPTION_ARG('M', CONFFLAG_MOH, OPT_ARG_MOH_CLASS ), @@ -2874,6 +2879,7 @@ res = ast_dsp_silence(dsp, f, &totalsilence); if (!user->talking && totalsilence < MEETME_DELAYDETECTTALK) { user->talking = 1; + ast_dsp_gain_reset(dsp); if (confflags & CONFFLAG_MONITORTALKER) manager_event(EVENT_FLAG_CALL, "MeetmeTalking", "Channel: %s\r\n" @@ -2896,6 +2902,22 @@ } } } + + /* If user is talking, adjust his gain */ + if ((confflags & CONFFLAG_MONITORGAIN) && + (confflags & CONFFLAG_MONITORTALKER) && + (user->talking > 0)) { + ast_dsp_gain(dsp, f); + int gain_mult_factor = ast_dsp_getgain_mult_factor(dsp); + ast_frame_adjust_volume(f, gain_mult_factor); + if (ast_dsp_getnumgainframes(dsp) >= MEETME_GAINFRAMES) { + ast_log(LOG_NOTICE, "MONITORGAIN: user=%d, gain_mult_factor=%d\n", + user->user_no, gain_mult_factor); + ast_dsp_calc_gain_mult_factor(dsp); + ast_dsp_gain_reset(dsp); + } + } + if (using_pseudo) { /* Absolutely do _not_ use careful_write here... it is important that we read data from the channel Index: include/asterisk/dsp.h =================================================================== --- include/asterisk/dsp.h (revision 169716) +++ include/asterisk/dsp.h (working copy) @@ -151,4 +151,22 @@ * \return nothing */ void ast_dsp_frame_freed(struct ast_frame *fr); + +/* \brief Return RMS gain for this frame, also maintain (bucket) the value + * for gain normalization in meetme + */ +float ast_dsp_gain(struct ast_dsp* dsp, struct ast_frame* f); + +/* \brief Calculate the gain multiplication factor */ +void ast_dsp_calc_gain_mult_factor(struct ast_dsp* dsp); + +/* \brief Reset the gain buckets */ +void ast_dsp_gain_reset(struct ast_dsp* dsp); + +/* \brief Returns the number of frames till now used in gain normalization */ +int ast_dsp_getnumgainframes(struct ast_dsp* dsp); + +/* \brief Returns the current gain multiplication factor */ +int ast_dsp_getgain_mult_factor(struct ast_dsp* dsp); + #endif /* _ASTERISK_DSP_H */ Index: main/dsp.c =================================================================== --- main/dsp.c (revision 169716) +++ main/dsp.c (working copy) @@ -303,6 +303,43 @@ static int thresholds[THRESHOLD_MAX]; +#define NUMGAINBUCKETS 10 + +/* + * Divide the range 0-32767 into 10 equal parts + * These numbers are the squares of those boundaries + */ +static float GAIN_SQUARED_BOUNDS[NUMGAINBUCKETS] = + {1.073e7, + 4.294e7, + 9.662e7, + 1.718e8, + 2.651e8, + 3.865e8, + 5.261e8, + 6.872e8, + 8.697e8, + 1.074e9 + }; + +/* + * The number of frames in a bucket to qualify it as a valid bucket + * when trying to find the highest RMS in a gain window + */ +#define GAIN_BUCKET_THRESHOLD 4 + +/* + * The gain multiplication factor corresponding to each bucket + */ +static int GMF_VALUES[NUMGAINBUCKETS] = + {5, 3, 2, 1, 1, 1, 1, -2, -3, -5}; + +/* + * The number of frames in the first bucket to qualify it as background noise + * See MEETME_GAINFRAMES in apps/app_meetme.c + */ +#define NUM_GAINFRAMES_FOR_NOISE 95 + static inline void goertzel_sample(goertzel_state_t *s, short sample) { int v1; @@ -399,6 +436,9 @@ tone_detect_state_t cng_tone_state; tone_detect_state_t ced_tone_state; int destroy; + int gain_mult_factor; + int gain_buckets[NUMGAINBUCKETS]; + int numgainframes; }; static void mute_fragment(struct ast_dsp *dsp, fragment_t *fragment) @@ -1301,7 +1341,105 @@ return __ast_dsp_silence_noise(dsp, s, len, NULL, totalnoise); } +/* Init all gain buckets to 0 */ +static void ast_dsp_gain_buckets_init(struct ast_dsp* dsp) { + int i = 0; + for (i=0; igain_buckets[i] = 0; +} +/* + * Bucket this RMS gain value into one of the buckets + */ +static void ast_dsp_gain_bucket_value(struct ast_dsp* dsp, float rms_squared) { + int i; + for (i=0; igain_buckets[i]++; + break; + } + } +} + +/* + * Return the RMS gain for this frame + * Bucket the RMS gain in dsp->gain_buckets + */ +float ast_dsp_gain(struct ast_dsp* dsp, struct ast_frame* f) { + short *s; + int len, x, gain; + float accum, rms_squared; + + if (f->frametype != AST_FRAME_VOICE) { + ast_log(LOG_WARNING, "Can't calculate gain on a non-voice frame\n"); + return 0; + } + if (f->subclass != AST_FORMAT_SLINEAR) { + ast_log(LOG_WARNING, "Can only calculate gain on signed-linear frames :(\n"); + return 0; + } + s = f->data.ptr; + len = f->datalen/2; + + if (!len) + return 0; + + accum = 0.0; + for (x=0; xnumgainframes)++; + return rms_squared; +} + +/* + * Based on the buckets, determine the gain multiplication factor + * We find the highest bucket which has atleast THRESHOLD amount of frames + * This is to exclude outliers + * Then just choose the gain_mult_factor corresponding to that bucket + */ +void ast_dsp_calc_gain_mult_factor(struct ast_dsp* dsp) { + int i; + + dsp->gain_mult_factor = 1; + /* Detect noise and let gain_mult_factor be 1 + If we have NUM_GAINFRAMES_FOR_NOISE samples in the + first (lowest) gain bucket, assume its just noise and don't modify it + */ + if (dsp->gain_buckets[0] > NUM_GAINFRAMES_FOR_NOISE) + return; + + for (i=NUMGAINBUCKETS-1; i>=0; i--) { + if (dsp->gain_buckets[i] >= GAIN_BUCKET_THRESHOLD) { + dsp->gain_mult_factor = GMF_VALUES[i]; + break; + } + } +} + +/* + * Get prepared for next gain window + * Don't reinitialise MF + */ +void ast_dsp_gain_reset(struct ast_dsp *dsp) { + dsp->numgainframes = 0; + ast_dsp_gain_buckets_init(dsp); +} + +int ast_dsp_getnumgainframes(struct ast_dsp* dsp) { + return dsp->numgainframes; +} + +int ast_dsp_getgain_mult_factor(struct ast_dsp* dsp) { + return dsp->gain_mult_factor; +} + struct ast_frame *ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp, struct ast_frame *af) { int silence; @@ -1518,6 +1656,10 @@ ast_dsp_prog_reset(dsp); /* Initialize fax detector */ ast_fax_detect_init(dsp); + + dsp->gain_mult_factor = 1; + dsp->numgainframes = 0; + ast_dsp_gain_buckets_init(dsp); } return dsp; }