diff --git a/linphone/coreapi/linphonecore.c b/linphone/coreapi/linphonecore.c index fa50ccac9..c55f1dbaf 100644 --- a/linphone/coreapi/linphonecore.c +++ b/linphone/coreapi/linphonecore.c @@ -22,6 +22,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "lpconfig.h" #include "private.h" #include "mediastreamer2/mediastream.h" +#include "mediastreamer2/msvolume.h" #include #include "sdphandler.h" @@ -407,6 +408,9 @@ void sound_config_read(LinphoneCore *lc) linphone_core_enable_echo_cancelation(lc, lp_config_get_int(lc->config,"sound","echocancelation",0)); + + linphone_core_enable_echo_limiter(lc, + lp_config_get_int(lc->config,"sound","echolimiter",0)); } void sip_config_read(LinphoneCore *lc) @@ -1409,6 +1413,9 @@ int linphone_core_change_qos(LinphoneCore *lc, int answer) void linphone_core_init_media_streams(LinphoneCore *lc){ lc->audiostream=audio_stream_new(linphone_core_get_audio_port(lc),linphone_core_ipv6_enabled(lc)); + if (linphone_core_echo_limiter_enabled(lc)){ + audio_stream_enable_echo_limiter(lc->audiostream,TRUE); + } #ifdef VIDEO_ENABLED if (lc->video_conf.display || lc->video_conf.capture) lc->videostream=video_stream_new(linphone_core_get_video_port(lc),linphone_core_ipv6_enabled(lc)); @@ -1423,6 +1430,23 @@ static void linphone_core_dtmf_received(RtpSession* s, int dtmf, void* user_data lc->vtable.dtmf_received(lc, dtmf); } +static void post_configure_audio_streams(LinphoneCore *lc){ + AudioStream *st=lc->audiostream; + if (st->volrecv && st->volsend){ + float speed=lp_config_get_float(lc->config,"sound","el_speed",-1); + float thres=lp_config_get_float(lc->config,"sound","el_thres",-1); + if (speed!=-1) + ms_filter_call_method(st->volsend,MS_VOLUME_SET_EA_SPEED,&speed); + if (thres!=-1) + ms_filter_call_method(st->volrecv,MS_VOLUME_SET_EA_THRESHOLD,&thres); + } + if (lc->vtable.dtmf_received!=NULL){ + /* replace by our default action*/ + audio_stream_play_received_dtmfs(lc->audiostream,FALSE); + rtp_session_signal_connect(lc->audiostream->session,"telephone-event",(RtpCallback)linphone_core_dtmf_received,(unsigned long)lc); + } +} + void linphone_core_start_media_streams(LinphoneCore *lc, LinphoneCall *call){ osip_from_t *me=linphone_core_get_primary_contact_parsed(lc); const char *tool="linphone-" LINPHONE_VERSION; @@ -1467,11 +1491,7 @@ void linphone_core_start_media_streams(LinphoneCore *lc, LinphoneCall *call){ lc->play_file, lc->rec_file); } - if (lc->vtable.dtmf_received!=NULL){ - /* replace by our default action*/ - audio_stream_play_received_dtmfs(lc->audiostream,FALSE); - rtp_session_signal_connect(lc->audiostream->session,"telephone-event",(RtpCallback)linphone_core_dtmf_received,(unsigned long)lc); - } + post_configure_audio_streams(lc); audio_stream_set_rtcp_information(lc->audiostream, cname, tool); } #ifdef VIDEO_ENABLED @@ -1884,6 +1904,14 @@ bool_t linphone_core_echo_cancelation_enabled(LinphoneCore *lc){ return lc->sound_conf.ec; } +void linphone_core_enable_echo_limiter(LinphoneCore *lc, bool_t val){ + lc->sound_conf.ea=val; +} + +bool_t linphone_core_echo_limiter_enabled(const LinphoneCore *lc){ + return lc->sound_conf.ea; +} + void linphone_core_send_dtmf(LinphoneCore *lc,char dtmf) { diff --git a/linphone/coreapi/linphonecore.h b/linphone/coreapi/linphonecore.h index 0cfec9cbb..7f36f6df3 100644 --- a/linphone/coreapi/linphonecore.h +++ b/linphone/coreapi/linphonecore.h @@ -103,10 +103,10 @@ typedef struct sound_config char play_lev; char ring_lev; char source; - char pad; char *local_ring; char *remote_ring; bool_t ec; + bool_t ea; } sound_config_t; typedef struct codecs_config @@ -681,6 +681,9 @@ int linphone_core_preview_ring(LinphoneCore *lc, const char *ring,LinphoneCoreCb void linphone_core_enable_echo_cancelation(LinphoneCore *lc, bool_t val); bool_t linphone_core_echo_cancelation_enabled(LinphoneCore *lc); +void linphone_core_enable_echo_limiter(LinphoneCore *lc, bool_t val); +bool_t linphone_core_echo_limiter_enabled(const LinphoneCore *lc); + void linphone_core_set_presence_info(LinphoneCore *lc,int minutes_away,const char *contact,LinphoneOnlineStatus os); LinphoneOnlineStatus linphone_core_get_presence_info(const LinphoneCore *lc); diff --git a/linphone/coreapi/lpconfig.c b/linphone/coreapi/lpconfig.c index 09a8e1b3f..4d3ba5660 100644 --- a/linphone/coreapi/lpconfig.c +++ b/linphone/coreapi/lpconfig.c @@ -290,6 +290,14 @@ int lp_config_get_int(LpConfig *lpconfig,const char *section, const char *key, i else return default_value; } +float lp_config_get_float(LpConfig *lpconfig,const char *section, const char *key, float default_value){ + const char *str=lp_config_get_string(lpconfig,section,key,NULL); + float ret; + if (str==NULL) return default_value; + sscanf(str,"%f",&ret); + return ret; +} + void lp_config_set_string(LpConfig *lpconfig,const char *section, const char *key, const char *value){ LpItem *item; LpSection *sec=lp_config_find_section(lpconfig,section); diff --git a/linphone/coreapi/lpconfig.h b/linphone/coreapi/lpconfig.h index b2f3372f7..5c146e7d3 100644 --- a/linphone/coreapi/lpconfig.h +++ b/linphone/coreapi/lpconfig.h @@ -34,6 +34,7 @@ extern "C" { LpConfig * lp_config_new(const char *filename); const char *lp_config_get_string(LpConfig *lpconfig, const char *section, const char *key, const char *default_string); int lp_config_get_int(LpConfig *lpconfig,const char *section, const char *key, int default_value); +float lp_config_get_float(LpConfig *lpconfig,const char *section, const char *key, float default_value); void lp_config_set_string(LpConfig *lpconfig,const char *section, const char *key, const char *value); void lp_config_set_int(LpConfig *lpconfig,const char *section, const char *key, int value); int lp_config_sync(LpConfig *lpconfig); diff --git a/linphone/mediastreamer2/include/mediastreamer2/mediastream.h b/linphone/mediastreamer2/include/mediastreamer2/mediastream.h index 5c575f73f..c47397ff8 100644 --- a/linphone/mediastreamer2/include/mediastreamer2/mediastream.h +++ b/linphone/mediastreamer2/include/mediastreamer2/mediastream.h @@ -45,7 +45,7 @@ struct _AudioStream unsigned int last_packet_count; time_t last_packet_time; bool_t play_dtmfs; - bool_t use_ea; /*use echo avoider: two MSVolume, measured input level controlling local output level*/ + bool_t use_ea; /*use echo limiter: two MSVolume, measured input level controlling local output level*/ }; #ifdef __cplusplus @@ -92,8 +92,8 @@ void audio_stream_set_relay_session_id(AudioStream *stream, const char *relay_se /*returns true if we are still receiving some data from remote end in the last timeout seconds*/ bool_t audio_stream_alive(AudioStream * stream, int timeout); -/*enable echo-avoider dispositve: one MSVolume in input branch controls a MSVolume in the output branch*/ -void audio_stream_enable_echo_avoider(AudioStream *stream, bool_t enabled); +/*enable echo-limiter dispositve: one MSVolume in input branch controls a MSVolume in the output branch*/ +void audio_stream_enable_echo_limiter(AudioStream *stream, bool_t enabled); /* stop the above process*/ void audio_stream_stop (AudioStream * stream); diff --git a/linphone/mediastreamer2/include/mediastreamer2/msvolume.h b/linphone/mediastreamer2/include/mediastreamer2/msvolume.h index 01901519f..807934ea0 100644 --- a/linphone/mediastreamer2/include/mediastreamer2/msvolume.h +++ b/linphone/mediastreamer2/include/mediastreamer2/msvolume.h @@ -42,6 +42,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define MS_VOLUME_SET_PEER MS_FILTER_METHOD(MS_VOLUME_ID,4, MSFilter ) +#define MS_VOLUME_SET_EA_THRESHOLD MS_FILTER_METHOD(MS_VOLUME_ID,5,float) + +#define MS_VOLUME_SET_EA_SPEED MS_FILTER_METHOD(MS_VOLUME_ID,6,float) + extern MSFilterDesc ms_volume_desc; #endif diff --git a/linphone/mediastreamer2/src/audiostream.c b/linphone/mediastreamer2/src/audiostream.c index 2d86677e8..577189b42 100644 --- a/linphone/mediastreamer2/src/audiostream.c +++ b/linphone/mediastreamer2/src/audiostream.c @@ -393,7 +393,7 @@ void audio_stream_set_relay_session_id(AudioStream *stream, const char *id){ ms_filter_call_method(stream->rtpsend, MS_RTP_SEND_SET_RELAY_SESSION_ID,(void*)id); } -void audio_stream_enable_echo_avoider(AudioStream *stream, bool_t enabled){ +void audio_stream_enable_echo_limiter(AudioStream *stream, bool_t enabled){ stream->use_ea=enabled; } diff --git a/linphone/mediastreamer2/src/msvolume.c b/linphone/mediastreamer2/src/msvolume.c index 5258a072f..7c7f8a85e 100644 --- a/linphone/mediastreamer2/src/msvolume.c +++ b/linphone/mediastreamer2/src/msvolume.c @@ -32,6 +32,8 @@ typedef struct Volume{ float norm_en; float gain; float static_gain; + float gain_k; + float thres; MSFilter *peer; bool_t ea_active; }Volume; @@ -42,8 +44,9 @@ static void volume_init(MSFilter *f){ v->norm_en=0; v->static_gain=v->gain=1; v->ea_active=FALSE; + v->gain_k=gain_k; + v->thres=noise_thres; f->data=v; - } static void volume_uninit(MSFilter *f){ @@ -69,7 +72,7 @@ static void volume_echo_avoider_process(Volume *v){ float gain; ms_filter_call_method(v->peer,MS_VOLUME_GET_LINEAR,&peer_e); if (v->ea_active){ - if (peer_e>noise_thres){ + if (peer_e>v->thres){ /*lower our output*/ gain=v->static_gain*(1-peer_e); }else { @@ -79,13 +82,13 @@ static void volume_echo_avoider_process(Volume *v){ }else{ int peer_active=FALSE; ms_filter_call_method(v->peer,MS_VOLUME_GET_EA_STATE,&peer_active); - if (peer_e>noise_thres && ! peer_active){ + if (peer_e>v->thres && ! peer_active){ /*lower our output*/ gain=v->static_gain*(1-peer_e); v->ea_active=TRUE; }else gain=v->static_gain; } - v->gain=(v->gain*(1-gain_k)) + (gain_k*coef); + v->gain=(v->gain*(1-v->gain_k)) + (v->gain_k*v->gain); } static int volume_set_gain(MSFilter *f, void *arg){ @@ -110,6 +113,28 @@ static int volume_set_peer(MSFilter *f, void *arg){ return 0; } +static int volume_set_ea_threshold(MSFilter *f, void*arg){ + Volume *v=(Volume*)f->data; + float val=*(float*)arg; + if (val<0 || val>1) { + ms_error("Error: threshold must be in range [0..1]"); + return -1; + } + v->thres=val; + return 0; +} + +static int volume_set_ea_speed(MSFilter *f, void*arg){ + Volume *v=(Volume*)f->data; + float val=*(float*)arg; + if (val<0 || val>1) { + ms_error("Error: speed must be in range [0..1]"); + return -1; + } + v->gain_k=val; + return 0; +} + static inline int16_t saturate(float val){ return (val>32767) ? 32767 : ( (val<-32767) ? -32767 : val); } @@ -148,6 +173,8 @@ static MSFilterMethod methods[]={ { MS_VOLUME_SET_GAIN , volume_set_gain }, { MS_VOLUME_GET_EA_STATE , volume_get_ea_state }, { MS_VOLUME_SET_PEER , volume_set_peer }, + { MS_VOLUME_SET_EA_THRESHOLD , volume_set_ea_threshold }, + { MS_VOLUME_SET_EA_SPEED , volume_set_ea_speed }, { 0 , NULL } };