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; }
msandroid_sound_read_data() : audio_record(0),audio_record_class(0),read_buff(0),read_chunk_size(0) { ms_bufferizer_init(&rb); aec=NULL; }
static void channel_init(ConfState *s, Channel *chan, int pos){ #ifndef DISABLE_SPEEX float f; int val; #endif memset(chan, 0, sizeof(Channel)); ms_bufferizer_init(&chan->buff); #ifndef DISABLE_SPEEX chan->speex_pp = speex_preprocess_state_init(s->conf_gran/2, s->samplerate); if (chan->speex_pp==NULL) return; /* configure sound card input on pin 0 */ val=0; if (pos==0) val=1; if (s->enable_halfduplex>0 && pos%2==1) val=1; speex_preprocess_ctl(chan->speex_pp, SPEEX_PREPROCESS_SET_DENOISE, &val); val = -30; speex_preprocess_ctl(chan->speex_pp, SPEEX_PREPROCESS_SET_NOISE_SUPPRESS, &val); /* enable VAD only on incoming RTP stream */ val=0; if (pos%2==1 || (pos==0 && s->enable_halfduplex>0)) { val=1; } speex_preprocess_ctl(chan->speex_pp, SPEEX_PREPROCESS_SET_VAD, &val); if (s->vad_prob_start>0 && s->vad_prob_continue>0) { val = s->vad_prob_start; // xx% speex_preprocess_ctl(chan->speex_pp, SPEEX_PREPROCESS_SET_PROB_START, &val); val = s->vad_prob_continue; // xx% speex_preprocess_ctl(chan->speex_pp, SPEEX_PREPROCESS_SET_PROB_CONTINUE, &val); } /* enable AGC only on local soundcard */ val=0; f=12000; if (s->agc_level>0 && pos==0) val=1; else if (pos==0 && s->enable_halfduplex>0) val=1; else if ( pos%2==1 && s->enable_halfduplex>0) val=1; //1; should not do that if (s->agc_level>0) f=(float)s->agc_level; speex_preprocess_ctl(chan->speex_pp, SPEEX_PREPROCESS_SET_AGC, &val); speex_preprocess_ctl(chan->speex_pp, SPEEX_PREPROCESS_SET_AGC_LEVEL, &f); val=s->max_gain; if ( pos%2==1 && s->enable_halfduplex>0) val=1; speex_preprocess_ctl(chan->speex_pp, SPEEX_PREPROCESS_SET_AGC_MAX_GAIN, &val); val=0; #if 0 val=1; // do more testing #endif speex_preprocess_ctl(chan->speex_pp, SPEEX_PREPROCESS_SET_DEREVERB, &val); f=(float).4; speex_preprocess_ctl(chan->speex_pp, SPEEX_PREPROCESS_SET_DEREVERB_DECAY, &f); f=(float).3; speex_preprocess_ctl(chan->speex_pp, SPEEX_PREPROCESS_SET_DEREVERB_LEVEL, &f); #endif }