static void discard_well_choosed_samples(mblk_t *m, int nsamples, int todrop) { int i; int16_t *samples = (int16_t *) m->b_rptr; int min_diff = 32768; int pos = 0; #ifdef TWO_SAMPLES_CRITERIA for (i = 0; i < nsamples - 1; ++i) { int tmp = abs((int) samples[i] - (int) samples[i + 1]); #else for (i = 0; i < nsamples - 2; ++i) { int tmp = abs((int) samples[i] - (int) samples[i + 1]) + abs((int) samples[i + 1] - (int) samples[i + 2]); #endif if (tmp <= min_diff) { pos = i; min_diff = tmp; } } /*ms_message("min_diff=%i at pos %i",min_diff, pos);*/ #ifdef TWO_SAMPLES_CRITERIA memmove(samples + pos, samples + pos + 1, (nsamples - pos - 1) * 2); #else memmove(samples + pos + 1, samples + pos + 2, (nsamples - pos - 2) * 2); #endif todrop--; m->b_wptr -= 2; nsamples--; if (todrop > 0) { /*repeat the same process again*/ discard_well_choosed_samples(m, nsamples, todrop); } } mblk_t *audio_flow_controller_process(AudioFlowController *ctl, mblk_t *m) { if (ctl->total_samples > 0 && ctl->target_samples > 0) { int nsamples = (m->b_wptr - m->b_rptr) / 2; if (ctl->target_samples * 16 > ctl->total_samples) { ms_warning("Too many samples to drop, dropping entire frames"); freemsg(m); ctl->current_pos += nsamples; m=NULL; } else { int th_dropped; int todrop; ctl->current_pos += nsamples; th_dropped = (ctl->target_samples * ctl->current_pos) / ctl->total_samples; todrop = th_dropped - ctl->current_dropped; if (todrop > 0) { if (todrop > nsamples) todrop = nsamples; discard_well_choosed_samples(m, nsamples, todrop); /*ms_message("th_dropped=%i, current_dropped=%i, %i samples dropped.",th_dropped,ctl->current_dropped,todrop);*/ ctl->current_dropped += todrop; } } if (ctl->current_pos >= ctl->total_samples) ctl->target_samples = 0; /*stop discarding*/ } return m; }
static void discard_well_choosed_samples(mblk_t *m, int nsamples, int todrop){ int i; int16_t *samples=(int16_t*)m->b_rptr; int min_diff=32768; int pos=0; #ifdef TWO_SAMPLES_CRITERIA for(i=0;i<nsamples-1;++i){ int tmp=abs((int)samples[i]- (int)samples[i+1]); #else for(i=0;i<nsamples-2;++i){ int tmp=abs((int)samples[i]- (int)samples[i+1])+abs((int)samples[i+1]- (int)samples[i+2]); #endif if (tmp<=min_diff){ pos=i; min_diff=tmp; } } /*ms_message("min_diff=%i at pos %i",min_diff, pos);*/ #ifdef TWO_SAMPLES_CRITERIA memmove(samples+pos,samples+pos+1,(nsamples-pos-1)*2); #else memmove(samples+pos+1,samples+pos+2,(nsamples-pos-2)*2); #endif todrop--; m->b_wptr-=2; nsamples--; if (todrop>0){ /*repeat the same process again*/ discard_well_choosed_samples(m,nsamples,todrop); } } mblk_t * audio_flow_controller_process(AudioFlowController *ctl, mblk_t *m){ if (ctl->total_samples>0 && ctl->target_samples>0){ int nsamples=(m->b_wptr-m->b_rptr)/2; if (ctl->target_samples*16>ctl->total_samples){ ms_warning("Too many samples to drop, dropping entire frames"); m->b_wptr=m->b_rptr; ctl->current_pos+=nsamples; }else{ int th_dropped; int todrop; ctl->current_pos+=nsamples; th_dropped=(ctl->target_samples*ctl->current_pos)/ctl->total_samples; todrop=th_dropped-ctl->current_dropped; if (todrop>0){ if (todrop>nsamples) todrop=nsamples; discard_well_choosed_samples(m,nsamples,todrop); /*ms_message("th_dropped=%i, current_dropped=%i, %i samples dropped.",th_dropped,ctl->current_dropped,todrop);*/ ctl->current_dropped+=todrop; } } if (ctl->current_pos>=ctl->total_samples) ctl->target_samples=0;/*stop discarding*/ } return m; } //#define EC_DUMP 1 #ifdef ANDROID #define EC_DUMP_PREFIX "/sdcard" #else #define EC_DUMP_PREFIX "." #endif static const float smooth_factor=0.05; static const int framesize=64; static const int flow_control_interval_ms=5000; typedef struct SpeexECState{ SpeexEchoState *ecstate; SpeexPreprocessState *den; MSBufferizer delayed_ref; MSBufferizer ref; MSBufferizer echo; int framesize; int filterlength; int samplerate; int delay_ms; int tail_length_ms; int nominal_ref_samples; int min_ref_samples; AudioFlowController afc; uint64_t flow_control_time; char *state_str; #ifdef EC_DUMP FILE *echofile; FILE *reffile; FILE *cleanfile; #endif bool_t echostarted; bool_t bypass_mode; bool_t using_zeroes; }SpeexECState; static void speex_ec_init(MSFilter *f){ SpeexECState *s=(SpeexECState *)ms_new(SpeexECState,1); s->samplerate=8000; ms_bufferizer_init(&s->delayed_ref); ms_bufferizer_init(&s->echo); ms_bufferizer_init(&s->ref); s->delay_ms=0; s->tail_length_ms=250; s->ecstate=NULL; s->framesize=framesize; s->den = NULL; s->state_str=NULL; s->using_zeroes=FALSE; s->echostarted=FALSE; s->bypass_mode=FALSE; #ifdef EC_DUMP { char *fname=ms_strdup_printf("%s/msspeexec-%p-echo.raw", EC_DUMP_PREFIX,f); s->echofile=fopen(fname,"w"); ms_free(fname); fname=ms_strdup_printf("%s/msspeexec-%p-ref.raw", EC_DUMP_PREFIX,f); s->reffile=fopen(fname,"w"); ms_free(fname); fname=ms_strdup_printf("%s/msspeexec-%p-clean.raw", EC_DUMP_PREFIX,f); s->cleanfile=fopen(fname,"w"); ms_free(fname); } #endif f->data=s; }