mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-03 11:25:35 +00:00
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
This commit is contained in:
130
main/dsp.c
130
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]);
|
||||
} 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;
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
Reference in New Issue
Block a user