From 7f23115ad2faeee58865afbec6bc11a43210fde7 Mon Sep 17 00:00:00 2001 From: David Vossel Date: Thu, 21 Apr 2011 18:11:40 +0000 Subject: New HD ConfBridge conferencing application. Includes a new highly optimized and customizable ConfBridge application capable of mixing audio at sample rates ranging from 8khz-192khz. Review: https://reviewboard.asterisk.org/r/1147/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@314598 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- main/dsp.c | 130 ++++++++++++++++++++++++++++++++----------------------------- 1 file changed, 69 insertions(+), 61 deletions(-) (limited to 'main/dsp.c') diff --git a/main/dsp.c b/main/dsp.c index a83adc2a0..5d5d1a2c2 100644 --- a/main/dsp.c +++ b/main/dsp.c @@ -192,15 +192,7 @@ enum gsamp_thresh { #define FAX_TONE_CED_DURATION 2600 #define FAX_TONE_CED_DB 16 -#define SAMPLE_RATE 8000 - -/* How many samples a frame has. This constant is used when calculating - * Goertzel block size for tone_detect. It is only important if we want to - * remove (squelch) the tone. In this case it is important to have block - * size not to exceed size of voice frame. Otherwise by the moment the tone - * is detected it is too late to squelch it from previous frames. - */ -#define SAMPLES_IN_FRAME 160 +#define DEFAULT_SAMPLE_RATE 8000 /* MF goertzel size */ #define MF_GSIZE 120 @@ -339,10 +331,10 @@ static inline float goertzel_result(goertzel_state_t *s) return (float)r.value * (float)(1 << r.power); } -static inline void goertzel_init(goertzel_state_t *s, float freq, int samples) +static inline void goertzel_init(goertzel_state_t *s, float freq, int samples, unsigned int sample_rate) { s->v2 = s->v3 = s->chunky = 0.0; - s->fac = (int)(32768.0 * 2.0 * cos(2.0 * M_PI * freq / SAMPLE_RATE)); + s->fac = (int)(32768.0 * 2.0 * cos(2.0 * M_PI * freq / sample_rate)); s->samples = samples; } @@ -394,6 +386,7 @@ struct ast_dsp { int display_inband_dtmf_warning; float genergy; int mute_fragments; + unsigned int sample_rate; fragment_t mute_data[5]; digit_detect_state_t digit_state; tone_detect_state_t cng_tone_state; @@ -410,7 +403,7 @@ static void mute_fragment(struct ast_dsp *dsp, fragment_t *fragment) dsp->mute_data[dsp->mute_fragments++] = *fragment; } -static void ast_tone_detect_init(tone_detect_state_t *s, int freq, int duration, int amp) +static void ast_tone_detect_init(tone_detect_state_t *s, int freq, int duration, int amp, unsigned int sample_rate) { int duration_samples; float x; @@ -419,16 +412,16 @@ static void ast_tone_detect_init(tone_detect_state_t *s, int freq, int duration, s->freq = freq; /* Desired tone duration in samples */ - duration_samples = duration * SAMPLE_RATE / 1000; + duration_samples = duration * sample_rate / 1000; /* We want to allow 10% deviation of tone duration */ duration_samples = duration_samples * 9 / 10; /* If we want to remove tone, it is important to have block size not to exceed frame size. Otherwise by the moment tone is detected it is too late - to squelch it from previous frames */ - s->block_size = SAMPLES_IN_FRAME; + to squelch it from previous frames. Block size is 20ms at the given sample rate.*/ + s->block_size = (20 * sample_rate) / 1000; - periods_in_block = s->block_size * freq / SAMPLE_RATE; + periods_in_block = s->block_size * freq / sample_rate; /* Make sure we will have at least 5 periods at target frequency for analisys. This may make block larger than expected packet and will make squelching impossible @@ -437,7 +430,7 @@ static void ast_tone_detect_init(tone_detect_state_t *s, int freq, int duration, periods_in_block = 5; /* Now calculate final block size. It will contain integer number of periods */ - s->block_size = periods_in_block * SAMPLE_RATE / freq; + s->block_size = periods_in_block * sample_rate / freq; /* tone_detect is currently only used to detect fax tones and we do not need suqlching the fax tones */ @@ -447,7 +440,7 @@ static void ast_tone_detect_init(tone_detect_state_t *s, int freq, int duration, and thus no tone will be detected in them */ s->hits_required = (duration_samples - (s->block_size - 1)) / s->block_size; - goertzel_init(&s->tone, freq, s->block_size); + goertzel_init(&s->tone, freq, s->block_size, sample_rate); s->samples_pending = s->block_size; s->hit_count = 0; @@ -472,19 +465,19 @@ static void ast_tone_detect_init(tone_detect_state_t *s, int freq, int duration, static void ast_fax_detect_init(struct ast_dsp *s) { - ast_tone_detect_init(&s->cng_tone_state, FAX_TONE_CNG_FREQ, FAX_TONE_CNG_DURATION, FAX_TONE_CNG_DB); - ast_tone_detect_init(&s->ced_tone_state, FAX_TONE_CED_FREQ, FAX_TONE_CED_DURATION, FAX_TONE_CED_DB); + ast_tone_detect_init(&s->cng_tone_state, FAX_TONE_CNG_FREQ, FAX_TONE_CNG_DURATION, FAX_TONE_CNG_DB, s->sample_rate); + ast_tone_detect_init(&s->ced_tone_state, FAX_TONE_CED_FREQ, FAX_TONE_CED_DURATION, FAX_TONE_CED_DB, s->sample_rate); } -static void ast_dtmf_detect_init (dtmf_detect_state_t *s) +static void ast_dtmf_detect_init (dtmf_detect_state_t *s, unsigned int sample_rate) { int i; s->lasthit = 0; s->current_hit = 0; for (i = 0; i < 4; i++) { - goertzel_init(&s->row_out[i], dtmf_row[i], DTMF_GSIZE); - goertzel_init(&s->col_out[i], dtmf_col[i], DTMF_GSIZE); + goertzel_init(&s->row_out[i], dtmf_row[i], DTMF_GSIZE, sample_rate); + goertzel_init(&s->col_out[i], dtmf_col[i], DTMF_GSIZE, sample_rate); s->energy = 0.0; } s->current_sample = 0; @@ -495,18 +488,18 @@ static void ast_dtmf_detect_init (dtmf_detect_state_t *s) s->misses_to_end = DTMF_MISSES_TO_END; } -static void ast_mf_detect_init (mf_detect_state_t *s) +static void ast_mf_detect_init (mf_detect_state_t *s, unsigned int sample_rate) { int i; s->hits[0] = s->hits[1] = s->hits[2] = s->hits[3] = s->hits[4] = 0; for (i = 0; i < 6; i++) { - goertzel_init (&s->tone_out[i], mf_tones[i], 160); + goertzel_init (&s->tone_out[i], mf_tones[i], 160, sample_rate); } s->current_sample = 0; s->current_hit = 0; } -static void ast_digit_detect_init(digit_detect_state_t *s, int mf) +static void ast_digit_detect_init(digit_detect_state_t *s, int mf, unsigned int sample_rate) { s->current_digits = 0; s->detected_digits = 0; @@ -514,9 +507,9 @@ static void ast_digit_detect_init(digit_detect_state_t *s, int mf) s->digits[0] = '\0'; if (mf) { - ast_mf_detect_init(&s->td.mf); + ast_mf_detect_init(&s->td.mf, sample_rate); } else { - ast_dtmf_detect_init(&s->td.dtmf); + ast_dtmf_detect_init(&s->td.dtmf, sample_rate); } } @@ -1105,7 +1098,7 @@ int ast_dsp_call_progress(struct ast_dsp *dsp, struct ast_frame *inf) ast_log(LOG_WARNING, "Can't check call progress of non-voice frames\n"); return 0; } - if (inf->subclass.format.id != AST_FORMAT_SLINEAR) { + if (!ast_format_is_slinear(&inf->subclass.format)) { ast_log(LOG_WARNING, "Can only check call progress in signed-linear frames\n"); return 0; } @@ -1128,7 +1121,7 @@ static int __ast_dsp_silence_noise(struct ast_dsp *dsp, short *s, int len, int * accum /= len; if (accum < dsp->threshold) { /* Silent */ - dsp->totalsilence += len / 8; + dsp->totalsilence += len / (dsp->sample_rate / 1000); if (dsp->totalnoise) { /* Move and save history */ memmove(dsp->historicnoise + DSP_HISTORY - dsp->busycount, dsp->historicnoise + DSP_HISTORY - dsp->busycount + 1, dsp->busycount * sizeof(dsp->historicnoise[0])); @@ -1142,7 +1135,7 @@ static int __ast_dsp_silence_noise(struct ast_dsp *dsp, short *s, int len, int * res = 1; } else { /* Not silent */ - dsp->totalnoise += len / 8; + dsp->totalnoise += len / (dsp->sample_rate / 1000); if (dsp->totalsilence) { int silence1 = dsp->historicsilence[DSP_HISTORY - 1]; int silence2 = dsp->historicsilence[DSP_HISTORY - 2]; @@ -1321,7 +1314,7 @@ int ast_dsp_silence(struct ast_dsp *dsp, struct ast_frame *f, int *totalsilence) ast_log(LOG_WARNING, "Can't calculate silence on a non-voice frame\n"); return 0; } - if (f->subclass.format.id != AST_FORMAT_SLINEAR) { + if (!ast_format_is_slinear(&f->subclass.format)) { ast_log(LOG_WARNING, "Can only calculate silence on signed-linear frames :(\n"); return 0; } @@ -1339,7 +1332,7 @@ int ast_dsp_noise(struct ast_dsp *dsp, struct ast_frame *f, int *totalnoise) ast_log(LOG_WARNING, "Can't calculate noise on a non-voice frame\n"); return 0; } - if (f->subclass.format.id != AST_FORMAT_SLINEAR) { + if (!ast_format_is_slinear(&f->subclass.format)) { ast_log(LOG_WARNING, "Can only calculate noise on signed-linear frames :(\n"); return 0; } @@ -1370,30 +1363,31 @@ struct ast_frame *ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp, odata = af->data.ptr; len = af->datalen; /* Make sure we have short data */ - switch (af->subclass.format.id) { - case AST_FORMAT_SLINEAR: + if (ast_format_is_slinear(&af->subclass.format)) { shortdata = af->data.ptr; len = af->datalen / 2; - break; - case AST_FORMAT_ULAW: - case AST_FORMAT_TESTLAW: - shortdata = alloca(af->datalen * 2); - for (x = 0;x < len; x++) { - shortdata[x] = AST_MULAW(odata[x]); - } - break; - case AST_FORMAT_ALAW: - shortdata = alloca(af->datalen * 2); - for (x = 0; x < len; x++) { - shortdata[x] = AST_ALAW(odata[x]); + } else { + switch (af->subclass.format.id) { + case AST_FORMAT_ULAW: + case AST_FORMAT_TESTLAW: + shortdata = alloca(af->datalen * 2); + for (x = 0;x < len; x++) { + shortdata[x] = AST_MULAW(odata[x]); + } + break; + case AST_FORMAT_ALAW: + shortdata = alloca(af->datalen * 2); + for (x = 0; x < len; x++) { + shortdata[x] = AST_ALAW(odata[x]); + } + break; + default: + /*Display warning only once. Otherwise you would get hundreds of warnings every second */ + if (dsp->display_inband_dtmf_warning) + ast_log(LOG_WARNING, "Inband DTMF is not supported on codec %s. Use RFC2833\n", ast_getformatname(&af->subclass.format)); + dsp->display_inband_dtmf_warning = 0; + return af; } - break; - default: - /*Display warning only once. Otherwise you would get hundreds of warnings every second */ - if (dsp->display_inband_dtmf_warning) - ast_log(LOG_WARNING, "Inband DTMF is not supported on codec %s. Use RFC2833\n", ast_getformatname(&af->subclass.format)); - dsp->display_inband_dtmf_warning = 0; - return af; } /* Initially we do not want to mute anything */ @@ -1454,7 +1448,7 @@ struct ast_frame *ast_dsp_process(struct ast_channel *chan, struct ast_dsp *dsp, if (dsp->features & DSP_FEATURE_DIGIT_DETECT) { event = AST_FRAME_DTMF_END; event_digit = dsp->digit_state.digits[0]; - event_len = dsp->digit_state.digitlen[0] * 1000 / SAMPLE_RATE; + event_len = dsp->digit_state.digitlen[0] * 1000 / dsp->sample_rate; } memmove(&dsp->digit_state.digits[0], &dsp->digit_state.digits[1], dsp->digit_state.current_digits); memmove(&dsp->digit_state.digitlen[0], &dsp->digit_state.digitlen[1], dsp->digit_state.current_digits * sizeof(dsp->digit_state.digitlen[0])); @@ -1521,8 +1515,6 @@ done: } switch (af->subclass.format.id) { - case AST_FORMAT_SLINEAR: - break; case AST_FORMAT_ULAW: for (x = 0; x < len; x++) { odata[x] = AST_LIN2MU((unsigned short) shortdata[x]); @@ -1557,7 +1549,7 @@ static void ast_dsp_prog_reset(struct ast_dsp *dsp) dsp->gsamps = 0; for (x = 0; x < ARRAY_LEN(modes[dsp->progmode].freqs); x++) { if (modes[dsp->progmode].freqs[x]) { - goertzel_init(&dsp->freqs[x], (float)modes[dsp->progmode].freqs[x], dsp->gsamp_size); + goertzel_init(&dsp->freqs[x], (float)modes[dsp->progmode].freqs[x], dsp->gsamp_size, dsp->sample_rate); max = x + 1; } } @@ -1565,7 +1557,12 @@ static void ast_dsp_prog_reset(struct ast_dsp *dsp) dsp->ringtimeout= 0; } -struct ast_dsp *ast_dsp_new(void) +unsigned int ast_dsp_get_sample_rate(const struct ast_dsp *dsp) +{ + return dsp->sample_rate; +} + +static struct ast_dsp *__ast_dsp_new(unsigned int sample_rate) { struct ast_dsp *dsp; @@ -1575,8 +1572,9 @@ struct ast_dsp *ast_dsp_new(void) dsp->busycount = DSP_HISTORY; dsp->digitmode = DSP_DIGITMODE_DTMF; dsp->faxmode = DSP_FAXMODE_DETECT_CNG; + dsp->sample_rate = sample_rate; /* Initialize digit detector */ - ast_digit_detect_init(&dsp->digit_state, dsp->digitmode & DSP_DIGITMODE_MF); + ast_digit_detect_init(&dsp->digit_state, dsp->digitmode & DSP_DIGITMODE_MF, dsp->sample_rate); dsp->display_inband_dtmf_warning = 1; /* Initialize initial DSP progress detect parameters */ ast_dsp_prog_reset(dsp); @@ -1586,6 +1584,16 @@ struct ast_dsp *ast_dsp_new(void) return dsp; } +struct ast_dsp *ast_dsp_new(void) +{ + return __ast_dsp_new(DEFAULT_SAMPLE_RATE); +} + +struct ast_dsp *ast_dsp_new_with_rate(unsigned int sample_rate) +{ + return __ast_dsp_new(sample_rate); +} + void ast_dsp_set_features(struct ast_dsp *dsp, int features) { dsp->features = features; @@ -1672,7 +1680,7 @@ int ast_dsp_set_digitmode(struct ast_dsp *dsp, int digitmode) new = digitmode & (DSP_DIGITMODE_DTMF | DSP_DIGITMODE_MF | DSP_DIGITMODE_MUTECONF | DSP_DIGITMODE_MUTEMAX); if (old != new) { /* Must initialize structures if switching from MF to DTMF or vice-versa */ - ast_digit_detect_init(&dsp->digit_state, new & DSP_DIGITMODE_MF); + ast_digit_detect_init(&dsp->digit_state, new & DSP_DIGITMODE_MF, dsp->sample_rate); } dsp->digitmode = digitmode; return 0; -- cgit v1.2.3