diff --git a/build/android/common.mk b/build/android/common.mk index 4db1f6809..c49d511bd 100644 --- a/build/android/common.mk +++ b/build/android/common.mk @@ -63,7 +63,8 @@ LOCAL_CFLAGS += \ -DENABLE_TRACE \ -DLINPHONE_VERSION=\"$(LINPHONE_VERSION)\" \ -DLINPHONE_PLUGINS_DIR=\"\\tmp\" \ - -DLOG_DOMAIN=$(MY_LOG_DOMAIN) + -DLOG_DOMAIN=$(MY_LOG_DOMAIN) \ + -DHAVE_EXOSIP_TRYLOCK=1 LOCAL_CFLAGS += -DIN_LINPHONE @@ -74,13 +75,18 @@ LOCAL_CFLAGS += -DHAVE_X264 endif endif +ifeq ($(USE_JAVAH),1) +LOCAL_CFLAGS += -DUSE_JAVAH +endif + LOCAL_C_INCLUDES += \ $(LOCAL_PATH) \ $(LOCAL_PATH)/include \ $(LOCAL_PATH)/../oRTP/include \ $(LOCAL_PATH)/../mediastreamer2/include \ $(LOCAL_PATH)/../../externals/exosip/include \ - $(LOCAL_PATH)/../../externals/osip/include + $(LOCAL_PATH)/../../externals/osip/include \ + $(LOCAL_PATH)/../../../gen LOCAL_LDLIBS += -llog -ldl diff --git a/coreapi/.gitignore b/coreapi/.gitignore index c5d084fa6..81d1b7647 100644 --- a/coreapi/.gitignore +++ b/coreapi/.gitignore @@ -5,3 +5,4 @@ Makefile.in *.lo *.la *.loT +liblinphone_gitversion.h diff --git a/coreapi/Makefile.am b/coreapi/Makefile.am index c706751ac..0c10c05da 100644 --- a/coreapi/Makefile.am +++ b/coreapi/Makefile.am @@ -1,7 +1,17 @@ +GITVERSION_FILE=liblinphone_gitversion.h +GITVERSION_FILE_TMP=liblinphone_gitversion.h.tmp +GITDESCRIBE=$(shell git describe) +GITREVISION=$(shell git rev-parse HEAD) + +ECHO=/bin/echo SUBDIRS=. help -EXTRA_DIST=linphonecore_jni.cc +EXTRA_DIST=linphonecore_jni.cc $(GITVERSION_FILE) + +BUILT_SOURCES=$(GITVERSION_FILE) + +CLEANFILES=$(GITVERSION_FILE) ## Process this file with automake to produce Makefile.in linphone_includedir=$(includedir)/linphone @@ -41,7 +51,8 @@ liblinphone_la_SOURCES=\ lsd.c linphonecore_utils.h \ ec-calibrator.c \ conference.c \ - linphone_tunnel.cc + linphone_tunnel.cc \ + $(GITVERSION_FILE) if BUILD_WIZARD liblinphone_la_SOURCES+=sipwizard.c @@ -97,3 +108,18 @@ AM_CFLAGS+= -DBUILD_WIZARD endif AM_CXXFLAGS=$(AM_CFLAGS) + +make_gitversion_h: + if test "$(GITDESCRIBE)" != "" ; then \ + $(ECHO) -n "#define LIBLINPHONE_GIT_VERSION \"$(GITDESCRIBE)\"" > $(GITVERSION_FILE_TMP) ; \ + elif test "$(GITREVISION)" != "" ; then \ + $(ECHO) -n "#define LIBLINPHONE_GIT_VERSION \"$(LINPHONE_VERSION)_$(GITREVISION)\"" > $(GITVERSION_FILE_TMP) ; \ + else \ + $(ECHO) -n "" > $(GITVERSION_FILE_TMP) ; \ + fi + if test "`cat $(GITVERSION_FILE_TMP)`" != "`cat $(srcdir)/$(GITVERSION_FILE)`" ; then \ + cp -f $(GITVERSION_FILE_TMP) $(srcdir)/$(GITVERSION_FILE) ; \ + fi + rm -f $(GITVERSION_FILE_TMP) ; + +$(GITVERSION_FILE): make_gitversion_h diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index e7f6a7b21..f99c9b224 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -27,9 +27,63 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. static void register_failure(SalOp *op, SalError error, SalReason reason, const char *details); -static bool_t media_parameters_changed(LinphoneCall *call, SalMediaDescription *oldmd, SalMediaDescription *newmd){ - if (call->params.in_conference!=call->current_params.in_conference) return TRUE; - return !sal_media_description_equals(oldmd,newmd) || call->up_bw!=linphone_core_get_upload_bandwidth(call->core); +static int media_parameters_changed(LinphoneCall *call, SalMediaDescription *oldmd, SalMediaDescription *newmd) { + if (call->params.in_conference != call->current_params.in_conference) return SAL_MEDIA_DESCRIPTION_CHANGED; + if (call->up_bw != linphone_core_get_upload_bandwidth(call->core)) return SAL_MEDIA_DESCRIPTION_CHANGED; + return sal_media_description_equals(oldmd, newmd); +} + +void linphone_core_update_streams_destinations(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription *old_md, SalMediaDescription *new_md) { + SalStreamDescription *old_audiodesc = NULL; + SalStreamDescription *old_videodesc = NULL; + SalStreamDescription *new_audiodesc = NULL; + SalStreamDescription *new_videodesc = NULL; + char *rtp_addr, *rtcp_addr; + int i; + + for (i = 0; i < old_md->nstreams; i++) { + if (old_md->streams[i].type == SalAudio) { + old_audiodesc = &old_md->streams[i]; + } else if (old_md->streams[i].type == SalVideo) { + old_videodesc = &old_md->streams[i]; + } + } + for (i = 0; i < new_md->nstreams; i++) { + if (new_md->streams[i].type == SalAudio) { + new_audiodesc = &new_md->streams[i]; + } else if (new_md->streams[i].type == SalVideo) { + new_videodesc = &new_md->streams[i]; + } + } + if (call->audiostream && new_audiodesc) { + rtp_addr = (new_audiodesc->rtp_addr[0] != '\0') ? new_audiodesc->rtp_addr : new_md->addr; + rtcp_addr = (new_audiodesc->rtcp_addr[0] != '\0') ? new_audiodesc->rtcp_addr : new_md->addr; + ms_message("Change audio stream destination: RTP=%s:%d RTCP=%s:%d", rtp_addr, new_audiodesc->rtp_port, rtcp_addr, new_audiodesc->rtcp_port); + rtp_session_set_remote_addr_full(call->audiostream->session, rtp_addr, new_audiodesc->rtp_port, rtcp_addr, new_audiodesc->rtcp_port); + } +#ifdef VIDEO_ENABLED + if (call->videostream && new_videodesc) { + rtp_addr = (new_videodesc->rtp_addr[0] != '\0') ? new_videodesc->rtp_addr : new_md->addr; + rtcp_addr = (new_videodesc->rtcp_addr[0] != '\0') ? new_videodesc->rtcp_addr : new_md->addr; + ms_message("Change video stream destination: RTP=%s:%d RTCP=%s:%d", rtp_addr, new_videodesc->rtp_port, rtcp_addr, new_videodesc->rtcp_port); + rtp_session_set_remote_addr_full(call->videostream->session, rtp_addr, new_videodesc->rtp_port, rtcp_addr, new_videodesc->rtcp_port); + } +#endif + + /* Copy address and port values from new_md to old_md since we will keep old_md as resultdesc */ + strcpy(old_md->addr, new_md->addr); + if (old_audiodesc && new_audiodesc) { + strcpy(old_audiodesc->rtp_addr, new_audiodesc->rtp_addr); + strcpy(old_audiodesc->rtcp_addr, new_audiodesc->rtcp_addr); + old_audiodesc->rtp_port = new_audiodesc->rtp_port; + old_audiodesc->rtcp_port = new_audiodesc->rtcp_port; + } + if (old_videodesc && new_videodesc) { + strcpy(old_videodesc->rtp_addr, new_videodesc->rtp_addr); + strcpy(old_videodesc->rtcp_addr, new_videodesc->rtcp_addr); + old_videodesc->rtp_port = new_videodesc->rtp_port; + old_videodesc->rtcp_port = new_videodesc->rtcp_port; + } } void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMediaDescription *new_md){ @@ -49,7 +103,8 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia if ((call->audiostream && call->audiostream->ticker) || (call->videostream && call->videostream->ticker)){ /* we already started media: check if we really need to restart it*/ if (oldmd){ - if (!media_parameters_changed(call,oldmd,new_md) && !call->playing_ringbacktone){ + int md_changed = media_parameters_changed(call, oldmd, new_md); + if ((md_changed == SAL_MEDIA_DESCRIPTION_UNCHANGED) && !call->playing_ringbacktone) { /*as nothing has changed, keep the oldmd */ call->resultdesc=oldmd; sal_media_description_unref(new_md); @@ -66,6 +121,12 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia } ms_message("No need to restart streams, SDP is unchanged."); return; + } else if ((md_changed == SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED) && !call->playing_ringbacktone) { + call->resultdesc = oldmd; + ms_message("Network parameters have changed, update them."); + linphone_core_update_streams_destinations(lc, call, oldmd, new_md); + sal_media_description_unref(new_md); + return; }else{ ms_message("Media descriptions are different, need to restart the streams."); } @@ -718,14 +779,33 @@ static void refer_received(Sal *sal, SalOp *op, const char *referto){ } } -static void text_received(Sal *sal, const char *from, const char *msg){ - LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal); - linphone_core_message_received(lc,from,msg,NULL); +static bool_t is_duplicate_msg(LinphoneCore *lc, const char *msg_id){ + MSList *elem=lc->last_recv_msg_ids; + int i; + bool_t is_duplicate=FALSE; + for(i=0;elem!=NULL;elem=elem->next,i++){ + if (strcmp((const char*)elem->data,msg_id)==0){ + is_duplicate=TRUE; + } + } + if (!is_duplicate){ + lc->last_recv_msg_ids=ms_list_prepend(lc->last_recv_msg_ids,ms_strdup(msg_id)); + } + if (i>=10){ + ms_free(elem->data); + ms_list_remove_link(lc->last_recv_msg_ids,elem); + } + return is_duplicate; } -void message_external_body_received(Sal *sal, const char *from, const char *url) { + + +static void text_received(Sal *sal, const SalMessage *msg){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal); - linphone_core_message_received(lc,from,NULL,url); + if (is_duplicate_msg(lc,msg->message_id)==FALSE){ + linphone_core_message_received(lc,msg->from,msg->text,msg->url); + } } + static void notify(SalOp *op, const char *from, const char *msg){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); LinphoneCall *call=(LinphoneCall*)sal_op_get_user_pointer (op); @@ -841,7 +921,6 @@ SalCallbacks linphone_sal_callbacks={ dtmf_received, refer_received, text_received, - message_external_body_received, text_delivery_update, notify, notify_presence, diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 70395841a..6f8c06ef2 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -27,7 +27,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "private.h" #include #include - +#include #include "mediastreamer2/mediastream.h" #include "mediastreamer2/msvolume.h" @@ -1189,7 +1189,7 @@ static void parametrize_equalizer(LinphoneCore *lc, AudioStream *st){ } void _post_configure_audio_stream(AudioStream *st, LinphoneCore *lc, bool_t muted){ - float mic_gain=lp_config_get_float(lc->config,"sound","mic_gain",1); + float mic_gain=lc->sound_conf.soft_mic_lev; float thres = 0; float recv_gain; float ng_thres=lp_config_get_float(lc->config,"sound","ng_thres",0.05); @@ -1197,7 +1197,7 @@ void _post_configure_audio_stream(AudioStream *st, LinphoneCore *lc, bool_t mute int dc_removal=lp_config_get_int(lc->config,"sound","dc_removal",0); if (!muted) - audio_stream_set_mic_gain(st,mic_gain); + linphone_core_set_mic_gain_db (lc, mic_gain); else audio_stream_set_mic_gain(st,0); @@ -1231,7 +1231,7 @@ void _post_configure_audio_stream(AudioStream *st, LinphoneCore *lc, bool_t mute } if (st->volrecv){ /* parameters for a limited noise-gate effect, using echo limiter threshold */ - float floorgain = 1/mic_gain; + float floorgain = 1/pow(10,(mic_gain)/10); int spk_agc=lp_config_get_int(lc->config,"sound","speaker_agc_enabled",0); ms_filter_call_method(st->volrecv, MS_VOLUME_ENABLE_AGC, &spk_agc); ms_filter_call_method(st->volrecv,MS_VOLUME_SET_NOISE_GATE_THRESHOLD,&ng_thres); diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index c39dfcbd9..381a60258 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -24,6 +24,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "lpconfig.h" #include "private.h" +#include #include #include #include "mediastreamer2/mediastream.h" @@ -40,13 +41,25 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #ifdef HAVE_CONFIG_H #include "config.h" +#include "liblinphone_gitversion.h" +#else +#ifndef LIBLINPHONE_GIT_VERSION +#define LIBLINPHONE_GIT_VERSION "unknown" #endif +#endif + /*#define UNSTANDART_GSM_11K 1*/ #define ROOT_CA_FILE PACKAGE_DATA_DIR "/linphone/rootca.pem" -static const char *liblinphone_version=LIBLINPHONE_VERSION; +static const char *liblinphone_version= +#ifdef LIBLINPHONE_GIT_VERSION + LIBLINPHONE_GIT_VERSION +#else + LIBLINPHONE_VERSION +#endif +; static void set_network_reachable(LinphoneCore* lc,bool_t isReachable, time_t curtime); static void linphone_core_run_hooks(LinphoneCore *lc); static void linphone_core_free_hooks(LinphoneCore *lc); @@ -413,7 +426,6 @@ static void sound_config_read(LinphoneCore *lc) int tmp; const char *tmpbuf; const char *devid; - float gain=0; #ifdef __linux /*alsadev let the user use custom alsa device within linphone*/ devid=lp_config_get_string(lc->config,"sound","alsadev",NULL); @@ -485,8 +497,8 @@ static void sound_config_read(LinphoneCore *lc) linphone_core_enable_agc(lc, lp_config_get_int(lc->config,"sound","agc",0)); - gain=lp_config_get_float(lc->config,"sound","playback_gain_db",0); - linphone_core_set_playback_gain_db (lc,gain); + linphone_core_set_playback_gain_db (lc,lp_config_get_float(lc->config,"sound","playback_gain_db",0)); + linphone_core_set_mic_gain_db (lc,lp_config_get_float(lc->config,"sound","mic_gain_db",0)); linphone_core_set_remote_ringback_tone (lc,lp_config_get_string(lc->config,"sound","ringback_tone",NULL)); @@ -583,6 +595,9 @@ static void sip_config_read(LinphoneCore *lc) tmp=lp_config_get_int(lc->config,"sip","inc_timeout",30); linphone_core_set_inc_timeout(lc,tmp); + tmp=lp_config_get_int(lc->config,"sip","in_call_timeout",0); + linphone_core_set_in_call_timeout(lc,tmp); + /* get proxies config */ for(i=0;; i++){ LinphoneProxyConfig *cfg=linphone_proxy_config_new_from_config_file(lc->config,i); @@ -1099,6 +1114,7 @@ static void misc_config_read (LinphoneCore *lc) { static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vtable, const char *config_path, const char *factory_config_path, void * userdata) { + ms_message("Initializing LinphoneCore %s", linphone_core_get_version()); memset (lc, 0, sizeof (LinphoneCore)); lc->data=userdata; lc->ringstream_autorelease=TRUE; @@ -1183,6 +1199,9 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta sal_set_user_pointer(lc->sal,lc); sal_set_callbacks(lc->sal,&linphone_sal_callbacks); + lc->network_last_check = 0; + lc->network_last_status = FALSE; + sip_setup_register_all(); sound_config_read(lc); net_config_read(lc); @@ -1794,24 +1813,22 @@ void linphone_core_enable_ipv6(LinphoneCore *lc, bool_t val){ static void monitor_network_state(LinphoneCore *lc, time_t curtime){ - static time_t last_check=0; - static bool_t last_status=FALSE; char result[LINPHONE_IPADDR_SIZE]; - bool_t new_status=last_status; + bool_t new_status=lc->network_last_status; /* only do the network up checking every five seconds */ - if (last_check==0 || (curtime-last_check)>=5){ + if (lc->network_last_check==0 || (curtime-lc->network_last_check)>=5){ linphone_core_get_local_ip_for(lc->sip_conf.ipv6_enabled ? AF_INET6 : AF_INET,NULL,result); if (strcmp(result,"::1")!=0 && strcmp(result,"127.0.0.1")!=0){ new_status=TRUE; }else new_status=FALSE; - last_check=curtime; - if (new_status!=last_status) { + lc->network_last_check=curtime; + if (new_status!=lc->network_last_status) { if (new_status){ ms_message("New local ip address is %s",result); } set_network_reachable(lc,new_status, curtime); - last_status=new_status; + lc->network_last_status=new_status; } } } @@ -1969,6 +1986,7 @@ void linphone_core_iterate(LinphoneCore *lc){ calls= lc->calls; while(calls!= NULL){ call = (LinphoneCall *)calls->data; + elapsed = curtime-call->start_time; /* get immediately a reference to next one in case the one we are going to examine is destroy and removed during linphone_core_start_invite() */ @@ -1985,7 +2003,6 @@ void linphone_core_iterate(LinphoneCore *lc){ linphone_core_start_invite(lc,call); } if (call->state==LinphoneCallIncomingReceived){ - elapsed=curtime-call->start_time; ms_message("incoming call ringing for %i seconds",elapsed); if (elapsed>lc->sip_conf.inc_timeout){ ms_message("incoming call timeout (%i)",lc->sip_conf.inc_timeout); @@ -1994,6 +2011,10 @@ void linphone_core_iterate(LinphoneCore *lc){ linphone_core_terminate_call(lc,call); } } + if (lc->sip_conf.in_call_timeout > 0 && elapsed>lc->sip_conf.in_call_timeout) { + ms_message("in call timeout (%i)",lc->sip_conf.in_call_timeout); + linphone_core_terminate_call(lc,call); + } } if (linphone_core_video_preview_enabled(lc)){ @@ -3201,6 +3222,26 @@ int linphone_core_get_inc_timeout(LinphoneCore *lc){ return lc->sip_conf.inc_timeout; } +/** + * Set the in call timeout in seconds. + * + * @ingroup call_control + * After this timeout period, the call is automatically hangup. +**/ +void linphone_core_set_in_call_timeout(LinphoneCore *lc, int seconds){ + lc->sip_conf.in_call_timeout=seconds; +} + +/** + * Returns the in call timeout + * + * @ingroup call_control + * See linphone_core_set_in_call_timeout() for details. +**/ +int linphone_core_get_in_call_timeout(LinphoneCore *lc){ + return lc->sip_conf.in_call_timeout; +} + void linphone_core_set_presence_info(LinphoneCore *lc,int minutes_away, const char *contact, LinphoneOnlineStatus presence_mode) @@ -3269,6 +3310,40 @@ void linphone_core_set_ring_level(LinphoneCore *lc, int level){ if (sndcard) ms_snd_card_set_level(sndcard,MS_SND_CARD_PLAYBACK,level); } +/** + * Allow to control microphone level: gain in db + * + * @ingroup media_parameters +**/ +void linphone_core_set_mic_gain_db (LinphoneCore *lc, float gaindb){ + float gain=gaindb; + LinphoneCall *call=linphone_core_get_current_call (lc); + AudioStream *st; + + lc->sound_conf.soft_mic_lev=gaindb; + + if (linphone_core_ready(lc)){ + lp_config_set_float(lc->config,"sound","mic_gain_db",lc->sound_conf.soft_mic_lev); + } + + if (call==NULL || (st=call->audiostream)==NULL){ + ms_message("linphone_core_set_mic_gain_db(): no active call."); + return; + } + if (st->volrecv){ + ms_filter_call_method(st->volsend,MS_VOLUME_SET_DB_GAIN,&gain); + }else ms_warning("Could not apply gain: gain control wasn't activated."); +} + +/** + * Get microphone gain in db. + * + * @ingroup media_parameters +**/ +float linphone_core_get_mic_gain_db(LinphoneCore *lc) { + return lc->sound_conf.soft_mic_lev; +} + /** * Allow to control play level before entering sound card: gain in db * @@ -3280,6 +3355,9 @@ void linphone_core_set_playback_gain_db (LinphoneCore *lc, float gaindb){ AudioStream *st; lc->sound_conf.soft_play_lev=gaindb; + if (linphone_core_ready(lc)){ + lp_config_set_float(lc->config,"sound","playback_gain_db",lc->sound_conf.soft_play_lev); + } if (call==NULL || (st=call->audiostream)==NULL){ ms_message("linphone_core_set_playback_gain_db(): no active call."); @@ -3680,7 +3758,7 @@ void linphone_core_mute_mic(LinphoneCore *lc, bool_t val){ } if (st!=NULL){ audio_stream_set_mic_gain(st, - (val==TRUE) ? 0 : lp_config_get_float(lc->config,"sound","mic_gain",1)); + (val==TRUE) ? 0 : pow(10,lc->sound_conf.soft_mic_lev/10)); if ( linphone_core_get_rtp_no_xmit_on_audio_mute(lc) ){ audio_stream_mute_rtp(st,val); } @@ -4044,7 +4122,7 @@ int linphone_core_set_video_device(LinphoneCore *lc, const char *id){ if (id!=NULL){ lc->video_conf.device=ms_web_cam_manager_get_cam(ms_web_cam_manager_get(),id); if (lc->video_conf.device==NULL){ - ms_warning("Could not found video device %s",id); + ms_warning("Could not find video device %s",id); } } if (lc->video_conf.device==NULL) @@ -4597,6 +4675,7 @@ void sip_config_uninit(LinphoneCore *lc) lp_config_set_int(lc->config,"sip","guess_hostname",config->guess_hostname); lp_config_set_string(lc->config,"sip","contact",config->contact); lp_config_set_int(lc->config,"sip","inc_timeout",config->inc_timeout); + lp_config_set_int(lc->config,"sip","in_call_timeout",config->in_call_timeout); lp_config_set_int(lc->config,"sip","use_info",config->use_info); lp_config_set_int(lc->config,"sip","use_rfc2833",config->use_rfc2833); lp_config_set_int(lc->config,"sip","use_ipv6",config->ipv6_enabled); @@ -4665,6 +4744,8 @@ static void sound_config_uninit(LinphoneCore *lc) ms_free(config->cards); lp_config_set_string(lc->config,"sound","remote_ring",config->remote_ring); + lp_config_set_float(lc->config,"sound","playback_gain_db",config->soft_play_lev); + lp_config_set_float(lc->config,"sound","mic_gain_db",config->soft_mic_lev); if (config->local_ring) ms_free(config->local_ring); if (config->remote_ring) ms_free(config->remote_ring); @@ -4784,6 +4865,9 @@ static void linphone_core_uninit(LinphoneCore *lc) ms_list_for_each(lc->call_logs,(void (*)(void*))linphone_call_log_destroy); lc->call_logs=ms_list_free(lc->call_logs); + + ms_list_for_each(lc->last_recv_msg_ids,ms_free); + lc->last_recv_msg_ids=ms_list_free(lc->last_recv_msg_ids); linphone_core_free_payload_types(lc); ortp_exit(); diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index d0ecc11a3..306f6b70b 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -1164,6 +1164,10 @@ void linphone_core_set_inc_timeout(LinphoneCore *lc, int seconds); int linphone_core_get_inc_timeout(LinphoneCore *lc); +void linphone_core_set_in_call_timeout(LinphoneCore *lc, int seconds); + +int linphone_core_get_in_call_timeout(LinphoneCore *lc); + void linphone_core_set_stun_server(LinphoneCore *lc, const char *server); const char * linphone_core_get_stun_server(const LinphoneCore *lc); @@ -1192,9 +1196,11 @@ int linphone_core_get_rec_level(LinphoneCore *lc); void linphone_core_set_ring_level(LinphoneCore *lc, int level); void linphone_core_set_play_level(LinphoneCore *lc, int level); +void linphone_core_set_mic_gain_db(LinphoneCore *lc, float level); +float linphone_core_get_mic_gain_db(LinphoneCore *lc); void linphone_core_set_playback_gain_db(LinphoneCore *lc, float level); - float linphone_core_get_playback_gain_db(LinphoneCore *lc); + void linphone_core_set_rec_level(LinphoneCore *lc, int level); const char * linphone_core_get_ringer_device(LinphoneCore *lc); const char * linphone_core_get_playback_device(LinphoneCore *lc); diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 080c8b009..85bd10259 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -17,6 +17,9 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include +#ifdef USE_JAVAH +#include "linphonecore_jni.h" +#endif #include "linphonecore_utils.h" #include @@ -2134,6 +2137,10 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setIncomingTimeout(JNIEn linphone_core_set_inc_timeout((LinphoneCore *)lc, timeout); } +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setInCallTimeout(JNIEnv *env, jobject thiz, jlong lc, jint timeout) { + linphone_core_set_in_call_timeout((LinphoneCore *)lc, timeout); +} + extern "C" jstring Java_org_linphone_core_LinphoneCoreImpl_getVersion(JNIEnv* env,jobject thiz,jlong ptr) { jstring jvalue =env->NewStringUTF(linphone_core_get_version()); return jvalue; diff --git a/coreapi/private.h b/coreapi/private.h index 07fd1c689..60587dbcd 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -382,6 +382,7 @@ typedef struct sip_config MSList *proxies; MSList *deleted_proxies; int inc_timeout; /*timeout after an un-answered incoming call is rejected*/ + int in_call_timeout; /*timeout after a call is hangup */ unsigned int keepalive_period; /* interval in ms between keep alive messages sent to the proxy server*/ LCSipTransports transports; bool_t use_info; @@ -436,6 +437,7 @@ typedef struct sound_config const char **cards; int latency; /* latency in samples of the current used sound device */ float soft_play_lev; /*playback gain in db.*/ + float soft_mic_lev; /*mic gain in db.*/ char rec_lev; char play_lev; char ring_lev; @@ -556,12 +558,16 @@ struct _LinphoneCore bool_t network_reachable; bool_t use_preview_window; + time_t network_last_check; + bool_t network_last_status; + bool_t ringstream_autorelease; bool_t pad[3]; int device_rotation; int max_calls; LinphoneTunnel *tunnel; char* device_id; + MSList *last_recv_msg_ids; }; LinphoneTunnel *linphone_core_tunnel_new(LinphoneCore *lc); diff --git a/coreapi/sal.c b/coreapi/sal.c index b349ad0a4..229ee577f 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -177,32 +177,40 @@ static bool_t payload_list_equals(const MSList *l1, const MSList *l2){ return TRUE; } -bool_t sal_stream_description_equals(const SalStreamDescription *sd1, const SalStreamDescription *sd2){ - if (sd1->proto!=sd2->proto) return FALSE; - if (sd1->type!=sd2->type) return FALSE; - if (strcmp(sd1->rtp_addr,sd2->rtp_addr)!=0) return FALSE; - if (sd1->rtp_port!=sd2->rtp_port) return FALSE; - if (strcmp(sd1->rtcp_addr,sd2->rtcp_addr)!=0) return FALSE; - if (sd1->rtcp_port!=sd2->rtcp_port) return FALSE; - if (!payload_list_equals(sd1->payloads,sd2->payloads)) return FALSE; - if (sd1->bandwidth!=sd2->bandwidth) return FALSE; - if (sd1->ptime!=sd2->ptime) return FALSE; - /* compare candidates: TODO */ - if (sd1->dir!=sd2->dir) return FALSE; - return TRUE; +int sal_stream_description_equals(const SalStreamDescription *sd1, const SalStreamDescription *sd2) { + int result = SAL_MEDIA_DESCRIPTION_UNCHANGED; + + /* A different proto should result in SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED but the encryption change + needs a stream restart for now, so use SAL_MEDIA_DESCRIPTION_CODEC_CHANGED */ + if (sd1->proto != sd2->proto) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; + + if (sd1->type != sd2->type) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; + if (strcmp(sd1->rtp_addr, sd2->rtp_addr) != 0) result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED; + if (sd1->rtp_port != sd2->rtp_port) { + if ((sd1->rtp_port == 0) || (sd2->rtp_port == 0)) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; + else result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED; + } + if (strcmp(sd1->rtcp_addr, sd2->rtcp_addr) != 0) result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED; + if (sd1->rtcp_port != sd2->rtcp_port) result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED; + if (!payload_list_equals(sd1->payloads, sd2->payloads)) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; + if (sd1->bandwidth != sd2->bandwidth) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; + if (sd1->ptime != sd2->ptime) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; + if (sd1->dir != sd2->dir) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; + + return result; } -bool_t sal_media_description_equals(const SalMediaDescription *md1, const SalMediaDescription *md2){ +int sal_media_description_equals(const SalMediaDescription *md1, const SalMediaDescription *md2) { + int result = SAL_MEDIA_DESCRIPTION_UNCHANGED; int i; - - if (strcmp(md1->addr,md2->addr)!=0) return FALSE; - if (md1->nstreams!=md2->nstreams) return FALSE; - if (md1->bandwidth!=md2->bandwidth) return FALSE; - for(i=0;instreams;++i){ - if (!sal_stream_description_equals(&md1->streams[i],&md2->streams[i])) - return FALSE; + + if (strcmp(md1->addr, md2->addr) != 0) result |= SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED; + if (md1->nstreams != md2->nstreams) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; + if (md1->bandwidth != md2->bandwidth) result |= SAL_MEDIA_DESCRIPTION_CODEC_CHANGED; + for(i = 0; i < md1->nstreams; ++i){ + result |= sal_stream_description_equals(&md1->streams[i], &md2->streams[i]); } - return TRUE; + return result; } static void assign_string(char **str, const char *arg){ diff --git a/coreapi/sal.h b/coreapi/sal.h index 2913096ca..e5eb1c190 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -53,6 +53,11 @@ typedef enum { SalTransportDTLS /*DTLS*/ }SalTransport; +#define SAL_MEDIA_DESCRIPTION_UNCHANGED 0x00 +#define SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED 0x01 +#define SAL_MEDIA_DESCRIPTION_CODEC_CHANGED 0x02 +#define SAL_MEDIA_DESCRIPTION_CHANGED (SAL_MEDIA_DESCRIPTION_NETWORK_CHANGED | SAL_MEDIA_DESCRIPTION_CODEC_CHANGED) + const char* sal_transport_to_string(SalTransport transport); SalTransport sal_transport_parse(const char*); /* Address manipulation API*/ @@ -183,13 +188,20 @@ typedef struct SalMediaDescription{ bool_t ice_completed; } SalMediaDescription; +typedef struct SalMessage{ + const char *from; + const char *text; + const char *url; + const char *message_id; +}SalMessage; + #define SAL_MEDIA_DESCRIPTION_MAX_MESSAGE_ATTRIBUTES 5 SalMediaDescription *sal_media_description_new(); void sal_media_description_ref(SalMediaDescription *md); void sal_media_description_unref(SalMediaDescription *md); bool_t sal_media_description_empty(const SalMediaDescription *md); -bool_t sal_media_description_equals(const SalMediaDescription *md1, const SalMediaDescription *md2); +int sal_media_description_equals(const SalMediaDescription *md1, const SalMediaDescription *md2); bool_t sal_media_description_has_dir(const SalMediaDescription *md, SalStreamDir dir); SalStreamDescription *sal_media_description_find_stream(SalMediaDescription *md, SalMediaProto proto, SalStreamType type); @@ -275,8 +287,7 @@ typedef void (*SalOnRegisterFailure)(SalOp *op, SalError error, SalReason reason typedef void (*SalOnVfuRequest)(SalOp *op); typedef void (*SalOnDtmfReceived)(SalOp *op, char dtmf); typedef void (*SalOnRefer)(Sal *sal, SalOp *op, const char *referto); -typedef void (*SalOnTextReceived)(Sal *sal, const char *from, const char *msg); -typedef void (*SalOnMessageExternalBodyReceived)(Sal *sal, const char *from, const char *url); +typedef void (*SalOnTextReceived)(Sal *sal, const SalMessage *msg); typedef void (*SalOnTextDeliveryUpdate)(SalOp *op, SalTextDeliveryStatus status); typedef void (*SalOnNotify)(SalOp *op, const char *from, const char *event); typedef void (*SalOnNotifyRefer)(SalOp *op, SalReferStatus state); @@ -302,7 +313,6 @@ typedef struct SalCallbacks{ SalOnDtmfReceived dtmf_received; SalOnRefer refer_received; SalOnTextReceived text_received; - SalOnMessageExternalBodyReceived message_external_body; SalOnTextDeliveryUpdate text_delivery_update; SalOnNotify notify; SalOnNotifyPresence notify_presence; diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index b5f6cc10f..2f6d4ae80 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -343,8 +343,6 @@ void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs){ ctx->callbacks.text_received=(SalOnTextReceived)unimplemented_stub; if (ctx->callbacks.ping_reply==NULL) ctx->callbacks.ping_reply=(SalOnPingReply)unimplemented_stub; - if (ctx->callbacks.message_external_body==NULL) - ctx->callbacks.message_external_body=(SalOnMessageExternalBodyReceived)unimplemented_stub; } int sal_unlisten_ports(Sal *ctx){ @@ -415,6 +413,7 @@ int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int i int dont_use_101 = !ctx->use_101; // Copy char to int to avoid bad alignment eXosip_set_option(EXOSIP_OPT_DONT_SEND_101,&dont_use_101); sal_set_dscp(ctx,ctx->dscp); + sal_use_dates(ctx,ctx->add_dates); ipv6=strchr(addr,':')!=NULL; eXosip_enable_ipv6(ipv6); @@ -1727,11 +1726,13 @@ static bool_t comes_from_local_if(osip_message_t *msg){ static void text_received(Sal *sal, eXosip_event_t *ev){ osip_body_t *body=NULL; - char *from=NULL,*msg; + char *from=NULL,*msg=NULL; osip_content_type_t* content_type; osip_uri_param_t* external_body_url; char unquoted_external_body_url [256]; int external_body_size=0; + SalMessage salmsg; + char message_id[256]={0}; content_type= osip_message_get_content_type(ev->request); if (!content_type) { @@ -1743,13 +1744,12 @@ static void text_received(Sal *sal, eXosip_event_t *ev){ && strcmp(content_type->type, "text")==0 && content_type->subtype && strcmp(content_type->subtype, "plain")==0 ) { - osip_message_get_body(ev->request,0,&body); - if (body==NULL){ - ms_error("Could not get text message from SIP body"); - return; - } - msg=body->body; - sal->callbacks.text_received(sal,from,msg); + osip_message_get_body(ev->request,0,&body); + if (body==NULL){ + ms_error("Could not get text message from SIP body"); + return; + } + msg=body->body; } if (content_type->type && strcmp(content_type->type, "message")==0 && content_type->subtype @@ -1761,11 +1761,18 @@ static void text_received(Sal *sal, eXosip_event_t *ev){ ,&external_body_url->gvalue[1] ,external_body_size=MIN(strlen(external_body_url->gvalue)-1,sizeof(unquoted_external_body_url))); unquoted_external_body_url[external_body_size-1]='\0'; - sal->callbacks.message_external_body(sal,from,unquoted_external_body_url); - } else { ms_warning("Unsupported content type [%s/%s]",content_type->type,content_type->subtype); + osip_free(from); + return; } + snprintf(message_id,sizeof(message_id)-1,"%s%s",ev->request->call_id->number,ev->request->cseq->number); + + salmsg.from=from; + salmsg.text=msg; + salmsg.url=external_body_size>0 ? unquoted_external_body_url : NULL; + salmsg.message_id=message_id; + sal->callbacks.text_received(sal,&salmsg); osip_free(from); } diff --git a/java/common/org/linphone/core/LinphoneCallLog.java b/java/common/org/linphone/core/LinphoneCallLog.java index 1abdb7bed..8d0e4073a 100644 --- a/java/common/org/linphone/core/LinphoneCallLog.java +++ b/java/common/org/linphone/core/LinphoneCallLog.java @@ -38,7 +38,7 @@ public interface LinphoneCallLog { /** * Call success. */ - public final static CallStatus Sucess = new CallStatus(0,"Sucess"); + public final static CallStatus Success = new CallStatus(0,"Sucess"); /** * Call aborted. */ diff --git a/java/common/org/linphone/core/LinphoneChatMessage.java b/java/common/org/linphone/core/LinphoneChatMessage.java index db75f9116..74f0961ac 100644 --- a/java/common/org/linphone/core/LinphoneChatMessage.java +++ b/java/common/org/linphone/core/LinphoneChatMessage.java @@ -7,8 +7,7 @@ public interface LinphoneChatMessage { interface StateListener{ void onLinphoneChatMessageStateChanged(LinphoneChatMessage msg, State state); } - static class State { - @SuppressWarnings("rawtypes") + public static class State { static private Vector values = new Vector(); private final int mValue; public final int value() {return mValue;} @@ -31,7 +30,6 @@ public interface LinphoneChatMessage { */ public final static State NotDelivered = new State(3,"NotDelivered"); - @SuppressWarnings("unchecked") private State(int value,String stringValue) { mValue = value; values.addElement(this); diff --git a/java/common/org/linphone/core/LinphoneCore.java b/java/common/org/linphone/core/LinphoneCore.java index 562ae86cd..49b15c369 100644 --- a/java/common/org/linphone/core/LinphoneCore.java +++ b/java/common/org/linphone/core/LinphoneCore.java @@ -189,21 +189,21 @@ public interface LinphoneCore { * Media (RTP) encryption enum-like. * */ - static public class MediaEncryption { + static public final class MediaEncryption { static private Vector values = new Vector(); /** * None */ - static public MediaEncryption None = new MediaEncryption(0,"None"); + static public final MediaEncryption None = new MediaEncryption(0,"None"); /** * SRTP */ - static public MediaEncryption SRTP = new MediaEncryption(1,"SRTP"); + static public final MediaEncryption SRTP = new MediaEncryption(1,"SRTP"); /** * ZRTP */ - static public MediaEncryption ZRTP = new MediaEncryption(2,"ZRTP"); + static public final MediaEncryption ZRTP = new MediaEncryption(2,"ZRTP"); protected final int mValue; private final String mStringValue; @@ -843,4 +843,10 @@ public interface LinphoneCore { * automatically declined. **/ void setIncomingTimeout(int timeout); + + /** + * Set the call timeout in seconds. + * Once this time is elapsed (ringing included), the call is automatically hung up. + **/ + void setInCallTimeout(int timeout); } diff --git a/java/common/org/linphone/core/PayloadType.java b/java/common/org/linphone/core/PayloadType.java index 952da57d2..648d77465 100644 --- a/java/common/org/linphone/core/PayloadType.java +++ b/java/common/org/linphone/core/PayloadType.java @@ -21,4 +21,6 @@ package org.linphone.core; public interface PayloadType { String getMime(); + + int getRate(); } diff --git a/java/impl/org/linphone/core/LinphoneCoreImpl.java b/java/impl/org/linphone/core/LinphoneCoreImpl.java index 6059915ea..072934204 100644 --- a/java/impl/org/linphone/core/LinphoneCoreImpl.java +++ b/java/impl/org/linphone/core/LinphoneCoreImpl.java @@ -115,6 +115,7 @@ class LinphoneCoreImpl implements LinphoneCore { private native void setAudioPortRange(long nativePtr, int minPort, int maxPort); private native void setVideoPortRange(long nativePtr, int minPort, int maxPort); private native void setIncomingTimeout(long nativePtr, int timeout); + private native void setInCallTimeout(long nativePtr, int timeout); LinphoneCoreImpl(LinphoneCoreListener listener, File userConfig,File factoryConfig,Object userdata) throws IOException { mListener=listener; @@ -782,4 +783,9 @@ class LinphoneCoreImpl implements LinphoneCore { public void setIncomingTimeout(int timeout) { setIncomingTimeout(nativePtr, timeout); } + + public void setInCallTimeout(int timeout) + { + setInCallTimeout(nativePtr, timeout); + } } diff --git a/mediastreamer2 b/mediastreamer2 index 49f616a4b..f743c8b4a 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 49f616a4b8d32b1ab2adeaa68c8f614ef77276da +Subproject commit f743c8b4ab7ec010a96aa53f2e179cea69bfb4e6