diff --git a/linphone/linphone.kdevelop b/linphone/linphone.kdevelop index e5a3d2ce64470f3d5d5c5f2354464093384670a9..ee96b41389ccb3e138ad9010a8f80f4df922be08 100644 --- a/linphone/linphone.kdevelop +++ b/linphone/linphone.kdevelop @@ -387,6 +387,7 @@ <path>win32acm/wine/winuser.h</path> <path>win32acm/wineacm.h</path> <path>win32acm/wrapper.h</path> + <path>builddate.h</path> </blacklist> <build> <buildtool>make</buildtool> diff --git a/linphone/mediastreamer2/include/mediastreamer2/mediastream.h b/linphone/mediastreamer2/include/mediastreamer2/mediastream.h index bdc3eff71d7ea56a19df0c88fc328111defd4691..9224d920a2f7abf20131e6471fede521d60bc617 100644 --- a/linphone/mediastreamer2/include/mediastreamer2/mediastream.h +++ b/linphone/mediastreamer2/include/mediastreamer2/mediastream.h @@ -57,6 +57,7 @@ struct _AudioStream bool_t use_gc; bool_t use_agc; bool_t eq_active; + bool_t use_ng;/*noise gate*/ }; #ifdef __cplusplus @@ -114,6 +115,9 @@ void audio_stream_enable_automatic_gain_control(AudioStream *stream, bool_t val) void audio_stream_set_mic_gain(AudioStream *stream, float gain); +/*enable noise gate, must be done before start()*/ +void audio_stream_enable_noise_gate(AudioStream *stream, bool_t val); + /*enable parametric equalizer in the stream that goes to the speaker*/ void audio_stream_enable_equalizer(AudioStream *stream, bool_t enabled); diff --git a/linphone/mediastreamer2/include/mediastreamer2/msvolume.h b/linphone/mediastreamer2/include/mediastreamer2/msvolume.h index 14574eecdd1785029d24403ab14e022d337d68d9..9599a810717aa6daadc48d37ffeb80c866d2a44c 100644 --- a/linphone/mediastreamer2/include/mediastreamer2/msvolume.h +++ b/linphone/mediastreamer2/include/mediastreamer2/msvolume.h @@ -50,6 +50,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define MS_VOLUME_ENABLE_AGC MS_FILTER_METHOD(MS_VOLUME_ID,8,int) +#define MS_VOLUME_ENABLE_NOISE_GATE MS_FILTER_METHOD(MS_VOLUME_ID,9,int) + extern MSFilterDesc ms_volume_desc; #endif diff --git a/linphone/mediastreamer2/src/audiostream.c b/linphone/mediastreamer2/src/audiostream.c index 6105140c73167f84eaa0db5700e24f85e08eb62f..4eec84a1b7e0f8d6bb2aa1c772e620d1d2e9c9be 100644 --- a/linphone/mediastreamer2/src/audiostream.c +++ b/linphone/mediastreamer2/src/audiostream.c @@ -250,7 +250,7 @@ int audio_stream_start_full(AudioStream *stream, RtpProfile *profile, const char ms_filter_call_method(stream->ec,MS_FILTER_SET_SAMPLE_RATE,&pt->clock_rate); } - if (stream->el_type!=ELInactive || stream->use_gc){ + if (stream->el_type!=ELInactive || stream->use_gc || stream->use_ng){ stream->volsend=ms_filter_new(MS_VOLUME_ID); stream->volrecv=ms_filter_new(MS_VOLUME_ID); if (stream->el_type!=ELInactive){ @@ -258,6 +258,10 @@ int audio_stream_start_full(AudioStream *stream, RtpProfile *profile, const char ms_filter_call_method(stream->volrecv,MS_VOLUME_SET_PEER,stream->volsend); else ms_filter_call_method(stream->volsend,MS_VOLUME_SET_PEER,stream->volrecv); } + if (stream->use_ng){ + int tmp=1; + ms_filter_call_method(stream->volsend,MS_VOLUME_ENABLE_NOISE_GATE,&tmp); + } } if (stream->use_agc){ @@ -409,6 +413,7 @@ AudioStream *audio_stream_new(int locport, bool_t ipv6){ stream->play_dtmfs=TRUE; stream->use_gc=FALSE; stream->use_agc=FALSE; + stream->use_ng=FALSE; return stream; } @@ -437,6 +442,10 @@ void audio_stream_enable_automatic_gain_control(AudioStream *stream, bool_t val) stream->use_agc=val; } +void audio_stream_enable_noise_gate(AudioStream *stream, bool_t val){ + stream->use_ng=val; +} + void audio_stream_set_mic_gain(AudioStream *stream, float gain){ if (stream->volsend){ ms_filter_call_method(stream->volsend,MS_VOLUME_SET_GAIN,&gain); diff --git a/linphone/mediastreamer2/src/msvolume.c b/linphone/mediastreamer2/src/msvolume.c index 664eb94c9b5c231ace77e615d51d216928c23699..3c59553a3fb0a388fde51d60e4cedbcd3588da72 100644 --- a/linphone/mediastreamer2/src/msvolume.c +++ b/linphone/mediastreamer2/src/msvolume.c @@ -38,20 +38,24 @@ static const float noise_thres=0.1; typedef struct Volume{ float energy; float norm_en; - float gain; - float static_gain; + float gain; /*the one really applied, smoothed by noise gate and echo limiter*/ + float static_gain; /*the one fixed by the user*/ float gain_k; float thres; float force; + float target_gain; /*the target gain choosed by echo limiter and noise gate*/ MSFilter *peer; #ifdef HAVE_SPEEXDSP SpeexPreprocessState *speex_pp; #endif int sample_rate; int nsamples; + int ng_cut_time; /*noise gate cut time, after last speech detected*/ + int ng_noise_dur; MSBufferizer *buffer; bool_t ea_active; bool_t agc_enabled; + bool_t noise_gate_enabled; }Volume; static void volume_init(MSFilter *f){ @@ -68,6 +72,9 @@ static void volume_init(MSFilter *f){ v->buffer=ms_bufferizer_new(); v->sample_rate=8000; v->nsamples=80; + v->noise_gate_enabled=FALSE; + v->ng_cut_time=100;/*milliseconds*/ + v->ng_noise_dur=0; #ifdef HAVE_SPEEXDSP v->speex_pp=NULL; #endif @@ -130,7 +137,6 @@ static void volume_echo_avoider_process(Volume *v){ gain=v->static_gain; v->ea_active=FALSE; } - v->gain=(v->gain*(1-v->gain_k)) + (v->gain_k*gain); }else{ int peer_active=FALSE; ms_filter_call_method(v->peer,MS_VOLUME_GET_EA_STATE,&peer_active); @@ -141,17 +147,29 @@ static void volume_echo_avoider_process(Volume *v){ v->gain=gain; }else { gain=v->static_gain; - v->gain=(v->gain*(1-v->gain_k)) + (v->gain_k*gain); } } - + v->target_gain=gain; ms_message("ea_active=%i, peer_e=%f gain=%f gain_k=%f force=%f",v->ea_active,peer_e,v->gain, v->gain_k,v->force); } +static void volume_noise_gate_process(Volume *v , float energy, mblk_t *om){ + int nsamples=((om->b_wptr-om->b_rptr)/2); + if ((energy/max_e)<v->thres){ + v->ng_noise_dur+=(nsamples*1000)/v->sample_rate; + if (v->ng_noise_dur>v->ng_cut_time){ + v->target_gain=0; + } + }else{ + v->ng_noise_dur=0; + /*let the target gain unchanged, ie let the echo-limiter choose the gain*/ + } +} + static int volume_set_gain(MSFilter *f, void *arg){ float *farg=(float*)arg; Volume *v=(Volume*)f->data; - v->gain=v->static_gain=*farg; + v->gain=v->static_gain=v->target_gain=*farg; return 0; } @@ -205,6 +223,12 @@ static int volume_set_ea_force(MSFilter *f, void*arg){ return 0; } +static int volume_enable_noise_gate(MSFilter *f, void *arg){ + Volume *v=(Volume*)f->data; + v->noise_gate_enabled=*(int*)arg; + return 0; +} + static inline int16_t saturate(float val){ return (val>32767) ? 32767 : ( (val<-32767) ? -32767 : val); } @@ -219,13 +243,17 @@ static float update_energy(int16_t *signal, int numsamples, float last_energy_va return en; } -static void apply_gain(mblk_t *m, float gain){ +static void apply_gain(Volume *v, mblk_t *m){ int16_t *sample; + float gain=v->target_gain; + + if (gain==1 && v->gain==1) return; + v->gain=(v->gain*(1-v->gain_k)) + (v->gain_k*gain); for ( sample=(int16_t*)m->b_rptr; sample<(int16_t*)m->b_wptr; ++sample){ float s=*sample; - *sample=saturate(s*gain); + *sample=saturate(s*v->gain); } } @@ -273,10 +301,11 @@ static void volume_process(MSFilter *f){ if (v->peer){ volume_echo_avoider_process(v); - } - if (v->gain!=1){ - apply_gain(om,v->gain); - } + }else v->target_gain=v->static_gain; + + if (v->noise_gate_enabled) + volume_noise_gate_process(v,en,om); + apply_gain(v,om); ms_queue_put(f->outputs[0],om); } }else{ @@ -285,10 +314,11 @@ static void volume_process(MSFilter *f){ en=update_energy((int16_t*)m->b_rptr,(m->b_wptr-m->b_rptr)/2,en); if (v->peer){ volume_echo_avoider_process(v); - } - if (v->gain!=1){ - apply_gain(m,v->gain); - } + }else v->target_gain=v->static_gain; + + if (v->noise_gate_enabled) + volume_noise_gate_process(v,en,m); + apply_gain(v,m); ms_queue_put(f->outputs[0],m); } } @@ -306,6 +336,7 @@ static MSFilterMethod methods[]={ { MS_VOLUME_SET_EA_FORCE , volume_set_ea_force }, { MS_FILTER_SET_SAMPLE_RATE, volume_set_sample_rate }, { MS_VOLUME_ENABLE_AGC , volume_set_agc }, + { MS_VOLUME_ENABLE_NOISE_GATE, volume_enable_noise_gate}, { 0 , NULL } }; diff --git a/linphone/mediastreamer2/tests/mediastream.c b/linphone/mediastreamer2/tests/mediastream.c index b02df047e968dbc7bf6225736d66d6ba4c56d81a..0b1a58f758e917b41fd4dbee67faeeb54e01419d 100644 --- a/linphone/mediastreamer2/tests/mediastream.c +++ b/linphone/mediastreamer2/tests/mediastream.c @@ -40,6 +40,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. static int cond=1; +static const char * capture_card=NULL; +static bool_t use_ng=FALSE; + static void stop_handler(int signum) { cond--; @@ -127,7 +130,9 @@ const char *usage="mediastream --local <port> --remote <ip:port> --payload <payl "[ --height <pixels> ]\n" "[ --bitrate <bits per seconds>]\n" "[ --ec (enable echo canceller)]\n" - "[ --agc (enable automatic gain control)]\n"; + "[ --agc (enable automatic gain control)]\n" + "[ --ng (enable noise gate)]\n" + "[ --capture-card <index>] \n"; static void run_media_streams(int localport, const char *remote_ip, int remoteport, int payload, const char *fmtp, int jitter, bool_t ec, int bitrate, MSVideoSize vs, bool_t agc, bool_t eq); @@ -193,12 +198,17 @@ int main(int argc, char * argv[]) }else if (strcmp(argv[i],"--height")==0){ i++; vs.height=atoi(argv[i]); + }else if (strcmp(argv[i],"--capture-card")==0){ + i++; + capture_card=argv[i]; }else if (strcmp(argv[i],"--ec")==0){ ec=TRUE; }else if (strcmp(argv[i],"--agc")==0){ agc=TRUE; }else if (strcmp(argv[i],"--eq")==0){ eq=TRUE; + }else if (strcmp(argv[i],"--ng")==0){ + use_ng=1; } } @@ -230,11 +240,14 @@ void run_media_streams(int localport, const char *remote_ip, int remoteport, in if (pt->type!=PAYLOAD_VIDEO){ printf("Starting audio stream.\n"); MSSndCardManager *manager=ms_snd_card_manager_get(); + MSSndCard *capt= capture_card==NULL ? ms_snd_card_manager_get_default_capture_card(manager) : + ms_snd_card_manager_get_card(manager,capture_card); audio=audio_stream_new(localport,ms_is_ipv6(remote_ip)); audio_stream_enable_automatic_gain_control(audio,agc); + audio_stream_enable_noise_gate(audio,use_ng); audio_stream_start_now(audio,profile,remote_ip,remoteport,remoteport+1,payload,jitter, ms_snd_card_manager_get_default_playback_card(manager), - ms_snd_card_manager_get_default_capture_card(manager), + capt, ec); if (audio) session=audio->session; }else{