]> sjero.net Git - linphone/commitdiff
Merge branch 'master' of git.linphone.org:linphone
authorSimon Morlat <simon.morlat@linphone.org>
Fri, 22 Feb 2013 20:37:11 +0000 (21:37 +0100)
committerSimon Morlat <simon.morlat@linphone.org>
Fri, 22 Feb 2013 20:37:11 +0000 (21:37 +0100)
Conflicts:
mediastreamer2

24 files changed:
configure.ac
coreapi/conference.c
coreapi/ec-calibrator.c
coreapi/linphonecall.c
coreapi/linphonecore.c
coreapi/linphonecore.h
coreapi/linphonecore_jni.cc
coreapi/private.h
coreapi/proxy.c
coreapi/upnp.c
coreapi/upnp.h
gtk/call_statistics.ui
gtk/conference.c
gtk/incall_view.c
gtk/linphone.h
gtk/main.c
gtk/main.ui
gtk/propertybox.c
gtk/update.c [changed mode: 0755->0644]
java/common/org/linphone/core/LinphoneCore.java
java/common/org/linphone/core/Reason.java [new file with mode: 0644]
java/impl/org/linphone/core/LinphoneCoreImpl.java
linphone.kdevelop [deleted file]
mediastreamer2

index 1372c5af32bcad8fc5e6262d9dba7011ae148e9d..43efbff30198fdf33b0d9d468fca786c578d989a 100644 (file)
@@ -782,6 +782,7 @@ printf "* %-30s %s\n" "Account assistant"   $build_wizard
 printf "* %-30s %s\n" "Console interface"      $console_ui
 printf "* %-30s %s\n" "Tools"                  $build_tools
 printf "* %-30s %s\n" "zRTP encryption (GPLv3)"        $zrtp
+printf "* %-30s %s\n" "uPnP support"           $build_upnp
 
 if test "$enable_tunnel" = "true" ; then
        printf "* Tunnel support\t\ttrue\n"
index a125673a29b0b91ef1861a748d76ffb8d5cc08db..16be62613f2b9697d5aaaed66dea6e0bf33ee489 100644 (file)
@@ -55,22 +55,38 @@ static void remove_local_endpoint(LinphoneConference *ctx){
        }
 }
 
+static int linphone_conference_get_size(LinphoneConference *conf){
+       if (conf->conf == NULL) {
+               return 0;
+       }
+       return ms_audio_conference_get_size(conf->conf) - (conf->record_endpoint ? 1 : 0);
+}
+
 static int remote_participants_count(LinphoneConference *ctx) {
-       if (!ctx->conf || ms_audio_conference_get_size(ctx->conf)==0) return 0;
-       if (!ctx->local_participant) return ms_audio_conference_get_size(ctx->conf);
-       return ms_audio_conference_get_size(ctx->conf) -1;
+       int count=linphone_conference_get_size(ctx);
+       if (count==0) return 0;
+       if (!ctx->local_participant) return count;
+       return count -1;
 }
 
 void linphone_core_conference_check_uninit(LinphoneCore *lc){
        LinphoneConference *ctx=&lc->conf_ctx;
        if (ctx->conf){
-               ms_message("conference_check_uninit(): nmembers=%i",ms_audio_conference_get_size(ctx->conf));
-               if (remote_participants_count(ctx)==1){
+               int remote_count=remote_participants_count(ctx);
+               ms_message("conference_check_uninit(): size=%i",linphone_conference_get_size(ctx));
+               if (remote_count==1){
                        convert_conference_to_call(lc);
                }
-               if (ms_audio_conference_get_size(ctx->conf)==1 && ctx->local_participant!=NULL){
-                       remove_local_endpoint(ctx);
+               if (remote_count==0){
+                       if (ctx->local_participant!=NULL)
+                               remove_local_endpoint(ctx);
+                       if (ctx->record_endpoint){
+                               ms_audio_conference_remove_member(ctx->conf,ctx->record_endpoint);
+                               ms_audio_endpoint_destroy(ctx->record_endpoint);
+                               ctx->record_endpoint=NULL;
+                       }
                }
+               
                if (ms_audio_conference_get_size(ctx->conf)==0){
                        ms_audio_conference_destroy(ctx->conf);
                        ctx->conf=NULL;
@@ -381,10 +397,37 @@ int linphone_core_terminate_conference(LinphoneCore *lc) {
  * @returns the number of participants to the conference
 **/
 int linphone_core_get_conference_size(LinphoneCore *lc) {
-       if (lc->conf_ctx.conf == NULL) {
-               return 0;
+       LinphoneConference *conf=&lc->conf_ctx;
+       return linphone_conference_get_size(conf);
+}
+
+
+int linphone_core_start_conference_recording(LinphoneCore *lc, const char *path){
+       LinphoneConference *conf=&lc->conf_ctx;
+       if (conf->conf == NULL) {
+               ms_warning("linphone_core_start_conference_recording(): no conference now.");
+               return -1;
+       }
+       if (conf->record_endpoint==NULL){
+               conf->record_endpoint=ms_audio_endpoint_new_recorder();
+               ms_audio_conference_add_member(conf->conf,conf->record_endpoint);
        }
-       return ms_audio_conference_get_size(lc->conf_ctx.conf);
+       ms_audio_recorder_endpoint_start(conf->record_endpoint,path);
+       return 0;
+}
+
+int linphone_core_stop_conference_recording(LinphoneCore *lc){
+       LinphoneConference *conf=&lc->conf_ctx;
+       if (conf->conf == NULL) {
+               ms_warning("linphone_core_stop_conference_recording(): no conference now.");
+               return -1;
+       }
+       if (conf->record_endpoint==NULL){
+               ms_warning("linphone_core_stop_conference_recording(): no record active.");
+               return -1;
+       }
+       ms_audio_recorder_endpoint_stop(conf->record_endpoint);
+       return 0;
 }
 
 /**
index 7fb001d3de75554467c4ddc83de2c04bcbe46e87..8efbabb1b0a0758c0fde6bcef4592860361eb296 100644 (file)
@@ -97,17 +97,37 @@ static void ecc_deinit_filters(EcCalibrator *ecc){
 static void on_tone_sent(void *data, MSFilter *f, unsigned int event_id, void *arg){
        MSDtmfGenEvent *ev=(MSDtmfGenEvent*)arg;
        EcCalibrator *ecc=(EcCalibrator*)data;
-       ecc->sent_count++;
        ecc->acc-=ev->tone_start_time;
        ms_message("Sent tone at %u",(unsigned int)ev->tone_start_time);
 }
 
+static bool_t is_valid_tone(EcCalibrator *ecc, MSToneDetectorEvent *ev){
+       bool_t *toneflag=NULL;
+       if (strcmp(ev->tone_name,"freq1")==0){
+               toneflag=&ecc->freq1;
+       }else if (strcmp(ev->tone_name,"freq2")==0){
+               toneflag=&ecc->freq2;
+       }else if (strcmp(ev->tone_name,"freq3")==0){
+               toneflag=&ecc->freq3;
+       }else{
+               ms_error("Calibrator bug.");
+               return FALSE;
+       }
+       if (*toneflag){
+               ms_message("Duplicated tone event, ignored.");
+               return FALSE;
+       }
+       *toneflag=TRUE;
+       return TRUE;
+}
+
 static void on_tone_received(void *data, MSFilter *f, unsigned int event_id, void *arg){
        MSToneDetectorEvent *ev=(MSToneDetectorEvent*)arg;
        EcCalibrator *ecc=(EcCalibrator*)data;
-       ecc->recv_count++;
-       ecc->acc+=ev->tone_start_time;
-       ms_message("Received tone at %u",(unsigned int)ev->tone_start_time);
+       if (is_valid_tone(ecc,ev)){
+               ecc->acc+=ev->tone_start_time;
+               ms_message("Received tone at %u",(unsigned int)ev->tone_start_time);
+       }
 }
 
 static void ecc_play_tones(EcCalibrator *ecc){
@@ -116,53 +136,76 @@ static void ecc_play_tones(EcCalibrator *ecc){
 
        ms_filter_set_notify_callback(ecc->det,on_tone_received,ecc);
 
+       /* configure the tones to be scanned */
+       
+       strncpy(expected_tone.tone_name,"freq1",sizeof(expected_tone.tone_name));
        expected_tone.frequency=2000;
        expected_tone.min_duration=40;
-       expected_tone.min_amplitude=0.02;
+       expected_tone.min_amplitude=0.1;
 
        ms_filter_call_method (ecc->det,MS_TONE_DETECTOR_ADD_SCAN,&expected_tone);
        
-       tone.frequency=1300;
-       tone.duration=1000;
-       tone.amplitude=1.0;
+       strncpy(expected_tone.tone_name,"freq2",sizeof(expected_tone.tone_name));
+       expected_tone.frequency=2300;
+       expected_tone.min_duration=40;
+       expected_tone.min_amplitude=0.1;
 
+       ms_filter_call_method (ecc->det,MS_TONE_DETECTOR_ADD_SCAN,&expected_tone);
+       
+       strncpy(expected_tone.tone_name,"freq3",sizeof(expected_tone.tone_name));
+       expected_tone.frequency=2500;
+       expected_tone.min_duration=40;
+       expected_tone.min_amplitude=0.1;
+
+       ms_filter_call_method (ecc->det,MS_TONE_DETECTOR_ADD_SCAN,&expected_tone);
+       
        /*play an initial tone to startup the audio playback/capture*/
+       
+       tone.frequency=140;
+       tone.duration=1000;
+       tone.amplitude=0.5;
+
        ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone);
        ms_sleep(2);
 
        ms_filter_set_notify_callback(ecc->gen,on_tone_sent,ecc);
+       
+       /* play the three tones*/
+       
        tone.frequency=2000;
        tone.duration=100;
-
        ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone);
-       ms_sleep(1);
+       ms_usleep(300000);
+       
+       tone.frequency=2300;
+       tone.duration=100;
        ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone);
-       ms_sleep(1);
+       ms_usleep(300000);
+       
+       tone.frequency=2500;
+       tone.duration=100;
        ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone);
        ms_sleep(1);
-
-       if (ecc->sent_count==3) {
-               if (ecc->recv_count==3){
-                       int delay=ecc->acc/3;
-                       if (delay<0){
-                               ms_error("Quite surprising calibration result, delay=%i",delay);
-                               ecc->status=LinphoneEcCalibratorFailed;
-                       }else{
-                               ms_message("Echo calibration estimated delay to be %i ms",delay);
-                               ecc->delay=delay;
-                               ecc->status=LinphoneEcCalibratorDone;
-                       }
-               } else if (ecc->recv_count == 0) {
+       
+       if (ecc->freq1 && ecc->freq2 && ecc->freq3) {
+               int delay=ecc->acc/3;
+               if (delay<0){
+                       ms_error("Quite surprising calibration result, delay=%i",delay);
+                       ecc->status=LinphoneEcCalibratorFailed;
+               }else{
+                       ms_message("Echo calibration estimated delay to be %i ms",delay);
+                       ecc->delay=delay;
+                       ecc->status=LinphoneEcCalibratorDone;
+               }
+       } else if ((ecc->freq1 || ecc->freq2 || ecc->freq3)==FALSE) {
                        ms_message("Echo calibration succeeded, no echo has been detected");
                        ecc->status = LinphoneEcCalibratorDoneNoEcho;
-               } else {
+       } else {
                        ecc->status = LinphoneEcCalibratorFailed;
-               }
-       }else{
-               ecc->status=LinphoneEcCalibratorFailed;
        }
+
        if (ecc->status == LinphoneEcCalibratorFailed) {
-               ms_error("Echo calibration failed, tones received = %i",ecc->recv_count);
+               ms_error("Echo calibration failed.");
        }
 }
 
index 31b945acb4d5b54547991640ef0e8d83a136b097..a7cad386c3895b0c87491c3d00b37840ae20465a 100644 (file)
@@ -508,14 +508,21 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro
        call->core=lc;
 
        if (lc->sip_conf.ping_with_options){
-               /*the following sends an option request back to the caller so that
-                we get a chance to discover our nat'd address before answering.*/
-               call->ping_op=sal_op_new(lc->sal);
-               from_str=linphone_address_as_string_uri_only(from);
-               sal_op_set_route(call->ping_op,sal_op_get_network_origin(op));
-               sal_op_set_user_pointer(call->ping_op,call);
-               sal_ping(call->ping_op,linphone_core_find_best_identity(lc,from,NULL),from_str);
-               ms_free(from_str);
+#ifdef BUILD_UPNP
+               if (lc->upnp != NULL && linphone_core_get_firewall_policy(lc)==LinphonePolicyUseUpnp &&
+                       linphone_upnp_context_get_state(lc->upnp) == LinphoneUpnpStateOk) {
+#else //BUILD_UPNP
+               {
+#endif //BUILD_UPNP
+                       /*the following sends an option request back to the caller so that
+                        we get a chance to discover our nat'd address before answering.*/
+                       call->ping_op=sal_op_new(lc->sal);
+                       from_str=linphone_address_as_string_uri_only(from);
+                       sal_op_set_route(call->ping_op,sal_op_get_network_origin(op));
+                       sal_op_set_user_pointer(call->ping_op,call);
+                       sal_ping(call->ping_op,linphone_core_find_best_identity(lc,from,NULL),from_str);
+                       ms_free(from_str);
+               }
        }
 
        linphone_address_clean(from);
@@ -1100,7 +1107,7 @@ void linphone_call_params_add_custom_header(LinphoneCallParams *params, const ch
        params->custom_headers=sal_custom_header_append(params->custom_headers,header_name,header_value);
 }
 
-const char *linphone_call_params_get_custom_header(LinphoneCallParams *params, const char *header_name){
+const char *linphone_call_params_get_custom_header(const LinphoneCallParams *params, const char *header_name){
        return sal_custom_header_find(params->custom_headers,header_name);
 }
 
index ad1bb5667e8ba4f5d3960260e456b91d8576cc9c..237590473f27d638f3eedf8e5018edb718bb82cd 100644 (file)
@@ -92,12 +92,7 @@ int lc_callback_obj_invoke(LCCallbackObj *obj, LinphoneCore *lc){
 
 /*prevent a gcc bug with %c*/
 static size_t my_strftime(char *s, size_t max, const char  *fmt,  const struct tm *tm){
-#if !defined(_WIN32_WCE)
        return strftime(s, max, fmt, tm);
-#else
-       return 0;
-       /*FIXME*/
-#endif /*_WIN32_WCE*/
 }
 
 static void set_call_log_date(LinphoneCallLog *cl, time_t start_time){
@@ -120,7 +115,7 @@ LinphoneCallLog * linphone_call_log_new(LinphoneCall *call, LinphoneAddress *fro
        set_call_log_date(cl,cl->start_date_time);
        cl->from=from;
        cl->to=to;
-    cl->status=LinphoneCallAborted; /*default status*/
+       cl->status=LinphoneCallAborted; /*default status*/
        return cl;
 }
 
@@ -666,6 +661,9 @@ static void sip_config_read(LinphoneCore *lc)
 
        tmp=lp_config_get_int(lc->config,"sip","in_call_timeout",0);
        linphone_core_set_in_call_timeout(lc,tmp);
+       
+       tmp=lp_config_get_int(lc->config,"sip","delayed_timeout",4);
+       linphone_core_set_delayed_timeout(lc,tmp);
 
        /* get proxies config */
        for(i=0;; i++){
@@ -1304,9 +1302,6 @@ static void linphone_core_init (LinphoneCore * lc, const LinphoneCoreVTable *vta
        lc->tunnel=linphone_core_tunnel_new(lc);
        if (lc->tunnel) linphone_tunnel_configure(lc->tunnel);
 #endif
-#ifdef BUILD_UPNP
-       lc->upnp = linphone_upnp_context_new(lc);
-#endif //BUILD_UPNP
        if (lc->vtable.display_status)
                lc->vtable.display_status(lc,_("Ready"));
        lc->auto_net_state_mon=lc->sip_conf.auto_net_state_mon;
@@ -2054,9 +2049,11 @@ void linphone_core_iterate(LinphoneCore *lc){
                                lc->ecc->cb(lc,ecs,lc->ecc->delay,lc->ecc->cb_data);
                        if (ecs==LinphoneEcCalibratorDone){
                                int len=lp_config_get_int(lc->config,"sound","ec_tail_len",0);
-                               lp_config_set_int(lc->config, "sound", "ec_delay",MAX(lc->ecc->delay-(len/2),0));
+                               int margin=len/2;
+                               
+                               lp_config_set_int(lc->config, "sound", "ec_delay",MAX(lc->ecc->delay-margin,0));
                        } else if (ecs == LinphoneEcCalibratorFailed) {
-                               lp_config_set_int(lc->config, "sound", "ec_delay", LP_CONFIG_DEFAULT_INT(lc->config, "ec_delay", 250));
+                               lp_config_set_int(lc->config, "sound", "ec_delay", -1);/*use default value from soundcard*/
                        } else if (ecs == LinphoneEcCalibratorDoneNoEcho) {
                                linphone_core_enable_echo_cancellation(lc, FALSE);
                        }
@@ -2095,7 +2092,7 @@ void linphone_core_iterate(LinphoneCore *lc){
                 linphone_core_start_invite() */
                calls=calls->next;
                linphone_call_background_tasks(call,one_second_elapsed);
-               if (call->state==LinphoneCallOutgoingInit && (elapsed>=4)){
+               if (call->state==LinphoneCallOutgoingInit && (elapsed>=lc->sip_conf.delayed_timeout)){
                        /*start the call even if the OPTIONS reply did not arrive*/
                        if (call->ice_session != NULL) {
                                ms_warning("ICE candidates gathering from [%s] has not finished yet, proceed with the call without ICE anyway."
@@ -2605,15 +2602,23 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const
        }
 
        if (call->dest_proxy==NULL && lc->sip_conf.ping_with_options==TRUE){
-               /*defer the start of the call after the OPTIONS ping*/
-               call->ping_replied=FALSE;
-               call->ping_op=sal_op_new(lc->sal);
-               sal_ping(call->ping_op,from,real_url);
-               sal_op_set_user_pointer(call->ping_op,call);
-               call->start_time=time(NULL);
-       }else{
-               if (defer==FALSE) linphone_core_start_invite(lc,call);
+#ifdef BUILD_UPNP
+               if (lc->upnp != NULL && linphone_core_get_firewall_policy(lc)==LinphonePolicyUseUpnp &&
+                       linphone_upnp_context_get_state(lc->upnp) == LinphoneUpnpStateOk) {
+#else //BUILD_UPNP
+               {
+#endif //BUILD_UPNP
+                       /*defer the start of the call after the OPTIONS ping*/
+                       call->ping_replied=FALSE;
+                       call->ping_op=sal_op_new(lc->sal);
+                       sal_ping(call->ping_op,from,real_url);
+                       sal_op_set_user_pointer(call->ping_op,call);
+                       call->start_time=time(NULL);
+                       defer = TRUE;
+               }
        }
+       
+       if (defer==FALSE) linphone_core_start_invite(lc,call);
 
        if (real_url!=NULL) ms_free(real_url);
        return call;
@@ -3496,6 +3501,26 @@ int linphone_core_get_in_call_timeout(LinphoneCore *lc){
        return lc->sip_conf.in_call_timeout;
 }
 
+/**
+ * Returns the delayed timeout
+ *
+ * @ingroup call_control
+ * See linphone_core_set_delayed_timeout() for details.
+**/
+int linphone_core_get_delayed_timeout(LinphoneCore *lc){
+       return lc->sip_conf.delayed_timeout;
+}
+
+/**
+ * Set the in delayed timeout in seconds.
+ *
+ * @ingroup call_control
+ * After this timeout period, a delayed call (internal call initialisation or resolution) is resumed.
+**/
+void linphone_core_set_delayed_timeout(LinphoneCore *lc, int seconds){
+       lc->sip_conf.delayed_timeout=seconds;
+}
+
 void linphone_core_set_presence_info(LinphoneCore *lc,int minutes_away,
                                                                                                        const char *contact,
                                                                                                        LinphoneOnlineStatus presence_mode)
@@ -4213,6 +4238,19 @@ void linphone_core_set_firewall_policy(LinphoneCore *lc, LinphoneFirewallPolicy
        }
 #endif //BUILD_UPNP
        lc->net_conf.firewall_policy=pol;
+#ifdef BUILD_UPNP
+       if(pol == LinphonePolicyUseUpnp) {
+               if(lc->upnp == NULL) {
+                       lc->upnp = linphone_upnp_context_new(lc);
+               }
+       } else {
+               if(lc->upnp != NULL) {
+                       linphone_upnp_context_destroy(lc->upnp);
+                       lc->upnp = NULL;
+               }
+       }
+       linphone_core_enable_keep_alive(lc, (lc->sip_conf.keepalive_period > 0));
+#endif //BUILD_UPNP
        if (lc->sip_conf.contact) update_primary_contact(lc);
        if (linphone_core_ready(lc))
                lp_config_set_int(lc->config,"net","firewall_policy",pol);
@@ -5006,6 +5044,7 @@ void sip_config_uninit(LinphoneCore *lc)
        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","delayed_timeout",config->delayed_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);
@@ -5168,10 +5207,11 @@ static void linphone_core_uninit(LinphoneCore *lc)
                usleep(50000);
 #endif
        }
-
 #ifdef BUILD_UPNP
-       linphone_upnp_context_destroy(lc->upnp);
-       lc->upnp = NULL;
+       if(lc->upnp != NULL) {
+               linphone_upnp_context_destroy(lc->upnp);
+               lc->upnp = NULL;
+       }
 #endif //BUILD_UPNP
 
        if (lc->friends)
@@ -5204,6 +5244,17 @@ static void linphone_core_uninit(LinphoneCore *lc)
        
        ms_list_for_each(lc->last_recv_msg_ids,ms_free);
        lc->last_recv_msg_ids=ms_list_free(lc->last_recv_msg_ids);
+       
+       // Free struct variable
+       if(lc->zrtp_secrets_cache != NULL) {
+               ms_free(lc->zrtp_secrets_cache);
+       }
+       if(lc->play_file!=NULL){
+               ms_free(lc->play_file);
+       }
+       if(lc->rec_file!=NULL){
+               ms_free(lc->rec_file);
+       }
 
        linphone_core_free_payload_types(lc);
        ortp_exit();
@@ -5438,6 +5489,11 @@ const char *linphone_error_to_string(LinphoneReason err){
  * Enables signaling keep alive
  */
 void linphone_core_enable_keep_alive(LinphoneCore* lc,bool_t enable) {
+#ifdef BUILD_UPNP
+       if (linphone_core_get_firewall_policy(lc)==LinphonePolicyUseUpnp) {
+               enable = FALSE;
+       }
+#endif //BUILD_UPNP
        if (enable > 0) {
                sal_use_tcp_tls_keepalive(lc->sal,lc->sip_conf.tcp_tls_keepalive);
                sal_set_keepalive_period(lc->sal,lc->sip_conf.keepalive_period);
@@ -5506,7 +5562,7 @@ void linphone_core_remove_iterate_hook(LinphoneCore *lc, LinphoneCoreIterateHook
        for(elem=lc->hooks;elem!=NULL;elem=elem->next){
                Hook *h=(Hook*)elem->data;
                if (h->fun==hook && h->data==hook_data){
-                       ms_list_remove_link(lc->hooks,elem);
+                       lc->hooks = ms_list_remove_link(lc->hooks,elem);
                        ms_free(h);
                        return;
                }
index 1de97d0b015e451948f138a098bae3e2b432ea55..2c2168646c6d38f4073532fabd3f87eba10fff88 100644 (file)
@@ -37,14 +37,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 extern "C" {
 #endif
 
-struct _MSSndCard;
 struct _LinphoneCore;
 /**
  * Linphone core main object created by function linphone_core_new() .
  * @ingroup initializing
  */
 typedef struct _LinphoneCore LinphoneCore;
-struct SalOp;
 
 struct _LpConfig;
 
@@ -201,7 +199,7 @@ void linphone_call_params_enable_low_bandwidth(LinphoneCallParams *cp, bool_t en
 void linphone_call_params_set_record_file(LinphoneCallParams *cp, const char *path);
 const char *linphone_call_params_get_record_file(const LinphoneCallParams *cp);
 void linphone_call_params_add_custom_header(LinphoneCallParams *params, const char *header_name, const char *header_value);
-const char *linphone_call_params_get_custom_header(LinphoneCallParams *params, const char *header_name);
+const char *linphone_call_params_get_custom_header(const LinphoneCallParams *params, const char *header_name);
 /**
  * Enum describing failure reasons.
  * @ingroup initializing
@@ -1101,6 +1099,10 @@ void linphone_core_set_in_call_timeout(LinphoneCore *lc, int seconds);
 
 int linphone_core_get_in_call_timeout(LinphoneCore *lc);
 
+void linphone_core_set_delayed_timeout(LinphoneCore *lc, int seconds);
+
+int linphone_core_get_delayed_timeout(LinphoneCore *lc);
+
 void linphone_core_set_stun_server(LinphoneCore *lc, const char *server);
 
 const char * linphone_core_get_stun_server(const LinphoneCore *lc);
@@ -1366,6 +1368,8 @@ float linphone_core_get_conference_local_input_volume(LinphoneCore *lc);
 
 int linphone_core_terminate_conference(LinphoneCore *lc);
 int linphone_core_get_conference_size(LinphoneCore *lc);
+int linphone_core_start_conference_recording(LinphoneCore *lc, const char *path);
+int linphone_core_stop_conference_recording(LinphoneCore *lc);
 
 int linphone_core_get_max_calls(LinphoneCore *lc);
 void linphone_core_set_max_calls(LinphoneCore *lc, int max);
index 64897b2189a89b53e03c06fa28b5d6e7173339a8..57ab7c4ca1a5b68f506b817761837e5c3a264f4b 100644 (file)
@@ -650,6 +650,13 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_terminateCall(     JNIEnv*
        linphone_core_terminate_call((LinphoneCore*)lc,(LinphoneCall*)call);
 }
 
+extern "C" void Java_org_linphone_core_LinphoneCoreImpl_declineCall(   JNIEnv*  env
+               ,jobject  thiz
+               ,jlong lc
+               ,jlong call, jint reason) {
+       linphone_core_decline_call((LinphoneCore*)lc,(LinphoneCall*)call,(LinphoneReason)reason);
+}
+
 extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_getRemoteAddress(     JNIEnv*  env
                ,jobject  thiz
                ,jlong lc) {
@@ -993,6 +1000,18 @@ extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_startEchoCalibration(JNI
 
 }
 
+extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_needsEchoCalibration(JNIEnv *env, jobject thiz, jlong lc){
+       MSSndCard *sndcard;
+       MSSndCardManager *m=ms_snd_card_manager_get();
+       const char *card=linphone_core_get_capture_device((LinphoneCore*)lc);
+       sndcard=ms_snd_card_manager_get_card(m,card);
+       if (sndcard == NULL){
+               ms_error("Could not get soundcard.");
+               return TRUE;
+       }
+       return (ms_snd_card_get_capabilities(sndcard) & MS_SND_CARD_CAP_BUILTIN_ECHO_CANCELLER) || (ms_snd_card_get_minimal_latency(sndcard)>0);
+}
+
 extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_getMediaEncryption(JNIEnv*  env
                                                                                                                                                        ,jobject  thiz
                                                                                                                                                        ,jlong lc
@@ -2041,9 +2060,11 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_leaveConference(JNIEnv *
 extern "C" void Java_org_linphone_core_LinphoneCoreImpl_addAllToConference(JNIEnv *env,jobject thiz,jlong pCore) {
        linphone_core_add_all_to_conference((LinphoneCore *) pCore);
 }
+
 extern "C" void Java_org_linphone_core_LinphoneCoreImpl_addToConference(JNIEnv *env,jobject thiz,jlong pCore, jlong pCall) {
        linphone_core_add_to_conference((LinphoneCore *) pCore, (LinphoneCall *) pCall);
 }
+
 extern "C" void Java_org_linphone_core_LinphoneCoreImpl_removeFromConference(JNIEnv *env,jobject thiz,jlong pCore, jlong pCall) {
        linphone_core_remove_from_conference((LinphoneCore *) pCore, (LinphoneCall *) pCall);
 }
@@ -2054,6 +2075,22 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_terminateConference(JNIE
 extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_getConferenceSize(JNIEnv *env,jobject thiz,jlong pCore) {
        return (jint)linphone_core_get_conference_size((LinphoneCore *) pCore);
 }
+
+extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_startConferenceRecording(JNIEnv *env,jobject thiz,jlong pCore, jstring jpath){
+       int err=-1;
+       if (jpath){
+               const char *path=env->GetStringUTFChars(jpath, NULL);
+               err=linphone_core_start_conference_recording((LinphoneCore*)pCore,path);
+               env->ReleaseStringUTFChars(jpath,path);
+       }
+       return err;
+}
+
+extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_stopConferenceRecording(JNIEnv *env,jobject thiz,jlong pCore){
+       int err=linphone_core_stop_conference_recording((LinphoneCore*)pCore);
+       return err;
+}
+
 extern "C" void Java_org_linphone_core_LinphoneCoreImpl_terminateAllCalls(JNIEnv *env,jobject thiz,jlong pCore) {
        linphone_core_terminate_all_calls((LinphoneCore *) pCore);
 }
index 149fbac58eceff612204437df929d4a08e634982..41d453df3bdea168cbde72fe76d1d626c0c93508 100644 (file)
@@ -420,6 +420,7 @@ typedef struct sip_config
        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 */
+       int delayed_timeout;    /*timeout after a delayed call is resumed */
        unsigned int keepalive_period; /* interval in ms between keep alive messages sent to the proxy server*/
        LCSipTransports transports;
        bool_t use_info;
@@ -529,6 +530,7 @@ struct _LinphoneConference{
        MSAudioConference *conf;
        AudioStream *local_participant;
        MSAudioEndpoint *local_endpoint;
+       MSAudioEndpoint *record_endpoint;
        RtpProfile *local_dummy_profile;
        bool_t local_muted;
 };
@@ -642,12 +644,11 @@ struct _EcCalibrator{
        MSTicker *ticker;
        LinphoneEcCalibrationCallback cb;
        void *cb_data;
-       int recv_count;
-       int sent_count;
        int64_t acc;
        int delay;
        unsigned int rate;
        LinphoneEcCalibratorStatus status;
+       bool_t freq1,freq2,freq3;
 };
 
 typedef struct _EcCalibrator EcCalibrator;
index fb650c852133e4f33ed7e206b0c0adea36a7e63e..75930adb14a52b2e5422fefb19975240e3381680 100644 (file)
@@ -263,15 +263,30 @@ static char *guess_contact_for_register(LinphoneProxyConfig *obj){
        if (proxy==NULL) return NULL;
        host=linphone_address_get_domain (proxy);
        if (host!=NULL){
-               char localip[LINPHONE_IPADDR_SIZE];
+               int localport = -1;
+               char localip_tmp[LINPHONE_IPADDR_SIZE] = {'\0'};
+               const char *localip = NULL;
                char *tmp;
                LCSipTransports tr;
                LinphoneAddress *contact;
                
-               linphone_core_get_local_ip(obj->lc,host,localip);
                contact=linphone_address_new(obj->reg_identity);
-               linphone_address_set_domain (contact,localip);
-               linphone_address_set_port_int(contact,linphone_core_get_sip_port(obj->lc));
+#ifdef BUILD_UPNP
+               if (obj->lc->upnp != NULL && linphone_core_get_firewall_policy(obj->lc)==LinphonePolicyUseUpnp &&
+                       linphone_upnp_context_get_state(obj->lc->upnp) == LinphoneUpnpStateOk) {
+                       localip = linphone_upnp_context_get_external_ipaddress(obj->lc->upnp);
+                       localport = linphone_upnp_context_get_external_port(obj->lc->upnp);
+               }
+#endif //BUILD_UPNP            
+               if(localip == NULL) {
+                       localip = localip_tmp;
+                       linphone_core_get_local_ip(obj->lc,host,localip_tmp);
+               }
+               if(localport == -1) {
+                       localport = linphone_core_get_sip_port(obj->lc);
+               }
+               linphone_address_set_port_int(contact,localport);
+               linphone_address_set_domain(contact,localip);
                linphone_address_set_display_name(contact,NULL);
                
                linphone_core_get_sip_transports(obj->lc,&tr);
@@ -1082,9 +1097,19 @@ void linphone_proxy_config_update(LinphoneProxyConfig *cfg){
                if (cfg->type && cfg->ssctx==NULL){
                        linphone_proxy_config_activate_sip_setup(cfg);
                }
-               if ((!lc->sip_conf.register_only_when_network_is_up || lc->network_reachable) &&
-                       (!lc->sip_conf.register_only_when_upnp_is_ok || linphone_core_get_upnp_state(lc) == LinphoneUpnpStateOk))
-                       linphone_proxy_config_register(cfg);
+               switch(linphone_core_get_firewall_policy(lc)) {
+                       case LinphonePolicyUseUpnp:
+#ifdef BUILD_UPNP
+                       if(!lc->sip_conf.register_only_when_upnp_is_ok || 
+                          (lc->upnp != NULL && !linphone_upnp_context_is_ready_for_register(lc->upnp))) {
+                               break;
+                       }
+#endif //BUILD_UPNP
+                       default:
+                       if ((!lc->sip_conf.register_only_when_network_is_up || lc->network_reachable)) {
+                               linphone_proxy_config_register(cfg);
+                       }
+               }       
                if (cfg->publish && cfg->publish_op==NULL){
                        linphone_proxy_config_send_publish(cfg,lc->presence_mode);
                }
index d86c8a42a4234a3fe51dd6cc278fbacf32e42225..e9ce18df7661c469167e44309895a3764bc5fdee 100644 (file)
@@ -21,9 +21,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 #include "private.h"
 #include "lpconfig.h"
 
-#define UPNP_ADD_MAX_RETRY 4
+#define UPNP_ADD_MAX_RETRY    4
 #define UPNP_REMOVE_MAX_RETRY 4
-#define UPNP_SECTION_NAME "uPnP"
+#define UPNP_SECTION_NAME     "uPnP"
+#define UPNP_CORE_READY_CHECK 1 
+#define UPNP_CORE_RETRY_DELAY 4
+#define UPNP_CALL_RETRY_DELAY 1
 
 /*
  * uPnP Definitions
@@ -41,6 +44,7 @@ typedef struct _UpnpPortBinding {
        int ref;
        bool_t to_remove;
        bool_t to_add;
+       time_t last_update;
 } UpnpPortBinding;
 
 typedef struct _UpnpStream {
@@ -69,7 +73,9 @@ struct _UpnpContext {
 
        ms_mutex_t mutex;
        ms_cond_t empty_cond;
-
+       
+       time_t last_ready_check;
+       LinphoneUpnpState last_ready_state;
 };
 
 
@@ -77,19 +83,25 @@ bool_t linphone_core_upnp_hook(void *data);
 void linphone_core_upnp_refresh(UpnpContext *ctx);
 
 UpnpPortBinding *linphone_upnp_port_binding_new();
+UpnpPortBinding *linphone_upnp_port_binding_new_with_parameters(upnp_igd_ip_protocol protocol, int local_port, int external_port);
+UpnpPortBinding *linphone_upnp_port_binding_new_or_collect(MSList *list, upnp_igd_ip_protocol protocol, int local_port, int external_port); 
 UpnpPortBinding *linphone_upnp_port_binding_copy(const UpnpPortBinding *port);
 bool_t linphone_upnp_port_binding_equal(const UpnpPortBinding *port1, const UpnpPortBinding *port2);
 UpnpPortBinding *linphone_upnp_port_binding_equivalent_in_list(MSList *list, const UpnpPortBinding *port);
 UpnpPortBinding *linphone_upnp_port_binding_retain(UpnpPortBinding *port);
+void linphone_upnp_update_port_binding(UpnpContext *lupnp, UpnpPortBinding **port_mapping, upnp_igd_ip_protocol protocol, int port, int retry_delay); 
 void linphone_upnp_port_binding_log(int level, const char *msg, const UpnpPortBinding *port);
 void linphone_upnp_port_binding_release(UpnpPortBinding *port);
+void linphone_upnp_update_config(UpnpContext *lupnp);
 
+// Configuration
 MSList *linphone_upnp_config_list_port_bindings(struct _LpConfig *lpc);
 void linphone_upnp_config_add_port_binding(UpnpContext *lupnp, const UpnpPortBinding *port);
 void linphone_upnp_config_remove_port_binding(UpnpContext *lupnp, const UpnpPortBinding *port);
 
-int linphone_upnp_context_send_remove_port_binding(UpnpContext *lupnp, UpnpPortBinding *port);
-int linphone_upnp_context_send_add_port_binding(UpnpContext *lupnp, UpnpPortBinding *port);
+// uPnP 
+int linphone_upnp_context_send_remove_port_binding(UpnpContext *lupnp, UpnpPortBinding *port, bool_t retry);
+int linphone_upnp_context_send_add_port_binding(UpnpContext *lupnp, UpnpPortBinding *port, bool_t retry);
 
 
 /**
@@ -172,7 +184,7 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) {
                mapping = (upnp_igd_port_mapping *) arg;
                port_mapping = (UpnpPortBinding*) mapping->cookie;
                port_mapping->external_port = -1; //Force random external port
-               if(linphone_upnp_context_send_add_port_binding(lupnp, port_mapping) != 0) {
+               if(linphone_upnp_context_send_add_port_binding(lupnp, port_mapping, TRUE) != 0) {
                        linphone_upnp_port_binding_log(ORTP_ERROR, "Can't add port binding", port_mapping);
                }
 
@@ -190,7 +202,7 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) {
        case UPNP_IGD_PORT_MAPPING_REMOVE_FAILURE:
                mapping = (upnp_igd_port_mapping *) arg;
                port_mapping = (UpnpPortBinding*) mapping->cookie;
-               if(linphone_upnp_context_send_remove_port_binding(lupnp, port_mapping) != 0) {
+               if(linphone_upnp_context_send_remove_port_binding(lupnp, port_mapping, TRUE) != 0) {
                        linphone_upnp_port_binding_log(ORTP_ERROR, "Can't remove port binding", port_mapping);
                        linphone_upnp_config_remove_port_binding(lupnp, port_mapping);
                }
@@ -208,7 +220,7 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) {
                if(port_mapping->to_remove) {
                        if(port_mapping->state == LinphoneUpnpStateOk) {
                                port_mapping->to_remove = FALSE;
-                               linphone_upnp_context_send_remove_port_binding(lupnp, port_mapping);
+                               linphone_upnp_context_send_remove_port_binding(lupnp, port_mapping, FALSE);
                        } else if(port_mapping->state == LinphoneUpnpStateKo) {
                                port_mapping->to_remove = FALSE;
                        }
@@ -216,7 +228,7 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) {
                if(port_mapping->to_add) {
                        if(port_mapping->state == LinphoneUpnpStateIdle || port_mapping->state == LinphoneUpnpStateKo) {
                                port_mapping->to_add = FALSE;
-                               linphone_upnp_context_send_add_port_binding(lupnp, port_mapping);
+                               linphone_upnp_context_send_add_port_binding(lupnp, port_mapping, FALSE);
                        }
                }
 
@@ -239,13 +251,14 @@ void linphone_upnp_igd_callback(void *cookie, upnp_igd_event event, void *arg) {
  */
 
 UpnpContext* linphone_upnp_context_new(LinphoneCore *lc) {
-       LCSipTransports transport;
        UpnpContext *lupnp = (UpnpContext *)ms_new0(UpnpContext,1);
-       const char *ip_address;
 
        ms_mutex_init(&lupnp->mutex, NULL);
        ms_cond_init(&lupnp->empty_cond, NULL);
 
+       lupnp->last_ready_check = 0;
+       lupnp->last_ready_state = LinphoneUpnpStateIdle;
+
        lupnp->lc = lc;
        lupnp->pending_bindings = NULL;
        lupnp->adding_configs = NULL;
@@ -253,31 +266,10 @@ UpnpContext* linphone_upnp_context_new(LinphoneCore *lc) {
        lupnp->state = LinphoneUpnpStateIdle;
        ms_message("uPnP IGD: New %p for core %p", lupnp, lc);
 
-       linphone_core_get_sip_transports(lc, &transport);
-       if(transport.udp_port != 0) {
-               lupnp->sip_udp = linphone_upnp_port_binding_new();
-               lupnp->sip_udp->protocol = UPNP_IGD_IP_PROTOCOL_UDP;
-               lupnp->sip_udp->local_port = transport.udp_port;
-               lupnp->sip_udp->external_port = transport.udp_port;
-       } else {
-               lupnp->sip_udp = NULL;
-       }
-       if(transport.tcp_port != 0) {
-               lupnp->sip_tcp = linphone_upnp_port_binding_new();
-               lupnp->sip_tcp->protocol = UPNP_IGD_IP_PROTOCOL_TCP;
-               lupnp->sip_tcp->local_port = transport.tcp_port;
-               lupnp->sip_tcp->external_port = transport.tcp_port;
-       } else {
-               lupnp->sip_tcp = NULL;
-       }
-       if(transport.tls_port != 0) {
-               lupnp->sip_tls = linphone_upnp_port_binding_new();
-               lupnp->sip_tls->protocol = UPNP_IGD_IP_PROTOCOL_TCP;
-               lupnp->sip_tls->local_port = transport.tls_port;
-               lupnp->sip_tls->external_port = transport.tls_port;
-       } else {
-               lupnp->sip_tls = NULL;
-       }
+       // Init ports
+       lupnp->sip_udp = NULL;
+       lupnp->sip_tcp = NULL;
+       lupnp->sip_tls = NULL;
 
        linphone_core_add_iterate_hook(lc, linphone_core_upnp_hook, lupnp);
 
@@ -289,17 +281,6 @@ UpnpContext* linphone_upnp_context_new(LinphoneCore *lc) {
                return NULL;
        }
 
-       ip_address = upnp_igd_get_local_ipaddress(lupnp->upnp_igd_ctxt);
-       if(lupnp->sip_udp != NULL) {
-               strncpy(lupnp->sip_udp->local_addr, ip_address, sizeof(lupnp->sip_udp->local_addr));
-       }
-       if(lupnp->sip_tcp != NULL) {
-               strncpy(lupnp->sip_tcp->local_addr, ip_address, sizeof(lupnp->sip_tcp->local_addr));
-       }
-       if(lupnp->sip_tls != NULL) {
-               strncpy(lupnp->sip_tls->local_addr, ip_address, sizeof(lupnp->sip_tls->local_addr));
-       }
-
        lupnp->state = LinphoneUpnpStatePending;
        upnp_igd_start(lupnp->upnp_igd_ctxt);
 
@@ -307,22 +288,19 @@ UpnpContext* linphone_upnp_context_new(LinphoneCore *lc) {
 }
 
 void linphone_upnp_context_destroy(UpnpContext *lupnp) {
-       /*
-        * Not need, all hooks are removed before
-        * linphone_core_remove_iterate_hook(lc, linphone_core_upnp_hook, lc);
-        */
+       linphone_core_remove_iterate_hook(lupnp->lc, linphone_core_upnp_hook, lupnp);
 
        ms_mutex_lock(&lupnp->mutex);
        
        /* Send port binding removes */
        if(lupnp->sip_udp != NULL) {
-               linphone_upnp_context_send_remove_port_binding(lupnp, lupnp->sip_udp);
+               linphone_upnp_context_send_remove_port_binding(lupnp, lupnp->sip_udp, TRUE);
        }
        if(lupnp->sip_tcp != NULL) {
-               linphone_upnp_context_send_remove_port_binding(lupnp, lupnp->sip_tcp);
+               linphone_upnp_context_send_remove_port_binding(lupnp, lupnp->sip_tcp, TRUE);
        }
        if(lupnp->sip_tls != NULL) {
-               linphone_upnp_context_send_remove_port_binding(lupnp, lupnp->sip_tls);
+               linphone_upnp_context_send_remove_port_binding(lupnp, lupnp->sip_tls, TRUE);
        }
 
        /* Wait all pending bindings are done */
@@ -330,14 +308,14 @@ void linphone_upnp_context_destroy(UpnpContext *lupnp) {
                ms_message("uPnP IGD: Wait all pending port bindings ...");
                ms_cond_wait(&lupnp->empty_cond, &lupnp->mutex);
        }
-       ms_mutex_unlock(&lupnp->mutex);
 
        if(lupnp->upnp_igd_ctxt != NULL) {
                upnp_igd_destroy(lupnp->upnp_igd_ctxt);
+               lupnp->upnp_igd_ctxt = NULL;
        }
 
-       /* Run one time the hook for configuration update */
-       linphone_core_upnp_hook(lupnp);
+       /* Run one more time configuration update */
+       linphone_upnp_update_config(lupnp);
 
        /* Release port bindings */
        if(lupnp->sip_udp != NULL) {
@@ -360,6 +338,8 @@ void linphone_upnp_context_destroy(UpnpContext *lupnp) {
        lupnp->removing_configs = ms_list_free(lupnp->removing_configs);
        ms_list_for_each(lupnp->pending_bindings,(void (*)(void*))linphone_upnp_port_binding_release);
        lupnp->pending_bindings = ms_list_free(lupnp->pending_bindings);
+       
+       ms_mutex_unlock(&lupnp->mutex);
 
        ms_mutex_destroy(&lupnp->mutex);
        ms_cond_destroy(&lupnp->empty_cond);
@@ -368,15 +348,88 @@ void linphone_upnp_context_destroy(UpnpContext *lupnp) {
        ms_free(lupnp);
 }
 
-LinphoneUpnpState linphone_upnp_context_get_state(UpnpContext *ctx) {
-       return ctx->state;
+LinphoneUpnpState linphone_upnp_context_get_state(UpnpContext *lupnp) {
+       LinphoneUpnpState state;
+       ms_mutex_lock(&lupnp->mutex);
+       state = lupnp->state;
+       ms_mutex_unlock(&lupnp->mutex);
+       return state;
+}
+
+bool_t _linphone_upnp_context_is_ready_for_register(UpnpContext *lupnp) {
+       bool_t ready = TRUE;
+       
+       // 1 Check global uPnP state
+       ready = (lupnp->state == LinphoneUpnpStateOk);
+       
+       // 2 Check external ip address
+       if(ready) {
+               if (upnp_igd_get_external_ipaddress(lupnp->upnp_igd_ctxt) == NULL) {
+                       ready = FALSE;
+               }
+       }
+       
+       // 3 Check sip ports bindings
+       if(ready) {
+               if(lupnp->sip_udp != NULL) {
+                       if(lupnp->sip_udp->state != LinphoneUpnpStateOk) {
+                               ready = FALSE;
+                       }
+               } else if(lupnp->sip_tcp != NULL) {
+                       if(lupnp->sip_tcp->state != LinphoneUpnpStateOk) {
+                               ready = FALSE;
+                       }
+               } else if(lupnp->sip_tls != NULL) {
+                       if(lupnp->sip_tls->state != LinphoneUpnpStateOk) {
+                               ready = FALSE;
+                       }
+               } else {
+                       ready = FALSE;
+               }
+       }
+       
+       return ready;
+}
+
+bool_t linphone_upnp_context_is_ready_for_register(UpnpContext *lupnp) {
+       bool_t ready;
+       ms_mutex_lock(&lupnp->mutex);
+       ready = _linphone_upnp_context_is_ready_for_register(lupnp);
+       ms_mutex_unlock(&lupnp->mutex);
+       return ready;
+}
+
+int linphone_upnp_context_get_external_port(UpnpContext *lupnp) {
+       int port = -1;
+       ms_mutex_lock(&lupnp->mutex);
+       
+       if(lupnp->sip_udp != NULL) {
+               if(lupnp->sip_udp->state == LinphoneUpnpStateOk) {
+                       port = lupnp->sip_udp->external_port;
+               }
+       } else if(lupnp->sip_tcp != NULL) {
+               if(lupnp->sip_tcp->state == LinphoneUpnpStateOk) {
+                       port = lupnp->sip_tcp->external_port;
+               }
+       } else if(lupnp->sip_tls != NULL) {
+               if(lupnp->sip_tls->state == LinphoneUpnpStateOk) {
+                       port = lupnp->sip_tls->external_port;
+               }
+       }
+       
+       ms_mutex_unlock(&lupnp->mutex);
+       return port;
 }
 
-const char* linphone_upnp_context_get_external_ipaddress(UpnpContext *ctx) {
-       return upnp_igd_get_external_ipaddress(ctx->upnp_igd_ctxt);
+const char* linphone_upnp_context_get_external_ipaddress(UpnpContext *lupnp) {
+       const char* addr = NULL;
+       ms_mutex_lock(&lupnp->mutex);
+       addr = upnp_igd_get_external_ipaddress(lupnp->upnp_igd_ctxt);
+       ms_mutex_unlock(&lupnp->mutex);
+       return addr;
 }
 
-int linphone_upnp_context_send_add_port_binding(UpnpContext *lupnp, UpnpPortBinding *port) {
+int linphone_upnp_context_send_add_port_binding(UpnpContext *lupnp, UpnpPortBinding *port, bool_t retry) {
        upnp_igd_port_mapping mapping;
        char description[128];
        int ret;
@@ -404,6 +457,11 @@ int linphone_upnp_context_send_add_port_binding(UpnpContext *lupnp, UpnpPortBind
                                return 0;
                }
        }
+       
+       // No retry if specified
+       if(port->retry != 0 && !retry) {
+               return -1;
+       }
 
        if(port->retry >= UPNP_ADD_MAX_RETRY) {
                ret = -1;
@@ -435,7 +493,7 @@ int linphone_upnp_context_send_add_port_binding(UpnpContext *lupnp, UpnpPortBind
        return ret;
 }
 
-int linphone_upnp_context_send_remove_port_binding(UpnpContext *lupnp, UpnpPortBinding *port) {
+int linphone_upnp_context_send_remove_port_binding(UpnpContext *lupnp, UpnpPortBinding *port, bool_t retry) {
        upnp_igd_port_mapping mapping;
        int ret;
        
@@ -461,6 +519,11 @@ int linphone_upnp_context_send_remove_port_binding(UpnpContext *lupnp, UpnpPortB
                                return 0;
                }
        }
+       
+       // No retry if specified
+       if(port->retry != 0 && !retry) {
+               return 1;
+       }
 
        if(port->retry >= UPNP_REMOVE_MAX_RETRY) {
                ret = -1;
@@ -489,68 +552,34 @@ int linphone_core_update_upnp_audio_video(LinphoneCall *call, bool_t audio, bool
        LinphoneCore *lc = call->core;
        UpnpContext *lupnp = lc->upnp;
        int ret = -1;
-       const char *local_addr, *external_addr;
 
        if(lupnp == NULL) {
                return ret;
        }
 
        ms_mutex_lock(&lupnp->mutex);
+
        // Don't handle when the call
        if(lupnp->state == LinphoneUpnpStateOk && call->upnp_session != NULL) {
                ret = 0;
-               local_addr = upnp_igd_get_local_ipaddress(lupnp->upnp_igd_ctxt);
-               external_addr = upnp_igd_get_external_ipaddress(lupnp->upnp_igd_ctxt);
 
                /*
                 * Audio part
                 */
-               strncpy(call->upnp_session->audio->rtp->local_addr, local_addr, LINPHONE_IPADDR_SIZE);
-               strncpy(call->upnp_session->audio->rtp->external_addr, external_addr, LINPHONE_IPADDR_SIZE);
-               call->upnp_session->audio->rtp->local_port = call->audio_port;
-               if(call->upnp_session->audio->rtp->external_port == -1) {
-                       call->upnp_session->audio->rtp->external_port = call->audio_port;
-               }
-               strncpy(call->upnp_session->audio->rtcp->local_addr, local_addr, LINPHONE_IPADDR_SIZE);
-               strncpy(call->upnp_session->audio->rtcp->external_addr, external_addr, LINPHONE_IPADDR_SIZE);
-               call->upnp_session->audio->rtcp->local_port = call->audio_port+1;
-               if(call->upnp_session->audio->rtcp->external_port == -1) {
-                       call->upnp_session->audio->rtcp->external_port = call->audio_port+1;
-               }
-               if(audio) {
-                       // Add audio port binding
-                       linphone_upnp_context_send_add_port_binding(lupnp, call->upnp_session->audio->rtp);
-                       linphone_upnp_context_send_add_port_binding(lupnp, call->upnp_session->audio->rtcp);
-               } else {
-                       // Remove audio port binding
-                       linphone_upnp_context_send_remove_port_binding(lupnp, call->upnp_session->audio->rtp);
-                       linphone_upnp_context_send_remove_port_binding(lupnp, call->upnp_session->audio->rtcp);
-               }
+               linphone_upnp_update_port_binding(lupnp, &call->upnp_session->audio->rtp, 
+                       UPNP_IGD_IP_PROTOCOL_UDP, (audio)? call->audio_port:0, UPNP_CALL_RETRY_DELAY);
 
+               linphone_upnp_update_port_binding(lupnp, &call->upnp_session->audio->rtcp, 
+                       UPNP_IGD_IP_PROTOCOL_UDP, (audio)? call->audio_port+1:0, UPNP_CALL_RETRY_DELAY);
+               
                /*
                 * Video part
                 */
-               strncpy(call->upnp_session->video->rtp->local_addr, local_addr, LINPHONE_IPADDR_SIZE);
-               strncpy(call->upnp_session->video->rtp->external_addr, external_addr, LINPHONE_IPADDR_SIZE);
-               call->upnp_session->video->rtp->local_port = call->video_port;
-               if(call->upnp_session->video->rtp->external_port == -1) {
-                       call->upnp_session->video->rtp->external_port = call->video_port;
-               }
-               strncpy(call->upnp_session->video->rtcp->local_addr, local_addr, LINPHONE_IPADDR_SIZE);
-               strncpy(call->upnp_session->video->rtcp->external_addr, external_addr, LINPHONE_IPADDR_SIZE);
-               call->upnp_session->video->rtcp->local_port = call->video_port+1;
-               if(call->upnp_session->video->rtcp->external_port == -1) {
-                       call->upnp_session->video->rtcp->external_port = call->video_port+1;
-               }
-               if(video) {
-                       // Add video port binding
-                       linphone_upnp_context_send_add_port_binding(lupnp, call->upnp_session->video->rtp);
-                       linphone_upnp_context_send_add_port_binding(lupnp, call->upnp_session->video->rtcp);
-               } else {
-                       // Remove video port binding
-                       linphone_upnp_context_send_remove_port_binding(lupnp, call->upnp_session->video->rtp);
-                       linphone_upnp_context_send_remove_port_binding(lupnp, call->upnp_session->video->rtcp);
-               }
+               linphone_upnp_update_port_binding(lupnp, &call->upnp_session->video->rtp, 
+                       UPNP_IGD_IP_PROTOCOL_UDP, (video)? call->video_port:0, UPNP_CALL_RETRY_DELAY);
+
+               linphone_upnp_update_port_binding(lupnp, &call->upnp_session->video->rtcp, 
+                       UPNP_IGD_IP_PROTOCOL_UDP, (video)? call->video_port+1:0, UPNP_CALL_RETRY_DELAY);
        }
 
        ms_mutex_unlock(&lupnp->mutex);
@@ -564,6 +593,7 @@ int linphone_core_update_upnp_audio_video(LinphoneCall *call, bool_t audio, bool
 }
 
 
+
 int linphone_core_update_upnp_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md) {
        bool_t audio = FALSE;
        bool_t video = FALSE;
@@ -591,6 +621,23 @@ void linphone_core_update_upnp_state_in_call_stats(LinphoneCall *call) {
        call->stats[LINPHONE_CALL_STATS_VIDEO].upnp_state = call->upnp_session->video->state;
 }
 
+void linphone_upnp_update_stream_state(UpnpStream *stream) {
+       if((stream->rtp == NULL || stream->rtp->state == LinphoneUpnpStateOk || stream->rtp->state == LinphoneUpnpStateIdle) &&
+          (stream->rtcp == NULL || stream->rtcp->state == LinphoneUpnpStateOk || stream->rtcp->state == LinphoneUpnpStateIdle)) {
+               stream->state = LinphoneUpnpStateOk;
+       } else if((stream->rtp != NULL && 
+                     (stream->rtp->state == LinphoneUpnpStateAdding || stream->rtp->state == LinphoneUpnpStateRemoving)) ||
+                 (stream->rtcp != NULL && 
+                    (stream->rtcp->state == LinphoneUpnpStateAdding || stream->rtcp->state == LinphoneUpnpStateRemoving))) {
+               stream->state = LinphoneUpnpStatePending;
+       } else if((stream->rtp != NULL && stream->rtp->state == LinphoneUpnpStateKo) ||
+                       (stream->rtcp != NULL && stream->rtcp->state == LinphoneUpnpStateKo)) {
+               stream->state = LinphoneUpnpStateKo;
+       } else {
+               ms_error("Invalid stream %p state", stream);            
+       }
+}
+
 int linphone_upnp_call_process(LinphoneCall *call) {
        LinphoneCore *lc = call->core;
        UpnpContext *lupnp = lc->upnp;
@@ -610,39 +657,18 @@ int linphone_upnp_call_process(LinphoneCall *call) {
                /*
                 * Update Audio state
                 */
-               if((call->upnp_session->audio->rtp->state == LinphoneUpnpStateOk || call->upnp_session->audio->rtp->state == LinphoneUpnpStateIdle) &&
-                               (call->upnp_session->audio->rtcp->state == LinphoneUpnpStateOk || call->upnp_session->audio->rtcp->state == LinphoneUpnpStateIdle)) {
-                       call->upnp_session->audio->state = LinphoneUpnpStateOk;
-               } else if(call->upnp_session->audio->rtp->state == LinphoneUpnpStateAdding ||
-                               call->upnp_session->audio->rtp->state == LinphoneUpnpStateRemoving ||
-                               call->upnp_session->audio->rtcp->state == LinphoneUpnpStateAdding ||
-                               call->upnp_session->audio->rtcp->state == LinphoneUpnpStateRemoving) {
-                       call->upnp_session->audio->state = LinphoneUpnpStatePending;
-               } else if(call->upnp_session->audio->rtcp->state == LinphoneUpnpStateKo ||
-                               call->upnp_session->audio->rtp->state == LinphoneUpnpStateKo) {
-                       call->upnp_session->audio->state = LinphoneUpnpStateKo;
-               } else {
-                       call->upnp_session->audio->state = LinphoneUpnpStateIdle;
-               }
+               linphone_upnp_update_stream_state(call->upnp_session->audio);
 
                /*
                 * Update Video state
                 */
-               if((call->upnp_session->video->rtp->state == LinphoneUpnpStateOk || call->upnp_session->video->rtp->state == LinphoneUpnpStateIdle) &&
-                               (call->upnp_session->video->rtcp->state == LinphoneUpnpStateOk || call->upnp_session->video->rtcp->state == LinphoneUpnpStateIdle)) {
-                       call->upnp_session->video->state = LinphoneUpnpStateOk;
-               } else if(call->upnp_session->video->rtp->state == LinphoneUpnpStateAdding ||
-                               call->upnp_session->video->rtp->state == LinphoneUpnpStateRemoving ||
-                               call->upnp_session->video->rtcp->state == LinphoneUpnpStateAdding ||
-                               call->upnp_session->video->rtcp->state == LinphoneUpnpStateRemoving) {
-                       call->upnp_session->video->state = LinphoneUpnpStatePending;
-               } else if(call->upnp_session->video->rtcp->state == LinphoneUpnpStateKo ||
-                               call->upnp_session->video->rtp->state == LinphoneUpnpStateKo) {
-                       call->upnp_session->video->state = LinphoneUpnpStateKo;
-               } else {
-                       call->upnp_session->video->state = LinphoneUpnpStateIdle;
-               }
+               linphone_upnp_update_stream_state(call->upnp_session->video);
 
+               /*
+                * Update stat
+                */
+               linphone_core_update_upnp_state_in_call_stats(call);
+               
                /*
                 * Update session state
                 */
@@ -660,41 +686,34 @@ int linphone_upnp_call_process(LinphoneCall *call) {
                        call->upnp_session->state = LinphoneUpnpStateIdle;
                }
                newState = call->upnp_session->state;
-
-               /* When change is done proceed update */
-               if(oldState != LinphoneUpnpStateOk && oldState != LinphoneUpnpStateKo &&
-                               (call->upnp_session->state == LinphoneUpnpStateOk || call->upnp_session->state == LinphoneUpnpStateKo)) {
-                       if(call->upnp_session->state == LinphoneUpnpStateOk)
-                               ms_message("uPnP IGD: uPnP for Call %p is ok", call);
-                       else
-                               ms_message("uPnP IGD: uPnP for Call %p is ko", call);
-
-                       switch (call->state) {
-                               case LinphoneCallUpdating:
-                                       linphone_core_start_update_call(lc, call);
-                                       break;
-                               case LinphoneCallUpdatedByRemote:
-                                       linphone_core_start_accept_call_update(lc, call);
-                                       break;
-                               case LinphoneCallOutgoingInit:
-                                       linphone_core_proceed_with_invite_if_ready(lc, call, NULL);
-                                       break;
-                               case LinphoneCallIdle:
-                                       linphone_core_notify_incoming_call(lc, call);
-                                       break;
-                               default:
-                                       break;
-                       }
-               }
        }
 
        ms_mutex_unlock(&lupnp->mutex);
-
-       /*
-        * Update uPnP call stats
-        */
-       if(oldState != newState) {
-               linphone_core_update_upnp_state_in_call_stats(call);
+       
+       /* When change is done proceed update */
+       if(oldState != LinphoneUpnpStateOk && oldState != LinphoneUpnpStateKo &&
+                       (newState == LinphoneUpnpStateOk || newState == LinphoneUpnpStateKo)) {
+               if(call->upnp_session->state == LinphoneUpnpStateOk)
+                       ms_message("uPnP IGD: uPnP for Call %p is ok", call);
+               else
+                       ms_message("uPnP IGD: uPnP for Call %p is ko", call);
+
+               switch (call->state) {
+                       case LinphoneCallUpdating:
+                               linphone_core_start_update_call(lc, call);
+                               break;
+                       case LinphoneCallUpdatedByRemote:
+                               linphone_core_start_accept_call_update(lc, call);
+                               break;
+                       case LinphoneCallOutgoingInit:
+                               linphone_core_proceed_with_invite_if_ready(lc, call, NULL);
+                               break;
+                       case LinphoneCallIdle:
+                               linphone_core_notify_incoming_call(lc, call);
+                               break;
+                       default:
+                               break;
+               }
        }
 
        return ret;
@@ -709,7 +728,6 @@ void linphone_core_upnp_refresh(UpnpContext *lupnp) {
 
        ms_message("uPnP IGD: Refresh mappings");
 
-       /* Remove context port bindings */
        if(lupnp->sip_udp != NULL) {
                global_list = ms_list_append(global_list, lupnp->sip_udp);
        }
@@ -720,26 +738,32 @@ void linphone_core_upnp_refresh(UpnpContext *lupnp) {
                global_list = ms_list_append(global_list, lupnp->sip_tls);
        }
 
-       /* Remove call port bindings */
        list = lupnp->lc->calls;
        while(list != NULL) {
                call = (LinphoneCall *)list->data;
                if(call->upnp_session != NULL) {
-                       global_list = ms_list_append(global_list, call->upnp_session->audio->rtp);
-                       global_list = ms_list_append(global_list, call->upnp_session->audio->rtcp);
-                       global_list = ms_list_append(global_list, call->upnp_session->video->rtp);
-                       global_list = ms_list_append(global_list, call->upnp_session->video->rtcp);
+                       if(call->upnp_session->audio->rtp != NULL) {
+                               global_list = ms_list_append(global_list, call->upnp_session->audio->rtp);
+                       }
+                       if(call->upnp_session->audio->rtcp != NULL) {
+                               global_list = ms_list_append(global_list, call->upnp_session->audio->rtcp);
+                       }
+                       if(call->upnp_session->video->rtp != NULL) {
+                               global_list = ms_list_append(global_list, call->upnp_session->video->rtp);
+                       }
+                       if(call->upnp_session->video->rtcp != NULL) {
+                               global_list = ms_list_append(global_list, call->upnp_session->video->rtcp);
+                       }
                }
                list = list->next;
        }
 
-       // Remove port binding configurations
        list = linphone_upnp_config_list_port_bindings(lupnp->lc->config);
        for(item = list;item != NULL; item = item->next) {
                        port_mapping = (UpnpPortBinding *)item->data;
                        port_mapping2 = linphone_upnp_port_binding_equivalent_in_list(global_list, port_mapping);
                        if(port_mapping2 == NULL) {
-                               linphone_upnp_context_send_remove_port_binding(lupnp, port_mapping);
+                               linphone_upnp_context_send_remove_port_binding(lupnp, port_mapping, TRUE);
                        } else if(port_mapping2->state == LinphoneUpnpStateIdle){
                                /* Force to remove */
                                port_mapping2->state = LinphoneUpnpStateOk;
@@ -753,20 +777,60 @@ void linphone_core_upnp_refresh(UpnpContext *lupnp) {
        list = global_list;
        while(list != NULL) {
                port_mapping = (UpnpPortBinding *)list->data;
-               linphone_upnp_context_send_remove_port_binding(lupnp, port_mapping);
-               linphone_upnp_context_send_add_port_binding(lupnp, port_mapping);
+               linphone_upnp_context_send_remove_port_binding(lupnp, port_mapping, TRUE);
+               linphone_upnp_context_send_add_port_binding(lupnp, port_mapping, TRUE);
                list = list->next;
        }
        global_list = ms_list_free(global_list);
 }
 
-bool_t linphone_core_upnp_hook(void *data) {
+void linphone_upnp_update_port_binding(UpnpContext *lupnp, UpnpPortBinding **port_mapping, upnp_igd_ip_protocol protocol, int port, int retry_delay) {
+       const char *local_addr, *external_addr;
+       time_t now = time(NULL);
+       if(port != 0) {
+               if(*port_mapping != NULL) {
+                       if(port != (*port_mapping)->local_port) {
+                               linphone_upnp_context_send_remove_port_binding(lupnp, *port_mapping, FALSE);
+                               *port_mapping = NULL;
+                       }
+               }
+               if(*port_mapping == NULL) {
+                       *port_mapping = linphone_upnp_port_binding_new_or_collect(lupnp->pending_bindings, protocol, port, port);
+               }
+               
+               // Get addresses
+               local_addr = upnp_igd_get_local_ipaddress(lupnp->upnp_igd_ctxt);
+               external_addr = upnp_igd_get_external_ipaddress(lupnp->upnp_igd_ctxt);
+
+               // Force binding update on local address change
+               if(local_addr != NULL) {
+                       if(strncmp((*port_mapping)->local_addr, local_addr, sizeof((*port_mapping)->local_addr))) {
+                               linphone_upnp_context_send_remove_port_binding(lupnp, *port_mapping, FALSE);
+                               strncpy((*port_mapping)->local_addr, local_addr, sizeof((*port_mapping)->local_addr));
+                       }
+               }
+               if(external_addr != NULL) {
+                       strncpy((*port_mapping)->external_addr, external_addr, sizeof((*port_mapping)->external_addr));
+               }
+
+               // Add (if not already done) the binding
+               if(now - (*port_mapping)->last_update >= retry_delay) {
+                       (*port_mapping)->last_update = now;
+                       linphone_upnp_context_send_add_port_binding(lupnp, *port_mapping, FALSE);
+               }
+       } else {
+               if(*port_mapping != NULL) {
+                       linphone_upnp_context_send_remove_port_binding(lupnp, *port_mapping, FALSE);
+                       *port_mapping = NULL;
+               }
+       }
+}
+
+void linphone_upnp_update_config(UpnpContext* lupnp) {
        char key[64];
-       MSList *item;
+       const MSList *item;
        UpnpPortBinding *port_mapping;
-       UpnpContext *lupnp = (UpnpContext *)data;
-       ms_mutex_lock(&lupnp->mutex);
-
+       
        /* Add configs */
        for(item = lupnp->adding_configs;item!=NULL;item=item->next) {
                port_mapping = (UpnpPortBinding *)item->data;
@@ -792,6 +856,48 @@ bool_t linphone_core_upnp_hook(void *data) {
        }
        ms_list_for_each(lupnp->removing_configs,(void (*)(void*))linphone_upnp_port_binding_release);
        lupnp->removing_configs = ms_list_free(lupnp->removing_configs);
+}
+
+bool_t linphone_core_upnp_hook(void *data) {
+       LCSipTransports transport;
+       LinphoneUpnpState ready_state;
+       const MSList *item;
+       time_t now = time(NULL);
+       UpnpContext *lupnp = (UpnpContext *)data;
+
+       ms_mutex_lock(&lupnp->mutex);
+
+       /* Update ports */
+       if(lupnp->state == LinphoneUpnpStateOk) {
+               linphone_core_get_sip_transports(lupnp->lc, &transport);
+               linphone_upnp_update_port_binding(lupnp, &lupnp->sip_udp, UPNP_IGD_IP_PROTOCOL_UDP, transport.udp_port, UPNP_CORE_RETRY_DELAY);
+               linphone_upnp_update_port_binding(lupnp, &lupnp->sip_tcp, UPNP_IGD_IP_PROTOCOL_TCP, transport.tcp_port, UPNP_CORE_RETRY_DELAY);
+               linphone_upnp_update_port_binding(lupnp, &lupnp->sip_tls, UPNP_IGD_IP_PROTOCOL_TCP, transport.tls_port, UPNP_CORE_RETRY_DELAY);
+       }
+
+       /* Refresh registers if we are ready */
+       if(now - lupnp->last_ready_check >= UPNP_CORE_READY_CHECK) {
+               lupnp->last_ready_check = now;
+               ready_state = (_linphone_upnp_context_is_ready_for_register(lupnp))? LinphoneUpnpStateOk: LinphoneUpnpStateKo;
+               if(ready_state != lupnp->last_ready_state) {
+                       for(item=linphone_core_get_proxy_config_list(lupnp->lc);item!=NULL;item=item->next) {
+                               LinphoneProxyConfig *cfg=(LinphoneProxyConfig*)item->data;
+                               if (linphone_proxy_config_register_enabled(cfg)) {
+                                       if (ready_state != LinphoneUpnpStateOk) {
+                                               // Only reset ithe registration if we require that upnp should be ok
+                                               if(lupnp->lc->sip_conf.register_only_when_upnp_is_ok) {
+                                                       linphone_proxy_config_set_state(cfg, LinphoneRegistrationNone, "Registration impossible (uPnP not ready)");
+                                               }
+                                       } else {
+                                               cfg->commit=TRUE;
+                                       }
+                               }
+                       }
+                       lupnp->last_ready_state = ready_state;
+               }
+       }
+                       
+       linphone_upnp_update_config(lupnp);
 
        ms_mutex_unlock(&lupnp->mutex);
        return TRUE;
@@ -811,11 +917,11 @@ int linphone_core_update_local_media_description_from_upnp(SalMediaDescription *
                        upnpStream = session->video;
                }
                if(upnpStream != NULL) {
-                       if(upnpStream->rtp->state == LinphoneUpnpStateOk) {
+                       if(upnpStream->rtp != NULL && upnpStream->rtp->state == LinphoneUpnpStateOk) {
                                strncpy(stream->rtp_addr, upnpStream->rtp->external_addr, LINPHONE_IPADDR_SIZE);
                                stream->rtp_port = upnpStream->rtp->external_port;
                        }
-                       if(upnpStream->rtcp->state == LinphoneUpnpStateOk) {
+                       if(upnpStream->rtcp != NULL && upnpStream->rtcp->state == LinphoneUpnpStateOk) {
                                strncpy(stream->rtcp_addr, upnpStream->rtcp->external_addr, LINPHONE_IPADDR_SIZE);
                                stream->rtcp_port = upnpStream->rtcp->external_port;
                        }
@@ -834,6 +940,7 @@ UpnpPortBinding *linphone_upnp_port_binding_new() {
        port = ms_new0(UpnpPortBinding,1);
        ms_mutex_init(&port->mutex, NULL);
        port->state = LinphoneUpnpStateIdle;
+       port->protocol = UPNP_IGD_IP_PROTOCOL_UDP;      
        port->local_addr[0] = '\0';
        port->local_port = -1;
        port->external_addr[0] = '\0';
@@ -841,9 +948,30 @@ UpnpPortBinding *linphone_upnp_port_binding_new() {
        port->to_remove = FALSE;
        port->to_add = FALSE;
        port->ref = 1;
+       port->last_update = 0;
        return port;
 }
 
+UpnpPortBinding *linphone_upnp_port_binding_new_with_parameters(upnp_igd_ip_protocol protocol, int local_port, int external_port) {
+       UpnpPortBinding *port_binding = linphone_upnp_port_binding_new();
+       port_binding->protocol = protocol;
+       port_binding->local_port = local_port;
+       port_binding->external_port = external_port;
+       return port_binding;
+}
+
+UpnpPortBinding *linphone_upnp_port_binding_new_or_collect(MSList *list, upnp_igd_ip_protocol protocol, int local_port, int external_port) {
+       UpnpPortBinding *tmp_binding;
+       UpnpPortBinding *end_binding;
+       end_binding = linphone_upnp_port_binding_new_with_parameters(protocol, local_port, external_port);
+       tmp_binding = linphone_upnp_port_binding_equivalent_in_list(list, end_binding);
+       if(tmp_binding != NULL) {
+               linphone_upnp_port_binding_release(end_binding);
+               end_binding = tmp_binding;
+       }
+       return end_binding;     
+} 
+
 UpnpPortBinding *linphone_upnp_port_binding_copy(const UpnpPortBinding *port) {
        UpnpPortBinding *new_port = NULL;
        new_port = ms_new0(UpnpPortBinding,1);
@@ -915,18 +1043,20 @@ void linphone_upnp_port_binding_release(UpnpPortBinding *port) {
 UpnpStream* linphone_upnp_stream_new() {
        UpnpStream *stream = ms_new0(UpnpStream,1);
        stream->state = LinphoneUpnpStateIdle;
-       stream->rtp = linphone_upnp_port_binding_new();
-       stream->rtp->protocol = UPNP_IGD_IP_PROTOCOL_UDP;
-       stream->rtcp = linphone_upnp_port_binding_new();
-       stream->rtcp->protocol = UPNP_IGD_IP_PROTOCOL_UDP;
+       stream->rtp = NULL; 
+       stream->rtcp = NULL;
        return stream;
 }
 
 void linphone_upnp_stream_destroy(UpnpStream* stream) {
-       linphone_upnp_port_binding_release(stream->rtp);
-       stream->rtp = NULL;
-       linphone_upnp_port_binding_release(stream->rtcp);
-       stream->rtcp = NULL;
+       if(stream->rtp != NULL) {
+               linphone_upnp_port_binding_release(stream->rtp);
+               stream->rtp = NULL;
+       }
+       if(stream->rtcp != NULL) {
+               linphone_upnp_port_binding_release(stream->rtcp);
+               stream->rtcp = NULL;
+       }
        ms_free(stream);
 }
 
@@ -949,10 +1079,18 @@ void linphone_upnp_session_destroy(UpnpSession *session) {
 
        if(lc->upnp != NULL) {
                /* Remove bindings */
-               linphone_upnp_context_send_remove_port_binding(lc->upnp, session->audio->rtp);
-               linphone_upnp_context_send_remove_port_binding(lc->upnp, session->audio->rtcp);
-               linphone_upnp_context_send_remove_port_binding(lc->upnp, session->video->rtp);
-               linphone_upnp_context_send_remove_port_binding(lc->upnp, session->video->rtcp);
+               if(session->audio->rtp != NULL) {
+                       linphone_upnp_context_send_remove_port_binding(lc->upnp, session->audio->rtp, TRUE);
+               }
+               if(session->audio->rtcp != NULL) {
+                       linphone_upnp_context_send_remove_port_binding(lc->upnp, session->audio->rtcp, TRUE);
+               }
+               if(session->video->rtp != NULL) {
+                       linphone_upnp_context_send_remove_port_binding(lc->upnp, session->video->rtp, TRUE);
+               }
+               if(session->video->rtcp != NULL) {
+                       linphone_upnp_context_send_remove_port_binding(lc->upnp, session->video->rtcp, TRUE);
+               }
        }
 
        linphone_upnp_stream_destroy(session->audio);
@@ -964,6 +1102,7 @@ LinphoneUpnpState linphone_upnp_session_get_state(UpnpSession *session) {
        return session->state;
 }
 
+
 /*
  * uPnP Config
  */
index b3a5b9e49a0ecf6288f11a4d773a4f449574e2be..fe403a7726c63114d17ebdcc7993275e88c7d932 100644 (file)
@@ -40,6 +40,8 @@ UpnpContext *linphone_upnp_context_new(LinphoneCore *lc);
 void linphone_upnp_context_destroy(UpnpContext *ctx);
 LinphoneUpnpState linphone_upnp_context_get_state(UpnpContext *ctx);
 const char *linphone_upnp_context_get_external_ipaddress(UpnpContext *ctx);
+int linphone_upnp_context_get_external_port(UpnpContext *ctx);
+bool_t linphone_upnp_context_is_ready_for_register(UpnpContext *ctx);
 void linphone_core_update_upnp_state_in_call_stats(LinphoneCall *call);
 
 #endif //LINPHONE_UPNP_H
index 6ed8bd9bd1cd175ccec1c6985fae2b017f91be5d..c6f71deb648150c843c54680be80b669548498d4 100644 (file)
@@ -1,34 +1,71 @@
-<?xml version="1.0"?>
+<?xml version="1.0" encoding="UTF-8"?>
 <interface>
   <requires lib="gtk+" version="2.24"/>
   <!-- interface-naming-policy project-wide -->
   <object class="GtkDialog" id="call_statistics">
+    <property name="can_focus">False</property>
     <property name="border_width">5</property>
     <property name="title" translatable="yes">Call statistics</property>
     <property name="type_hint">dialog</property>
-    <signal name="response" handler="linphone_gtk_call_statistics_closed"/>
+    <signal name="response" handler="linphone_gtk_call_statistics_closed" swapped="no"/>
     <child internal-child="vbox">
       <object class="GtkVBox" id="dialog-vbox1">
         <property name="visible">True</property>
+        <property name="can_focus">False</property>
         <property name="spacing">2</property>
+        <child internal-child="action_area">
+          <object class="GtkHButtonBox" id="dialog-action_area1">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="layout_style">end</property>
+            <child>
+              <placeholder/>
+            </child>
+            <child>
+              <object class="GtkButton" id="button1">
+                <property name="label">gtk-close</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_action_appearance">False</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
         <child>
           <object class="GtkFrame" id="frame1">
             <property name="visible">True</property>
+            <property name="can_focus">False</property>
             <property name="label_xalign">0</property>
             <property name="shadow_type">none</property>
             <child>
               <object class="GtkAlignment" id="alignment1">
                 <property name="visible">True</property>
+                <property name="can_focus">False</property>
                 <property name="left_padding">12</property>
                 <child>
                   <object class="GtkTable" id="table1">
                     <property name="visible">True</property>
-                    <property name="n_rows">6</property>
+                    <property name="can_focus">False</property>
+                    <property name="n_rows">7</property>
                     <property name="n_columns">2</property>
                     <property name="homogeneous">True</property>
                     <child>
                       <object class="GtkLabel" id="audio_codec_label">
                         <property name="visible">True</property>
+                        <property name="can_focus">False</property>
                         <property name="label" translatable="yes">Audio codec</property>
                       </object>
                       <packing>
@@ -38,6 +75,7 @@
                     <child>
                       <object class="GtkLabel" id="video_codec_label">
                         <property name="visible">True</property>
+                        <property name="can_focus">False</property>
                         <property name="label" translatable="yes">Video codec</property>
                       </object>
                       <packing>
@@ -49,6 +87,7 @@
                     <child>
                       <object class="GtkLabel" id="label3">
                         <property name="visible">True</property>
+                        <property name="can_focus">False</property>
                         <property name="label" translatable="yes">Audio IP bandwidth usage</property>
                       </object>
                       <packing>
@@ -60,6 +99,7 @@
                     <child>
                       <object class="GtkLabel" id="audio_codec">
                         <property name="visible">True</property>
+                        <property name="can_focus">False</property>
                       </object>
                       <packing>
                         <property name="left_attach">1</property>
                     <child>
                       <object class="GtkLabel" id="video_codec">
                         <property name="visible">True</property>
+                        <property name="can_focus">False</property>
                       </object>
                       <packing>
                         <property name="left_attach">1</property>
                     <child>
                       <object class="GtkLabel" id="audio_bandwidth_usage">
                         <property name="visible">True</property>
+                        <property name="can_focus">False</property>
                       </object>
                       <packing>
                         <property name="left_attach">1</property>
                     <child>
                       <object class="GtkLabel" id="label4">
                         <property name="visible">True</property>
+                        <property name="can_focus">False</property>
                         <property name="label" translatable="yes">Audio Media connectivity</property>
                       </object>
                       <packing>
                     <child>
                       <object class="GtkLabel" id="audio_media_connectivity">
                         <property name="visible">True</property>
+                        <property name="can_focus">False</property>
                       </object>
                       <packing>
                         <property name="left_attach">1</property>
                     <child>
                       <object class="GtkLabel" id="label1">
                         <property name="visible">True</property>
+                        <property name="can_focus">False</property>
                         <property name="label" translatable="yes">Video IP bandwidth usage</property>
                       </object>
                       <packing>
                     <child>
                       <object class="GtkLabel" id="video_bandwidth_usage">
                         <property name="visible">True</property>
+                        <property name="can_focus">False</property>
                       </object>
                       <packing>
                         <property name="left_attach">1</property>
                     <child>
                       <object class="GtkLabel" id="label2">
                         <property name="visible">True</property>
+                        <property name="can_focus">False</property>
                         <property name="label" translatable="yes">Video Media connectivity</property>
                       </object>
                       <packing>
                     <child>
                       <object class="GtkLabel" id="video_media_connectivity">
                         <property name="visible">True</property>
+                        <property name="can_focus">False</property>
                       </object>
                       <packing>
                         <property name="left_attach">1</property>
                         <property name="bottom_attach">6</property>
                       </packing>
                     </child>
+                    <child>
+                      <object class="GtkLabel" id="label5">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="label" translatable="yes">Round trip time</property>
+                      </object>
+                      <packing>
+                        <property name="top_attach">6</property>
+                        <property name="bottom_attach">7</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel" id="round_trip_time">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                      </object>
+                      <packing>
+                        <property name="left_attach">1</property>
+                        <property name="right_attach">2</property>
+                        <property name="top_attach">6</property>
+                        <property name="bottom_attach">7</property>
+                      </packing>
+                    </child>
                   </object>
                 </child>
               </object>
             <child type="label">
               <object class="GtkLabel" id="call_statistics_label">
                 <property name="visible">True</property>
+                <property name="can_focus">False</property>
                 <property name="label" translatable="yes">&lt;b&gt;Call statistics and information&lt;/b&gt;</property>
                 <property name="use_markup">True</property>
               </object>
             <property name="position">1</property>
           </packing>
         </child>
-        <child internal-child="action_area">
-          <object class="GtkHButtonBox" id="dialog-action_area1">
-            <property name="visible">True</property>
-            <property name="layout_style">end</property>
-            <child>
-              <placeholder/>
-            </child>
-            <child>
-              <object class="GtkButton" id="button1">
-                <property name="label">gtk-close</property>
-                <property name="visible">True</property>
-                <property name="can_focus">True</property>
-                <property name="receives_default">True</property>
-                <property name="use_stock">True</property>
-              </object>
-              <packing>
-                <property name="expand">False</property>
-                <property name="fill">False</property>
-                <property name="position">1</property>
-              </packing>
-            </child>
-          </object>
-          <packing>
-            <property name="expand">False</property>
-            <property name="pack_type">end</property>
-            <property name="position">0</property>
-          </packing>
-        </child>
       </object>
     </child>
     <action-widgets>
index dddb3cec98c7e5e0dc5f191254c84e68f25e4eb9..08262c771db9e1b7fa98c31062e1090225880bb6 100644 (file)
 
 #define PADDING_PIXELS 4
 
+/*
+ * conferencee_box = a vbox where participants are added or removed
+ * conf_frame = the conference tab
+ */
+
 static GtkWidget *create_conference_label(void){
        GtkWidget *box=gtk_hbox_new(FALSE,0);
        gtk_box_pack_start(GTK_BOX(box),gtk_image_new_from_stock(GTK_STOCK_ADD,GTK_ICON_SIZE_MENU),FALSE,FALSE,0);
@@ -46,34 +51,21 @@ static void init_local_participant(GtkWidget *participant){
        linphone_gtk_init_audio_meter(sound_meter, (get_volume_t) linphone_core_get_conference_local_input_volume, linphone_gtk_get_core());
 }
 
-static GtkWidget *get_conference_tab(GtkWidget *mw){
-       GtkWidget *box=(GtkWidget*)g_object_get_data(G_OBJECT(mw),"conference_tab");
-       GtkWidget *conf_frame=(GtkWidget*)g_object_get_data(G_OBJECT(mw),"conf_frame");
-       if(conf_frame!=NULL){
-               if (box==NULL){
-                       GtkWidget *conf_box=linphone_gtk_get_widget(conf_frame,"conf_box");
-                       box=gtk_vbox_new(FALSE,0);
-                       GtkWidget *participant=linphone_gtk_create_widget("main","callee_frame");
-                       gtk_box_set_homogeneous(GTK_BOX(box),TRUE);
-                       init_local_participant(participant);
-                       gtk_box_pack_start(GTK_BOX(box),participant,FALSE,FALSE,PADDING_PIXELS);
-                       gtk_widget_show(box);
-                       g_object_set_data(G_OBJECT(mw),"conference_tab",box);
-                       gtk_box_pack_start(GTK_BOX(conf_box),box,FALSE,FALSE,PADDING_PIXELS);
-               }
-       }
+static GtkWidget *get_conferencee_box(GtkWidget *mw){
+       GtkWidget *box=(GtkWidget*)g_object_get_data(G_OBJECT(mw),"conferencee_box");
        return box;
 }
 
 static GtkWidget *find_conferencee_from_call(LinphoneCall *call){
        GtkWidget *mw=linphone_gtk_get_main_window();
-       get_conference_tab(mw);
-       GtkWidget *conf_frame=(GtkWidget *)g_object_get_data(G_OBJECT(mw),"conf_frame");
-       GtkWidget *conf_box=linphone_gtk_get_widget(conf_frame,"conf_box");
+       GtkWidget *conferencee_box=get_conferencee_box(mw);
        GList *elem;
        GtkWidget *ret=NULL;
+       
+       if (conferencee_box==NULL) return NULL;
+       
        if (call!=NULL){
-               GList *l=gtk_container_get_children(GTK_CONTAINER(conf_box));
+               GList *l=gtk_container_get_children(GTK_CONTAINER(conferencee_box));
                for(elem=l;elem!=NULL;elem=elem->next){
                        GtkWidget *frame=(GtkWidget*)elem->data;
                        if (call==g_object_get_data(G_OBJECT(frame),"call")){
@@ -87,28 +79,53 @@ static GtkWidget *find_conferencee_from_call(LinphoneCall *call){
        return ret;
 }
 
-void linphone_gtk_set_in_conference(LinphoneCall *call){
+static GtkWidget * create_conference_panel(void){
        GtkWidget *mw=linphone_gtk_get_main_window();
+       GtkWidget *conf_frame=linphone_gtk_create_widget("main","conf_frame");
+       GtkWidget *conf_box=linphone_gtk_get_widget(conf_frame,"conf_box");
+       GtkWidget *button_conf=linphone_gtk_get_widget(conf_frame,"terminate_conf");
+       GtkWidget *image=create_pixmap("stopcall-small.png");
+       GtkWidget *box;
        GtkWidget *viewswitch=linphone_gtk_get_widget(mw,"viewswitch");
+       
+       gtk_button_set_image(GTK_BUTTON(button_conf),image);
+       g_signal_connect_swapped(G_OBJECT(button_conf),"clicked",(GCallback)linphone_gtk_terminate_call,NULL);
+       g_object_set_data(G_OBJECT(mw),"conf_frame",(gpointer)conf_frame);
+       
+       box=gtk_vbox_new(FALSE,0);
+       GtkWidget *participant=linphone_gtk_create_widget("main","callee_frame");
+       gtk_widget_show(participant);
+       gtk_box_set_homogeneous(GTK_BOX(box),TRUE);
+       init_local_participant(participant);
+       gtk_box_pack_start(GTK_BOX(box),participant,FALSE,FALSE,PADDING_PIXELS);
+       gtk_widget_show(box);
+       g_object_set_data(G_OBJECT(mw),"conferencee_box",box);
+       gtk_box_pack_start(GTK_BOX(conf_box),box,FALSE,FALSE,PADDING_PIXELS);
+       
+       gtk_notebook_append_page(GTK_NOTEBOOK(viewswitch),conf_frame,
+                               create_conference_label());
+       return conf_frame;
+}
+
+void linphone_gtk_set_in_conference(LinphoneCall *call){
+       GtkWidget *mw=linphone_gtk_get_main_window();
        GtkWidget *conf_frame=(GtkWidget *)g_object_get_data(G_OBJECT(mw),"conf_frame");
-       g_object_set_data(G_OBJECT(mw),"is_conf",GINT_TO_POINTER(TRUE));
+       GtkWidget *viewswitch=linphone_gtk_get_widget(mw,"viewswitch");
+       
        if(conf_frame==NULL){
-               conf_frame=linphone_gtk_create_widget("main","conf_frame");
-               GtkWidget *button_conf=linphone_gtk_get_widget(conf_frame,"terminate_conf");
-               GtkWidget *image=create_pixmap("stopcall-small.png");
-               gtk_button_set_image(GTK_BUTTON(button_conf),image);
-               g_signal_connect_swapped(G_OBJECT(button_conf),"clicked",(GCallback)linphone_gtk_terminate_call,NULL);
-               g_object_set_data(G_OBJECT(mw),"conf_frame",(gpointer)conf_frame);
-               gtk_notebook_append_page(GTK_NOTEBOOK(viewswitch),conf_frame,
-                                     create_conference_label());
+               conf_frame=create_conference_panel();
        }
-       GtkWidget *participant=find_conferencee_from_call(call);        
-       GtkWidget *conf_box=linphone_gtk_get_widget(conf_frame,"conf_box");
+       GtkWidget *participant=find_conferencee_from_call(call);
+       
        if (participant==NULL){
-               const LinphoneAddress *addr=linphone_call_get_remote_address(call);
-               participant=linphone_gtk_create_widget("main","callee_frame");
+               /*create and add it */
+               GtkWidget *conferencee_box=get_conferencee_box(mw);
                GtkWidget *sound_meter;
+               const LinphoneAddress *addr=linphone_call_get_remote_address(call);
                gchar *markup;
+               
+               participant=linphone_gtk_create_widget("main","callee_frame");
+               gtk_widget_show(participant);
                if (linphone_address_get_display_name(addr)!=NULL){
                        markup=g_strdup_printf("<b>%s</b>",linphone_address_get_display_name(addr));
                }else{
@@ -119,11 +136,11 @@ void linphone_gtk_set_in_conference(LinphoneCall *call){
                gtk_label_set_markup(GTK_LABEL(linphone_gtk_get_widget(participant,"callee_name_label")),markup);
                g_free(markup);
                sound_meter=linphone_gtk_get_widget(participant,"sound_indicator");
-               linphone_gtk_init_audio_meter(sound_meter, (get_volume_t) linphone_call_get_play_volume, call); 
-               gtk_box_pack_start(GTK_BOX(conf_box),participant,FALSE,FALSE,PADDING_PIXELS);
+               linphone_gtk_init_audio_meter(sound_meter, (get_volume_t) linphone_call_get_play_volume, call);
+               gtk_box_pack_start(GTK_BOX(conferencee_box),participant,FALSE,FALSE,PADDING_PIXELS);
                g_object_set_data_full(G_OBJECT(participant),"call",linphone_call_ref(call),(GDestroyNotify)linphone_call_unref);
                gtk_notebook_set_current_page(GTK_NOTEBOOK(viewswitch),
-               gtk_notebook_page_num(GTK_NOTEBOOK(viewswitch),conf_frame));
+                       gtk_notebook_page_num(GTK_NOTEBOOK(viewswitch),conf_frame));
        }
 }
 
@@ -135,24 +152,26 @@ void linphone_gtk_terminate_conference_participant(LinphoneCall *call){
 }
 
 void linphone_gtk_unset_from_conference(LinphoneCall *call){
-       GtkWidget *mw=linphone_gtk_get_main_window();
-       GtkWidget *conf_frame=(GtkWidget *)g_object_get_data(G_OBJECT(mw),"conf_frame");
-       GtkWidget *conf_box=linphone_gtk_get_widget(conf_frame,"conf_box");
-       GtkWidget *frame;
-       if (conf_box==NULL) return; /*conference tab already destroyed*/
-       frame=find_conferencee_from_call(call);
-       GList *children;
+       GtkWidget *frame=find_conferencee_from_call(call);
+       
        if (frame){
+               GtkWidget *mw=linphone_gtk_get_main_window();
+               GtkWidget *conf_frame=(GtkWidget *)g_object_get_data(G_OBJECT(mw),"conf_frame");
+               GtkWidget *conferencee_box=g_object_get_data(G_OBJECT(mw),"conferencee_box");
+               GList *children;
+               
+               g_message("Removing a participant from conference");
                gtk_widget_destroy(frame);
+               children=gtk_container_get_children(GTK_CONTAINER(conferencee_box));
+               if (g_list_length(children)==1){ /* only local participant */
+                       /*the conference is terminated */
+                       g_message("The conference is terminated");
+                       g_object_set_data(G_OBJECT(mw),"conferencee_box",NULL);
+                       gtk_widget_destroy(conf_frame);
+                       g_object_set_data(G_OBJECT(mw),"conf_frame",NULL);
+               }
+               g_list_free(children);
        }
-       children=gtk_container_get_children(GTK_CONTAINER(conf_box));
-       if (g_list_length(children)==2){
-               /*the conference is terminated */
-               gtk_widget_destroy(conf_box);
-               g_object_set_data(G_OBJECT(mw),"conference_tab",NULL);          
-       }
-       gtk_widget_destroy(conf_frame);
-       g_list_free(children);
-       g_object_set_data(G_OBJECT(mw),"is_conf",GINT_TO_POINTER(FALSE));
-       g_object_set_data(G_OBJECT(mw),"conf_frame",NULL);
 }
+
+
index 60aa7cb1421734d9d8b5542c02192e1595edfa31..0a64a1041d2484f6cca2b1eb21f9f2e9c48b9414 100644 (file)
@@ -50,7 +50,8 @@ LinphoneCall *linphone_gtk_get_currently_displayed_call(gboolean *is_conf){
                if (page!=NULL){
                        LinphoneCall *call=(LinphoneCall*)g_object_get_data(G_OBJECT(page),"call");
                        if (call==NULL){
-                               if (GPOINTER_TO_INT(g_object_get_data(G_OBJECT(main_window),"is_conf"))){
+                               GtkWidget *conf_frame=(GtkWidget *)g_object_get_data(G_OBJECT(main_window),"conf_frame");
+                               if (conf_frame==page){
                                        if (is_conf)
                                                *is_conf=TRUE;
                                        return NULL;
@@ -75,25 +76,28 @@ static GtkWidget *make_tab_header(int number){
 }
 
 void update_tab_header(LinphoneCall *call,gboolean pause){
-    GtkWidget *w=(GtkWidget*)linphone_call_get_user_pointer(call);
-    GtkWidget *main_window=linphone_gtk_get_main_window();
-    GtkNotebook *notebook=GTK_NOTEBOOK(linphone_gtk_get_widget(main_window,"viewswitch"));
-    gint call_index=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w),"call_index"));
-    GtkWidget *new_label=gtk_hbox_new (FALSE,0);
-    GtkWidget *i=NULL;
-    if(pause){
-i=gtk_image_new_from_stock(GTK_STOCK_MEDIA_PAUSE,GTK_ICON_SIZE_SMALL_TOOLBAR);
-    } else {
-        i=create_pixmap ("startcall-small.png");
-    }
+       GtkWidget *w=(GtkWidget*)linphone_call_get_user_pointer(call);
+       GtkWidget *main_window=linphone_gtk_get_main_window();
+       GtkNotebook *notebook=GTK_NOTEBOOK(linphone_gtk_get_widget(main_window,"viewswitch"));
+       gint call_index=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(w),"call_index"));
+       GtkWidget *new_label=gtk_hbox_new (FALSE,0);
+       GtkWidget *i=NULL;
        GtkWidget *l;
-       gchar *text=g_strdup_printf(_("Call #%i"),call_index);
+       gchar *text;
+       
+       if(pause){
+               i=gtk_image_new_from_stock(GTK_STOCK_MEDIA_PAUSE,GTK_ICON_SIZE_SMALL_TOOLBAR);
+       } else {
+               i=create_pixmap ("startcall-small.png");
+       }
+       
+       text=g_strdup_printf(_("Call #%i"),call_index);
        l=gtk_label_new (text);
        gtk_box_pack_start (GTK_BOX(new_label),i,FALSE,FALSE,0);
        gtk_box_pack_end(GTK_BOX(new_label),l,TRUE,TRUE,0);
 
-    gtk_notebook_set_tab_label(notebook,w,new_label);
-    gtk_widget_show_all(new_label);
+       gtk_notebook_set_tab_label(notebook,w,new_label);
+       gtk_widget_show_all(new_label);
 }
 
 static void linphone_gtk_in_call_set_animation_image(GtkWidget *callview, const char *image_name, gboolean is_stock){
@@ -157,8 +161,7 @@ void transfer_button_clicked(GtkWidget *button, gpointer call_ref){
                        g_signal_connect_swapped(G_OBJECT(menu_item),"activate",(GCallback)linphone_gtk_transfer_call,other_call);
                }
        }
-       gtk_menu_popup(GTK_MENU(menu),NULL,NULL,NULL,NULL,0,
-       gtk_get_current_event_time());
+       gtk_menu_popup(GTK_MENU(menu),NULL,NULL,NULL,NULL,0,gtk_get_current_event_time());
        gtk_widget_show(menu);
 }
 
@@ -178,7 +181,6 @@ static void conference_button_clicked(GtkWidget *button, gpointer call_ref){
        gtk_widget_set_sensitive(button,FALSE);
        g_object_set_data(G_OBJECT(linphone_gtk_get_main_window()),"conf_frame",NULL);
        linphone_core_add_all_to_conference(linphone_gtk_get_core());
-       //linphone_core_add_to_conference(linphone_gtk_get_core(),(LinphoneCall*)call_ref);
        
 }
 
@@ -202,7 +204,6 @@ static void show_used_codecs(GtkWidget *callstats, LinphoneCall *call){
                GtkWidget *acodec_ui=linphone_gtk_get_widget(callstats,"audio_codec");
                GtkWidget *vcodec_ui=linphone_gtk_get_widget(callstats,"video_codec");
                if (acodec){
-
                        char tmp[64]={0};
                        snprintf(tmp,sizeof(tmp)-1,"%s/%i/%i",acodec->mime_type,acodec->clock_rate,acodec->channels);
                        gtk_label_set_label(GTK_LABEL(acodec_ui),tmp);
@@ -252,28 +253,40 @@ static const char *upnp_state_to_string(LinphoneUpnpState ice_state){
 static void _refresh_call_stats(GtkWidget *callstats, LinphoneCall *call){
        const LinphoneCallStats *as=linphone_call_get_audio_stats(call);
        const LinphoneCallStats *vs=linphone_call_get_video_stats(call);
-       const char *audio_media_connectivity = _("Direct");
-       const char *video_media_connectivity = _("Direct");
+       const char *audio_media_connectivity = _("Direct or through server");
+       const char *video_media_connectivity = _("Direct or through server");
+       gboolean has_video=linphone_call_params_video_enabled(linphone_call_get_current_params(call));
        gchar *tmp=g_strdup_printf(_("download: %f\nupload: %f (kbit/s)"),
                as->download_bandwidth,as->upload_bandwidth);
+       
        gtk_label_set_markup(GTK_LABEL(linphone_gtk_get_widget(callstats,"audio_bandwidth_usage")),tmp);
        g_free(tmp);
-       tmp=g_strdup_printf(_("download: %f\nupload: %f (kbit/s)"),
-               vs->download_bandwidth,vs->upload_bandwidth);
+       if (has_video)
+               tmp=g_strdup_printf(_("download: %f\nupload: %f (kbit/s)"),vs->download_bandwidth,vs->upload_bandwidth);
+       else tmp=NULL;
        gtk_label_set_markup(GTK_LABEL(linphone_gtk_get_widget(callstats,"video_bandwidth_usage")),tmp);
-       g_free(tmp);
+       if (tmp) g_free(tmp);
        if(as->upnp_state != LinphoneUpnpStateNotAvailable && as->upnp_state != LinphoneUpnpStateIdle) {
                audio_media_connectivity = upnp_state_to_string(as->upnp_state);
        } else if(as->ice_state != LinphoneIceStateNotActivated) {
                audio_media_connectivity = ice_state_to_string(as->ice_state);
        }
        gtk_label_set_text(GTK_LABEL(linphone_gtk_get_widget(callstats,"audio_media_connectivity")),audio_media_connectivity);
-       if(vs->upnp_state != LinphoneUpnpStateNotAvailable && vs->upnp_state != LinphoneUpnpStateIdle) {
-                       video_media_connectivity = upnp_state_to_string(vs->upnp_state);
-       } else if(vs->ice_state != LinphoneIceStateNotActivated) {
-               video_media_connectivity = ice_state_to_string(vs->ice_state);
-       }
+       
+       if (has_video){
+               if(vs->upnp_state != LinphoneUpnpStateNotAvailable && vs->upnp_state != LinphoneUpnpStateIdle) {
+                               video_media_connectivity = upnp_state_to_string(vs->upnp_state);
+               } else if(vs->ice_state != LinphoneIceStateNotActivated) {
+                       video_media_connectivity = ice_state_to_string(vs->ice_state);
+               }
+       }else video_media_connectivity=NULL;
        gtk_label_set_text(GTK_LABEL(linphone_gtk_get_widget(callstats,"video_media_connectivity")),video_media_connectivity);
+       
+       if (as->round_trip_delay>0){
+               tmp=g_strdup_printf(_("%.3f seconds"),as->round_trip_delay);
+               gtk_label_set_text(GTK_LABEL(linphone_gtk_get_widget(callstats,"round_trip_time")),tmp);
+               g_free(tmp);
+       }
 }
 
 static gboolean refresh_call_stats(GtkWidget *callstats){
@@ -689,6 +702,9 @@ void linphone_gtk_in_call_view_set_in_call(LinphoneCall *call){
        if (in_conf){
                linphone_gtk_set_in_conference(call);
                gtk_widget_set_sensitive(linphone_gtk_get_widget(callview,"incall_mute"),FALSE);
+       }else{
+               linphone_gtk_unset_from_conference(call); /*in case it was previously*/
+               gtk_widget_set_sensitive(linphone_gtk_get_widget(callview,"incall_mute"),TRUE);
        }
        gtk_widget_show_all(linphone_gtk_get_widget(callview,"buttons_panel"));
        if (!in_conf) gtk_widget_show_all(linphone_gtk_get_widget(callview,"record_hbox"));
@@ -857,18 +873,46 @@ void linphone_gtk_call_statistics_closed(GtkWidget *call_stats){
 
 void linphone_gtk_record_call_toggled(GtkWidget *button){
        gboolean active=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
-       LinphoneCall *call=linphone_gtk_get_currently_displayed_call(NULL);
-       GtkWidget *callview=(GtkWidget*)linphone_call_get_user_pointer (call);
-       const LinphoneCallParams *params=linphone_call_get_current_params(call);
-       const char *filepath=linphone_call_params_get_record_file(params);
-       gchar *message=g_strdup_printf(_("<small><i>Recording into %s %s</i></small>"),filepath,active ? "" : _("(Paused)"));
+       gboolean is_conf=FALSE;
+       const char *filepath;
+       gchar *message;
+       LinphoneCore *lc=linphone_gtk_get_core();
+       LinphoneCall *call=linphone_gtk_get_currently_displayed_call(&is_conf);
+       GtkWidget *callview;
+       GtkWidget *label;
+       if (call){
+               callview=(GtkWidget*)linphone_call_get_user_pointer (call);
+               const LinphoneCallParams *params=linphone_call_get_current_params(call);
+               filepath=linphone_call_params_get_record_file(params);
+               label=linphone_gtk_get_widget(callview,"record_status");
+       }else if (is_conf){
+               GtkWidget *mw=linphone_gtk_get_main_window();
+               callview=(GtkWidget *)g_object_get_data(G_OBJECT(linphone_gtk_get_main_window()),"conf_frame");
+               label=linphone_gtk_get_widget(callview,"conf_record_status");
+               filepath=(const char*)g_object_get_data(G_OBJECT(mw),"conf_record_path");
+               if (filepath==NULL){
+                       filepath=linphone_gtk_get_record_path(NULL,TRUE);
+                       g_object_set_data_full(G_OBJECT(mw),"conf_record_path",(char*)filepath,g_free);
+               }
+       }else{
+               g_warning("linphone_gtk_record_call_toggled(): bug.");
+               return;
+       }
+       message=g_strdup_printf(_("<small><i>Recording into\n%s %s</i></small>"),filepath,active ? "" : _("(Paused)"));
        
        if (active){
-               linphone_call_start_recording(call);
+               if (call)
+                       linphone_call_start_recording(call);
+               else
+                       linphone_core_start_conference_recording(lc,filepath);
        }else {
-               linphone_call_stop_recording(call);
+               if (call)
+                       linphone_call_stop_recording(call);
+               else
+                       linphone_core_stop_conference_recording(lc);
+               
        }
-       gtk_label_set_markup(GTK_LABEL(linphone_gtk_get_widget(callview,"record_status")),message);
+       gtk_label_set_markup(GTK_LABEL(label),message);
        g_free(message);
 }
 
index abb395127dda042cd87430c919e91ace83a8a96e..f9597849d8e68f7c49dcadc5732c3af6941d9c0c 100644 (file)
@@ -149,3 +149,5 @@ void linphone_gtk_uninit_instance(void);
 void linphone_gtk_monitor_usb(void);
 void linphone_gtk_unmonitor_usb(void);
 
+gchar *linphone_gtk_get_record_path(const LinphoneAddress *address, gboolean is_conference);
+
index 94d94f662e1696bfd37c8e725bf2fddd356e91d3..2f34cd4d420862f93e776c4a899a5452c842d4d7 100644 (file)
@@ -750,14 +750,35 @@ static void linphone_gtk_update_call_buttons(LinphoneCall *call){
        }
 }
 
-gchar *linphone_gtk_get_call_record_path(LinphoneAddress *address){
+gchar *linphone_gtk_get_record_path(const LinphoneAddress *address, gboolean is_conference){
        const char *dir=g_get_user_special_dir(G_USER_DIRECTORY_MUSIC);
-       const char *id=linphone_address_get_username(address);
+       const char *id="unknown";
        char filename[256]={0};
-       if (id==NULL) id=linphone_address_get_domain(address);
-       snprintf(filename,sizeof(filename)-1,"%s-%lu-%s-record.wav",
-                linphone_gtk_get_ui_config("title","Linphone"),
-                (unsigned long)time(NULL),id);
+       char date[64]={0};
+       time_t curtime=time(NULL);
+       struct tm loctime;
+       
+#ifdef WIN32
+       loctime=*localtime(&curtime);
+#else
+       localtime_r(&curtime,&loctime);
+#endif
+       snprintf(date,sizeof(date)-1,"%i%02i%02i-%02i%02i",loctime.tm_year+1900,loctime.tm_mon+1,loctime.tm_mday, loctime.tm_hour, loctime.tm_min);
+       
+       if (address){
+               id=linphone_address_get_username(address);
+               if (id==NULL) id=linphone_address_get_domain(address);
+       }
+       if (is_conference){
+               snprintf(filename,sizeof(filename)-1,"%s-conference-%s.wav",
+                       linphone_gtk_get_ui_config("title","Linphone"),
+                       date);
+       }else{
+               snprintf(filename,sizeof(filename)-1,"%s-call-%s-%s.wav",
+                       linphone_gtk_get_ui_config("title","Linphone"),
+                       date,
+                       id);
+       }
        return g_build_filename(dir,filename,NULL);
 }
 
@@ -768,7 +789,7 @@ static gboolean linphone_gtk_start_call_do(GtkWidget *uri_bar){
        
        if (addr!=NULL){
                LinphoneCallParams *params=linphone_core_create_default_call_parameters(lc);
-               gchar *record_file=linphone_gtk_get_call_record_path(addr);
+               gchar *record_file=linphone_gtk_get_record_path(addr,FALSE);
                linphone_call_params_set_record_file(params,record_file);
                linphone_core_invite_address_with_params(lc,addr,params);
                completion_add_text(GTK_ENTRY(uri_bar),entered);
@@ -781,24 +802,34 @@ static gboolean linphone_gtk_start_call_do(GtkWidget *uri_bar){
        return FALSE;
 }
 
+
+static void accept_incoming_call(LinphoneCall *call){
+       LinphoneCore *lc=linphone_gtk_get_core();
+       LinphoneCallParams *params=linphone_core_create_default_call_parameters(lc);
+       gchar *record_file=linphone_gtk_get_record_path(linphone_call_get_remote_address(call),FALSE);
+       linphone_call_params_set_record_file(params,record_file);
+       linphone_core_accept_call_with_params(lc,call,params);
+       linphone_call_params_destroy(params);
+}
+
 static gboolean linphone_gtk_auto_answer(LinphoneCall *call){
-       if (linphone_call_get_state(call)==LinphoneCallIncomingReceived){
-               linphone_core_accept_call (linphone_gtk_get_core(),call);
+       LinphoneCallState state=linphone_call_get_state(call);
+       if (state==LinphoneCallIncomingReceived || state==LinphoneCallIncomingEarlyMedia){
+               accept_incoming_call(call);
                linphone_call_unref(call);
        }
        return FALSE;
 }
 
 void linphone_gtk_start_call(GtkWidget *w){
-       LinphoneCore *lc=linphone_gtk_get_core();
-       LinphoneCall *call;
+       LinphoneCall *call=linphone_gtk_get_currently_displayed_call(NULL);
        /*change into in-call mode, then do the work later as it might block a bit */
        GtkWidget *mw=gtk_widget_get_toplevel(w);
        GtkWidget *uri_bar=linphone_gtk_get_widget(mw,"uribar");
+       LinphoneCallState state= call ? linphone_call_get_state(call) : LinphoneCallIdle;
 
-       call=linphone_gtk_get_currently_displayed_call(NULL);
-       if (call!=NULL && linphone_call_get_state(call)==LinphoneCallIncomingReceived){
-               linphone_core_accept_call(lc,call);
+       if (state == LinphoneCallIncomingReceived || state == LinphoneCallIncomingEarlyMedia){
+               accept_incoming_call(call);
        }else{
                /*immediately disable the button and delay a bit the execution the linphone_core_invite()
                so that we don't freeze the button. linphone_core_invite() might block for some hundreds of milliseconds*/
@@ -831,7 +862,7 @@ void linphone_gtk_decline_clicked(GtkWidget *button){
 void linphone_gtk_answer_clicked(GtkWidget *button){
        LinphoneCall *call=linphone_gtk_get_currently_displayed_call(NULL);
        if (call){
-               linphone_core_accept_call(linphone_gtk_get_core(),call);
+               accept_incoming_call(call);
                linphone_gtk_show_main_window(); /* useful when the button is clicked on a notification */
        }
 }
index b42470e5ad612a59032fb420624d4a88996fcf36..e1c8c91291fcdd0b9cc626d84fff03a8e22f49a8 100644 (file)
           <object class="GtkVBox" id="conf_box">
             <property name="visible">True</property>
             <property name="can_focus">False</property>
-            <child>
-              <placeholder/>
-            </child>
             <child>
               <object class="GtkHButtonBox" id="button_conf">
                 <property name="visible">True</property>
                 <property name="expand">True</property>
                 <property name="fill">True</property>
                 <property name="pack_type">end</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkHBox" id="conf_record_hbox">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <child>
+                  <object class="GtkToggleButton" id="conf_record_button">
+                    <property name="label">gtk-media-record</property>
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="receives_default">True</property>
+                    <property name="use_action_appearance">False</property>
+                    <property name="use_stock">True</property>
+                    <signal name="toggled" handler="linphone_gtk_record_call_toggled" swapped="no"/>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="conf_record_status">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="wrap">True</property>
+                    <property name="wrap_mode">char</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="pack_type">end</property>
                 <property name="position">1</property>
               </packing>
             </child>
+            <child>
+              <placeholder/>
+            </child>
           </object>
         </child>
       </object>
index c2258ea57c175a8878b91b798e8285caca266012..8481bef7e6532dae73ce02b8bd58c0c4cafa67be 100644 (file)
@@ -972,7 +972,8 @@ static void linphone_gtk_show_media_encryption(GtkWidget *pb){
                }
                g_signal_connect(G_OBJECT(combo),"changed",(GCallback)linphone_gtk_media_encryption_changed,NULL);
        }
-       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"media_encryption_mandatory")),linphone_core_is_media_encryption_mandatory(lc));
+       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"media_encryption_mandatory")),
+                                    linphone_core_is_media_encryption_mandatory(lc));
        g_object_unref(G_OBJECT(model));
 }
 
@@ -1015,10 +1016,8 @@ void linphone_gtk_show_parameters(void){
        if (pb==NULL) {
                pb=linphone_gtk_create_window("parameters");
                g_object_set_data(G_OBJECT(mw),"parameters",pb);
-               ms_error("linphone_gtk_show_paramters: create");
        }else {
                gtk_widget_show(pb);
-               ms_error("linphone_gtk_show_parameters: show");
                return;
        }
        codec_list=linphone_gtk_get_widget(pb,"codec_list");
@@ -1028,21 +1027,21 @@ void linphone_gtk_show_parameters(void){
                                linphone_core_ipv6_enabled(lc));
        linphone_core_get_sip_transports(lc,&tr);
 
-    if (tr.tcp_port > 0) {
-        gtk_combo_box_set_active(GTK_COMBO_BOX(linphone_gtk_get_widget(pb,"proto_combo")), 1);
-        gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"proto_port")),
+       if (tr.tcp_port > 0) {
+               gtk_combo_box_set_active(GTK_COMBO_BOX(linphone_gtk_get_widget(pb,"proto_combo")), 1);
+               gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"proto_port")),
                                tr.tcp_port);
-    }
-    else if (tr.tls_port > 0) {
-        gtk_combo_box_set_active(GTK_COMBO_BOX(linphone_gtk_get_widget(pb,"proto_combo")), 2);
-        gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"proto_port")),
+       }
+       else if (tr.tls_port > 0) {
+               gtk_combo_box_set_active(GTK_COMBO_BOX(linphone_gtk_get_widget(pb,"proto_combo")), 2);
+               gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"proto_port")),
                                tr.tls_port);
-    }
-    else {
-        gtk_combo_box_set_active(GTK_COMBO_BOX(linphone_gtk_get_widget(pb,"proto_combo")), 0);
-        gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"proto_port")),
+       }
+       else {
+               gtk_combo_box_set_active(GTK_COMBO_BOX(linphone_gtk_get_widget(pb,"proto_combo")), 0);
+               gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb,"proto_port")),
                                tr.udp_port);
-    }
+       }
 
        linphone_core_get_audio_port_range(lc, &min_port, &max_port);
        gtk_spin_button_set_value(GTK_SPIN_BUTTON(linphone_gtk_get_widget(pb, "audio_min_rtp_port")), min_port);
@@ -1083,6 +1082,10 @@ void linphone_gtk_show_parameters(void){
                        gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(linphone_gtk_get_widget(pb,"use_upnp")),TRUE);
                break;
        }
+       if(!linphone_core_upnp_available(lc)) {
+               gtk_widget_hide(linphone_gtk_get_widget(pb,"use_upnp"));
+       }
+
        mtu=linphone_core_get_mtu(lc);
        if (mtu<=0){
                gtk_widget_set_sensitive(linphone_gtk_get_widget(pb,"mtu"),FALSE);
old mode 100755 (executable)
new mode 100644 (file)
index 11a7c275f9f569c8c1f7b7068f69c436dd9fb144..87b5de094aacac1c4f86279c5e93f79d0daef637 100644 (file)
@@ -396,6 +396,10 @@ public interface LinphoneCore {
         * @param aCall to be terminated
         */
        public void terminateCall(LinphoneCall aCall);
+       /**
+        * Declines an incoming call, providing a reason for declining it.
+        */
+       public void declineCall(LinphoneCall aCall, Reason reason);
        /**
         * Returns The LinphoneCall the current call if one is in call
         *
@@ -744,6 +748,12 @@ public interface LinphoneCore {
        **/
        void startEchoCalibration(Object data) throws LinphoneCoreException;
 
+       /**
+        * Returns true if echo calibration is recommended.
+        * If the device has a builtin echo canceller or calibration value is already known, it will return false.
+        */
+       boolean needsEchoCalibration();
+       
        void enableIpv6(boolean enable);
        /**
         * @deprecated
@@ -751,25 +761,63 @@ public interface LinphoneCore {
         */
        void adjustSoftwareVolume(int i);
        
+       /**
+        * Pause a call.
+       **/
        boolean pauseCall(LinphoneCall call);
+       /**
+        * Resume a call.
+       **/
        boolean resumeCall(LinphoneCall call);
        boolean pauseAllCalls();
        
        void setZrtpSecretsCache(String file);
        void enableEchoLimiter(boolean val);
 
+       /**
+        * Indicates whether the local user is part of the conference.
+       **/
        boolean isInConference();
+       /**
+        * Connect the local user to the conference.
+       **/
        boolean enterConference();
+       /**
+        * Disconnect the local user from the conference.
+       **/
        void leaveConference();
 
+       /**
+        * Add an established call to the conference. The LinphoneCore is able to manage one client based conference.
+       **/
        void addToConference(LinphoneCall call);
-       void addAllToConference();
+       /**
+        * Remove an established call from the conference.
+       **/
        void removeFromConference(LinphoneCall call);
-
+       void addAllToConference();
+       
+       /**
+        * Terminate the conference, all users are disconnected.
+       **/
        void terminateConference();
        int getConferenceSize();
+
+       /**
+        * Request recording of the conference into a supplied file path.
+        * The format is wav.
+       **/
+       void startConferenceRecording(String path);
        
+       /**
+        * Stop recording of the conference.
+       **/
+       void stopConferenceRecording();
+
        void terminateAllCalls();
+       /**
+        * Returns all calls.
+       **/
        LinphoneCall[] getCalls();
        int getCallsNb();
 
diff --git a/java/common/org/linphone/core/Reason.java b/java/common/org/linphone/core/Reason.java
new file mode 100644 (file)
index 0000000..b07686a
--- /dev/null
@@ -0,0 +1,56 @@
+package org.linphone.core;
+
+import java.util.Vector;
+
+public class Reason {
+       static private Vector<Reason> values = new Vector<Reason>();
+       /**
+        * None (no failure)
+        */
+       static public Reason None = new Reason(0,"None");
+       /**
+        * No response 
+        */
+       static public Reason NoResponse = new Reason(1,"NoResponse");
+       /**
+        * Bad credentials
+        */
+       static public Reason BadCredentials = new Reason(2,"BadCredentials");
+       /**
+        * Call declined
+        */
+       static public Reason Declined = new Reason(3,"Declined");
+       /**
+        * Not found
+        */
+       static public Reason NotFound = new Reason(4,"NotFound");
+       /**
+        * Call not answered (in time).
+        */
+       static public Reason NotAnswered = new Reason(5,"NotAnswered");
+       /**
+        * Call not answered (in time).
+        */
+       static public Reason Busy = new Reason(6,"Busy");
+       
+       protected final int mValue;
+       private final String mStringValue;
+
+       
+       private Reason(int value,String stringValue) {
+               mValue = value;
+               values.addElement(this);
+               mStringValue=stringValue;
+       }
+       public static Reason fromInt(int value) {
+               for (int i=0; i<values.size();i++) {
+                       Reason state = (Reason) values.elementAt(i);
+                       if (state.mValue == value) return state;
+               }
+               throw new RuntimeException("Reason not found ["+value+"]");
+       }
+
+       public String toString() {
+               return mStringValue;
+       }
+}
index 2d42c8f550ed5727b5ea079b6ae6c25346f49c68..5a52f7559a7408718f2a898fbb33ae3d8afeae1e 100644 (file)
@@ -757,30 +757,30 @@ class LinphoneCoreImpl implements LinphoneCore {
                setVideoPolicy(nativePtr, autoInitiate, autoAccept);
        }
        private native void setStaticPicture(long nativePtr, String path);
-       public void setStaticPicture(String path) {
+       public synchronized void setStaticPicture(String path) {
                setStaticPicture(nativePtr, path);
        }
        private native void setUserAgent(long nativePtr, String name, String version);
        @Override
-       public void setUserAgent(String name, String version) {
+       public synchronized void setUserAgent(String name, String version) {
                setUserAgent(nativePtr,name,version);
        }
 
        private native void setCpuCountNative(int count);
-       public void setCpuCount(int count)
+       public synchronized void setCpuCount(int count)
        {
                setCpuCountNative(count);
        }
        
-       public int getMissedCallsCount() {
+       public synchronized int getMissedCallsCount() {
                return getMissedCallsCount(nativePtr);
        }
        
-       public void removeCallLog(LinphoneCallLog log) {
+       public synchronized void removeCallLog(LinphoneCallLog log) {
                removeCallLog(nativePtr, ((LinphoneCallLogImpl) log).getNativePtr());
        }
 
-       public void resetMissedCallsCount() {
+       public synchronized void resetMissedCallsCount() {
                resetMissedCallsCount(nativePtr);
        }
        
@@ -793,7 +793,7 @@ class LinphoneCoreImpl implements LinphoneCore {
        }
        
        private native void refreshRegisters(long nativePtr);
-       public void refreshRegisters() {
+       public synchronized void refreshRegisters() {
                refreshRegisters(nativePtr);
        }
        
@@ -803,19 +803,19 @@ class LinphoneCoreImpl implements LinphoneCore {
        }
        
        @Override
-       public PayloadType findPayloadType(String mime, int clockRate) {
+       public synchronized PayloadType findPayloadType(String mime, int clockRate) {
                return findPayloadType(mime, clockRate, 1);
        }
        
        private native void removeFriend(long ptr, long lf);
        @Override
-       public void removeFriend(LinphoneFriend lf) {
+       public synchronized void removeFriend(LinphoneFriend lf) {
                removeFriend(nativePtr, lf.getNativePtr());
        }
        
        private native long getFriendByAddress(long ptr, String sipUri);
        @Override
-       public LinphoneFriend findFriendByAddress(String sipUri) {
+       public synchronized LinphoneFriend findFriendByAddress(String sipUri) {
                long ptr = getFriendByAddress(nativePtr, sipUri);
                if (ptr == 0) {
                        return null;
@@ -823,55 +823,65 @@ class LinphoneCoreImpl implements LinphoneCore {
                return new LinphoneFriendImpl(ptr);
        }
        
-       public void setAudioPort(int port) {
+       public synchronized void setAudioPort(int port) {
                setAudioPort(nativePtr, port);
        }
        
-       public void setVideoPort(int port) {
+       public synchronized void setVideoPort(int port) {
                setVideoPort(nativePtr, port);
        }
        
-       public void setAudioPortRange(int minPort, int maxPort) {
+       public synchronized void setAudioPortRange(int minPort, int maxPort) {
                setAudioPortRange(nativePtr, minPort, maxPort);
        }
        
-       public void setVideoPortRange(int minPort, int maxPort) {
+       public synchronized void setVideoPortRange(int minPort, int maxPort) {
                setVideoPortRange(nativePtr, minPort, maxPort);
        }
        
-       public void setIncomingTimeout(int timeout) {
+       public synchronized void setIncomingTimeout(int timeout) {
                setIncomingTimeout(nativePtr, timeout);
        }
        
-       public void setInCallTimeout(int timeout)
+       public synchronized void setInCallTimeout(int timeout)
        {
                setInCallTimeout(nativePtr, timeout);
        }
        
        private native void setMicrophoneGain(long ptr, float gain);
-       public void setMicrophoneGain(float gain) {
+       public synchronized void setMicrophoneGain(float gain) {
                setMicrophoneGain(nativePtr, gain);
        }
        
-       public void setPrimaryContact(String displayName, String username) {
+       public synchronized void setPrimaryContact(String displayName, String username) {
                setPrimaryContact(nativePtr, displayName, username);
        }
        
        private native void setUseSipInfoForDtmfs(long ptr, boolean use);
-       public void setUseSipInfoForDtmfs(boolean use) {
+       public synchronized void setUseSipInfoForDtmfs(boolean use) {
                setUseSipInfoForDtmfs(nativePtr, use);
        }
        
        private native void setUseRfc2833ForDtmfs(long ptr, boolean use);
-       public void setUseRfc2833ForDtmfs(boolean use) {
+       public synchronized void setUseRfc2833ForDtmfs(boolean use) {
                setUseRfc2833ForDtmfs(nativePtr, use);
        }
 
        private native long getConfig(long ptr);
-       public LpConfig getConfig() {
+       public synchronized LpConfig getConfig() {
                long configPtr=getConfig(nativePtr);
                return new LpConfigImpl(configPtr);
        }
+       private native boolean needsEchoCalibration(long ptr);
+       @Override
+       public synchronized boolean needsEchoCalibration() {
+               return needsEchoCalibration(nativePtr);
+       }
+       private native void declineCall(long coreptr, long callptr, int reason);
+       @Override
+       public synchronized void declineCall(LinphoneCall aCall, Reason reason) {
+               declineCall(nativePtr,((LinphoneCallImpl)aCall).nativePtr,reason.mValue);
+       }
        
        private native boolean upnpAvailable(long ptr);
        public boolean upnpAvailable() {
@@ -887,4 +897,15 @@ class LinphoneCoreImpl implements LinphoneCore {
        public String getUpnpExternalIpaddress() {
                return getUpnpExternalIpaddress(nativePtr);
        }
+       private native int startConferenceRecording(long nativePtr, String path);
+       @Override
+       public void startConferenceRecording(String path) {
+               startConferenceRecording(nativePtr,path);
+       }
+       
+       private native int stopConferenceRecording(long nativePtr);
+       @Override
+       public void stopConferenceRecording() {
+               stopConferenceRecording(nativePtr);
+       }
 }
diff --git a/linphone.kdevelop b/linphone.kdevelop
deleted file mode 100644 (file)
index 2cb0437..0000000
+++ /dev/null
@@ -1,558 +0,0 @@
-<?xml version = '1.0'?>
-<kdevelop>
-  <general>
-    <author>Simon Morlat</author>
-    <email>simon.morlat@linphone.org</email>
-    <version>[3.1.2]</version>
-    <projectmanagement>KDevCustomProject</projectmanagement>
-    <primarylanguage>C</primarylanguage>
-    <ignoreparts/>
-    <projectname>linphone</projectname>
-    <projectdirectory>.</projectdirectory>
-    <absoluteprojectpath>false</absoluteprojectpath>
-    <description/>
-    <defaultencoding/>
-  </general>
-  <kdevcustomproject>
-    <run>
-      <directoryradio>executable</directoryradio>
-      <mainprogram>gtk-glade/linphone</mainprogram>
-      <programargs/>
-      <globaldebugarguments/>
-      <globalcwd/>
-      <useglobalprogram>false</useglobalprogram>
-      <terminal>false</terminal>
-      <autocompile>false</autocompile>
-      <autoinstall>false</autoinstall>
-      <autokdesu>false</autokdesu>
-      <envvars/>
-    </run>
-    <filetypes>
-      <filetype>*.java</filetype>
-      <filetype>*.h</filetype>
-      <filetype>*.H</filetype>
-      <filetype>*.hh</filetype>
-      <filetype>*.hxx</filetype>
-      <filetype>*.hpp</filetype>
-      <filetype>*.c</filetype>
-      <filetype>*.C</filetype>
-      <filetype>*.cc</filetype>
-      <filetype>*.cpp</filetype>
-      <filetype>*.c++</filetype>
-      <filetype>*.cxx</filetype>
-    </filetypes>
-    <blacklist>
-      <path>config.h</path>
-      <path>exosip</path>
-      <path>exosip/eXosip2.h</path>
-      <path>exosip/eXosip.c</path>
-      <path>exosip/eXosip_cfg.h</path>
-      <path>exosip/eXosip.h</path>
-      <path>exosip/eXutils.c</path>
-      <path>exosip/jauth.c</path>
-      <path>exosip/jcallback.c</path>
-      <path>exosip/jcall.c</path>
-      <path>exosip/jdialog.c</path>
-      <path>exosip/jevents.c</path>
-      <path>exosip/jfreinds.c</path>
-      <path>exosip/jidentity.c</path>
-      <path>exosip/jnotify.c</path>
-      <path>exosip/jpipe.c</path>
-      <path>exosip/jpipe.h</path>
-      <path>exosip/jpublish.c</path>
-      <path>exosip/jreg.c</path>
-      <path>exosip/jrequest.c</path>
-      <path>exosip/jresponse.c</path>
-      <path>exosip/jsubscribe.c</path>
-      <path>exosip/jsubscribers.c</path>
-      <path>exosip/misc.c</path>
-      <path>exosip/sdp_offans.c</path>
-      <path>exosip/udp.c</path>
-      <path>gnome</path>
-      <path>gnome/addressbook.c</path>
-      <path>gnome/addressbook.h</path>
-      <path>gnome/applet.c</path>
-      <path>gnome/callbacks.c</path>
-      <path>gnome/callbacks.h</path>
-      <path>gnome/friends.c</path>
-      <path>gnome/friends.h</path>
-      <path>gnome/gui_utils.c</path>
-      <path>gnome/gui_utils.h</path>
-      <path>gnome/interface.c</path>
-      <path>gnome/interface.h</path>
-      <path>gnome/linphone.c</path>
-      <path>gnome/linphone.h</path>
-      <path>gnome/main.c</path>
-      <path>gnome/presence.c</path>
-      <path>gnome/presence.h</path>
-      <path>gnome/propertybox.c</path>
-      <path>gnome/propertybox.h</path>
-      <path>gnome/support.c</path>
-      <path>gnome/support.h</path>
-      <path>gsmlib</path>
-      <path>gsmlib/code.c</path>
-      <path>gsmlib/config.h</path>
-      <path>gsmlib/debug.c</path>
-      <path>gsmlib/decode.c</path>
-      <path>gsmlib/gsmadd.c</path>
-      <path>gsmlib/gsm_create.c</path>
-      <path>gsmlib/gsm_decode.c</path>
-      <path>gsmlib/gsm_destroy.c</path>
-      <path>gsmlib/gsm_encode.c</path>
-      <path>gsmlib/gsm_explode.c</path>
-      <path>gsmlib/gsm.h</path>
-      <path>gsmlib/gsm_implode.c</path>
-      <path>gsmlib/gsm_option.c</path>
-      <path>gsmlib/gsm_print.c</path>
-      <path>gsmlib/gsm_wrapper.c</path>
-      <path>gsmlib/gsm_wrapper.h</path>
-      <path>gsmlib/long_term.c</path>
-      <path>gsmlib/lpc.c</path>
-      <path>gsmlib/preprocess.c</path>
-      <path>gsmlib/private.h</path>
-      <path>gsmlib/proto.h</path>
-      <path>gsmlib/rpe.c</path>
-      <path>gsmlib/short_term.c</path>
-      <path>gsmlib/table.c</path>
-      <path>gsmlib/toast.h</path>
-      <path>gsmlib/unproto.h</path>
-      <path>gtk</path>
-      <path>gtk/addressbook.c</path>
-      <path>gtk/addressbook.h</path>
-      <path>gtk/applet.c</path>
-      <path>gtk/callbacks.c</path>
-      <path>gtk/callbacks.h</path>
-      <path>gtk/friends.c</path>
-      <path>gtk/friends.h</path>
-      <path>gtk/gui_utils.c</path>
-      <path>gtk/gui_utils.h</path>
-      <path>gtk/interface.c</path>
-      <path>gtk/interface.h</path>
-      <path>gtk/linphone.c</path>
-      <path>gtk/linphone.h</path>
-      <path>gtk/main.c</path>
-      <path>gtk/presence.c</path>
-      <path>gtk/presence.h</path>
-      <path>gtk/propertybox.c</path>
-      <path>gtk/propertybox.h</path>
-      <path>gtk/support.c</path>
-      <path>gtk/support.h</path>
-      <path>intl</path>
-      <path>intl/bindtextdom.c</path>
-      <path>intl/cat-compat.c</path>
-      <path>intl/dcgettext.c</path>
-      <path>intl/dgettext.c</path>
-      <path>intl/explodename.c</path>
-      <path>intl/finddomain.c</path>
-      <path>intl/gettext.c</path>
-      <path>intl/gettext.h</path>
-      <path>intl/gettextP.h</path>
-      <path>intl/hash-string.h</path>
-      <path>intl/intl-compat.c</path>
-      <path>intl/l10nflist.c</path>
-      <path>intl/libgettext.h</path>
-      <path>intl/loadinfo.h</path>
-      <path>intl/loadmsgcat.c</path>
-      <path>intl/localealias.c</path>
-      <path>intl/textdomain.c</path>
-      <path>lpc10-1.5</path>
-      <path>lpc10-1.5/analys.c</path>
-      <path>lpc10-1.5/bitio.c</path>
-      <path>lpc10-1.5/bsynz.c</path>
-      <path>lpc10-1.5/chanwr.c</path>
-      <path>lpc10-1.5/dcbias.c</path>
-      <path>lpc10-1.5/decode.c</path>
-      <path>lpc10-1.5/deemp.c</path>
-      <path>lpc10-1.5/difmag.c</path>
-      <path>lpc10-1.5/dyptrk.c</path>
-      <path>lpc10-1.5/encode.c</path>
-      <path>lpc10-1.5/energy.c</path>
-      <path>lpc10-1.5/f2c.h</path>
-      <path>lpc10-1.5/f2clib.c</path>
-      <path>lpc10-1.5/ham84.c</path>
-      <path>lpc10-1.5/hp100.c</path>
-      <path>lpc10-1.5/invert.c</path>
-      <path>lpc10-1.5/irc2pc.c</path>
-      <path>lpc10-1.5/ivfilt.c</path>
-      <path>lpc10-1.5/lpc10.h</path>
-      <path>lpc10-1.5/lpc10_wrapper.c</path>
-      <path>lpc10-1.5/lpc10_wrapper.h</path>
-      <path>lpc10-1.5/lpcdec.c</path>
-      <path>lpc10-1.5/lpcenc.c</path>
-      <path>lpc10-1.5/lpcini.c</path>
-      <path>lpc10-1.5/lpfilt.c</path>
-      <path>lpc10-1.5/median.c</path>
-      <path>lpc10-1.5/mload.c</path>
-      <path>lpc10-1.5/onset.c</path>
-      <path>lpc10-1.5/pitsyn.c</path>
-      <path>lpc10-1.5/placea.c</path>
-      <path>lpc10-1.5/placev.c</path>
-      <path>lpc10-1.5/preemp.c</path>
-      <path>lpc10-1.5/prepro.c</path>
-      <path>lpc10-1.5/random.c</path>
-      <path>lpc10-1.5/rcchk.c</path>
-      <path>lpc10-1.5/synths.c</path>
-      <path>lpc10-1.5/tbdm.c</path>
-      <path>lpc10-1.5/voicin.c</path>
-      <path>lpc10-1.5/vparms.c</path>
-      <path>media_api</path>
-      <path>media_api/apitest.c</path>
-      <path>media_api/apitest.h</path>
-      <path>media_api/basiccall.c</path>
-      <path>media_api/basiccall.h</path>
-      <path>media_api/callmember.c</path>
-      <path>media_api/callmember.h</path>
-      <path>media_api/common.h</path>
-      <path>media_api/media_api.c</path>
-      <path>media_api/media_api.h</path>
-      <path>media_api/mediaflow.c</path>
-      <path>media_api/mediaflow.h</path>
-      <path>mediastreamer</path>
-      <path>mediastreamer/affine.c</path>
-      <path>mediastreamer/affine.h</path>
-      <path>mediastreamer/alsacard.c</path>
-      <path>mediastreamer/alsacard.h</path>
-      <path>mediastreamer/audiostream.c</path>
-      <path>mediastreamer/g711common.h</path>
-      <path>mediastreamer/hpuxsndcard.c</path>
-      <path>mediastreamer/jackcard.c</path>
-      <path>mediastreamer/jackcard.h</path>
-      <path>mediastreamer/mediastream.c</path>
-      <path>mediastreamer/mediastream.h</path>
-      <path>mediastreamer/msAlawdec.c</path>
-      <path>mediastreamer/msAlawdec.h</path>
-      <path>mediastreamer/msAlawenc.c</path>
-      <path>mediastreamer/msAlawenc.h</path>
-      <path>mediastreamer/msavdecoder.c</path>
-      <path>mediastreamer/msavdecoder.h</path>
-      <path>mediastreamer/msavencoder.c</path>
-      <path>mediastreamer/msavencoder.h</path>
-      <path>mediastreamer/msbuffer.c</path>
-      <path>mediastreamer/msbuffer.h</path>
-      <path>mediastreamer/ms.c</path>
-      <path>mediastreamer/mscodec.c</path>
-      <path>mediastreamer/mscodec.h</path>
-      <path>mediastreamer/mscopy.c</path>
-      <path>mediastreamer/mscopy.h</path>
-      <path>mediastreamer/msfdispatcher.c</path>
-      <path>mediastreamer/msfdispatcher.h</path>
-      <path>mediastreamer/msfifo.c</path>
-      <path>mediastreamer/msfifo.h</path>
-      <path>mediastreamer/msfilter.c</path>
-      <path>mediastreamer/msfilter.h</path>
-      <path>mediastreamer/msGSMdecoder.c</path>
-      <path>mediastreamer/msGSMdecoder.h</path>
-      <path>mediastreamer/msGSMencoder.c</path>
-      <path>mediastreamer/msGSMencoder.h</path>
-      <path>mediastreamer/ms.h</path>
-      <path>mediastreamer/msLPC10decoder.c</path>
-      <path>mediastreamer/msLPC10decoder.h</path>
-      <path>mediastreamer/msLPC10encoder.c</path>
-      <path>mediastreamer/msLPC10encoder.h</path>
-      <path>mediastreamer/msMUlawdec.c</path>
-      <path>mediastreamer/msMUlawdec.h</path>
-      <path>mediastreamer/msMUlawenc.c</path>
-      <path>mediastreamer/msMUlawenc.h</path>
-      <path>mediastreamer/msnosync.c</path>
-      <path>mediastreamer/msnosync.h</path>
-      <path>mediastreamer/msossread.c</path>
-      <path>mediastreamer/msossread.h</path>
-      <path>mediastreamer/msosswrite.c</path>
-      <path>mediastreamer/msosswrite.h</path>
-      <path>mediastreamer/msqdispatcher.c</path>
-      <path>mediastreamer/msqdispatcher.h</path>
-      <path>mediastreamer/msqueue.c</path>
-      <path>mediastreamer/msqueue.h</path>
-      <path>mediastreamer/msread.c</path>
-      <path>mediastreamer/msread.h</path>
-      <path>mediastreamer/msringplayer.c</path>
-      <path>mediastreamer/msringplayer.h</path>
-      <path>mediastreamer/msrtprecv.c</path>
-      <path>mediastreamer/msrtprecv.h</path>
-      <path>mediastreamer/msrtpsend.c</path>
-      <path>mediastreamer/msrtpsend.h</path>
-      <path>mediastreamer/mssdlout.c</path>
-      <path>mediastreamer/mssdlout.h</path>
-      <path>mediastreamer/mssmpeg.c</path>
-      <path>mediastreamer/mssmpeg.h</path>
-      <path>mediastreamer/mssoundread.c</path>
-      <path>mediastreamer/mssoundread.h</path>
-      <path>mediastreamer/mssoundwrite.c</path>
-      <path>mediastreamer/mssoundwrite.h</path>
-      <path>mediastreamer/msspeexdec.c</path>
-      <path>mediastreamer/msspeexdec.h</path>
-      <path>mediastreamer/msspeexenc.c</path>
-      <path>mediastreamer/msspeexenc.h</path>
-      <path>mediastreamer/mssync.c</path>
-      <path>mediastreamer/mssync.h</path>
-      <path>mediastreamer/mstcpclient.c</path>
-      <path>mediastreamer/mstcpclient.h</path>
-      <path>mediastreamer/mstcpserv.c</path>
-      <path>mediastreamer/mstcpserv.h</path>
-      <path>mediastreamer/mstimer.c</path>
-      <path>mediastreamer/mstimer.h</path>
-      <path>mediastreamer/mstruespeechdecoder.c</path>
-      <path>mediastreamer/mstruespeechdecoder.h</path>
-      <path>mediastreamer/mstruespeechencoder.c</path>
-      <path>mediastreamer/mstruespeechencoder.h</path>
-      <path>mediastreamer/msutils.h</path>
-      <path>mediastreamer/msv4l.c</path>
-      <path>mediastreamer/msv4l.h</path>
-      <path>mediastreamer/msvideooutput.c</path>
-      <path>mediastreamer/msvideooutput.h</path>
-      <path>mediastreamer/msvideosource.c</path>
-      <path>mediastreamer/msvideosource.h</path>
-      <path>mediastreamer/mswrite.c</path>
-      <path>mediastreamer/mswrite.h</path>
-      <path>mediastreamer/msxine.c</path>
-      <path>mediastreamer/msxine.h</path>
-      <path>mediastreamer/osscard.c</path>
-      <path>mediastreamer/osscard.h</path>
-      <path>mediastreamer/rfc2429.h</path>
-      <path>mediastreamer/ring_test.c</path>
-      <path>mediastreamer/sndcard.c</path>
-      <path>mediastreamer/sndcard.h</path>
-      <path>mediastreamer/test_alaw.c</path>
-      <path>mediastreamer/test.c</path>
-      <path>mediastreamer/test_gsm.c</path>
-      <path>mediastreamer/test_lpc10.c</path>
-      <path>mediastreamer/test_mulaw.c</path>
-      <path>mediastreamer/test_rtprecv.c</path>
-      <path>mediastreamer/test_smpeg.c</path>
-      <path>mediastreamer/test_speex.c</path>
-      <path>mediastreamer/test_truespeech.c</path>
-      <path>mediastreamer/test_v4l.c</path>
-      <path>mediastreamer/test_videostream.c</path>
-      <path>mediastreamer/test_xine.c</path>
-      <path>mediastreamer/videoclient.c</path>
-      <path>mediastreamer/videoserver.c</path>
-      <path>mediastreamer/videostream.c</path>
-      <path>mediastreamer/waveheader.h</path>
-      <path>po</path>
-      <path>po/cat-id-tbl.c</path>
-      <path>win32acm</path>
-      <path>win32acm/afl.c</path>
-      <path>win32acm/com.h</path>
-      <path>win32acm/config.h</path>
-      <path>win32acm/cpudetect.c</path>
-      <path>win32acm/cpudetect.h</path>
-      <path>win32acm/cputable.h</path>
-      <path>win32acm/driver.c</path>
-      <path>win32acm/driver.h</path>
-      <path>win32acm/elfdll.c</path>
-      <path>win32acm/ext.c</path>
-      <path>win32acm/ext.h</path>
-      <path>win32acm/ldt_keeper.c</path>
-      <path>win32acm/ldt_keeper.h</path>
-      <path>win32acm/loader.h</path>
-      <path>win32acm/module.c</path>
-      <path>win32acm/mp_msg.c</path>
-      <path>win32acm/mp_msg.h</path>
-      <path>win32acm/pe_image.c</path>
-      <path>win32acm/pe_resource.c</path>
-      <path>win32acm/registry.c</path>
-      <path>win32acm/registry.h</path>
-      <path>win32acm/resource.c</path>
-      <path>win32acm/test_truespeech.c</path>
-      <path>win32acm/win32.c</path>
-      <path>win32acm/win32codec.c</path>
-      <path>win32acm/win32codec.h</path>
-      <path>win32acm/win32.h</path>
-      <path>win32acm/wine</path>
-      <path>win32acm/wine/basetsd.h</path>
-      <path>win32acm/wine/debugtools.h</path>
-      <path>win32acm/wine/driver.h</path>
-      <path>win32acm/wine/elfdll.h</path>
-      <path>win32acm/wine/heap.h</path>
-      <path>win32acm/wine/ldt.h</path>
-      <path>win32acm/wine/mmreg.h</path>
-      <path>win32acm/wine/module.h</path>
-      <path>win32acm/wine/msacmdrv.h</path>
-      <path>win32acm/wine/msacm.h</path>
-      <path>win32acm/wine/ntdef.h</path>
-      <path>win32acm/wine/pe_image.h</path>
-      <path>win32acm/wine/poppack.h</path>
-      <path>win32acm/wine/pshpack1.h</path>
-      <path>win32acm/wine/pshpack2.h</path>
-      <path>win32acm/wine/pshpack4.h</path>
-      <path>win32acm/wine/pshpack8.h</path>
-      <path>win32acm/wine/vfw.h</path>
-      <path>win32acm/wine/winbase.h</path>
-      <path>win32acm/wine/windef.h</path>
-      <path>win32acm/wine/windows.h</path>
-      <path>win32acm/wine/winerror.h</path>
-      <path>win32acm/wine/winestring.h</path>
-      <path>win32acm/wine/winnt.h</path>
-      <path>win32acm/wine/winreg.h</path>
-      <path>win32acm/wine/winuser.h</path>
-      <path>win32acm/wineacm.h</path>
-      <path>win32acm/wrapper.h</path>
-      <path>builddate.h</path>
-    </blacklist>
-    <build>
-      <buildtool>make</buildtool>
-      <builddir/>
-    </build>
-    <other>
-      <prio>0</prio>
-      <otherbin/>
-      <defaulttarget/>
-      <otheroptions/>
-      <selectedenvironment>default</selectedenvironment>
-      <environments>
-        <default/>
-      </environments>
-    </other>
-    <make>
-      <abortonerror>true</abortonerror>
-      <numberofjobs>0</numberofjobs>
-      <prio>0</prio>
-      <dontact>false</dontact>
-      <makebin/>
-      <defaulttarget/>
-      <makeoptions/>
-      <selectedenvironment>default</selectedenvironment>
-      <environments>
-        <default/>
-      </environments>
-    </make>
-  </kdevcustomproject>
-  <kdevdebugger>
-    <general>
-      <dbgshell/>
-      <gdbpath/>
-      <configGdbScript/>
-      <runShellScript/>
-      <runGdbScript/>
-      <breakonloadinglibs>true</breakonloadinglibs>
-      <separatetty>false</separatetty>
-      <floatingtoolbar>false</floatingtoolbar>
-      <raiseGDBOnStart>false</raiseGDBOnStart>
-    </general>
-    <display>
-      <staticmembers>false</staticmembers>
-      <demanglenames>true</demanglenames>
-      <outputradix>10</outputradix>
-    </display>
-  </kdevdebugger>
-  <kdevdoctreeview>
-    <ignoretocs>
-      <toc>ada</toc>
-      <toc>ada_bugs_gcc</toc>
-      <toc>bash</toc>
-      <toc>bash_bugs</toc>
-      <toc>clanlib</toc>
-      <toc>fortran_bugs_gcc</toc>
-      <toc>gnome1</toc>
-      <toc>gnustep</toc>
-      <toc>gtk</toc>
-      <toc>gtk_bugs</toc>
-      <toc>haskell</toc>
-      <toc>haskell_bugs_ghc</toc>
-      <toc>java_bugs_gcc</toc>
-      <toc>java_bugs_sun</toc>
-      <toc>kde2book</toc>
-      <toc>libstdc++</toc>
-      <toc>opengl</toc>
-      <toc>pascal_bugs_fp</toc>
-      <toc>php</toc>
-      <toc>php_bugs</toc>
-      <toc>perl</toc>
-      <toc>perl_bugs</toc>
-      <toc>python</toc>
-      <toc>python_bugs</toc>
-      <toc>qt-kdev3</toc>
-      <toc>ruby</toc>
-      <toc>ruby_bugs</toc>
-      <toc>sdl</toc>
-      <toc>stl</toc>
-      <toc>sw</toc>
-      <toc>w3c-dom-level2-html</toc>
-      <toc>w3c-svg</toc>
-      <toc>w3c-uaag10</toc>
-      <toc>wxwidgets_bugs</toc>
-    </ignoretocs>
-    <ignoreqt_xml>
-      <toc>Guide to the Qt Translation Tools</toc>
-      <toc>Qt Assistant Manual</toc>
-      <toc>Qt Designer Manual</toc>
-      <toc>Qt Reference Documentation</toc>
-      <toc>qmake User Guide</toc>
-    </ignoreqt_xml>
-    <ignoredoxygen>
-      <toc>KDE Libraries (Doxygen)</toc>
-    </ignoredoxygen>
-  </kdevdoctreeview>
-  <kdevfilecreate>
-    <filetypes/>
-    <useglobaltypes>
-      <type ext="c" />
-      <type ext="h" />
-    </useglobaltypes>
-  </kdevfilecreate>
-  <kdevcppsupport>
-    <qt>
-      <used>false</used>
-      <version>3</version>
-      <includestyle>3</includestyle>
-      <root></root>
-      <designerintegration>EmbeddedKDevDesigner</designerintegration>
-      <qmake></qmake>
-      <designer></designer>
-      <designerpluginpaths/>
-    </qt>
-    <references/>
-    <codecompletion>
-      <automaticCodeCompletion>false</automaticCodeCompletion>
-      <automaticArgumentsHint>true</automaticArgumentsHint>
-      <automaticHeaderCompletion>true</automaticHeaderCompletion>
-      <codeCompletionDelay>250</codeCompletionDelay>
-      <argumentsHintDelay>400</argumentsHintDelay>
-      <headerCompletionDelay>250</headerCompletionDelay>
-      <showOnlyAccessibleItems>false</showOnlyAccessibleItems>
-      <completionBoxItemOrder>0</completionBoxItemOrder>
-      <howEvaluationContextMenu>true</howEvaluationContextMenu>
-      <showCommentWithArgumentHint>true</showCommentWithArgumentHint>
-      <statusBarTypeEvaluation>false</statusBarTypeEvaluation>
-      <namespaceAliases>std=_GLIBCXX_STD;__gnu_cxx=std</namespaceAliases>
-      <processPrimaryTypes>true</processPrimaryTypes>
-      <processFunctionArguments>false</processFunctionArguments>
-      <preProcessAllHeaders>false</preProcessAllHeaders>
-      <parseMissingHeadersExperimental>false</parseMissingHeadersExperimental>
-      <resolveIncludePathsUsingMakeExperimental>false</resolveIncludePathsUsingMakeExperimental>
-      <alwaysParseInBackground>true</alwaysParseInBackground>
-      <usePermanentCaching>true</usePermanentCaching>
-      <alwaysIncludeNamespaces>false</alwaysIncludeNamespaces>
-      <includePaths>.;</includePaths>
-    </codecompletion>
-    <creategettersetter>
-      <prefixGet/>
-      <prefixSet>set</prefixSet>
-      <prefixVariable>m_,_</prefixVariable>
-      <parameterName>theValue</parameterName>
-      <inlineGet>true</inlineGet>
-      <inlineSet>true</inlineSet>
-    </creategettersetter>
-    <splitheadersource>
-      <enabled>false</enabled>
-      <synchronize>true</synchronize>
-      <orientation>Vertical</orientation>
-    </splitheadersource>
-  </kdevcppsupport>
-  <kdevfileview>
-    <groups>
-      <hidenonprojectfiles>false</hidenonprojectfiles>
-      <hidenonlocation>false</hidenonlocation>
-    </groups>
-    <tree>
-      <hidepatterns>*.o,*.lo,CVS</hidepatterns>
-      <hidenonprojectfiles>false</hidenonprojectfiles>
-    </tree>
-  </kdevfileview>
-  <cppsupportpart>
-    <filetemplates>
-      <interfacesuffix>.h</interfacesuffix>
-      <implementationsuffix>.cpp</implementationsuffix>
-    </filetemplates>
-  </cppsupportpart>
-</kdevelop>
index 44992c096673ace578ba5248db7019ba1e0d78d5..4ed2e518cf79c62fe8df7f23ce99e0fbfe2e799d 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 44992c096673ace578ba5248db7019ba1e0d78d5
+Subproject commit 4ed2e518cf79c62fe8df7f23ce99e0fbfe2e799d