summaryrefslogtreecommitdiff
path: root/main/dsp.c
diff options
context:
space:
mode:
authorDavid Vossel <dvossel@digium.com>2011-04-21 18:11:40 +0000
committerDavid Vossel <dvossel@digium.com>2011-04-21 18:11:40 +0000
commit7f23115ad2faeee58865afbec6bc11a43210fde7 (patch)
tree3be8de1bbbce5eb12a63028caa39167d69b54e96 /main/dsp.c
parentb8f253161b0bc60953fdd5a82b495dd0ddbf61a3 (diff)
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
Diffstat (limited to 'main/dsp.c')
-rw-r--r--main/dsp.c130
1 files changed, 69 insertions, 61 deletions
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;