From: Jehan Monnier Date: Mon, 11 Jul 2011 17:04:30 +0000 (+0200) Subject: merge public branch X-Git-Url: http://sjero.net/git/?p=linphone;a=commitdiff_plain;h=59ae512cdf2565b10f6b5370c9670243fd75c5c5 merge public branch --- diff --git a/Makefile.am b/Makefile.am index d07aad6c..b972eba8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -98,6 +98,7 @@ other-cherrypick: /mingw/bin/libstdc++-6.dll \ /mingw/bin/libintl-8.dll \ /mingw/bin/libiconv-2.dll \ + /mingw/bin/libpthread-2.dll \ $(INSTALLDIR_WITH_PREFIX)/bin/. diff --git a/configure.ac b/configure.ac index 556941c0..08bcd8bf 100644 --- a/configure.ac +++ b/configure.ac @@ -320,7 +320,11 @@ if test "$video" = "true"; then if test "$enable_x11" = "true"; then AC_CHECK_HEADERS(X11/Xlib.h) - AC_CHECK_LIB(X11,XUnmapWindow, X11_LIBS="-lX11") + if test "$build_macos" = "yes"; then + X11_LIBS="-L/usr/X11/lib -lX11" + else + AC_CHECK_LIB(X11,XUnmapWindow, X11_LIBS="-lX11") + fi AC_SUBST(X11_LIBS) fi AC_DEFINE(VIDEO_ENABLED,1,[defined if video support is available]) diff --git a/console/linphonec.c b/console/linphonec.c index 38cf24f2..40a24360 100644 --- a/console/linphonec.c +++ b/console/linphonec.c @@ -328,7 +328,7 @@ static void linphonec_call_state_changed(LinphoneCore *lc, LinphoneCall *call, L long id=(long)linphone_call_get_user_pointer (call); switch(st){ case LinphoneCallEnd: - linphonec_out("Call %i with %s ended.\n", id, from); + linphonec_out("Call %i with %s ended (%s).\n", id, from, linphone_reason_to_string(linphone_call_get_reason(call))); break; case LinphoneCallResuming: linphonec_out("Resuming call %i with %s.\n", id, from); @@ -358,7 +358,6 @@ static void linphonec_call_state_changed(LinphoneCore *lc, LinphoneCall *call, L case LinphoneCallOutgoingInit: linphonec_call_identify(call); id=(long)linphone_call_get_user_pointer (call); - from=linphone_call_get_remote_address_as_string(call); linphonec_out("Establishing call id to %s, assigned id %i\n", from,id); break; case LinphoneCallUpdatedByRemote: diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 046f7edb..a101dbc8 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -49,7 +49,9 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia /* 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){ - sal_media_description_unref(oldmd); + /*as nothing has changed, keep the oldmd */ + call->resultdesc=oldmd; + sal_media_description_unref(new_md); if (call->all_muted){ ms_message("Early media finished, unmuting inputs..."); /*we were in early media, now we want to enable real media */ @@ -145,6 +147,7 @@ static void call_received(SalOp *h){ if (is_duplicate_call(lc,from_addr,to_addr)){ ms_warning("Receiving duplicated call, refusing this one."); sal_call_decline(h,SalReasonBusy,NULL); + sal_op_release(h); linphone_address_destroy(from_addr); linphone_address_destroy(to_addr); return; diff --git a/coreapi/help/doxygen.dox b/coreapi/help/doxygen.dox index 99293c65..7d0a8284 100644 --- a/coreapi/help/doxygen.dox +++ b/coreapi/help/doxygen.dox @@ -43,6 +43,13 @@ * **/ +/** + * @defgroup call_misc Obtaining information about a running call: sound volumes, quality indicators + * + * When a call is running, it is possible to retrieve in real time current measured volumes and quality indicator. + * +**/ + /** * @defgroup media_parameters Controlling media parameters **/ diff --git a/coreapi/linphonecall.c b/coreapi/linphonecall.c index 4230a156..7e6e0380 100644 --- a/coreapi/linphonecall.c +++ b/coreapi/linphonecall.c @@ -223,7 +223,6 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro /* this function is called internally to get rid of a call. It performs the following tasks: - remove the call from the internal list of calls - - unref the LinphoneCall object - update the call logs accordingly */ @@ -586,6 +585,17 @@ void linphone_call_params_set_audio_bandwidth_limit(LinphoneCallParams *cp, int cp->audio_bw=bandwidth; } +#ifdef VIDEO_ENABLED +/** + * Request remote side to send us a Video Fast Update. +**/ +void linphone_call_send_vfu_request(LinphoneCall *call) +{ + if (LinphoneCallStreamsRunning == linphone_call_get_state(call)) + sal_call_send_vfu_request(call->op); +} +#endif + /** * **/ @@ -659,6 +669,7 @@ void linphone_call_init_media_streams(LinphoneCall *call){ int enabled=lp_config_get_int(lc->config,"sound","noisegate",0); audio_stream_enable_noise_gate(audiostream,enabled); } + if (lc->a_rtp) rtp_session_set_transports(audiostream->session,lc->a_rtp,lc->a_rtcp); @@ -772,9 +783,6 @@ static void post_configure_audio_streams(LinphoneCall*call){ } } - - - static RtpProfile *make_profile(LinphoneCall *call, const SalMediaDescription *md, const SalStreamDescription *desc, int *used_pt){ int bw; const MSList *elem; @@ -782,15 +790,17 @@ static RtpProfile *make_profile(LinphoneCall *call, const SalMediaDescription *m bool_t first=TRUE; int remote_bw=0; LinphoneCore *lc=call->core; + int up_ptime=0; *used_pt=-1; for(elem=desc->payloads;elem!=NULL;elem=elem->next){ PayloadType *pt=(PayloadType*)elem->data; int number; - if (first) { + if ((pt->flags & PAYLOAD_TYPE_FLAG_CAN_SEND) && first) { if (desc->type==SalAudio){ linphone_core_update_allocated_audio_bandwidth_in_call(call,pt); + up_ptime=linphone_core_get_upload_ptime(lc); } *used_pt=payload_type_get_number(pt); first=FALSE; @@ -812,8 +822,11 @@ static RtpProfile *make_profile(LinphoneCall *call, const SalMediaDescription *m pt->normal_bitrate=-1; } if (desc->ptime>0){ + up_ptime=desc->ptime; + } + if (up_ptime>0){ char tmp[40]; - snprintf(tmp,sizeof(tmp),"ptime=%i",desc->ptime); + snprintf(tmp,sizeof(tmp),"ptime=%i",up_ptime); payload_type_append_send_fmtp(pt,tmp); } number=payload_type_get_number(pt); @@ -843,6 +856,7 @@ void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_mut const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc, SalProtoRtpAvp,SalVideo); #endif + bool_t use_arc=linphone_core_adaptive_rate_control_enabled(lc); if(call->audiostream == NULL) { @@ -866,7 +880,7 @@ void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_mut const char *playfile=lc->play_file; const char *recfile=lc->rec_file; call->audio_profile=make_profile(call,call->resultdesc,stream,&used_pt); - bool_t use_ec; + bool_t use_ec,use_arc_audio=use_arc; if (used_pt!=-1){ if (playcard==NULL) { @@ -897,11 +911,17 @@ void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_mut playcard=NULL; } use_ec=captcard==NULL ? FALSE : linphone_core_echo_cancellation_enabled(lc); -#if defined(VIDEO_ENABLED) && defined(ANDROID) - /*On android we have to disable the echo canceller to preserve CPU for video codecs */ - if (vstream && vstream->dir!=SalStreamInactive && vstream->payloads!=NULL) +#if defined(VIDEO_ENABLED) + if (vstream && vstream->dir!=SalStreamInactive && vstream->payloads!=NULL){ + /*when video is used, do not make adaptive rate control on audio, it is stupid.*/ + use_arc_audio=FALSE; + #if defined(ANDROID) + /*On android we have to disable the echo canceller to preserve CPU for video codecs */ use_ec=FALSE; + #endif + } #endif + audio_stream_enable_adaptive_bitrate_control(call->audiostream,use_arc_audio); audio_stream_start_full( call->audiostream, call->audio_profile, @@ -1005,6 +1025,7 @@ void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_mut static void linphone_call_log_fill_stats(LinphoneCallLog *log, AudioStream *st){ audio_stream_get_local_rtp_stats (st,&log->local_stats); + log->quality=audio_stream_get_average_quality_rating(st); } void linphone_call_stop_media_streams(LinphoneCall *call){ @@ -1041,16 +1062,7 @@ void linphone_call_stop_media_streams(LinphoneCall *call){ } } -#ifdef VIDEO_ENABLED -/** - * Request remote side to send us VFU. -**/ -void linphone_call_send_vfu_request(LinphoneCall *call) -{ - if (LinphoneCallStreamsRunning == linphone_call_get_state(call)) - sal_call_send_vfu_request(call->op); -} -#endif + void linphone_call_enable_echo_cancellation(LinphoneCall *call, bool_t enable) { if (call!=NULL && call->audiostream!=NULL && call->audiostream->ec){ @@ -1090,6 +1102,11 @@ bool_t linphone_call_echo_limiter_enabled(const LinphoneCall *call){ } } +/** + * @addtogroup call_misc + * @{ +**/ + /** * Returns the measured sound volume played locally (received from remote) * It is expressed in dbm0. @@ -1120,6 +1137,45 @@ float linphone_call_get_record_volume(LinphoneCall *call){ return LINPHONE_VOLUME_DB_LOWEST; } +/** + * Obtain real-time quality rating of the call + * + * Based on local RTP statistics and RTCP feedback, a quality rating is computed and updated + * during all the duration of the call. This function returns its value at the time of the function call. + * It is expected that the rating is updated at least every 5 seconds or so. + * The rating is a floating point number comprised between 0 and 5. + * + * 4-5 = good quality
+ * 3-4 = average quality
+ * 2-3 = poor quality
+ * 1-2 = very poor quality
+ * 0-1 = can't be worse, mostly unusable
+ * + * @returns The function returns -1 if no quality measurement is available, for example if no + * active audio stream exist. Otherwise it returns the quality rating. +**/ +float linphone_call_get_current_quality(LinphoneCall *call){ + if (call->audiostream){ + return audio_stream_get_quality_rating(call->audiostream); + } + return -1; +} + +/** + * Returns call quality averaged over all the duration of the call. + * + * See linphone_call_get_current_quality() for more details about quality measurement. +**/ +float linphone_call_get_average_quality(LinphoneCall *call){ + if (call->audiostream){ + return audio_stream_get_average_quality_rating(call->audiostream); + } + return -1; +} + +/** + * @} +**/ static void display_bandwidth(RtpSession *as, RtpSession *vs){ ms_message("bandwidth usage: audio=[d=%.1f,u=%.1f] video=[d=%.1f,u=%.1f] kbit/sec", @@ -1172,6 +1228,8 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse if (call->videostream!=NULL) video_stream_iterate(call->videostream); #endif + if (call->audiostream!=NULL) + audio_stream_iterate(call->audiostream); if (one_second_elapsed && call->audiostream!=NULL && disconnect_timeout>0 ) disconnected=!audio_stream_alive(call->audiostream,disconnect_timeout); if (disconnected) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 4c6deea9..934ebefa 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -124,6 +124,7 @@ void call_logs_write_to_config_file(LinphoneCore *lc){ lp_config_set_string(cfg,logsection,"start_date",cl->start_date); lp_config_set_int(cfg,logsection,"duration",cl->duration); if (cl->refkey) lp_config_set_string(cfg,logsection,"refkey",cl->refkey); + lp_config_set_float(cfg,logsection,"quality",cl->quality); } for(;imax_call_logs;++i){ snprintf(logsection,sizeof(logsection),"call_log_%i",i); @@ -151,6 +152,7 @@ static void call_logs_read_from_config_file(LinphoneCore *lc){ cl->duration=lp_config_get_int(cfg,logsection,"duration",0); tmp=lp_config_get_string(cfg,logsection,"refkey",NULL); if (tmp) cl->refkey=ms_strdup(tmp); + cl->quality=lp_config_get_float(cfg,logsection,"quality",-1); lc->call_logs=ms_list_append(lc->call_logs,cl); }else break; } @@ -464,6 +466,7 @@ static void sip_config_read(LinphoneCore *lc) sal_use_rport(lc->sal,lp_config_get_int(lc->config,"sip","use_rport",1)); sal_use_101(lc->sal,lp_config_get_int(lc->config,"sip","use_101",1)); + sal_reuse_authorization(lc->sal, lp_config_get_int(lc->config,"sip","reuse_authorization",0)); tmp=lp_config_get_int(lc->config,"sip","use_rfc2833",0); linphone_core_set_use_rfc2833_for_dtmf(lc,tmp); @@ -780,6 +783,26 @@ static void autoreplier_config_init(LinphoneCore *lc) } */ +/** + * Enable adaptive rate control (experimental feature, audio-only). + * + * Adaptive rate control consists in using RTCP feedback provided information to dynamically + * control the output bitrate of the encoders, so that we can adapt to the network conditions and + * available bandwidth. +**/ +void linphone_core_enable_adaptive_rate_control(LinphoneCore *lc, bool_t enabled){ + lp_config_set_int(lc->config,"net","adaptive_rate_control",(int)enabled); +} + +/** + * Returns whether adaptive rate control is enabled. + * + * See linphone_core_enable_adaptive_rate_control(). +**/ +bool_t linphone_core_adaptive_rate_control_enabled(const LinphoneCore *lc){ + return lp_config_get_int(lc->config,"net","adaptive_rate_control",FALSE); +} + /** * Sets maximum available download bandwidth * @@ -839,16 +862,38 @@ int linphone_core_get_upload_bandwidth(const LinphoneCore *lc){ return lc->net_conf.upload_bw; } /** - * set audio packetization time linphone expect to received from peer + * Set audio packetization time linphone expects to receive from peer */ void linphone_core_set_download_ptime(LinphoneCore *lc, int ptime) { lc->net_conf.down_ptime=ptime; } -int linphone_core_get_download_ptime(LinphoneCore *lc) { +/** + * Get audio packetization time linphone expects to receive from peer + */ +int linphone_core_get_download_ptime(LinphoneCore *lc) { return lc->net_conf.down_ptime; } +/** + * Set audio packetization time linphone will send (in absence of requirement from peer) + * A value of 0 stands for the current codec default packetization time. + * +**/ +void linphone_core_set_upload_ptime(LinphoneCore *lc, int ptime){ + lp_config_set_int(lc->config,"rtp","upload_ptime",ptime); +} + +/** + * Set audio packetization time linphone will send (in absence of requirement from peer) + * A value of 0 stands for the current codec default packetization time. + * +**/ +int linphone_core_get_upload_ptime(LinphoneCore *lc){ + return lp_config_get_int(lc->config,"rtp","upload_ptime",0); +} + + /** * Returns liblinphone's version as a string. @@ -1373,13 +1418,13 @@ static int apply_transports(LinphoneCore *lc){ sal_unlisten_ports (sal); if (tr->udp_port>0){ - if (sal_listen_port (sal,anyaddr,tr->udp_port,SalTransportDatagram,FALSE)!=0){ + if (sal_listen_port (sal,anyaddr,tr->udp_port,SalTransportUDP,FALSE)!=0){ transport_error(lc,"UDP",tr->udp_port); return -1; } } if (tr->tcp_port>0){ - if (sal_listen_port (sal,anyaddr,tr->tcp_port,SalTransportStream,FALSE)!=0){ + if (sal_listen_port (sal,anyaddr,tr->tcp_port,SalTransportTCP,FALSE)!=0){ transport_error(lc,"TCP",tr->tcp_port); } } @@ -1636,9 +1681,9 @@ void linphone_core_iterate(LinphoneCore *lc){ linphone_core_start_invite() */ calls=calls->next; if (call->state==LinphoneCallOutgoingInit && (curtime-call->start_time>=2)){ - /*start the call even if the OPTIONS reply did not arrive*/ - linphone_core_start_invite(lc,call,NULL); - } + /*start the call even if the OPTIONS reply did not arrive*/ + linphone_core_start_invite(lc,call,NULL); + } if (call->dir==LinphoneCallIncoming && call->state==LinphoneCallOutgoingRinging){ elapsed=curtime-call->start_time; ms_message("incoming call ringing for %i seconds",elapsed); @@ -1996,7 +2041,6 @@ LinphoneCall * linphone_core_invite_address(LinphoneCore *lc, const LinphoneAddr **/ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const LinphoneAddress *addr, const LinphoneCallParams *params) { - int err=0; const char *route=NULL; const char *from=NULL; LinphoneProxyConfig *proxy=NULL; @@ -2049,7 +2093,7 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const lc->current_call=call; linphone_call_set_state (call,LinphoneCallOutgoingInit,"Starting outgoing call"); if (dest_proxy!=NULL || lc->sip_conf.ping_with_options==FALSE){ - err=linphone_core_start_invite(lc,call,dest_proxy); + linphone_core_start_invite(lc,call,dest_proxy); }else{ /*defer the start of the call after the OPTIONS ping*/ call->ping_op=sal_op_new(lc->sal); @@ -4079,7 +4123,7 @@ LinphoneCallParams *linphone_core_create_default_call_parameters(LinphoneCore *l return p; } -const char *linphone_error_to_string(LinphoneReason err){ +const char *linphone_reason_to_string(LinphoneReason err){ switch(err){ case LinphoneReasonNone: return "No error"; @@ -4092,6 +4136,10 @@ const char *linphone_error_to_string(LinphoneReason err){ } return "unknown error"; } + +const char *linphone_error_to_string(LinphoneReason err){ + return linphone_reason_to_string(err); +} /** * Enables signaling keep alive */ diff --git a/coreapi/linphonecore.h b/coreapi/linphonecore.h index 50fdb96d..12bf7265 100644 --- a/coreapi/linphonecore.h +++ b/coreapi/linphonecore.h @@ -152,6 +152,7 @@ typedef struct _LinphoneCallLog{ void *user_pointer; rtp_stats_t local_stats; rtp_stats_t remote_stats; + float quality; struct _LinphoneCore *lc; } LinphoneCallLog; @@ -255,6 +256,8 @@ LinphoneReason linphone_call_get_reason(const LinphoneCall *call); const char *linphone_call_get_remote_user_agent(LinphoneCall *call); float linphone_call_get_play_volume(LinphoneCall *call); float linphone_call_get_record_volume(LinphoneCall *call); +float linphone_call_get_current_quality(LinphoneCall *call); +float linphone_call_get_average_quality(LinphoneCall *call); void *linphone_call_get_user_pointer(LinphoneCall *call); void linphone_call_set_user_pointer(LinphoneCall *call, void *user_pointer); /** @@ -702,18 +705,25 @@ void linphone_core_set_upload_bandwidth(LinphoneCore *lc, int bw); int linphone_core_get_download_bandwidth(const LinphoneCore *lc); int linphone_core_get_upload_bandwidth(const LinphoneCore *lc); + +void linphone_core_enable_adaptive_rate_control(LinphoneCore *lc, bool_t enabled); +bool_t linphone_core_adaptive_rate_control_enabled(const LinphoneCore *lc); /** - * set audio packetization time linphone expect to received from peer + * set audio packetization time linphone expect to receive from peer * @ingroup media_parameters * */ void linphone_core_set_download_ptime(LinphoneCore *lc, int ptime); /** - * get audio packetization time linphone expect to received from peer, 0 means unspecified + * get audio packetization time linphone expect to receive from peer, 0 means unspecified * @ingroup media_parameters */ int linphone_core_get_download_ptime(LinphoneCore *lc); +void linphone_core_set_upload_ptime(LinphoneCore *lc, int ptime); + +int linphone_core_get_upload_ptime(LinphoneCore *lc); + /* returns a MSList of PayloadType */ const MSList *linphone_core_get_audio_codecs(const LinphoneCore *lc); diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 4e201c84..f858f8d1 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -1023,6 +1023,18 @@ extern "C" jlong Java_org_linphone_core_LinphoneCallImpl_getReplacedCall( JNIEnv return (jlong)linphone_call_get_replaced_call((LinphoneCall*)ptr); } +extern "C" jfloat Java_org_linphone_core_LinphoneCallImpl_getCurrentQuality( JNIEnv* env + ,jobject thiz + ,jlong ptr) { + return (jfloat)linphone_call_get_current_quality((LinphoneCall*)ptr); +} + +extern "C" jfloat Java_org_linphone_core_LinphoneCallImpl_getAverageQuality( JNIEnv* env + ,jobject thiz + ,jlong ptr) { + return (jfloat)linphone_call_get_average_quality((LinphoneCall*)ptr); +} + //LinphoneFriend extern "C" long Java_org_linphone_core_LinphoneFriendImpl_newLinphoneFriend(JNIEnv* env @@ -1194,6 +1206,15 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setDownloadBandwidth(JNI extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setUploadBandwidth(JNIEnv *env, jobject thiz, jlong lc, jint bw){ linphone_core_set_upload_bandwidth((LinphoneCore *)lc, (int) bw); } + +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setDownloadPtime(JNIEnv *env, jobject thiz, jlong lc, jint ptime){ + linphone_core_set_download_ptime((LinphoneCore *)lc, (int) ptime); +} + +extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setUploadPtime(JNIEnv *env, jobject thiz, jlong lc, jint ptime){ + linphone_core_set_upload_ptime((LinphoneCore *)lc, (int) ptime); +} + extern "C" int Java_org_linphone_core_LinphoneProxyConfigImpl_getState(JNIEnv* env,jobject thiz,jlong ptr) { return (int) linphone_proxy_config_get_state((const LinphoneProxyConfig *) ptr); } diff --git a/coreapi/lpconfig.c b/coreapi/lpconfig.c index ce093cba..0de019e5 100644 --- a/coreapi/lpconfig.c +++ b/coreapi/lpconfig.c @@ -307,9 +307,14 @@ void lp_config_set_string(LpConfig *lpconfig,const char *section, const char *ke void lp_config_set_int(LpConfig *lpconfig,const char *section, const char *key, int value){ char tmp[30]; - snprintf(tmp,30,"%i",value); + snprintf(tmp,sizeof(tmp),"%i",value); + lp_config_set_string(lpconfig,section,key,tmp); +} + +void lp_config_set_float(LpConfig *lpconfig,const char *section, const char *key, float value){ + char tmp[30]; + snprintf(tmp,sizeof(tmp),"%f",value); lp_config_set_string(lpconfig,section,key,tmp); - lpconfig->modified++; } void lp_item_write(LpItem *item, FILE *file){ diff --git a/coreapi/lpconfig.h b/coreapi/lpconfig.h index bb731acb..ed7a66b1 100644 --- a/coreapi/lpconfig.h +++ b/coreapi/lpconfig.h @@ -86,6 +86,12 @@ void lp_config_set_string(LpConfig *lpconfig,const char *section, const char *ke * @ingroup misc **/ void lp_config_set_int(LpConfig *lpconfig,const char *section, const char *key, int value); +/** + * Sets a float config item + * + * @ingroup misc +**/ +void lp_config_set_float(LpConfig *lpconfig,const char *section, const char *key, float value); /** * Writes the config file to disk. * diff --git a/coreapi/lsd.c b/coreapi/lsd.c index 1ad7c7db..f22a5b20 100644 --- a/coreapi/lsd.c +++ b/coreapi/lsd.c @@ -250,7 +250,6 @@ LinphoneSoundDaemon * linphone_sound_daemon_new(const char *cardname, int rate, lsd_player_init(&lsd->branches[0],mp,MS_ITC_SOURCE_ID,lsd); ms_filter_set_notify_callback(lsd->branches[0].player,(MSFilterNotifyFunc)lsd_player_configure,&lsd->branches[0]); - ms_filter_enable_synchronous_notifcations (lsd->branches[0].player,TRUE); for(i=1;ibranches[i],mp,MS_FILE_PLAYER_ID,lsd); diff --git a/coreapi/offeranswer.c b/coreapi/offeranswer.c index 5748a6d5..3e054508 100644 --- a/coreapi/offeranswer.c +++ b/coreapi/offeranswer.c @@ -61,7 +61,7 @@ static PayloadType * find_payload_type_best_match(const MSList *l, const Payload } static MSList *match_payloads(const MSList *local, const MSList *remote, bool_t reading_response, bool_t one_matching_codec){ - const MSList *e2; + const MSList *e2,*e1; MSList *res=NULL; PayloadType *matched; bool_t found_codec=FALSE; @@ -85,6 +85,7 @@ static MSList *match_payloads(const MSList *local, const MSList *remote, bool_t newp=payload_type_clone(matched); if (p2->send_fmtp) payload_type_set_send_fmtp(newp,p2->send_fmtp); + newp->flags|=PAYLOAD_TYPE_FLAG_CAN_RECV|PAYLOAD_TYPE_FLAG_CAN_SEND; res=ms_list_append(res,newp); /* we should use the remote numbering even when parsing a response */ payload_type_set_number(newp,remote_number); @@ -96,7 +97,7 @@ static MSList *match_payloads(const MSList *local, const MSList *remote, bool_t Indeed despite we must sent with the remote numbering, we must be able to receive with our local one. */ - newp=payload_type_clone(matched); + newp=payload_type_clone(newp); payload_type_set_number(newp,local_number); res=ms_list_append(res,newp); } @@ -104,6 +105,26 @@ static MSList *match_payloads(const MSList *local, const MSList *remote, bool_t ms_message("No match for %s/%i",p2->mime_type,p2->clock_rate); } } + if (reading_response){ + /* add remaning local payload as CAN_RECV only so that if we are in front of a non-compliant equipment we are still able to decode the RTP stream*/ + for(e1=local;e1!=NULL;e1=e1->next){ + PayloadType *p1=(PayloadType*)e1->data; + bool_t found=FALSE; + for(e2=res;e2!=NULL;e2=e2->next){ + PayloadType *p2=(PayloadType*)e2->data; + if (payload_type_get_number(p2)==payload_type_get_number(p1)){ + found=TRUE; + break; + } + } + if (!found){ + ms_message("Adding %s/%i for compatibility, just in case.",p1->mime_type,p1->clock_rate); + p1=payload_type_clone(p1); + p1->flags|=PAYLOAD_TYPE_FLAG_CAN_RECV; + res=ms_list_append(res,p1); + } + } + } return res; } diff --git a/coreapi/proxy.c b/coreapi/proxy.c index a4a062dc..ff13f839 100644 --- a/coreapi/proxy.c +++ b/coreapi/proxy.c @@ -259,7 +259,7 @@ static char *guess_contact_for_register(LinphoneProxyConfig *obj){ linphone_core_get_sip_transports(obj->lc,&tr); if (tr.udp_port <= 0 && tr.tcp_port>0) { - sal_address_add_param(contact,"transport","tcp"); + sal_address_set_param(contact,"transport","TCP"); } ret=linphone_address_as_string(contact); linphone_address_destroy(contact); @@ -269,10 +269,6 @@ static char *guess_contact_for_register(LinphoneProxyConfig *obj){ } static void linphone_proxy_config_register(LinphoneProxyConfig *obj){ - const char *id_str; - - if (obj->reg_identity!=NULL) id_str=obj->reg_identity; - else id_str=linphone_core_get_primary_contact(obj->lc); if (obj->reg_sendregister){ char *contact; if (obj->op) diff --git a/coreapi/sal.c b/coreapi/sal.c index b25f3945..b237e9ad 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -24,7 +24,27 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. **/ #include "sal.h" - +const char* sal_transport_to_string(SalTransport transport) { + switch (transport) { + case SalTransportUDP:return "UDP"; + case SalTransportTCP: return "TCP"; + case SalTransportTLS:return "TLS"; + case SalTransportDTLS:return "DTLS"; + default: { + ms_fatal("Unexpected transport [%i]",transport); + return NULL; + } + + } +} +SalTransport sal_transport_parse(const char* param) { + if (strcasecmp("UDP",param)==0) return SalTransportUDP; + if (strcasecmp("TCP",param)==0) return SalTransportTCP; + if (strcasecmp("TLS",param)==0) return SalTransportTLS; + if (strcasecmp("DTLS",param)==0) return SalTransportDTLS; + ms_error("Unkown transport type[%s], returning UDP", param); + return SalTransportUDP; +} SalMediaDescription *sal_media_description_new(){ SalMediaDescription *md=ms_new0(SalMediaDescription,1); md->refcount=1; @@ -309,3 +329,4 @@ void sal_auth_info_delete(const SalAuthInfo* auth_info) { if (auth_info->password) ms_free(auth_info->password); ms_free((void*)auth_info); } + diff --git a/coreapi/sal.h b/coreapi/sal.h index a89b862c..47286b09 100644 --- a/coreapi/sal.h +++ b/coreapi/sal.h @@ -28,6 +28,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "mediastreamer2/mscommon.h" +/*Dirty hack, keep in sync with mediastreamer2/include/mediastream.h */ +#ifndef PAYLOAD_TYPE_FLAG_CAN_RECV +#define PAYLOAD_TYPE_FLAG_CAN_RECV PAYLOAD_TYPE_USER_FLAG_1 +#define PAYLOAD_TYPE_FLAG_CAN_SEND PAYLOAD_TYPE_USER_FLAG_2 +#endif struct Sal; typedef struct Sal Sal; @@ -40,6 +45,15 @@ struct SalAddress; typedef struct SalAddress SalAddress; +typedef enum { + SalTransportUDP, /*UDP*/ + SalTransportTCP, /*TCP*/ + SalTransportTLS, /*TLS*/ + SalTransportDTLS /*DTLS*/ +}SalTransport; + +const char* sal_transport_to_string(SalTransport transport); +SalTransport sal_transport_parse(const char*); /* Address manipulation API*/ SalAddress * sal_address_new(const char *uri); SalAddress * sal_address_clone(const SalAddress *addr); @@ -49,7 +63,8 @@ char *sal_address_get_display_name_unquoted(const SalAddress *addr); const char *sal_address_get_username(const SalAddress *addr); const char *sal_address_get_domain(const SalAddress *addr); const char * sal_address_get_port(const SalAddress *addr); -int sal_address_get_port_int(const SalAddress *uri); +int sal_address_get_port_int(const SalAddress *addr); +SalTransport sal_address_get_transport(const SalAddress* addr); void sal_address_set_display_name(SalAddress *addr, const char *display_name); void sal_address_set_username(SalAddress *addr, const char *username); @@ -60,8 +75,8 @@ void sal_address_clean(SalAddress *addr); char *sal_address_as_string(const SalAddress *u); char *sal_address_as_string_uri_only(const SalAddress *u); void sal_address_destroy(SalAddress *u); -void sal_address_add_param(SalAddress *u,const char* name,const char* value); - +void sal_address_set_param(SalAddress *u,const char* name,const char* value); +void sal_address_set_transport(SalAddress* addr,SalTransport transport); Sal * sal_init(); @@ -69,10 +84,6 @@ void sal_uninit(Sal* sal); void sal_set_user_pointer(Sal *sal, void *user_data); void *sal_get_user_pointer(const Sal *sal); -typedef enum { - SalTransportDatagram, - SalTransportStream -}SalTransport; typedef enum { SalAudio, @@ -261,6 +272,7 @@ void sal_set_keepalive_period(Sal *ctx,unsigned int value); unsigned int sal_get_keepalive_period(Sal *ctx); void sal_use_session_timers(Sal *ctx, int expires); void sal_use_double_registrations(Sal *ctx, bool_t enabled); +void sal_reuse_authorization(Sal *ctx, bool_t enabled); void sal_use_one_matching_codec_policy(Sal *ctx, bool_t one_matching_codec); void sal_use_rport(Sal *ctx, bool_t use_rports); void sal_use_101(Sal *ctx, bool_t use_101); @@ -313,6 +325,7 @@ int sal_call_send_dtmf(SalOp *h, char dtmf); int sal_call_terminate(SalOp *h); bool_t sal_call_autoanswer_asked(SalOp *op); void sal_call_send_vfu_request(SalOp *h); +int sal_call_is_offerer(const SalOp *h); /*Registration*/ int sal_register(SalOp *op, const char *proxy, const char *from, int expires); @@ -337,6 +350,8 @@ int sal_publish(SalOp *op, const char *from, const char *to, SalPresenceStatus s /*ping: main purpose is to obtain its own contact address behind firewalls*/ int sal_ping(SalOp *op, const char *from, const char *to); + + #define payload_type_set_number(pt,n) (pt)->user_data=(void*)((long)n); #define payload_type_get_number(pt) ((int)(long)(pt)->user_data) diff --git a/coreapi/sal_eXosip2.c b/coreapi/sal_eXosip2.c index 33ef079c..7c04454b 100644 --- a/coreapi/sal_eXosip2.c +++ b/coreapi/sal_eXosip2.c @@ -32,6 +32,10 @@ static bool_t call_failure(Sal *sal, eXosip_event_t *ev); static void text_received(Sal *sal, eXosip_event_t *ev); +static void masquerade_via(osip_message_t *msg, const char *ip, const char *port); +static bool_t fix_message_contact(SalOp *op, osip_message_t *request,osip_message_t *last_answer); +static void update_contact_from_response(SalOp *op, osip_message_t *response); + void _osip_list_set_empty(osip_list_t *l, void (*freefunc)(void*)){ void *data; while(!osip_list_eol(l,0)) { @@ -189,6 +193,7 @@ void sal_op_release(SalOp *op){ eXosip_event_free(op->pending_auth); if (op->rid!=-1){ sal_remove_register(op->base.root,op->rid); + eXosip_register_remove(op->rid); } if (op->cid!=-1){ ms_message("Cleaning cid %i",op->cid); @@ -275,6 +280,7 @@ Sal * sal_init(){ sal->double_reg=TRUE; sal->use_rports=TRUE; sal->use_101=TRUE; + sal->reuse_authorization=FALSE; return sal; } @@ -351,11 +357,11 @@ int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int i int keepalive = ctx->keepalive_period; switch (tr) { - case SalTransportDatagram: + case SalTransportUDP: proto=IPPROTO_UDP; eXosip_set_option (EXOSIP_OPT_UDP_KEEP_ALIVE, &keepalive); break; - case SalTransportStream: + case SalTransportTCP: proto= IPPROTO_TCP; keepalive=-1; eXosip_set_option (EXOSIP_OPT_UDP_KEEP_ALIVE,&keepalive); @@ -424,7 +430,8 @@ void sal_use_rport(Sal *ctx, bool_t use_rports){ void sal_use_101(Sal *ctx, bool_t use_101){ ctx->use_101=use_101; } -static int extract_received_rport(osip_message_t *msg, const char **received, int *rportval){ + +static int extract_received_rport(osip_message_t *msg, const char **received, int *rportval,SalTransport* transport){ osip_via_t *via=NULL; osip_generic_param_t *param=NULL; const char *rport=NULL; @@ -434,10 +441,7 @@ static int extract_received_rport(osip_message_t *msg, const char **received, in osip_message_get_via(msg,0,&via); if (!via) return -1; - /* it is useless to do that with tcp since client socket might have a different port - than the server socket. - */ - if (strcasecmp(via->protocol,"tcp")==0) return -1; + *transport = sal_transport_parse(via->protocol); if (via->port && via->port[0]!='\0') *rportval=atoi(via->port); @@ -507,6 +511,10 @@ static void sdp_process(SalOp *h){ } +int sal_call_is_offerer(const SalOp *h){ + return h->sdp_offering; +} + int sal_call_set_local_media_description(SalOp *h, SalMediaDescription *desc){ if (desc) sal_media_description_ref(desc); @@ -561,19 +569,18 @@ int sal_call(SalOp *h, const char *from, const char *to){ int sal_call_notify_ringing(SalOp *h, bool_t early_media){ osip_message_t *msg; - int err; /*if early media send also 180 and 183 */ if (early_media && h->sdp_answer){ msg=NULL; eXosip_lock(); - err=eXosip_call_build_answer(h->tid,180,&msg); + eXosip_call_build_answer(h->tid,180,&msg); if (msg){ set_sdp(msg,h->sdp_answer); eXosip_call_send_answer(h->tid,180,msg); } msg=NULL; - err=eXosip_call_build_answer(h->tid,183,&msg); + eXosip_call_build_answer(h->tid,183,&msg); if (msg){ set_sdp(msg,h->sdp_answer); eXosip_call_send_answer(h->tid,183,msg); @@ -792,7 +799,7 @@ int sal_call_terminate(SalOp *h){ eXosip_lock(); err=eXosip_call_terminate(h->cid,h->did); eXosip_unlock(); - pop_auth_from_exosip(); + if (!h->base.root->reuse_authorization) pop_auth_from_exosip(); if (err!=0){ ms_warning("Exosip could not terminate the call: cid=%i did=%i", h->cid,h->did); } @@ -801,13 +808,21 @@ int sal_call_terminate(SalOp *h){ } void sal_op_authenticate(SalOp *h, const SalAuthInfo *info){ - if (h->pending_auth){ + if (h->pending_auth){ push_auth_to_exosip(info); + + /*FIXME exosip does not take into account this update register message*/ + /* + if (fix_message_contact(h, h->pending_auth->request,h->pending_auth->response)) { + + }; + */ + update_contact_from_response(h,h->pending_auth->response); eXosip_lock(); eXosip_default_action(h->pending_auth); eXosip_unlock(); ms_message("eXosip_default_action() done"); - pop_auth_from_exosip(); + if (!h->base.root->reuse_authorization) pop_auth_from_exosip(); if (h->auth_info) sal_auth_info_delete(h->auth_info); /*if already exist*/ h->auth_info=sal_auth_info_clone(info); /*store auth info for subsequent request*/ @@ -826,8 +841,9 @@ void sal_op_cancel_authentication(SalOp *h) { static void set_network_origin(SalOp *op, osip_message_t *req){ const char *received=NULL; int rport=5060; - char origin[64]; - if (extract_received_rport(req,&received,&rport)!=0){ + char origin[64]={0}; + SalTransport transport; + if (extract_received_rport(req,&received,&rport,&transport)!=0){ osip_via_t *via=NULL; char *tmp; osip_message_get_via(req,0,&via); @@ -835,7 +851,11 @@ static void set_network_origin(SalOp *op, osip_message_t *req){ tmp=osip_via_get_port(via); if (tmp) rport=atoi(tmp); } - snprintf(origin,sizeof(origin)-1,"sip:%s:%i",received,rport); + if (transport != SalTransportUDP) { + snprintf(origin,sizeof(origin)-1,"sip:%s:%i",received,rport); + } else { + snprintf(origin,sizeof(origin)-1,"sip:%s:%i;transport=%s",received,rport,sal_transport_to_string(transport)); + } __sal_op_set_network_origin(op,origin); } @@ -993,7 +1013,8 @@ static void handle_ack(Sal *sal, eXosip_event_t *ev){ static void update_contact_from_response(SalOp *op, osip_message_t *response){ const char *received; int rport; - if (extract_received_rport(response,&received,&rport)==0){ + SalTransport transport; + if (extract_received_rport(response,&received,&rport,&transport)==0){ const char *contact=sal_op_get_contact(op); if (!contact){ /*no contact given yet, use from instead*/ @@ -1004,8 +1025,10 @@ static void update_contact_from_response(SalOp *op, osip_message_t *response){ char *tmp; sal_address_set_domain(addr,received); sal_address_set_port_int(addr,rport); + if (transport!=SalTransportUDP) + sal_address_set_transport(addr,transport); tmp=sal_address_as_string(addr); - ms_message("Contact address updated to %s for this dialog",tmp); + ms_message("Contact address updated to %s",tmp); sal_op_set_contact(op,tmp); sal_address_destroy(addr); ms_free(tmp); @@ -1015,13 +1038,12 @@ static void update_contact_from_response(SalOp *op, osip_message_t *response){ static int call_proceeding(Sal *sal, eXosip_event_t *ev){ SalOp *op=find_op(sal,ev); - - if (op==NULL) { + + if (op==NULL || op->terminated==TRUE) { ms_warning("This call has been canceled."); eXosip_lock(); eXosip_call_terminate(ev->cid,ev->did); eXosip_unlock(); - op->terminated=TRUE; return -1; } if (ev->did>0) @@ -1056,9 +1078,12 @@ static void call_accepted(Sal *sal, eXosip_event_t *ev){ SalOp *op=find_op(sal,ev); const char *contact; - if (op==NULL){ - ms_error("A closed call is accepted ?"); - return; + if (op==NULL || op->terminated==TRUE) { + ms_warning("This call has been already terminated."); + eXosip_lock(); + eXosip_call_terminate(ev->cid,ev->did); + eXosip_unlock(); + return ; } op->did=ev->did; @@ -1600,39 +1625,20 @@ static void masquerade_via(osip_message_t *msg, const char *ip, const char *port } } -static bool_t register_again_with_updated_contact(SalOp *op, osip_message_t *orig_request, osip_message_t *last_answer){ - osip_message_t *msg; + +static bool_t fix_message_contact(SalOp *op, osip_message_t *request,osip_message_t *last_answer) { + osip_contact_t *ctt=NULL; const char *received; int rport; - osip_contact_t *ctt=NULL; - char *tmp; + SalTransport transport; char port[20]; - SalAddress *addr; - Sal *sal=op->base.root; - if (sal->double_reg==FALSE) return FALSE; - - if (extract_received_rport(last_answer,&received,&rport)==-1) return FALSE; - osip_message_get_contact(orig_request,0,&ctt); - if (strcmp(ctt->url->host,received)==0){ - /*ip address matches, check ports*/ - const char *contact_port=ctt->url->port; - if (contact_port==NULL || contact_port[0]=='\0') - contact_port="5060"; - if (atoi(contact_port)==rport){ - ms_message("Register has up to date contact, doing nothing."); - return FALSE; - }else ms_message("ports do not match, need to update the register (%s <> %i)", contact_port,rport); - } - eXosip_lock(); - msg=NULL; - eXosip_register_build_register(op->rid,op->expires,&msg); - if (msg==NULL){ - eXosip_unlock(); - ms_warning("Fail to create a contact updated register."); + if (extract_received_rport(last_answer,&received,&rport,&transport)==-1) return FALSE; + osip_message_get_contact(request,0,&ctt); + if (ctt == NULL) { + /*nothing to update*/ return FALSE; } - osip_message_get_contact(msg,0,&ctt); if (ctt->url->host!=NULL){ osip_free(ctt->url->host); } @@ -1642,19 +1648,69 @@ static bool_t register_again_with_updated_contact(SalOp *op, osip_message_t *ori } snprintf(port,sizeof(port),"%i",rport); ctt->url->port=osip_strdup(port); - if (op->masquerade_via) masquerade_via(msg,received,port); - eXosip_register_send_register(op->rid,msg); - eXosip_unlock(); + if (op->masquerade_via) masquerade_via(request,received,port); + + if (transport != SalTransportUDP) { + sal_address_set_param((SalAddress *)ctt, "transport", sal_transport_to_string(transport)); + } + return TRUE; +} + +static bool_t register_again_with_updated_contact(SalOp *op, osip_message_t *orig_request, osip_message_t *last_answer){ + osip_contact_t *ctt=NULL; + SalAddress* ori_contact_address=NULL; + const char *received; + int rport; + SalTransport transport; + char* tmp; + osip_message_t *msg=NULL; + Sal* sal=op->base.root; + + if (sal->double_reg==FALSE ) return FALSE; + + if (extract_received_rport(last_answer,&received,&rport,&transport)==-1) return FALSE; + osip_message_get_contact(orig_request,0,&ctt); osip_contact_to_str(ctt,&tmp); - addr=sal_address_new(tmp); + ori_contact_address = sal_address_new((const char*)tmp); + + /*check if contact is up to date*/ + if (strcmp(sal_address_get_domain(ori_contact_address),received) ==0 + && sal_address_get_port_int(ori_contact_address) == rport + && sal_address_get_transport(ori_contact_address) == transport) { + ms_message("Register has up to date contact, doing nothing."); + osip_free(tmp); + return FALSE; + } else ms_message("contact do not match, need to update the register (%s with %s:%i;transport=%s)" + ,tmp + ,received + ,rport + ,sal_transport_to_string(transport)); osip_free(tmp); - sal_address_clean(addr); - tmp=sal_address_as_string(addr); - sal_op_set_contact(op,tmp); - sal_address_destroy(addr); - ms_message("Resending new register with updated contact %s",tmp); - ms_free(tmp); - return TRUE; + sal_address_destroy(ori_contact_address); + + if (transport == SalTransportUDP) { + eXosip_lock(); + eXosip_register_build_register(op->rid,op->expires,&msg); + if (msg==NULL){ + eXosip_unlock(); + ms_warning("Fail to create a contact updated register."); + return FALSE; + } + if (fix_message_contact(op,msg,last_answer)) { + eXosip_register_send_register(op->rid,msg); + eXosip_unlock(); + ms_message("Resending new register with updated contact"); + return TRUE; + } else { + ms_warning("Fail to send updated register."); + eXosip_unlock(); + return FALSE; + } + eXosip_unlock(); + } + + update_contact_from_response(op,last_answer); + return FALSE; } static void registration_success(Sal *sal, eXosip_event_t *ev){ @@ -2080,8 +2136,16 @@ char *sal_address_as_string_uri_only(const SalAddress *u){ osip_free(tmp); return ret; } -void sal_address_add_param(SalAddress *u,const char* name,const char* value) { - osip_uri_uparam_add (((osip_from_t*)u)->url,ms_strdup(name),ms_strdup(value)); +void sal_address_set_param(SalAddress *u,const char* name,const char* value) { + osip_uri_param_t *param=NULL; + osip_uri_uparam_get_byname(((osip_from_t*)u)->url,(char*)name,¶m); + if (param == NULL){ + osip_uri_uparam_add (((osip_from_t*)u)->url,ms_strdup(name),ms_strdup(value)); + } else { + osip_free(param->gvalue); + param->gvalue=osip_strdup(value); + } + } void sal_address_destroy(SalAddress *u){ @@ -2109,6 +2173,19 @@ int sal_address_get_port_int(const SalAddress *uri) { return 5060; } } +SalTransport sal_address_get_transport(const SalAddress* addr) { + const osip_from_t *u=(const osip_from_t*)addr; + osip_uri_param_t *transport_param=NULL; + osip_uri_uparam_get_byname(u->url,"transport",&transport_param); + if (transport_param == NULL){ + return SalTransportUDP; + } else { + return sal_transport_parse(transport_param->gvalue); + } +} +void sal_address_set_transport(SalAddress* addr,SalTransport transport) { + sal_address_set_param(addr, "transport", sal_transport_to_string(transport)); +} /* sends a reinvite. Local media description may have changed by application since call establishment*/ int sal_call_update(SalOp *h, const char *subject){ @@ -2136,3 +2213,6 @@ int sal_call_update(SalOp *h, const char *subject){ eXosip_unlock(); return err; } +void sal_reuse_authorization(Sal *ctx, bool_t value) { + ctx->reuse_authorization=value; +} diff --git a/coreapi/sal_eXosip2.h b/coreapi/sal_eXosip2.h index a050f513..201cb65a 100644 --- a/coreapi/sal_eXosip2.h +++ b/coreapi/sal_eXosip2.h @@ -44,6 +44,7 @@ struct Sal{ bool_t double_reg; bool_t use_rports; bool_t use_101; + bool_t reuse_authorization; }; struct SalOp{ diff --git a/gtk/calllogs.c b/gtk/calllogs.c index c196c2c4..f336992d 100644 --- a/gtk/calllogs.c +++ b/gtk/calllogs.c @@ -40,14 +40,20 @@ void linphone_gtk_call_log_update(GtkWidget *w){ char *addr= linphone_address_as_string_uri_only (la); const char *display; gchar *logtxt; + gchar quality[20]; + display=linphone_address_get_display_name (la); if (display==NULL){ display=linphone_address_get_username (la); if (display==NULL) display=linphone_address_get_domain (la); } - logtxt=g_markup_printf_escaped("%s\t%s\n" - "%s\t%i minutes %i seconds",display, addr, cl->start_date, + if (cl->quality!=-1){ + snprintf(quality,sizeof(quality),"%.1f",cl->quality); + } + logtxt=g_markup_printf_escaped("%s\t%s\tQuality: %s\n" + "%s\t%i minutes %i seconds\t",display, addr, cl->quality!=-1 ? quality : _("n/a"), + cl->start_date, cl->duration/60,cl->duration%60); gtk_list_store_append (store,&iter); gtk_list_store_set (store,&iter, diff --git a/gtk/friendlist.c b/gtk/friendlist.c index f1930760..d1b11627 100644 --- a/gtk/friendlist.c +++ b/gtk/friendlist.c @@ -70,7 +70,7 @@ static GdkPixbuf *create_status_picture(LinphoneOnlineStatus ss){ void linphone_gtk_set_friend_status(GtkWidget *friendlist , LinphoneFriend * fid, const gchar *url, const gchar *status, const gchar *img){ GtkTreeIter iter; LinphoneFriend *tmp=0; - gboolean found=FALSE; + GtkTreeModel *model=gtk_tree_view_get_model(GTK_TREE_VIEW(friendlist)); if (gtk_tree_model_get_iter_first(model,&iter)) { do{ @@ -81,10 +81,9 @@ void linphone_gtk_set_friend_status(GtkWidget *friendlist , LinphoneFriend * fid gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_PRESENCE_STATUS,status,-1); pixbuf = create_pixbuf(img); if (pixbuf) - { - gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_PRESENCE_IMG, pixbuf,-1); - } - found=TRUE; + { + gtk_list_store_set(GTK_LIST_STORE(model),&iter,FRIEND_PRESENCE_IMG, pixbuf,-1); + } } }while(gtk_tree_model_iter_next(model,&iter)); } diff --git a/gtk/incall_view.c b/gtk/incall_view.c index 96f672cf..919adaa3 100644 --- a/gtk/incall_view.c +++ b/gtk/incall_view.c @@ -205,7 +205,6 @@ void linphone_gtk_in_call_view_set_incoming(LinphoneCall *call, bool_t with_paus gtk_label_set_markup(GTK_LABEL(status),_("Incoming call")); gtk_widget_show_all(linphone_gtk_get_widget(callview,"answer_decline_panel")); - gtk_widget_hide(linphone_gtk_get_widget(callview,"duration_frame")); gtk_widget_hide(linphone_gtk_get_widget(callview,"mute_pause_buttons")); display_peer_name_in_label(callee,linphone_call_get_remote_address (call)); @@ -228,6 +227,57 @@ void linphone_gtk_in_call_view_set_incoming(LinphoneCall *call, bool_t with_paus }else gtk_image_set_from_stock(GTK_IMAGE(animation),GTK_STOCK_EXECUTE,GTK_ICON_SIZE_DIALOG); } +static void rating_to_color(float rating, GdkColor *color){ + const char *colorname="grey"; + if (rating>=4.0) + colorname="green"; + else if (rating>=3.0) + colorname="white"; + else if (rating>=2.0) + colorname="yellow"; + else if (rating>=1.0) + colorname="orange"; + else if (rating>=0) + colorname="red"; + if (!gdk_color_parse(colorname,color)){ + g_warning("Fail to parse color %s",colorname); + } +} + +static const char *rating_to_text(float rating){ + if (rating>=4.0) + return _("good"); + if (rating>=3.0) + return _("average"); + if (rating>=2.0) + return _("poor"); + if (rating>=1.0) + return _("very poor"); + if (rating>=0) + return _("too bad"); + return _("unavailable"); +} + +static gboolean linphone_gtk_in_call_view_refresh(LinphoneCall *call){ + GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call); + GtkWidget *qi=linphone_gtk_get_widget(callview,"quality_indicator"); + float rating=linphone_call_get_current_quality(call); + GdkColor color; + gchar tmp[50]; + linphone_gtk_in_call_view_update_duration(call); + if (rating>=0){ + gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(qi),rating/5.0); + snprintf(tmp,sizeof(tmp),"%.1f (%s)",rating,rating_to_text(rating)); + gtk_progress_bar_set_text(GTK_PROGRESS_BAR(qi),tmp); + }else{ + gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(qi),0); + gtk_progress_bar_set_text(GTK_PROGRESS_BAR(qi),_("unavailable")); + } + rating_to_color(rating,&color); + gtk_widget_modify_bg(qi,GTK_STATE_NORMAL,&color); + return TRUE; +} + void linphone_gtk_in_call_view_set_in_call(LinphoneCall *call){ GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer(call); GtkWidget *status=linphone_gtk_get_widget(callview,"in_call_status"); @@ -235,10 +285,10 @@ void linphone_gtk_in_call_view_set_in_call(LinphoneCall *call){ GtkWidget *duration=linphone_gtk_get_widget(callview,"in_call_duration"); GtkWidget *animation=linphone_gtk_get_widget(callview,"in_call_animation"); GdkPixbufAnimation *pbuf=create_pixbuf_animation("incall_anim.gif"); + guint taskid=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(callview),"taskid")); display_peer_name_in_label(callee,linphone_call_get_remote_address (call)); - gtk_widget_show(linphone_gtk_get_widget(callview,"duration_frame")); gtk_widget_show(linphone_gtk_get_widget(callview,"mute_pause_buttons")); gtk_widget_hide(linphone_gtk_get_widget(callview,"answer_decline_panel")); gtk_label_set_markup(GTK_LABEL(status),_("In call")); @@ -250,6 +300,10 @@ void linphone_gtk_in_call_view_set_in_call(LinphoneCall *call){ }else gtk_image_set_from_stock(GTK_IMAGE(animation),GTK_STOCK_EXECUTE,GTK_ICON_SIZE_DIALOG); linphone_gtk_enable_mute_button( GTK_BUTTON(linphone_gtk_get_widget(callview,"incall_mute")),TRUE); + if (taskid==0){ + taskid=g_timeout_add(250,(GSourceFunc)linphone_gtk_in_call_view_refresh,call); + g_object_set_data(G_OBJECT(callview),"taskid",GINT_TO_POINTER(taskid)); + } } void linphone_gtk_in_call_view_set_paused(LinphoneCall *call){ @@ -283,6 +337,7 @@ void linphone_gtk_in_call_view_terminate(LinphoneCall *call, const char *error_m GtkWidget *status=linphone_gtk_get_widget(callview,"in_call_status"); GtkWidget *animation=linphone_gtk_get_widget(callview,"in_call_animation"); GdkPixbuf *pbuf=create_pixbuf(linphone_gtk_get_ui_config("stop_call_icon","stopcall-red.png")); + guint taskid=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(callview),"taskid")); if (error_msg==NULL) gtk_label_set_markup(GTK_LABEL(status),_("Call ended.")); @@ -299,6 +354,7 @@ void linphone_gtk_in_call_view_terminate(LinphoneCall *call, const char *error_m linphone_gtk_enable_mute_button( GTK_BUTTON(linphone_gtk_get_widget(callview,"incall_mute")),FALSE); linphone_gtk_enable_hold_button(call,FALSE,TRUE); + if (taskid!=0) g_source_remove(taskid); g_timeout_add_seconds(2,(GSourceFunc)in_call_view_terminated,call); } diff --git a/gtk/main.c b/gtk/main.c index b47296f2..6968466d 100644 --- a/gtk/main.c +++ b/gtk/main.c @@ -632,15 +632,6 @@ void linphone_gtk_call_terminated(LinphoneCall *call, const char *error){ update_video_title(); } -static gboolean in_call_timer(){ - LinphoneCall *call=linphone_core_get_current_call(linphone_gtk_get_core()); - if (call){ - linphone_gtk_in_call_view_update_duration(call); - return TRUE; - } - return FALSE; -} - static bool_t all_other_calls_paused(LinphoneCall *refcall, const MSList *calls){ for(;calls!=NULL;calls=calls->next){ LinphoneCall *call=(LinphoneCall*)calls->data; @@ -961,7 +952,6 @@ static void linphone_gtk_call_state_changed(LinphoneCore *lc, LinphoneCall *call linphone_gtk_enable_mute_button( GTK_BUTTON(linphone_gtk_get_widget(linphone_gtk_get_main_window(),"main_mute")), TRUE); - g_timeout_add(250,(GSourceFunc)in_call_timer,NULL); break; case LinphoneCallError: linphone_gtk_in_call_view_terminate (call,msg); diff --git a/gtk/main.ui b/gtk/main.ui index aaa4ae4a..c24591a9 100644 --- a/gtk/main.ui +++ b/gtk/main.ui @@ -1,4 +1,4 @@ - + @@ -62,7 +62,6 @@ True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - vertical True @@ -234,7 +233,6 @@ True - vertical True @@ -285,7 +283,7 @@ True True Enter username, phone number, or full sip address - + ● @@ -337,7 +335,6 @@ True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - vertical True @@ -345,7 +342,6 @@ True - vertical True @@ -361,7 +357,6 @@ True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - vertical True @@ -381,7 +376,7 @@ True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - + ● @@ -459,10 +454,10 @@ True True - + ● + - @@ -702,7 +697,6 @@ True - vertical True @@ -1089,7 +1083,6 @@ True - vertical True @@ -1144,7 +1137,7 @@ True True - + ● 1 @@ -1156,7 +1149,7 @@ True True False - + ● 1 @@ -1334,7 +1327,6 @@ True - vertical True @@ -1346,22 +1338,10 @@ - + True - 0 - - - True - label - center - - - - - True - True - - + label + center 1 @@ -1405,39 +1385,6 @@ 2 - - - True - 0 - - - True - vertical - - - True - Duration - center - - - 0 - - - - - - - True - Duration: - True - - - - - False - 3 - - True @@ -1474,7 +1421,7 @@ False False - 4 + 3 @@ -1482,11 +1429,39 @@ - + True - In call - True - center + True + + + True + In call + True + center + + + 0 + + + + + True + Duration + center + + + 1 + + + + + True + Call quality rating + + + 2 + + diff --git a/java/common/org/linphone/core/LinphoneCall.java b/java/common/org/linphone/core/LinphoneCall.java index 9f029b05..e0f7cde3 100644 --- a/java/common/org/linphone/core/LinphoneCall.java +++ b/java/common/org/linphone/core/LinphoneCall.java @@ -190,4 +190,28 @@ public interface LinphoneCall { * @return call duration computed from media start */ int getDuration(); + /** + * Obtain real-time quality rating of the call + * + * Based on local RTP statistics and RTCP feedback, a quality rating is computed and updated + * during all the duration of the call. This function returns its value at the time of the function call. + * It is expected that the rating is updated at least every 5 seconds or so. + * The rating is a floating point number comprised between 0 and 5. + * + * 4-5 = good quality
+ * 3-4 = average quality
+ * 2-3 = poor quality
+ * 1-2 = very poor quality
+ * 0-1 = can't be worse, mostly unusable
+ * + * @returns The function returns -1 if no quality measurement is available, for example if no + * active audio stream exist. Otherwise it returns the quality rating. + */ + float getCurrentQuality(); + /** + * Returns call quality averaged over all the duration of the call. + * + * See getCurrentQuality() for more details about quality measurement. + */ + float getAverageQuality(); } diff --git a/java/common/org/linphone/core/LinphoneCore.java b/java/common/org/linphone/core/LinphoneCore.java index 1c7dd2ff..4afe7182 100644 --- a/java/common/org/linphone/core/LinphoneCore.java +++ b/java/common/org/linphone/core/LinphoneCore.java @@ -531,6 +531,18 @@ public interface LinphoneCore { void setUploadBandwidth(int bw); void setDownloadBandwidth(int bw); + + /** + * Sets audio packetization interval suggested for remote end. + * @param ptime packetization interval in milliseconds + */ + void setDownloadPtime(int ptime); + + /** + * Sets audio packetization interval sent to remote end. + * @param ptime packetization interval in milliseconds + */ + void setUploadPtime(int ptime); void setPreferredVideoSize(VideoSize vSize); diff --git a/linphone-deps.filelist b/linphone-deps.filelist index 22e069ed..de01182c 100755 --- a/linphone-deps.filelist +++ b/linphone-deps.filelist @@ -1,10 +1,9 @@ -./bin/avcodec-52.dll -./bin/avutil-50.dll +./bin/avcodec-53.dll +./bin/avutil-51.dll ./bin/libeXosip2-6.dll ./bin/libogg-0.dll ./bin/libtheora-0.dll ./bin/libxml2-2.dll ./bin/libosip2-6.dll ./bin/libosipparser2-6.dll -./bin/swscale-0.dll - +./bin/swscale-2.dll diff --git a/mediastreamer2 b/mediastreamer2 index 3428fc9d..06f75eec 160000 --- a/mediastreamer2 +++ b/mediastreamer2 @@ -1 +1 @@ -Subproject commit 3428fc9d84c363c677d0db0a3682b4bd2ca6d21a +Subproject commit 06f75eec486b8a5be3032d387bc91d9f4ca135e3 diff --git a/oRTP b/oRTP index b0c5530b..662a6586 160000 --- a/oRTP +++ b/oRTP @@ -1 +1 @@ -Subproject commit b0c5530bee255033f09011e5aab6d036e00520dc +Subproject commit 662a65869902a927673d9ceff10781e217ca8e9d diff --git a/po/de.po b/po/de.po index 55ce35cd..d826a1ff 100644 --- a/po/de.po +++ b/po/de.po @@ -7,7 +7,7 @@ msgstr "" "Project-Id-Version: linphone 0.7.1\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2011-04-08 22:32+0200\n" -"PO-Revision-Date: 2011-04-10 02:35+0200\n" +"PO-Revision-Date: 2011-05-27 23:45+0200\n" "Last-Translator: Gerhard Stengel \n" "Language-Team: German \n" "Language: \n" @@ -573,7 +573,7 @@ msgstr "Dauer:" #: ../gtk/main.ui.h:33 msgid "Enable self-view" -msgstr "Selbstansicht einschalten" +msgstr "Selbstansicht ein" #: ../gtk/main.ui.h:34 msgid "Enter username, phone number, or full sip address" @@ -1391,7 +1391,7 @@ msgstr "Abmeldung von %s ist erfolgt." #: ../coreapi/callbacks.c:574 msgid "no response timeout" -msgstr "keine Zeitüberschreitung bei der Antwort" +msgstr "Zeitüberschreitung bei der Antwort" #: ../coreapi/callbacks.c:577 #, c-format