]> sjero.net Git - linphone/commitdiff
Merge remote-tracking branch 'origin/master' into dev_gtk_new_ui
authorMargaux Clerc <margaux.clerc@belledonne-communications>
Thu, 18 Oct 2012 13:32:21 +0000 (15:32 +0200)
committerMargaux Clerc <margaux.clerc@belledonne-communications>
Thu, 18 Oct 2012 13:32:21 +0000 (15:32 +0200)
Conflicts:
gtk/incall_view.c
gtk/main.ui

66 files changed:
Makefile.am
configure.ac
console/linphonec.h
coreapi/TunnelManager.cc
coreapi/TunnelManager.hh
coreapi/callbacks.c
coreapi/chat.c
coreapi/ec-calibrator.c
coreapi/friend.c
coreapi/help/java/org/linphone/core/tutorials/TutorialBuddyStatus.java
coreapi/help/java/org/linphone/core/tutorials/TutorialChatRoom.java
coreapi/help/java/org/linphone/core/tutorials/TutorialHelloWorld.java
coreapi/help/java/org/linphone/core/tutorials/TutorialRegistration.java
coreapi/linphone_tunnel.cc
coreapi/linphone_tunnel.h
coreapi/linphonecall.c
coreapi/linphonecore.c
coreapi/linphonecore.h
coreapi/linphonecore_jni.cc
coreapi/linphonecore_utils.h
coreapi/lpconfig.c
coreapi/lpconfig.h
coreapi/misc.c
coreapi/private.h
coreapi/proxy.c
coreapi/sal.c
coreapi/sal.h
coreapi/sal_eXosip2.c
coreapi/sal_eXosip2.h
gtk/Makefile.am
gtk/call_statistics.ui [new file with mode: 0644]
gtk/dscp_settings.ui
gtk/incall_view.c
gtk/main.c
gtk/main.ui
java/common/org/linphone/core/LinphoneCall.java
java/common/org/linphone/core/LinphoneCallLog.java
java/common/org/linphone/core/LinphoneCallParams.java
java/common/org/linphone/core/LinphoneCallStats.java [new file with mode: 0644]
java/common/org/linphone/core/LinphoneChatMessage.java
java/common/org/linphone/core/LinphoneChatRoom.java
java/common/org/linphone/core/LinphoneCore.java
java/common/org/linphone/core/LinphoneCoreListener.java
java/common/org/linphone/core/LinphoneFriend.java
java/common/org/linphone/core/LinphoneProxyConfig.java
java/common/org/linphone/core/package.html
java/impl/org/linphone/core/LinphoneAddressImpl.java [new file with mode: 0644]
java/impl/org/linphone/core/LinphoneAuthInfoImpl.java [new file with mode: 0644]
java/impl/org/linphone/core/LinphoneCallImpl.java [new file with mode: 0644]
java/impl/org/linphone/core/LinphoneCallLogImpl.java [new file with mode: 0644]
java/impl/org/linphone/core/LinphoneCallParamsImpl.java [new file with mode: 0644]
java/impl/org/linphone/core/LinphoneCallStatsImpl.java [new file with mode: 0644]
java/impl/org/linphone/core/LinphoneChatMessageImpl.java [new file with mode: 0644]
java/impl/org/linphone/core/LinphoneChatRoomImpl.java [new file with mode: 0644]
java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java [new file with mode: 0644]
java/impl/org/linphone/core/LinphoneCoreImpl.java [new file with mode: 0644]
java/impl/org/linphone/core/LinphoneFriendImpl.java [new file with mode: 0644]
java/impl/org/linphone/core/LinphoneProxyConfigImpl.java [new file with mode: 0644]
java/impl/org/linphone/core/Log.java [new file with mode: 0644]
java/impl/org/linphone/core/PayloadTypeImpl.java [new file with mode: 0644]
java/impl/org/linphone/core/video/VideoUtil.java [new file with mode: 0644]
m4/exosip.m4
m4/readline.m4
mediastreamer2
oRTP
po/POTFILES.in

index 6faebc4fc7a971cf6cd42b358a65207d332524f2..4aa4332f2f99962cc4b085e3c66f015dbb994c12 100644 (file)
@@ -218,7 +218,9 @@ bundle: $(LIBICONV_HACK)
        MS2_PLUGINS_INSTALL_PREFIX=$(prefix) \
        gtk-mac-bundler $(PACKAGE_BUNDLE_FILE)
        printf "[Pango]\nModuleFiles=./etc/pango/pango.modules\n" \
-       > $(BUNDLEDIR)/Contents/Resources/etc/pango/pangorc 
+       > $(BUNDLEDIR)/Contents/Resources/etc/pango/pangorc
+       cp -f $(BUNDLEDIR)/Contents/Resources/etc/pango/pango.modules $(BUNDLEDIR)/Contents/Resources/etc/pango/pango.modules.orig
+       sed -e 's:@executable_path/../Resources:../..:g' $(BUNDLEDIR)/Contents/Resources/etc/pango/pango.modules.orig  > $(BUNDLEDIR)/Contents/Resources/etc/pango/pango.modules
        cp -f $(LIBICONV_HACK) $(BUNDLEDIR)/Contents/Resources/lib/.
        cd $(BUNDLEDIR)/.. && rm -f $(MACAPPZIP) && zip -r $(MACAPPZIP) $(MACAPPNAME) && cd -
 
@@ -230,6 +232,4 @@ clean-local:
 discovery:
        touch specs.cpp
        $(CC) --include $(top_builddir)/config.h \
-          --include $(top_builddir)/mediastreamer2/mediastreamer-config.h  \
-          --include $(top_builddir)/oRTP/ortp-config.h \
           $(TUNNEL_CFLAGS) $(CFLAGS) $(MEDIASTREAMER2_CFLAGS) $(ORTP_CFLAGS) -E -P -v -dD specs.cpp
index 6e68f7ba10a70445bb7df6573b8859aad8f12e1c..84081f46c76fa15c80028fd6b7e62e4b6fb80e38 100644 (file)
@@ -61,7 +61,7 @@ case $target in
                CONSOLE_FLAGS="-mconsole"
                mingw_found=yes
        ;;
-       armv6-apple-darwin|armv7-apple-darwin|i386-apple-darwin)
+       armv6-apple-darwin|armv7-apple-darwin|i386-apple-darwin|armv7s-apple-darwin)
                 CFLAGS="$CFLAGS -DTARGET_OS_IPHONE "
                 build_tests=no
                 ios_found=yes
@@ -107,6 +107,7 @@ if test "$mingw_found" != "yes" ; then
        dnl AM_GNU_GETTEXT pollutes CPPFLAGS: workaround this.
        CPPFLAGS_save=$CPPFLAGS
        AM_GNU_GETTEXT([external])
+       AC_SUBST(INTLLIBS)
        CPPFLAGS=$CPPFLAGS_save
        LIBS="$LIBS $LIBINTL"
 else
index ba7d346f8408d3999b0a836be6ebc3db98b756c3..3265d42ac3de2ed191342815cdc3ab99026edd03 100644 (file)
 #include "config.h"
 #endif
 
+#ifdef HAVE_READLINE
 #ifdef HAVE_READLINE_H
 #include <readline.h>
-#define HAVE_READLINE
 #else
 #ifdef HAVE_READLINE_READLINE_H
 #include <readline/readline.h>
-#define HAVE_READLINE
 #endif
 #endif
 #ifdef HAVE_HISTORY_H
@@ -45,6 +44,7 @@
 #include <readline/history.h>
 #endif
 #endif
+#endif
 
 #undef PARAMS
 /**************************************************************************
index e3c7e659578329ba380543904f1c8cce75b1702b..71ecc51843c288dc45d414a63435a954595b14af 100644 (file)
@@ -59,12 +59,12 @@ int TunnelManager::eXosipRecvfrom(int fd, void *buf, size_t len, int flags, stru
 int TunnelManager::eXosipSelect(int max_fds, fd_set *s1, fd_set *s2, fd_set *s3, struct timeval *tv,void* userdata){
        struct timeval begin,cur;
        TunnelManager* lTunnelMgr=(TunnelManager*)userdata;
-       if (tv!=0 && tv->tv_sec){
+       if (s1 && tv!=0 && tv->tv_sec){
                /*this is the select from udp.c, the one that is interesting to us*/
                NativeSocket udp_fd=(NativeSocket)eXosip_get_udp_socket();
                NativeSocket controlfd=(NativeSocket)eXosip_get_control_fd();
 
-               FD_ZERO(s1);            
+               FD_ZERO(s1);
                gettimeofday(&begin,NULL);
                do{
                        struct timeval abit;
@@ -212,7 +212,6 @@ TunnelManager::TunnelManager(LinphoneCore* lc) :TunnelClientController()
        mExosipTransport.recvfrom=eXosipRecvfrom;
        mExosipTransport.sendto=eXosipSendto;
        mExosipTransport.select=eXosipSelect;
-       mStateChanged=false;
        linphone_core_add_iterate_hook(mCore,(LinphoneCoreIterateHook)sOnIterate,this);
        mTransportFactories.audio_rtcp_func=sCreateRtpTransport;
        mTransportFactories.audio_rtcp_func_data=this;
@@ -242,12 +241,13 @@ void TunnelManager::stopClient(){
        }
 }
 
-void TunnelManager::processTunnelEvent(){
+void TunnelManager::processTunnelEvent(const Event &ev){
        LinphoneProxyConfig* lProxy;
        linphone_core_get_default_proxy(mCore, &lProxy);
 
        if (mEnabled && mTunnelClient->isReady()){
-               ms_message("Tunnel is up, registering now");            
+               ms_message("Tunnel is up, registering now");
+               linphone_core_set_firewall_policy(mCore,LinphonePolicyNoFirewall);
                linphone_core_set_rtp_transport_factories(mCore,&mTransportFactories);
                eXosip_transport_hook_register(&mExosipTransport);
                //force transport to udp
@@ -258,7 +258,7 @@ void TunnelManager::processTunnelEvent(){
                lTransport.tls_port=0;
                lTransport.dtls_port=0;
                
-               linphone_core_set_sip_transports(mCore, &lTransport);           
+               linphone_core_set_sip_transports(mCore, &lTransport);
                //register
                if (lProxy) {
                        linphone_proxy_config_done(lProxy);
@@ -296,8 +296,9 @@ void TunnelManager::enable(bool isEnable) {
        ms_message("Turning tunnel [%s]",(isEnable?"on":"off"));
        if (isEnable && !mEnabled){
                mEnabled=true;
-               //1 save transport 
+               //1 save transport and firewall policy
                linphone_core_get_sip_transports(mCore, &mRegularTransport);
+               mPreviousFirewallPolicy=linphone_core_get_firewall_policy(mCore);
                //2 unregister
                waitUnRegistration();
                //3 insert tunnel
@@ -312,8 +313,9 @@ void TunnelManager::enable(bool isEnable) {
                linphone_core_set_rtp_transport_factories(mCore,NULL);
 
                eXosip_transport_hook_register(NULL);
-               //Restore transport
+               //Restore transport and firewall policy
                linphone_core_set_sip_transports(mCore, &mRegularTransport);
+               linphone_core_set_firewall_policy(mCore, mPreviousFirewallPolicy);
                //register
                LinphoneProxyConfig* lProxy;
                linphone_core_get_default_proxy(mCore, &lProxy);
@@ -325,15 +327,31 @@ void TunnelManager::enable(bool isEnable) {
 }
 
 void TunnelManager::tunnelCallback(bool connected, TunnelManager *zis){
-       zis->mStateChanged=true;
+       Event ev;
+       ev.mType=TunnelEvent;
+       ev.mData.mConnected=connected;
+       zis->postEvent(ev);
+}
+
+void TunnelManager::onIterate(){
+       mMutex.lock();
+       while(!mEvq.empty()){
+               Event ev=mEvq.front();
+               mEvq.pop();
+               mMutex.unlock();
+               if (ev.mType==TunnelEvent)
+                       processTunnelEvent(ev);
+               else if (ev.mType==UdpMirrorClientEvent){
+                       processUdpMirrorEvent(ev);
+               }
+               mMutex.lock();
+       }
+       mMutex.unlock();
 }
 
 /*invoked from linphone_core_iterate() */
 void TunnelManager::sOnIterate(TunnelManager *zis){
-       if (zis->mStateChanged){
-               zis->mStateChanged=false;
-               zis->processTunnelEvent();
-       }
+       zis->onIterate();
 }
 
 #ifdef ANDROID
@@ -374,26 +392,39 @@ void TunnelManager::enableLogs(bool isEnabled,LogHandler logHandler) {
 bool TunnelManager::isEnabled() {
        return mEnabled;
 }
-void TunnelManager::UdpMirrorClientListener(bool isUdpAvailable, void* data) {
-       TunnelManager* thiz = (TunnelManager*)data;
-       if (isUdpAvailable) {
+
+void TunnelManager::processUdpMirrorEvent(const Event &ev){
+       if (ev.mData.mHaveUdp) {
                LOGI("Tunnel is not required, disabling");
-               thiz->enable(false);
-               thiz->mAutoDetectStarted = false;
+               enable(false);
+               mAutoDetectStarted = false;
        } else {
-               if (++thiz->mCurrentUdpMirrorClient !=thiz->mUdpMirrorClients.end()) {
-                       //1 enable tunnable but also try backup server
+               if (mCurrentUdpMirrorClient !=mUdpMirrorClients.end()) {
+                       // enable tunnel but also try backup server
                        LOGI("Tunnel is required, enabling; Trying backup udp mirror");
                        
-                       UdpMirrorClient &lUdpMirrorClient=*thiz->mCurrentUdpMirrorClient;
-                       lUdpMirrorClient.start(TunnelManager::UdpMirrorClientListener,(void*)thiz);
+                       UdpMirrorClient &lUdpMirrorClient=*mCurrentUdpMirrorClient;
+                       lUdpMirrorClient.start(TunnelManager::sUdpMirrorClientCallback,(void*)this);
                } else {
                        LOGI("Tunnel is required, enabling; no backup udp mirror available");
-                       thiz->mAutoDetectStarted = false;
+                       mAutoDetectStarted = false;
                }
-               thiz->enable(true);
+               enable(true);
        }
-       return;
+}
+
+void TunnelManager::postEvent(const Event &ev){
+       mMutex.lock();
+       mEvq.push(ev);
+       mMutex.unlock();
+}
+
+void TunnelManager::sUdpMirrorClientCallback(bool isUdpAvailable, void* data) {
+       TunnelManager* thiz = (TunnelManager*)data;
+       Event ev;
+       ev.mType=UdpMirrorClientEvent;
+       ev.mData.mHaveUdp=isUdpAvailable;
+       thiz->postEvent(ev);
 }
 
 void TunnelManager::autoDetect() {
@@ -409,7 +440,7 @@ void TunnelManager::autoDetect() {
        mAutoDetectStarted=true;
        mCurrentUdpMirrorClient =mUdpMirrorClients.begin();
        UdpMirrorClient &lUdpMirrorClient=*mCurrentUdpMirrorClient;
-       lUdpMirrorClient.start(TunnelManager::UdpMirrorClientListener,(void*)this);
+       lUdpMirrorClient.start(TunnelManager::sUdpMirrorClientCallback,(void*)this);
        
 }
 
index 1fb55429e3c061e39f21da8b27dad98059949d63..d4c1458fcfc933c122b8cec44604fe298a974958 100644 (file)
@@ -130,9 +130,21 @@ class UdpMirrorClient;
                LinphoneCore *getLinphoneCore();
                virtual void setHttpProxy(const char *host,int port, const char *username, const char *passwd);
        private:
+               enum EventType{
+                       UdpMirrorClientEvent,
+                       TunnelEvent,
+               };
+               struct Event{
+                       EventType mType;
+                       union EventData{
+                               bool mConnected;
+                               bool mHaveUdp;
+                       }mData;
+               };
                typedef std::list<UdpMirrorClient> UdpMirrorClientList;
                virtual bool isStarted();
                virtual bool isReady() const;
+               void onIterate();
                static int customSendto(struct _RtpTransport *t, mblk_t *msg , int flags, const struct sockaddr *to, socklen_t tolen);
                static int customRecvfrom(struct _RtpTransport *t, mblk_t *msg, int flags, struct sockaddr *from, socklen_t *fromlen);
                static int eXosipSendto(int fd,const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen,void* userdata);
@@ -140,9 +152,11 @@ class UdpMirrorClient;
                static int eXosipSelect(int nfds, fd_set *s1, fd_set *s2, fd_set *s3, struct timeval *tv,void* userdata);
                static void tunnelCallback(bool connected, TunnelManager *zis);
                static void sOnIterate(TunnelManager *zis);
-               static void UdpMirrorClientListener(bool result, void* data);
+               static void sUdpMirrorClientCallback(bool result, void* data);
                void waitUnRegistration();
-               void processTunnelEvent();
+               void processTunnelEvent(const Event &ev);
+               void processUdpMirrorEvent(const Event &ev);
+               void postEvent(const Event &ev);
                LinphoneCore* mCore;
                LCSipTransports mRegularTransport;
                TunnelSocket *mSipSocket;
@@ -150,19 +164,21 @@ class UdpMirrorClient;
                StateCallback mCallback;
                void * mCallbackData;
                bool mEnabled;
-               bool mStateChanged;
+               std::queue<Event> mEvq;
                std::list <ServerAddr> mServerAddrs;
                UdpMirrorClientList mUdpMirrorClients;
                UdpMirrorClientList::iterator mCurrentUdpMirrorClient;
                TunnelClient* mTunnelClient;
                void stopClient();
+               Mutex mMutex;
                static Mutex sMutex;
                bool mAutoDetectStarted;
                LinphoneRtpTransportFactories mTransportFactories;
                std::string mHttpUserName;
                std::string mHttpPasswd;
                std::string mHttpProxyHost;
-               int mHttpProxyPort;             
+               int mHttpProxyPort;
+               LinphoneFirewallPolicy mPreviousFirewallPolicy;
        };
 
 /**
index 14ca748e135968ce18570de3c61dbf95f08f0291..e7f6a7b219846c85b47eb1a76d90b2a39ca3cbf4 100644 (file)
@@ -46,9 +46,6 @@ void linphone_core_update_streams(LinphoneCore *lc, LinphoneCall *call, SalMedia
                call->media_pending=TRUE;
        }
        call->resultdesc=new_md;
-       if (call->ice_session != NULL) {
-               linphone_core_deactivate_ice_for_deactivated_media_streams(call, call->resultdesc);
-       }
        if ((call->audiostream && call->audiostream->ticker) || (call->videostream && call->videostream->ticker)){
                /* we already started media: check if we really need to restart it*/
                if (oldmd){
@@ -184,7 +181,6 @@ static void call_received(SalOp *h){
        }
        
        call=linphone_call_new_incoming(lc,from_addr,to_addr,h);
-       sal_call_set_local_media_description(h,call->localdesc);
        
        /* the call is acceptable so we can now add it to our list */
        linphone_core_add_call(lc,call);
@@ -270,6 +266,7 @@ static void call_accepted(SalOp *op){
        }
 
        md=sal_call_get_final_media_description(op);
+       call->params.has_video &= linphone_core_media_description_contains_video_stream(md);
        
        if (call->state==LinphoneCallOutgoingProgress ||
            call->state==LinphoneCallOutgoingRinging ||
@@ -303,11 +300,7 @@ static void call_accepted(SalOp *op){
                        linphone_core_update_streams (lc,call,md);
                        linphone_call_set_state(call,LinphoneCallPausedByRemote,"Call paused by remote");
                }else{
-                       if (call->state==LinphoneCallStreamsRunning){
-                               /*media was running before, the remote as acceted a call modification (that is
-                                       a reinvite made by us. We must notify the application this reinvite was accepted*/
-                               linphone_call_set_state(call, LinphoneCallUpdated, "Call updated");
-                       }else{
+                       if (call->state!=LinphoneCallUpdating){
                                if (call->state==LinphoneCallResuming){
                                        if (lc->vtable.display_status){
                                                lc->vtable.display_status(lc,_("Call resumed."));
@@ -344,11 +337,6 @@ static void call_ack(SalOp *op){
        if (call->media_pending){
                SalMediaDescription *md=sal_call_get_final_media_description(op);
                if (md && !sal_media_description_empty(md)){
-                       if (call->state==LinphoneCallStreamsRunning){
-                               /*media was running before, the remote as acceted a call modification (that is
-                                       a reinvite made by us. We must notify the application this reinvite was accepted*/
-                               linphone_call_set_state(call, LinphoneCallUpdated, "Call updated");
-                       }
                        linphone_core_update_streams (lc,call,md);
                        linphone_call_set_state (call,LinphoneCallStreamsRunning,"Connected (streams running)");
                }else{
@@ -535,7 +523,7 @@ static void call_failure(SalOp *op, SalError error, SalReason sr, const char *de
                                                        call->localdesc->streams[i].proto = SalProtoRtpAvp;
                                                        memset(call->localdesc->streams[i].crypto, 0, sizeof(call->localdesc->streams[i].crypto));
                                                }
-                                               linphone_core_start_invite(lc, call, NULL);
+                                               linphone_core_start_invite(lc, call);
                                        }
                                        return;
                                }
@@ -816,14 +804,24 @@ static LinphoneChatMessageState chatStatusSal2Linphone(SalTextDeliveryStatus sta
        return LinphoneChatMessageStateIdle;
 }
 
+static int op_equals(LinphoneCall *a, SalOp *b) {
+       return a->op !=b; /*return 0 if equals*/
+}
 static void text_delivery_update(SalOp *op, SalTextDeliveryStatus status){
        LinphoneChatMessage *chat_msg=(LinphoneChatMessage* )sal_op_get_user_pointer(op);
+       const MSList* calls = linphone_core_get_calls(chat_msg->chat_room->lc);
+       
        if (chat_msg && chat_msg->cb) {
                chat_msg->cb(chat_msg
                        ,chatStatusSal2Linphone(status)
                        ,chat_msg->cb_ud);
        }
        linphone_chat_message_destroy(chat_msg);
+       
+       if (!ms_list_find_custom((MSList*)calls, (MSCompareFunc) op_equals, op)) {
+               /*op was only create for messaging purpose, destroying*/
+               sal_op_release(op);
+       }
 }
 
 SalCallbacks linphone_sal_callbacks={
index 2aca72ff841d4d7820f47060c3d9d65716c7c995..00f237377aabc6f2ae87b9f15bb17850fb062e80 100644 (file)
@@ -22,8 +22,9 @@
  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
  
- #include "linphonecore.h"
- #include "private.h"
+#include "linphonecore.h"
+#include "private.h"
+#include "lpconfig.h"
  
  LinphoneChatRoom * linphone_core_create_chat_room(LinphoneCore *lc, const char *to){
        LinphoneAddress *parsed_url=NULL;
@@ -45,8 +46,6 @@
        lc->chatrooms=ms_list_remove(lc->chatrooms,(void *) cr);
        linphone_address_destroy(cr->peer_url);
        ms_free(cr->peer);
-       if (cr->op)
-                sal_op_release(cr->op);
  }
 
 
@@ -56,26 +55,24 @@ static void _linphone_chat_room_send_message(LinphoneChatRoom *cr, LinphoneChatM
        SalOp *op=NULL;
        LinphoneCall *call;
        char* content_type;
-       if((call = linphone_core_get_call_by_remote_address(cr->lc,cr->peer))!=NULL){
-               if (call->state==LinphoneCallConnected ||
-                   call->state==LinphoneCallStreamsRunning ||
-                   call->state==LinphoneCallPaused ||
-                   call->state==LinphoneCallPausing ||
-                   call->state==LinphoneCallPausedByRemote){
-                       ms_message("send SIP message through the existing call.");
-                       op = call->op;
-                       call->pending_message=msg;
+       
+       if (lp_config_get_int(cr->lc->config,"sip","chat_use_call_dialogs",1)){
+               if((call = linphone_core_get_call_by_remote_address(cr->lc,cr->peer))!=NULL){
+                       if (call->state==LinphoneCallConnected ||
+                       call->state==LinphoneCallStreamsRunning ||
+                       call->state==LinphoneCallPaused ||
+                       call->state==LinphoneCallPausing ||
+                       call->state==LinphoneCallPausedByRemote){
+                               ms_message("send SIP message through the existing call.");
+                               op = call->op;
+                               call->pending_message=msg;
+                       }
                }
        }
        if (op==NULL){
                /*sending out of calls*/
                op = sal_op_new(cr->lc->sal);
                sal_op_set_route(op,route);
-               if (cr->op!=NULL){
-                       sal_op_release (cr->op);
-                       cr->op=NULL;
-               }
-               cr->op=op;
                sal_op_set_user_pointer(op, msg); /*if out of call, directly store msg*/
        }
        if (msg->external_body_url) {
index 2f4fa65009fa6376de46de262c4231426948055b..7fb001d3de75554467c4ddc83de2c04bcbe46e87 100644 (file)
@@ -29,45 +29,57 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 static void ecc_init_filters(EcCalibrator *ecc){
        unsigned int rate;
-       ecc->ticker=ms_ticker_new();
+       MSTickerParams params={0};
+       params.name="Echo calibrator";
+       params.prio=MS_TICKER_PRIO_HIGH;
+       ecc->ticker=ms_ticker_new_with_params(&params);
 
        ecc->sndread=ms_snd_card_create_reader(ecc->play_card);
        ms_filter_call_method(ecc->sndread,MS_FILTER_SET_SAMPLE_RATE,&ecc->rate);
+       ms_filter_call_method(ecc->sndread,MS_FILTER_GET_SAMPLE_RATE,&rate);
+       ecc->read_resampler=ms_filter_new(MS_RESAMPLE_ID);
+       ms_filter_call_method(ecc->read_resampler,MS_FILTER_SET_SAMPLE_RATE,&rate);
+       ms_filter_call_method(ecc->read_resampler,MS_FILTER_SET_OUTPUT_SAMPLE_RATE,&ecc->rate);
+       
+       
        ecc->det=ms_filter_new(MS_TONE_DETECTOR_ID);
        ms_filter_call_method(ecc->det,MS_FILTER_SET_SAMPLE_RATE,&ecc->rate);
        ecc->rec=ms_filter_new(MS_FILE_REC_ID);
 
-       ms_filter_link(ecc->sndread,0,ecc->det,0);
+       ms_filter_link(ecc->sndread,0,ecc->read_resampler,0);
+       ms_filter_link(ecc->read_resampler,0,ecc->det,0);
        ms_filter_link(ecc->det,0,ecc->rec,0);
 
        ecc->play=ms_filter_new(MS_FILE_PLAYER_ID);
        ecc->gen=ms_filter_new(MS_DTMF_GEN_ID);
        ms_filter_call_method(ecc->gen,MS_FILTER_SET_SAMPLE_RATE,&ecc->rate);
-       ecc->resampler=ms_filter_new(MS_RESAMPLE_ID);
+       ecc->write_resampler=ms_filter_new(MS_RESAMPLE_ID);
        ecc->sndwrite=ms_snd_card_create_writer(ecc->capt_card);
-
-       ms_filter_link(ecc->play,0,ecc->gen,0);
-       ms_filter_link(ecc->gen,0,ecc->resampler,0);
-       ms_filter_link(ecc->resampler,0,ecc->sndwrite,0);
-
+       
        ms_filter_call_method(ecc->sndwrite,MS_FILTER_SET_SAMPLE_RATE,&ecc->rate);
        ms_filter_call_method(ecc->sndwrite,MS_FILTER_GET_SAMPLE_RATE,&rate);
-       ms_filter_call_method(ecc->resampler,MS_FILTER_SET_SAMPLE_RATE,&ecc->rate);
-       ms_filter_call_method(ecc->resampler,MS_FILTER_SET_OUTPUT_SAMPLE_RATE,&rate);
+       ms_filter_call_method(ecc->write_resampler,MS_FILTER_SET_SAMPLE_RATE,&ecc->rate);
+       ms_filter_call_method(ecc->write_resampler,MS_FILTER_SET_OUTPUT_SAMPLE_RATE,&rate);
+
+       ms_filter_link(ecc->play,0,ecc->gen,0);
+       ms_filter_link(ecc->gen,0,ecc->write_resampler,0);
+       ms_filter_link(ecc->write_resampler,0,ecc->sndwrite,0);
 
-       ms_ticker_attach(ecc->ticker,ecc->play);
        ms_ticker_attach(ecc->ticker,ecc->sndread);
+       ms_ticker_attach(ecc->ticker,ecc->play);
+       
 }
 
 static void ecc_deinit_filters(EcCalibrator *ecc){
-       ms_ticker_detach(ecc->ticker,ecc->play);
        ms_ticker_detach(ecc->ticker,ecc->sndread);
+       ms_ticker_detach(ecc->ticker,ecc->play);
 
        ms_filter_unlink(ecc->play,0,ecc->gen,0);
-       ms_filter_unlink(ecc->gen,0,ecc->resampler,0);
-       ms_filter_unlink(ecc->resampler,0,ecc->sndwrite,0);
+       ms_filter_unlink(ecc->gen,0,ecc->write_resampler,0);
+       ms_filter_unlink(ecc->write_resampler,0,ecc->sndwrite,0);
 
-       ms_filter_unlink(ecc->sndread,0,ecc->det,0);
+       ms_filter_unlink(ecc->sndread,0,ecc->read_resampler,0);
+       ms_filter_unlink(ecc->read_resampler,0,ecc->det,0);
        ms_filter_unlink(ecc->det,0,ecc->rec,0);
 
        ms_filter_destroy(ecc->sndread);
@@ -75,7 +87,8 @@ static void ecc_deinit_filters(EcCalibrator *ecc){
        ms_filter_destroy(ecc->rec);
        ms_filter_destroy(ecc->play);
        ms_filter_destroy(ecc->gen);
-       ms_filter_destroy(ecc->resampler);
+       ms_filter_destroy(ecc->read_resampler);
+       ms_filter_destroy(ecc->write_resampler);
        ms_filter_destroy(ecc->sndwrite);
 
        ms_ticker_destroy(ecc->ticker);
@@ -101,7 +114,6 @@ static void ecc_play_tones(EcCalibrator *ecc){
        MSDtmfGenCustomTone tone;
        MSToneDetectorDef expected_tone;
 
-       
        ms_filter_set_notify_callback(ecc->det,on_tone_received,ecc);
 
        expected_tone.frequency=2000;
@@ -110,7 +122,7 @@ static void ecc_play_tones(EcCalibrator *ecc){
 
        ms_filter_call_method (ecc->det,MS_TONE_DETECTOR_ADD_SCAN,&expected_tone);
        
-       tone.frequency=1000;
+       tone.frequency=1300;
        tone.duration=1000;
        tone.amplitude=1.0;
 
@@ -129,20 +141,29 @@ static void ecc_play_tones(EcCalibrator *ecc){
        ms_filter_call_method(ecc->gen,MS_DTMF_GEN_PLAY_CUSTOM,&tone);
        ms_sleep(1);
 
-       if (ecc->sent_count==3 && 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;
+       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) {
+                       ms_message("Echo calibration succeeded, no echo has been detected");
+                       ecc->status = LinphoneEcCalibratorDoneNoEcho;
+               } else {
+                       ecc->status = LinphoneEcCalibratorFailed;
                }
        }else{
-               ms_error("Echo calibration failed, tones received = %i",ecc->recv_count);
                ecc->status=LinphoneEcCalibratorFailed;
        }
-       
+       if (ecc->status == LinphoneEcCalibratorFailed) {
+               ms_error("Echo calibration failed, tones received = %i",ecc->recv_count);
+       }
 }
 
 static void  * ecc_thread(void *p){
index 05a1baeec3a7ed26013cc44a758b614042dc138f..c6dee2440a8d28019c003893123cc2dfde218b0a 100644 (file)
@@ -396,8 +396,8 @@ void linphone_core_add_friend(LinphoneCore *lc, LinphoneFriend *lf)
 void linphone_core_remove_friend(LinphoneCore *lc, LinphoneFriend* fl){
        MSList *el=ms_list_find(lc->friends,(void *)fl);
        if (el!=NULL){
-               lc->friends=ms_list_remove_link(lc->friends,el);
                linphone_friend_destroy((LinphoneFriend*)el->data);
+               lc->friends=ms_list_remove_link(lc->friends,el);
                linphone_core_write_friends_config(lc);
        }
 }
index 58a75e56be2b6a408db286f444313860dcaccddf..dc1341d8042587dfa2979e5e254e58644054bc99 100644 (file)
@@ -20,6 +20,8 @@ package org.linphone.core.tutorials;
 
 import org.linphone.core.LinphoneAddress;
 import org.linphone.core.LinphoneCall;
+import org.linphone.core.LinphoneCallStats;
+import org.linphone.core.LinphoneChatMessage;
 import org.linphone.core.LinphoneChatRoom;
 import org.linphone.core.LinphoneCore;
 import org.linphone.core.LinphoneCore.EcCalibratorStatus;
@@ -96,9 +98,11 @@ public class TutorialBuddyStatus implements LinphoneCoreListener {
        public void globalState(LinphoneCore lc, GlobalState state, String message) {}
        public void textReceived(LinphoneCore lc, LinphoneChatRoom cr,LinphoneAddress from, String message) {}
        public void callState(LinphoneCore lc, LinphoneCall call, State cstate, String msg) {}
+       public void callStatsUpdated(LinphoneCore lc, LinphoneCall call, LinphoneCallStats stats) {}
        public void ecCalibrationStatus(LinphoneCore lc, EcCalibratorStatus status,int delay_ms, Object data) {}
        public void callEncryptionChanged(LinphoneCore lc, LinphoneCall call,boolean encrypted, String authenticationToken) {}
        public void notifyReceived(LinphoneCore lc, LinphoneCall call, LinphoneAddress from, byte[] event){}
+       public void dtmfReceived(LinphoneCore lc, LinphoneCall call, int dtmf) {}
 
 
        public static void main(String[] args) {
@@ -231,5 +235,11 @@ public class TutorialBuddyStatus implements LinphoneCoreListener {
                TutorialNotifier.notify(s);
        }
 
+       @Override
+       public void messageReceived(LinphoneCore lc, LinphoneChatRoom cr, LinphoneChatMessage message) {
+               // TODO Auto-generated method stub
+               
+       }
+
 
 }
index c81823e8a66b0bdb3a8d01e746f40882c7a9f701..3e41dba002726d606d19a583e393a61d6d49784a 100644 (file)
@@ -20,6 +20,8 @@ package org.linphone.core.tutorials;
 
 import org.linphone.core.LinphoneAddress;
 import org.linphone.core.LinphoneCall;
+import org.linphone.core.LinphoneCallStats;
+import org.linphone.core.LinphoneChatMessage;
 import org.linphone.core.LinphoneChatRoom;
 import org.linphone.core.LinphoneCore;
 import org.linphone.core.LinphoneCore.EcCalibratorStatus;
@@ -74,9 +76,11 @@ public class TutorialChatRoom implements LinphoneCoreListener {
        public void newSubscriptionRequest(LinphoneCore lc, LinphoneFriend lf,String url) {}
        public void notifyPresenceReceived(LinphoneCore lc, LinphoneFriend lf) {}
        public void callState(LinphoneCore lc, LinphoneCall call, State cstate, String msg){}
+       public void callStatsUpdated(LinphoneCore lc, LinphoneCall call, LinphoneCallStats stats) {}
        public void ecCalibrationStatus(LinphoneCore lc, EcCalibratorStatus status,int delay_ms, Object data) {}
        public void callEncryptionChanged(LinphoneCore lc, LinphoneCall call,boolean encrypted, String authenticationToken) {}
        public void notifyReceived(LinphoneCore lc, LinphoneCall call, LinphoneAddress from, byte[] event){}
+       public void dtmfReceived(LinphoneCore lc, LinphoneCall call, int dtmf) {}
        
        public void textReceived(LinphoneCore lc, LinphoneChatRoom cr,LinphoneAddress from, String message) {
         write("Message ["+message+"] received from ["+from.asString()+"]");
@@ -146,5 +150,12 @@ public class TutorialChatRoom implements LinphoneCoreListener {
                TutorialNotifier.notify(s);
        }
 
+       @Override
+       public void messageReceived(LinphoneCore lc, LinphoneChatRoom cr,
+                       LinphoneChatMessage message) {
+               // TODO Auto-generated method stub
+               
+       }
+
 
 }
index 6daa65711f0f2e8c96aaac375f1b64ded179df0c..d6b61cf8b075b181a684e6a86046e50599061049 100644 (file)
@@ -20,6 +20,8 @@ package org.linphone.core.tutorials;
 
 import org.linphone.core.LinphoneAddress;
 import org.linphone.core.LinphoneCall;
+import org.linphone.core.LinphoneCallStats;
+import org.linphone.core.LinphoneChatMessage;
 import org.linphone.core.LinphoneChatRoom;
 import org.linphone.core.LinphoneCore;
 import org.linphone.core.LinphoneCore.EcCalibratorStatus;
@@ -68,9 +70,11 @@ public class TutorialHelloWorld implements LinphoneCoreListener {
        public void newSubscriptionRequest(LinphoneCore lc, LinphoneFriend lf,String url) {}
        public void notifyPresenceReceived(LinphoneCore lc, LinphoneFriend lf) {}
        public void textReceived(LinphoneCore lc, LinphoneChatRoom cr,LinphoneAddress from, String message) {}
+       public void callStatsUpdated(LinphoneCore lc, LinphoneCall call, LinphoneCallStats stats) {}
        public void ecCalibrationStatus(LinphoneCore lc, EcCalibratorStatus status,int delay_ms, Object data) {}
        public void callEncryptionChanged(LinphoneCore lc, LinphoneCall call,boolean encrypted, String authenticationToken) {}
        public void notifyReceived(LinphoneCore lc, LinphoneCall call, LinphoneAddress from, byte[] event){}
+       public void dtmfReceived(LinphoneCore lc, LinphoneCall call, int dtmf) {}
        /*
         * Call state notification listener
         */
@@ -156,5 +160,12 @@ public class TutorialHelloWorld implements LinphoneCoreListener {
                TutorialNotifier.notify(s);
        }
 
+       @Override
+       public void messageReceived(LinphoneCore lc, LinphoneChatRoom cr,
+                       LinphoneChatMessage message) {
+               // TODO Auto-generated method stub
+               
+       }
+
 
 }
index 674044471ce76e1f9b1af867586aedb28e6835b7..fa18d51f80cd81bbc82e129c6455bf24d9f36428 100644 (file)
@@ -20,6 +20,8 @@ package org.linphone.core.tutorials;
 
 import org.linphone.core.LinphoneAddress;
 import org.linphone.core.LinphoneCall;
+import org.linphone.core.LinphoneCallStats;
+import org.linphone.core.LinphoneChatMessage;
 import org.linphone.core.LinphoneChatRoom;
 import org.linphone.core.LinphoneCore;
 import org.linphone.core.LinphoneCore.EcCalibratorStatus;
@@ -79,9 +81,11 @@ public class TutorialRegistration implements LinphoneCoreListener {
        public void notifyPresenceReceived(LinphoneCore lc, LinphoneFriend lf) {}
        public void textReceived(LinphoneCore lc, LinphoneChatRoom cr,LinphoneAddress from, String message) {}
        public void callState(LinphoneCore lc, LinphoneCall call, State cstate, String msg) {}
+       public void callStatsUpdated(LinphoneCore lc, LinphoneCall call, LinphoneCallStats stats) {}
        public void ecCalibrationStatus(LinphoneCore lc, EcCalibratorStatus status,int delay_ms, Object data) {}
        public void callEncryptionChanged(LinphoneCore lc, LinphoneCall call,boolean encrypted, String authenticationToken) {}
        public void notifyReceived(LinphoneCore lc, LinphoneCall call, LinphoneAddress from, byte[] event){}
+       public void dtmfReceived(LinphoneCore lc, LinphoneCall call, int dtmf) {}
 
        public static void main(String[] args) {
                // Check tutorial was called with the right number of arguments
@@ -187,6 +191,13 @@ public class TutorialRegistration implements LinphoneCoreListener {
                TutorialNotifier.notify(s);
        }
 
+       @Override
+       public void messageReceived(LinphoneCore lc, LinphoneChatRoom cr,
+                       LinphoneChatMessage message) {
+               // TODO Auto-generated method stub
+               
+       }
+
 
 
 }
index 6a47e83ab909a559b3a2fd5c6f350975ac50b50b..f5a5d361f92286ecb78c136a6f99f0afa3497920 100644 (file)
@@ -173,17 +173,26 @@ void linphone_tunnel_auto_detect(LinphoneTunnel *tunnel){
        bcTunnel(tunnel)->autoDetect();
 }
 
-static void tunnel_add_servers_from_config(LinphoneTunnel *tunnel, char* confaddress){
-       char *str1;
-       for(str1=confaddress;;str1=NULL){
-               char *port;
-               char *address=strtok(str1," "); // Not thread safe
-               if (!address) break;
-               port=strchr(address, ':');
-               if (!port) ms_fatal("Bad tunnel address %s",confaddress);
-               *port++='\0';
-               linphone_tunnel_add_server(tunnel, address, atoi(port));
-       }
+static void tunnel_add_servers_from_config(LinphoneTunnel *tunnel, const char* confaddress){
+       char *tmp=(char*)ms_malloc0(strlen(confaddress)+1);
+       const char *it=confaddress;
+       int adv;
+       do{
+               int ret=sscanf(it,"%s%n",tmp,&adv);
+               if (ret>=1){
+                       it+=adv;
+                       char *port=strchr(tmp,':');
+                       if (!port){
+                               ms_error("Tunnel server addresses incorrectly specified from config file: %s",it);
+                               break;
+                       }else{
+                               *port='\0';
+                               port++;
+                               bcTunnel(tunnel)->addServer(tmp, atoi(port));
+                       }
+               }else break;
+       }while(1);
+       ms_free(tmp);
 }
 
 static void my_ortp_logv(OrtpLogLevel level, const char *fmt, va_list args){
@@ -197,13 +206,9 @@ static void my_ortp_logv(OrtpLogLevel level, const char *fmt, va_list args){
 void linphone_tunnel_configure(LinphoneTunnel *tunnel){
        bool_t enabled=(bool_t)lp_config_get_int(config(tunnel),"tunnel","enabled",FALSE);
        const char* addresses=lp_config_get_string(config(tunnel),"tunnel","server_addresses", NULL);
-       char *copy=addresses ? ms_strdup(addresses) : NULL;
        linphone_tunnel_enable_logs_with_handler(tunnel,TRUE,my_ortp_logv);
-       linphone_tunnel_clean_servers(tunnel);
-       if (copy){
-               tunnel_add_servers_from_config(tunnel,copy);
-               ms_free(copy);
-       }
+       if (addresses)
+               tunnel_add_servers_from_config(tunnel,addresses);
        linphone_tunnel_enable(tunnel, enabled);
 }
 
index 5d78fe8f60a2a2728dd7db95cbf38557c2b5c76f..bb343008a667272e0d5a77db4e5eed7667aac77f 100644 (file)
@@ -62,10 +62,10 @@ void linphone_tunnel_add_server(LinphoneTunnel *tunnel, const char *host, int po
  * @param  tunnel object
  * @param host tunnel server ip address
  * @param port tunnel server tls port, recommended value is 443
- * @param remote_udp_mirror remote port on the tunnel server side  used to test udp reachability
+ * @param remote_udp_mirror_port remote port on the tunnel server side used to test udp reachability
  * @param delay udp packet round trip delay in ms considered as acceptable. recommended value is 1000 ms.
  */
-void linphone_tunnel_add_server_and_mirror(LinphoneTunnel *tunnel, const char *host, int port, int remote_udp_mirror, int delay);
+void linphone_tunnel_add_server_and_mirror(LinphoneTunnel *tunnel, const char *host, int port, int remote_udp_mirror_port, int delay);
 /**
  * @param  tunnel object
  * returns a string of space separated list of host:port of tunnel server addresses
@@ -98,16 +98,37 @@ bool_t linphone_tunnel_enabled(LinphoneTunnel *tunnel);
 **/
 void linphone_tunnel_reconnect(LinphoneTunnel *tunnel);
 /**
+ * Start tunnel need detection.
  * @param  tunnel object
  * In auto detect mode, the tunnel manager try to establish a real time rtp cummunication with the tunnel server on  specified port.
  *<br>In case of success, the tunnel is automatically turned off. Otherwise, if no udp commmunication is feasible, tunnel mode is turned on.
  *<br> Call this method each time to run the auto detection algorithm
  */
 void linphone_tunnel_auto_detect(LinphoneTunnel *tunnel);
+
+/**
+ * Set an optional http proxy to go through when connecting to tunnel server.
+ * @param tunnel LinphoneTunnel object
+ * @param host Http proxy host.
+ * @param port http proxy port.
+ * @param username optional http proxy username if the proxy request authentication. Currently only basic authentication is supported. Use NULL if not needed.
+ * @param password optional http proxy password. Use NULL if not needed.
+ **/
 void linphone_tunnel_set_http_proxy(LinphoneTunnel *tunnel, const char *host, int port, const char* username,const char* passwd);
-void linphone_tunnel_set_http_proxy_auth_info(LinphoneTunnel*tunnel, const char* username,const char* passwd);
+
+/**
+ * Retrieve optional http proxy configuration previously set with linphone_tunnel_set_http_proxy().
+ * @param tunnel LinphoneTunnel object
+ * @param host Http proxy host.
+ * @param port http proxy port.
+ * @param username optional http proxy username if the proxy request authentication. Currently only basic authentication is supported. Use NULL if not needed.
+ * @param password optional http proxy password. Use NULL if not needed.
+ **/
 void linphone_tunnel_get_http_proxy(LinphoneTunnel*tunnel,const char **host, int *port, const char **username, const char **passwd);
 
+void linphone_tunnel_set_http_proxy_auth_info(LinphoneTunnel*tunnel, const char* username,const char* passwd);
+
+
 void linphone_tunnel_enable_logs(LinphoneTunnel *tunnel, bool_t enabled);
 
 /**
index 5962badd3a257e2503ca019c4beb3cbe0aa50dce..32dc9d59c37a398208c554c8a7300a5046f7074e 100644 (file)
@@ -193,6 +193,22 @@ static MSList *make_codec_list(LinphoneCore *lc, const MSList *codecs, int bandw
        return l;
 }
 
+static void update_media_description_from_stun(SalMediaDescription *md, const StunCandidate *ac, const StunCandidate *vc){
+       if (ac->port!=0){
+               strcpy(md->streams[0].rtp_addr,ac->addr);
+               md->streams[0].rtp_port=ac->port;
+               if ((ac->addr[0]!='\0' && vc->addr[0]!='\0' && strcmp(ac->addr,vc->addr)==0) || md->nstreams==1){
+                       strcpy(md->addr,ac->addr);
+               }
+       }
+       if (vc->port!=0){
+               strcpy(md->streams[1].rtp_addr,vc->addr);
+               md->streams[1].rtp_port=vc->port;
+       }
+       
+}
+
+
 static SalMediaDescription *_create_local_media_description(LinphoneCore *lc, LinphoneCall *call, unsigned int session_id, unsigned int session_ver){
        MSList *l;
        PayloadType *pt;
@@ -201,6 +217,10 @@ static SalMediaDescription *_create_local_media_description(LinphoneCore *lc, Li
        LinphoneAddress *addr=linphone_address_new(me);
        const char *username=linphone_address_get_username (addr);
        SalMediaDescription *md=sal_media_description_new();
+       
+       if (call->ping_time>0) {
+               linphone_core_adapt_to_network(lc,call->ping_time,&call->params);
+       }
 
        md->session_id=session_id;
        md->session_ver=session_ver;
@@ -253,11 +273,12 @@ static SalMediaDescription *_create_local_media_description(LinphoneCore *lc, Li
                                md->streams[i].crypto[1].algo = 0;
                        md->streams[i].crypto[2].algo = 0;
                }
-               if ((linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseIce) && (call->ice_session != NULL) && (ice_session_check_list(call->ice_session, i) == NULL)) {
-                       ice_session_add_check_list(call->ice_session, ice_check_list_new());
-               }
        }
-       
+       update_media_description_from_stun(md,&call->ac,&call->vc);
+       if (call->ice_session != NULL) {
+               linphone_core_update_local_media_description_from_ice(md, call->ice_session);
+               linphone_core_update_ice_state_in_call_stats(call);
+       }
        linphone_address_destroy(addr);
        return md;
 }
@@ -277,17 +298,35 @@ SalMediaDescription *create_local_media_description(LinphoneCore *lc, LinphoneCa
        return _create_local_media_description(lc,call,id,id);
 }
 
-static int find_port_offset(LinphoneCore *lc){
+static int find_port_offset(LinphoneCore *lc, SalStreamType type){
        int offset;
        MSList *elem;
-       int audio_port;
+       int tried_port;
+       int existing_port;
        bool_t already_used=FALSE;
        for(offset=0;offset<100;offset+=2){
-               audio_port=linphone_core_get_audio_port (lc)+offset;
+               switch (type) {
+                       default:
+                       case SalAudio:
+                               tried_port=linphone_core_get_audio_port (lc)+offset;
+                               break;
+                       case SalVideo:
+                               tried_port=linphone_core_get_video_port (lc)+offset;
+                               break;
+               }
                already_used=FALSE;
                for(elem=lc->calls;elem!=NULL;elem=elem->next){
                        LinphoneCall *call=(LinphoneCall*)elem->data;
-                       if (call->audio_port==audio_port) {
+                       switch (type) {
+                               default:
+                               case SalAudio:
+                                       existing_port = call->audio_port;
+                                       break;
+                               case SalVideo:
+                                       existing_port = call->video_port;
+                                       break;
+                       }
+                       if (existing_port==tried_port) {
                                already_used=TRUE;
                                break;
                        }
@@ -301,8 +340,54 @@ static int find_port_offset(LinphoneCore *lc){
        return offset;
 }
 
+static int select_random_port(LinphoneCore *lc, SalStreamType type) {
+       MSList *elem;
+       int nb_tries;
+       int tried_port = 0;
+       int existing_port = 0;
+       int min_port = 0, max_port = 0;
+       bool_t already_used = FALSE;
+
+       switch (type) {
+               default:
+               case SalAudio:
+                       linphone_core_get_audio_port_range(lc, &min_port, &max_port);
+                       break;
+               case SalVideo:
+                       linphone_core_get_video_port_range(lc, &min_port, &max_port);
+                       break;
+       }
+       tried_port = (rand() % (max_port - min_port) + min_port) & ~0x1;
+       if (tried_port < min_port) tried_port = min_port + 2;
+       for (nb_tries = 0; nb_tries < 100; nb_tries++) {
+               for (elem = lc->calls; elem != NULL; elem = elem->next) {
+                       LinphoneCall *call = (LinphoneCall *)elem->data;
+                       switch (type) {
+                               default:
+                               case SalAudio:
+                                       existing_port = call->audio_port;
+                                       break;
+                               case SalVideo:
+                                       existing_port = call->video_port;
+                                       break;
+                       }
+                       if (existing_port == tried_port) {
+                               already_used = TRUE;
+                               break;
+                       }
+               }
+               if (!already_used) break;
+       }
+       if (nb_tries == 100) {
+               ms_error("Could not find any free port!");
+               return -1;
+       }
+       return tried_port;
+}
+
 static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from, LinphoneAddress *to){
        int port_offset;
+       int min_port, max_port;
        call->magic=linphone_call_magic;
        call->refcnt=1;
        call->state=LinphoneCallIdle;
@@ -312,10 +397,26 @@ static void linphone_call_init_common(LinphoneCall *call, LinphoneAddress *from,
        call->log=linphone_call_log_new(call, from, to);
        call->owns_call_log=TRUE;
        linphone_core_notify_all_friends(call->core,LinphoneStatusOnThePhone);
-       port_offset=find_port_offset (call->core);
-       if (port_offset==-1) return;
-       call->audio_port=linphone_core_get_audio_port(call->core)+port_offset;
-       call->video_port=linphone_core_get_video_port(call->core)+port_offset;
+       linphone_core_get_audio_port_range(call->core, &min_port, &max_port);
+       if (min_port == max_port) {
+               /* Used fixed RTP audio port. */
+               port_offset=find_port_offset (call->core, SalAudio);
+               if (port_offset==-1) return;
+               call->audio_port=linphone_core_get_audio_port(call->core)+port_offset;
+       } else {
+               /* Select random RTP audio port in the specified range. */
+               call->audio_port = select_random_port(call->core, SalAudio);
+       }
+       linphone_core_get_video_port_range(call->core, &min_port, &max_port);
+       if (min_port == max_port) {
+               /* Used fixed RTP video port. */
+               port_offset=find_port_offset (call->core, SalVideo);
+               if (port_offset==-1) return;
+               call->video_port=linphone_core_get_video_port(call->core)+port_offset;
+       } else {
+               /* Select random RTP video port in the specified range. */
+               call->video_port = select_random_port(call->core, SalVideo);
+       }
        linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_AUDIO], LINPHONE_CALL_STATS_AUDIO);
        linphone_call_init_stats(&call->stats[LINPHONE_CALL_STATS_VIDEO], LINPHONE_CALL_STATS_VIDEO);
 }
@@ -324,22 +425,9 @@ void linphone_call_init_stats(LinphoneCallStats *stats, int type) {
        stats->type = type;
        stats->received_rtcp = NULL;
        stats->sent_rtcp = NULL;
+       stats->ice_state = LinphoneIceStateNotActivated;
 }
 
-static void update_media_description_from_stun(SalMediaDescription *md, const StunCandidate *ac, const StunCandidate *vc){
-       if (ac->port!=0){
-               strcpy(md->streams[0].rtp_addr,ac->addr);
-               md->streams[0].rtp_port=ac->port;
-               if ((ac->addr[0]!='\0' && vc->addr[0]!='\0' && strcmp(ac->addr,vc->addr)==0) || md->nstreams==1){
-                       strcpy(md->addr,ac->addr);
-               }
-       }
-       if (vc->port!=0){
-               strcpy(md->streams[1].rtp_addr,vc->addr);
-               md->streams[1].rtp_port=vc->port;
-       }
-       
-}
 
 static void discover_mtu(LinphoneCore *lc, const char *remote){
        int mtu;
@@ -354,13 +442,9 @@ static void discover_mtu(LinphoneCore *lc, const char *remote){
        }
 }
 
-#define STUN_CANDIDATE_INIT {{0},0}
-
 LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, const LinphoneCallParams *params)
 {
        LinphoneCall *call=ms_new0(LinphoneCall,1);
-       StunCandidate ac=STUN_CANDIDATE_INIT,vc=STUN_CANDIDATE_INIT;
-       int ping_time=-1;
        call->dir=LinphoneCallOutgoing;
        call->op=sal_op_new(lc->sal);
        sal_op_set_user_pointer(call->op,call);
@@ -373,13 +457,8 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr
                ice_session_set_role(call->ice_session, IR_Controlling);
        }
        if (linphone_core_get_firewall_policy(call->core) == LinphonePolicyUseStun) {
-               ping_time=linphone_core_run_stun_tests(call->core,call,&ac, &vc);
+               call->ping_time=linphone_core_run_stun_tests(call->core,call);
        }
-       if (ping_time>=0) {
-               linphone_core_adapt_to_network(lc,ping_time,&call->params);
-       }
-       call->localdesc=create_local_media_description(lc,call);
-       update_media_description_from_stun(call->localdesc,&ac,&vc);
        call->camera_active=params->has_video;
        
        discover_mtu(lc,linphone_address_get_domain (to));
@@ -393,8 +472,6 @@ LinphoneCall * linphone_call_new_outgoing(struct _LinphoneCore *lc, LinphoneAddr
 LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *from, LinphoneAddress *to, SalOp *op){
        LinphoneCall *call=ms_new0(LinphoneCall,1);
        char *from_str;
-       int ping_time=-1;
-       StunCandidate ac=STUN_CANDIDATE_INIT,vc=STUN_CANDIDATE_INIT;
 
        call->dir=LinphoneCallIncoming;
        sal_op_set_user_pointer(op,call);
@@ -415,8 +492,10 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro
        linphone_address_clean(from);
        linphone_core_get_local_ip(lc,linphone_address_get_domain(from),call->localip);
        linphone_call_init_common(call, from, to);
+       call->log->call_id=ms_strdup(sal_op_get_call_id(op)); /*must be known at that time*/
        linphone_core_init_default_params(lc, &call->params);
        call->params.has_video &= !!lc->video_policy.automatically_accept;
+       call->params.has_video &= linphone_core_media_description_contains_video_stream(sal_call_get_remote_media_description(op));
        switch (linphone_core_get_firewall_policy(call->core)) {
                case LinphonePolicyUseIce:
                        call->ice_session = ice_session_new();
@@ -428,21 +507,16 @@ LinphoneCall * linphone_call_new_incoming(LinphoneCore *lc, LinphoneAddress *fro
                                if (linphone_core_gather_ice_candidates(call->core,call)<0) {
                                        /* Ice candidates gathering failed, proceed with the call anyway. */
                                        linphone_call_delete_ice_session(call);
-                                       linphone_call_stop_media_streams(call);
+                                       linphone_call_stop_media_streams_for_ice_gathering(call);
                                }
                        }
                        break;
                case LinphonePolicyUseStun:
-                       ping_time=linphone_core_run_stun_tests(call->core,call,&ac, &vc);
+                       call->ping_time=linphone_core_run_stun_tests(call->core,call);
                        /* No break to also destroy ice session in this case. */
                default:
                        break;
        }
-       if (ping_time>=0) {
-               linphone_core_adapt_to_network(lc,ping_time,&call->params);
-       };
-       call->localdesc=create_local_media_description(lc,call);
-       update_media_description_from_stun(call->localdesc,&ac,&vc);
        call->camera_active=call->params.has_video;
        
        discover_mtu(lc,linphone_address_get_domain(from));
@@ -528,8 +602,8 @@ const char *linphone_call_state_to_string(LinphoneCallState cs){
                        return "LinphoneCallUpdatedByRemote";
                case LinphoneCallIncomingEarlyMedia:
                        return "LinphoneCallIncomingEarlyMedia";
-               case LinphoneCallUpdated:
-                       return "LinphoneCallUpdated";
+               case LinphoneCallUpdating:
+                       return "LinphoneCallUpdating";
                case LinphoneCallReleased:
                        return "LinphoneCallReleased";
        }
@@ -588,6 +662,7 @@ void linphone_call_set_state(LinphoneCall *call, LinphoneCallState cstate, const
 
 static void linphone_call_destroy(LinphoneCall *obj)
 {
+       linphone_call_delete_ice_session(obj);
        if (obj->op!=NULL) {
                sal_op_release(obj->op);
                obj->op=NULL;
@@ -611,9 +686,6 @@ static void linphone_call_destroy(LinphoneCall *obj)
        if (obj->auth_token) {
                ms_free(obj->auth_token);
        }
-       if (obj->ice_session) {
-               ice_session_destroy(obj->ice_session);
-       }
 
        ms_free(obj);
 }
@@ -861,6 +933,9 @@ const PayloadType* linphone_call_params_get_used_video_codec(const LinphoneCallP
        return cp->video_codec;
 }
 
+bool_t linphone_call_params_low_bandwidth_enabled(const LinphoneCallParams *cp) {
+       return cp->low_bandwidth;
+}
 /**
  * Returns whether video is enabled.
 **/
@@ -974,9 +1049,11 @@ void linphone_call_set_next_video_frame_decoded_callback(LinphoneCall *call, Lin
 void linphone_call_init_audio_stream(LinphoneCall *call){
        LinphoneCore *lc=call->core;
        AudioStream *audiostream;
-       int dscp=linphone_core_get_audio_dscp(lc);
+       int dscp;
 
+       if (call->audiostream != NULL) return;
        call->audiostream=audiostream=audio_stream_new(call->audio_port,call->audio_port+1,linphone_core_ipv6_enabled(lc));
+       dscp=linphone_core_get_audio_dscp(lc);
        if (dscp!=-1)
                audio_stream_set_dscp(audiostream,dscp);
        if (linphone_core_echo_limiter_enabled(lc)){
@@ -1014,6 +1091,9 @@ void linphone_call_init_audio_stream(LinphoneCall *call){
        if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){
                rtp_session_set_pktinfo(audiostream->session, TRUE);
                rtp_session_set_symmetric_rtp(audiostream->session, FALSE);
+               if (ice_session_check_list(call->ice_session, 0) == NULL) {
+                       ice_session_add_check_list(call->ice_session, ice_check_list_new());
+               }
                audiostream->ice_check_list = ice_session_check_list(call->ice_session, 0);
                ice_check_list_set_rtp_session(audiostream->ice_check_list, audiostream->session);
        }
@@ -1026,6 +1106,11 @@ void linphone_call_init_video_stream(LinphoneCall *call){
 #ifdef VIDEO_ENABLED
        LinphoneCore *lc=call->core;
 
+       if (!call->params.has_video) {
+               linphone_call_stop_video_stream(call);
+               return;
+       }
+       if (call->videostream != NULL) return;
        if ((lc->video_conf.display || lc->video_conf.capture) && call->params.has_video){
                int video_recv_buf_size=lp_config_get_int(lc->config,"video","recv_buf_size",0);
                int dscp=linphone_core_get_video_dscp(lc);
@@ -1044,9 +1129,12 @@ void linphone_call_init_video_stream(LinphoneCall *call){
                        RtpTransport *vrtcp=lc->rtptf->video_rtcp_func(lc->rtptf->video_rtcp_func_data, call->video_port+1);
                        rtp_session_set_transports(call->videostream->session,vrtp,vrtcp);
                }
-               if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL) && (ice_session_check_list(call->ice_session, 1))){
+               if ((linphone_core_get_firewall_policy(lc) == LinphonePolicyUseIce) && (call->ice_session != NULL)){
                        rtp_session_set_pktinfo(call->videostream->session, TRUE);
                        rtp_session_set_symmetric_rtp(call->videostream->session, FALSE);
+                       if (ice_session_check_list(call->ice_session, 1) == NULL) {
+                               ice_session_add_check_list(call->ice_session, ice_check_list_new());
+                       }
                        call->videostream->ice_check_list = ice_session_check_list(call->ice_session, 1);
                        ice_check_list_set_rtp_session(call->videostream->ice_check_list, call->videostream->session);
                }
@@ -1069,8 +1157,7 @@ void linphone_call_init_media_streams(LinphoneCall *call){
 
 static int dtmf_tab[16]={'0','1','2','3','4','5','6','7','8','9','*','#','A','B','C','D'};
 
-static void linphone_core_dtmf_received(RtpSession* s, int dtmf, void* user_data){
-       LinphoneCore* lc = (LinphoneCore*)user_data;
+static void linphone_core_dtmf_received(LinphoneCore *lc, int dtmf){
        if (dtmf<0 || dtmf>15){
                ms_warning("Bad dtmf value %i",dtmf);
                return;
@@ -1160,7 +1247,7 @@ static void post_configure_audio_streams(LinphoneCall*call){
        if (lc->vtable.dtmf_received!=NULL){
                /* replace by our default action*/
                audio_stream_play_received_dtmfs(call->audiostream,FALSE);
-               rtp_session_signal_connect(call->audiostream->session,"telephone-event",(RtpCallback)linphone_core_dtmf_received,(unsigned long)lc);
+               /*rtp_session_signal_connect(call->audiostream->session,"telephone-event",(RtpCallback)linphone_core_dtmf_received,(unsigned long)lc);*/
        }
 }
 
@@ -1234,8 +1321,6 @@ static void setup_ring_player(LinphoneCore *lc, LinphoneCall *call){
        ms_filter_call_method(call->audiostream->soundread,MS_FILE_PLAYER_LOOP,&pause_time);
 }
 
-#define LINPHONE_RTCP_SDES_TOOL "Linphone-" LINPHONE_VERSION
-
 static bool_t linphone_call_sound_resources_available(LinphoneCall *call){
        LinphoneCore *lc=call->core;
        LinphoneCall *current=linphone_core_get_current_call(lc);
@@ -1254,6 +1339,8 @@ static int find_crypto_index_from_tag(const SalSrtpCryptoAlgo crypto[],unsigned
 static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cname, bool_t muted, bool_t send_ringbacktone, bool_t use_arc){
        LinphoneCore *lc=call->core;
        int used_pt=-1;
+       char rtcp_tool[128]={0};
+       snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version());
        /* look for savp stream first */
        const SalStreamDescription *stream=sal_media_description_find_stream(call->resultdesc,
                                                SalProtoRtpSavp,SalAudio);
@@ -1339,7 +1426,7 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna
                        if (send_ringbacktone){
                                setup_ring_player(lc,call);
                        }
-                       audio_stream_set_rtcp_information(call->audiostream, cname, LINPHONE_RTCP_SDES_TOOL);
+                       audio_stream_set_rtcp_information(call->audiostream, cname, rtcp_tool);
                        
             /* valid local tags are > 0 */
                        if (stream->proto == SalProtoRtpSavp) {
@@ -1365,6 +1452,7 @@ static void linphone_call_start_audio_stream(LinphoneCall *call, const char *cna
                                linphone_call_add_to_conf(call, mute);
                        }
                        call->current_params.in_conference=call->params.in_conference;
+                       call->current_params.low_bandwidth=call->params.low_bandwidth;
                }else ms_warning("No audio stream accepted ?");
        }
 }
@@ -1376,6 +1464,9 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna
        /* look for savp stream first */
        const SalStreamDescription *vstream=sal_media_description_find_stream(call->resultdesc,
                                                SalProtoRtpSavp,SalVideo);
+       char rtcp_tool[128]={0};
+       snprintf(rtcp_tool,sizeof(rtcp_tool)-1,"%s-%s",linphone_core_get_user_agent_name(),linphone_core_get_user_agent_version());
+       
        /* no savp audio stream, use avp */
        if (!vstream)
                vstream=sal_media_description_find_stream(call->resultdesc,
@@ -1431,7 +1522,7 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna
                                cam=get_nowebcam_device();
                        }
                        if (!is_inactive){
-                call->log->video_enabled = TRUE;
+                               call->log->video_enabled = TRUE;
                                video_stream_set_direction (call->videostream, dir);
                                ms_message("%s lc rotation:%d\n", __FUNCTION__, lc->device_rotation);
                                video_stream_set_device_rotation(call->videostream, lc->device_rotation);
@@ -1439,7 +1530,7 @@ static void linphone_call_start_video_stream(LinphoneCall *call, const char *cna
                                        call->video_profile, rtp_addr, vstream->rtp_port,
                                        rtcp_addr, linphone_core_rtcp_enabled(lc) ? (vstream->rtcp_port) : 0,
                                        used_pt, linphone_core_get_video_jittcomp(lc), cam);
-                               video_stream_set_rtcp_information(call->videostream, cname,LINPHONE_RTCP_SDES_TOOL);
+                               video_stream_set_rtcp_information(call->videostream, cname,rtcp_tool);
                        }
                        
                        if (vstream->proto == SalProtoRtpSavp) {
@@ -1535,12 +1626,23 @@ void linphone_call_start_media_streams_for_ice_gathering(LinphoneCall *call){
 #endif
 }
 
+void linphone_call_stop_media_streams_for_ice_gathering(LinphoneCall *call){
+       audio_stream_unprepare_sound(call->audiostream);
+#ifdef VIDEO_ENABLED
+       if (call->videostream) {
+               video_stream_unprepare_video(call->videostream);
+       }
+#endif
+}
+
 void linphone_call_delete_ice_session(LinphoneCall *call){
        if (call->ice_session != NULL) {
                ice_session_destroy(call->ice_session);
                call->ice_session = NULL;
                if (call->audiostream != NULL) call->audiostream->ice_check_list = NULL;
                if (call->videostream != NULL) call->videostream->ice_check_list = NULL;
+               call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateNotActivated;
+               call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateNotActivated;
        }
 }
 
@@ -1549,9 +1651,8 @@ static void linphone_call_log_fill_stats(LinphoneCallLog *log, AudioStream *st){
        log->quality=audio_stream_get_average_quality_rating(st);
 }
 
-void linphone_call_stop_media_streams(LinphoneCall *call){
+void linphone_call_stop_audio_stream(LinphoneCall *call) {
        if (call->audiostream!=NULL) {
-               call->audiostream->ice_check_list = NULL;
                rtp_session_unregister_event_queue(call->audiostream->session,call->audiostream_app_evq);
                ortp_ev_queue_flush(call->audiostream_app_evq);
                ortp_ev_queue_destroy(call->audiostream_app_evq);
@@ -1572,11 +1673,11 @@ void linphone_call_stop_media_streams(LinphoneCall *call){
                audio_stream_stop(call->audiostream);
                call->audiostream=NULL;
        }
+}
 
-
+void linphone_call_stop_video_stream(LinphoneCall *call) {
 #ifdef VIDEO_ENABLED
        if (call->videostream!=NULL){
-               call->videostream->ice_check_list = NULL;
                rtp_session_unregister_event_queue(call->videostream->session,call->videostream_app_evq);
                ortp_ev_queue_flush(call->videostream_app_evq);
                ortp_ev_queue_destroy(call->videostream_app_evq);
@@ -1585,6 +1686,11 @@ void linphone_call_stop_media_streams(LinphoneCall *call){
                call->videostream=NULL;
        }
 #endif
+}
+
+void linphone_call_stop_media_streams(LinphoneCall *call){
+       linphone_call_stop_audio_stream(call);
+       linphone_call_stop_video_stream(call);
        ms_event_queue_skip(call->core->msevq);
        
        if (call->audio_profile){
@@ -1729,12 +1835,17 @@ const LinphoneCallStats *linphone_call_get_video_stats(const LinphoneCall *call)
  * @}
 **/
 
-static void display_bandwidth(RtpSession *as, RtpSession *vs){
+static void report_bandwidth(LinphoneCall *call, RtpSession *as, RtpSession *vs){
+       call->stats[LINPHONE_CALL_STATS_AUDIO].download_bandwidth=(as!=NULL) ? (rtp_session_compute_recv_bandwidth(as)*1e-3) : 0;
+       call->stats[LINPHONE_CALL_STATS_AUDIO].upload_bandwidth=(as!=NULL) ? (rtp_session_compute_send_bandwidth(as)*1e-3) : 0;
+       call->stats[LINPHONE_CALL_STATS_VIDEO].download_bandwidth=(vs!=NULL) ? (rtp_session_compute_recv_bandwidth(vs)*1e-3) : 0;
+       call->stats[LINPHONE_CALL_STATS_VIDEO].upload_bandwidth=(vs!=NULL) ? (rtp_session_compute_send_bandwidth(vs)*1e-3) : 0;
        ms_message("bandwidth usage: audio=[d=%.1f,u=%.1f] video=[d=%.1f,u=%.1f] kbit/sec",
-       (as!=NULL) ? (rtp_session_compute_recv_bandwidth(as)*1e-3) : 0,
-       (as!=NULL) ? (rtp_session_compute_send_bandwidth(as)*1e-3) : 0,
-       (vs!=NULL) ? (rtp_session_compute_recv_bandwidth(vs)*1e-3) : 0,
-       (vs!=NULL) ? (rtp_session_compute_send_bandwidth(vs)*1e-3) : 0);
+               call->stats[LINPHONE_CALL_STATS_AUDIO].download_bandwidth,
+               call->stats[LINPHONE_CALL_STATS_AUDIO].upload_bandwidth ,
+               call->stats[LINPHONE_CALL_STATS_VIDEO].download_bandwidth,
+               call->stats[LINPHONE_CALL_STATS_VIDEO].upload_bandwidth
+       );
 }
 
 static void linphone_core_disconnected(LinphoneCore *lc, LinphoneCall *call){
@@ -1759,20 +1870,21 @@ static void linphone_core_disconnected(LinphoneCore *lc, LinphoneCall *call){
 static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){
        OrtpEventType evt=ortp_event_get_type(ev);
        OrtpEventData *evd=ortp_event_get_data(ev);
+       int ping_time;
 
        if (evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) {
                switch (ice_session_state(call->ice_session)) {
                        case IS_Completed:
+                               ice_session_select_candidates(call->ice_session);
                                if (ice_session_role(call->ice_session) == IR_Controlling) {
-                                       ice_session_select_candidates(call->ice_session);
                                        linphone_core_update_call(call->core, call, &call->current_params);
                                }
                                break;
                        case IS_Failed:
                                if (ice_session_has_completed_check_list(call->ice_session) == TRUE) {
+                                       ice_session_select_candidates(call->ice_session);
                                        if (ice_session_role(call->ice_session) == IR_Controlling) {
                                                /* At least one ICE session has succeeded, so perform a call update. */
-                                               ice_session_select_candidates(call->ice_session);
                                                linphone_core_update_call(call->core, call, &call->current_params);
                                        }
                                }
@@ -1780,44 +1892,42 @@ static void handle_ice_events(LinphoneCall *call, OrtpEvent *ev){
                        default:
                                break;
                }
+               linphone_core_update_ice_state_in_call_stats(call);
        } else if (evt == ORTP_EVENT_ICE_GATHERING_FINISHED) {
-               int ping_time = -1;
+
                if (evd->info.ice_processing_successful==TRUE) {
                        ice_session_compute_candidates_foundations(call->ice_session);
                        ice_session_eliminate_redundant_candidates(call->ice_session);
                        ice_session_choose_default_candidates(call->ice_session);
-                       ping_time = ice_session_gathering_duration(call->ice_session);
+                       ping_time = ice_session_average_gathering_round_trip_time(call->ice_session);
                        if (ping_time >=0) {
-                               ping_time /= ice_session_nb_check_lists(call->ice_session);
+                               call->ping_time=ping_time;
                        }
                } else {
                        ms_warning("No STUN answer from [%s], disabling ICE",linphone_core_get_stun_server(call->core));
                        linphone_call_delete_ice_session(call);
                }
                switch (call->state) {
-                       case LinphoneCallStreamsRunning:
+                       case LinphoneCallUpdating:
                                linphone_core_start_update_call(call->core, call);
                                break;
                        case LinphoneCallUpdatedByRemote:
                                linphone_core_start_accept_call_update(call->core, call);
                                break;
                        case LinphoneCallOutgoingInit:
-                               if (ping_time >= 0) {
-                                       linphone_core_adapt_to_network(call->core, ping_time, &call->params);
-                               }
-                               linphone_call_stop_media_streams(call);
+                               linphone_call_stop_media_streams_for_ice_gathering(call);
                                linphone_core_proceed_with_invite_if_ready(call->core, call, NULL);
                                break;
-                       default:
-                               if (ping_time >= 0) {
-                                       linphone_core_adapt_to_network(call->core, ping_time, &call->params);
-                               }
-                               linphone_call_stop_media_streams(call);
+                       case LinphoneCallIdle:
+                               linphone_call_stop_media_streams_for_ice_gathering(call);
                                linphone_core_notify_incoming_call(call->core, call);
                                break;
+                       default:
+                               break;
                }
        } else if (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) {
                linphone_core_start_accept_call_update(call->core, call);
+               linphone_core_update_ice_state_in_call_stats(call);
        } else if (evt == ORTP_EVENT_ICE_RESTART_NEEDED) {
                ice_session_restart(call->ice_session);
                ice_session_set_role(call->ice_session, IR_Controlling);
@@ -1843,7 +1953,7 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse
                                video_load=ms_ticker_get_average_load(call->videostream->ticker);
                        vs=call->videostream->session;
                }
-               display_bandwidth(as,vs);
+               report_bandwidth(call,as,vs);
                ms_message("Thread processing load: audio=%f\tvideo=%f",audio_load,video_load);
        }
 #ifdef VIDEO_ENABLED
@@ -1922,6 +2032,8 @@ void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapse
                        } else if ((evt == ORTP_EVENT_ICE_SESSION_PROCESSING_FINISHED) || (evt == ORTP_EVENT_ICE_GATHERING_FINISHED)
                                || (evt == ORTP_EVENT_ICE_LOSING_PAIRS_COMPLETED) || (evt == ORTP_EVENT_ICE_RESTART_NEEDED)) {
                                handle_ice_events(call, ev);
+                       } else if (evt==ORTP_EVENT_TELEPHONE_EVENT){
+                               linphone_core_dtmf_received(lc,evd->info.telephone_event);
                        }
                        ortp_event_destroy(ev);
                }
@@ -1980,3 +2092,38 @@ void linphone_call_set_transfer_state(LinphoneCall* call, LinphoneCallState stat
 bool_t linphone_call_is_in_conference(const LinphoneCall *call) {
        return call->params.in_conference;
 }
+
+
+/**
+ * Perform a zoom of the video displayed during a call.
+ * @param zoom_factor a floating point number describing the zoom factor. A value 1.0 corresponds to no zoom applied.
+ * @param cx a floating point number pointing the horizontal center of the zoom to be applied. This value should be between 0.0 and 1.0.
+ * @param cy a floating point number pointing the vertical center of the zoom to be applied. This value should be between 0.0 and 1.0.
+ * 
+ * cx and cy are updated in return in case their coordinates were to excentrated for the requested zoom factor. The zoom ensures that all the screen is fullfilled with the video.
+**/
+void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, float* cy) {
+       VideoStream* vstream = call->videostream;
+       if (vstream) {
+               float zoom[3];
+               
+               if (zoom_factor < 1)
+                       zoom_factor = 1;
+               float halfsize = 0.5 * 1.0 / zoom_factor;
+
+               if ((*cx - halfsize) < 0)
+                       *cx = 0 + halfsize;
+               if ((*cx + halfsize) > 1)
+                       *cx = 1 - halfsize;
+               if ((*cy - halfsize) < 0)
+                       *cy = 0 + halfsize;
+               if ((*cy + halfsize) > 1)
+                       *cy = 1 - halfsize;
+       
+               zoom[0] = zoom_factor;
+               zoom[1] = *cx;
+               zoom[2] = *cy;
+               ms_filter_call_method(vstream->output, MS_VIDEO_DISPLAY_ZOOM, &zoom);
+       }else ms_warning("Could not apply zoom: video output wasn't activated.");
+}
+
index 42f11820c3f1705c568463c0fd635b77ece60030..d96a1905b50dfb23cdf7a874b2b03d960f1fb516 100644 (file)
@@ -139,6 +139,7 @@ void call_logs_write_to_config_file(LinphoneCore *lc){
                if (cl->refkey) lp_config_set_string(cfg,logsection,"refkey",cl->refkey);
                lp_config_set_float(cfg,logsection,"quality",cl->quality);
                lp_config_set_int(cfg,logsection,"video_enabled", cl->video_enabled);
+               lp_config_set_string(cfg,logsection,"call_id",cl->call_id);
        }
        for(;i<lc->max_call_logs;++i){
                snprintf(logsection,sizeof(logsection),"call_log_%i",i);
@@ -189,6 +190,8 @@ static void call_logs_read_from_config_file(LinphoneCore *lc){
                        if (tmp) cl->refkey=ms_strdup(tmp);
                        cl->quality=lp_config_get_float(cfg,logsection,"quality",-1);
                        cl->video_enabled=lp_config_get_int(cfg,logsection,"video_enabled",0);
+                       cl->call_id=lp_config_get_string(cfg,logsection,"call_id",NULL);
+                       if(cl->call_id) cl->call_id=ms_strdup(cl->call_id);
                        lc->call_logs=ms_list_append(lc->call_logs,cl);
                }else break;
        }
@@ -296,6 +299,7 @@ void linphone_call_log_destroy(LinphoneCallLog *cl){
        if (cl->from!=NULL) linphone_address_destroy(cl->from);
        if (cl->to!=NULL) linphone_address_destroy(cl->to);
        if (cl->refkey!=NULL) ms_free(cl->refkey);
+       if (cl->call_id) ms_free((void*)cl->call_id);
        ms_free(cl);
 }
 
@@ -616,22 +620,34 @@ static void sip_config_read(LinphoneCore *lc)
        sal_use_one_matching_codec_policy(lc->sal,lp_config_get_int(lc->config,"sip","only_one_codec",0));
        sal_use_double_registrations(lc->sal,lp_config_get_int(lc->config,"sip","use_double_registrations",1));
        sal_set_dscp(lc->sal,linphone_core_get_sip_dscp(lc));
+       sal_use_dates(lc->sal,lp_config_get_int(lc->config,"sip","put_date",0));
 }
 
 static void rtp_config_read(LinphoneCore *lc)
 {
-       int port;
+       int min_port, max_port;
        int jitt_comp;
        int nortp_timeout;
        bool_t rtp_no_xmit_on_audio_mute;
        bool_t adaptive_jitt_comp_enabled;
 
-       port=lp_config_get_int(lc->config,"rtp","audio_rtp_port",7078);
-       linphone_core_set_audio_port(lc,port);
+       if (lp_config_get_range(lc->config, "rtp", "audio_rtp_port", &min_port, &max_port, 7078, 7078) == TRUE) {
+               if (min_port <= 0) min_port = 1;
+               if (max_port > 65535) max_port = 65535;
+               linphone_core_set_audio_port_range(lc, min_port, max_port);
+       } else {
+               min_port = lp_config_get_int(lc->config, "rtp", "audio_rtp_port", 7078);
+               linphone_core_set_audio_port(lc, min_port);
+       }
 
-       port=lp_config_get_int(lc->config,"rtp","video_rtp_port",9078);
-       if (port==0) port=9078;
-       linphone_core_set_video_port(lc,port);
+       if (lp_config_get_range(lc->config, "rtp", "video_rtp_port", &min_port, &max_port, 9078, 9078) == TRUE) {
+               if (min_port <= 0) min_port = 1;
+               if (max_port > 65535) max_port = 65535;
+               linphone_core_set_video_port_range(lc, min_port, max_port);
+       } else {
+               min_port = lp_config_get_int(lc->config, "rtp", "video_rtp_port", 9078);
+               linphone_core_set_video_port(lc, min_port);
+       }
 
        jitt_comp=lp_config_get_int(lc->config,"rtp","audio_jitt_comp",60);
        linphone_core_set_audio_jittcomp(lc,jitt_comp);
@@ -700,25 +716,28 @@ static bool_t get_codec(LpConfig *config, const char* type, int index, PayloadTy
 }
 
 #define RANK_END 10000
-static const char *codec_pref_order[]={
-       "SILK",
-       "speex",
-       "iLBC",
-       "amr",
-       "gsm",
-       "pcmu",
-       "pcma",
-       "VP8",
-       "H264",
-       "MP4V-ES",
-       "H263-1998",
-       NULL,
+
+typedef struct codec_desc{
+       const char *name;
+       int rate;
+}codec_desc_t;
+
+static codec_desc_t codec_pref_order[]={
+       {"SILK", 16000},
+       {"speex", 16000},
+       {"speex", 8000},
+       {"pcmu",8000},
+       {"pcma",8000},
+       {"VP8",90000},
+       {"H264",90000},
+       {"MP4V-ES",90000},
+       {NULL,0}
 };
 
-static int find_codec_rank(const char *mime){
+static int find_codec_rank(const char *mime, int clock_rate){
        int i;
-       for(i=0;codec_pref_order[i]!=NULL;++i){
-               if (strcasecmp(codec_pref_order[i],mime)==0)
+       for(i=0;codec_pref_order[i].name!=NULL;++i){
+               if (strcasecmp(codec_pref_order[i].name,mime)==0 && clock_rate==codec_pref_order[i].rate)
                        return i;
        }
        return RANK_END;
@@ -726,8 +745,8 @@ static int find_codec_rank(const char *mime){
 
 static int codec_compare(const PayloadType *a, const PayloadType *b){
        int ra,rb;
-       ra=find_codec_rank(a->mime_type);
-       rb=find_codec_rank(b->mime_type);
+       ra=find_codec_rank(a->mime_type,a->clock_rate);
+       rb=find_codec_rank(b->mime_type,b->clock_rate);
        if (ra>rb) return 1;
        if (ra<rb) return -1;
        return 0;
@@ -747,7 +766,7 @@ static MSList *add_missing_codecs(SalStreamType mtype, MSList *l){
                        if (pt && ms_filter_codec_supported(pt->mime_type)){
                                if (ms_list_find(l,pt)==NULL){
                                        /*unranked codecs are disabled by default*/
-                                       if (find_codec_rank(pt->mime_type)!=RANK_END){
+                                       if (find_codec_rank(pt->mime_type, pt->clock_rate)!=RANK_END){
                                                payload_type_set_flag(pt,PAYLOAD_TYPE_ENABLED);
                                        }
                                        ms_message("Adding new codec %s/%i with fmtp %s",
@@ -823,6 +842,7 @@ static void video_config_read(LinphoneCore *lc){
        const char *str;        
 #ifdef VIDEO_ENABLED   
        LinphoneVideoPolicy vpol;
+       memset(&vpol, 0, sizeof(LinphoneVideoPolicy));
 #endif
        build_video_devices_table(lc);
 
@@ -844,6 +864,7 @@ static void video_config_read(LinphoneCore *lc){
                ms_message("we are using a specific display:%s\n",lc->video_conf.displaytype);
 
        linphone_core_enable_video(lc,capture,display);
+       linphone_core_enable_video_preview(lc,lp_config_get_int(lc->config,"video","show_local",0));
        linphone_core_enable_self_view(lc,self_view);
        linphone_core_set_video_policy(lc,&vpol);
 #endif
@@ -1431,7 +1452,18 @@ int linphone_core_get_video_jittcomp(LinphoneCore *lc)
 **/
 int linphone_core_get_audio_port(const LinphoneCore *lc)
 {
-       return lc->rtp_conf.audio_rtp_port;
+       return lc->rtp_conf.audio_rtp_min_port;
+}
+
+/**
+ * Get the audio port range from which is randomly chosen the UDP port used for audio streaming.
+ *
+ * @ingroup network_parameters
+ */
+void linphone_core_get_audio_port_range(const LinphoneCore *lc, int *min_port, int *max_port)
+{
+       *min_port = lc->rtp_conf.audio_rtp_min_port;
+       *max_port = lc->rtp_conf.audio_rtp_max_port;
 }
 
 /**
@@ -1440,7 +1472,18 @@ int linphone_core_get_audio_port(const LinphoneCore *lc)
  * @ingroup network_parameters
 **/
 int linphone_core_get_video_port(const LinphoneCore *lc){
-       return lc->rtp_conf.video_rtp_port;
+       return lc->rtp_conf.video_rtp_min_port;
+}
+
+/**
+ * Get the video port range from which is randomly chosen the UDP port used for video streaming.
+ *
+ * @ingroup network_parameters
+ */
+void linphone_core_get_video_port_range(const LinphoneCore *lc, int *min_port, int *max_port)
+{
+       *min_port = lc->rtp_conf.video_rtp_min_port;
+       *max_port = lc->rtp_conf.video_rtp_max_port;
 }
 
 
@@ -1492,7 +1535,16 @@ void linphone_core_set_rtp_no_xmit_on_audio_mute(LinphoneCore *lc,bool_t rtp_no_
 **/
 void linphone_core_set_audio_port(LinphoneCore *lc, int port)
 {
-       lc->rtp_conf.audio_rtp_port=port;
+       lc->rtp_conf.audio_rtp_min_port=lc->rtp_conf.audio_rtp_max_port=port;
+}
+
+/**
+ * Sets the UDP port range from which to randomly select the port used for audio streaming.
+ */
+void linphone_core_set_audio_port_range(LinphoneCore *lc, int min_port, int max_port)
+{
+       lc->rtp_conf.audio_rtp_min_port=min_port;
+       lc->rtp_conf.audio_rtp_max_port=max_port;
 }
 
 /**
@@ -1501,7 +1553,16 @@ void linphone_core_set_audio_port(LinphoneCore *lc, int port)
  * @ingroup network_parameters
 **/
 void linphone_core_set_video_port(LinphoneCore *lc, int port){
-       lc->rtp_conf.video_rtp_port=port;
+       lc->rtp_conf.video_rtp_min_port=lc->rtp_conf.video_rtp_max_port=port;
+}
+
+/**
+ * Sets the UDP port range from which to randomly select the port used for video streaming.
+ */
+void linphone_core_set_video_port_range(LinphoneCore *lc, int min_port, int max_port)
+{
+       lc->rtp_conf.video_rtp_min_port=min_port;
+       lc->rtp_conf.video_rtp_max_port=max_port;
 }
 
 /**
@@ -1595,6 +1656,14 @@ void linphone_core_set_user_agent(const char *name, const char *ver){
        strncpy(_ua_version,ver,sizeof(_ua_version));
 }
 
+const char *linphone_core_get_user_agent_name(void){
+       return _ua_name;
+}
+
+const char *linphone_core_get_user_agent_version(void){
+       return _ua_version;
+}
+
 static void transport_error(LinphoneCore *lc, const char* transport, int port){
        char *msg=ortp_strdup_printf("Could not start %s transport on port %i, maybe this port is already used.",transport,port);
        ms_warning("%s",msg);
@@ -1866,6 +1935,10 @@ void linphone_core_iterate(LinphoneCore *lc){
                        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));
+                       } else if (ecs == LinphoneEcCalibratorFailed) {
+                               lp_config_set_int(lc->config, "sound", "ec_delay", LP_CONFIG_DEFAULT_INT(lc->config, "ec_delay", 250));
+                       } else if (ecs == LinphoneEcCalibratorDoneNoEcho) {
+                               linphone_core_enable_echo_cancellation(lc, FALSE);
                        }
                        ec_calibrator_destroy(lc->ecc);
                        lc->ecc=NULL;
@@ -1907,9 +1980,9 @@ void linphone_core_iterate(LinphoneCore *lc){
                                ms_warning("ICE candidates gathering from [%s] has not finished yet, proceed with the call without ICE anyway."
                                                ,linphone_core_get_stun_server(lc));
                                linphone_call_delete_ice_session(call);
-                               linphone_call_stop_media_streams(call);
+                               linphone_call_stop_media_streams_for_ice_gathering(call);
                        }
-                       linphone_core_start_invite(lc,call,NULL);
+                       linphone_core_start_invite(lc,call);
                }
                if (call->state==LinphoneCallIncomingReceived){
                        elapsed=curtime-call->start_time;
@@ -2173,16 +2246,17 @@ int linphone_core_proceed_with_invite_if_ready(LinphoneCore *lc, LinphoneCall *c
        }
 
        if ((ice_ready == TRUE) && (ping_ready == TRUE)) {
-               return linphone_core_start_invite(lc, call, dest_proxy);
+               return linphone_core_start_invite(lc, call);
        }
        return 0;
 }
 
-int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, LinphoneProxyConfig *dest_proxy){
+int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call){
        int err;
        char *contact;
        char *real_url,*barmsg;
        char *from;
+       LinphoneProxyConfig *dest_proxy=call->dest_proxy;
 
        /*try to be best-effort in giving real local or routable contact address */
        contact=get_fixed_contact(lc,call,dest_proxy);
@@ -2194,15 +2268,15 @@ int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, LinphonePro
        linphone_call_init_media_streams(call);
        if (lc->ringstream==NULL)
                audio_stream_prepare_sound(call->audiostream,lc->sound_conf.play_sndcard,lc->sound_conf.capt_sndcard);
+       call->localdesc=create_local_media_description(lc,call);
        if (!lc->sip_conf.sdp_200_ack){
                call->media_pending=TRUE;
-               if (call->ice_session != NULL)
-                       linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session);
                sal_call_set_local_media_description(call->op,call->localdesc);
        }
        real_url=linphone_address_as_string(call->log->to);
        from=linphone_address_as_string(call->log->from);
        err=sal_call(call->op,from,real_url);
+       call->log->call_id=ms_strdup(sal_op_get_call_id(call->op)); /*must be known at that time*/
 
        if (lc->sip_conf.sdp_200_ack){
                call->media_pending=TRUE;
@@ -2315,10 +2389,9 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const
 {
        const char *route=NULL;
        const char *from=NULL;
-       LinphoneProxyConfig *proxy=NULL;
+       LinphoneProxyConfig *proxy=NULL,*dest_proxy=NULL;
        LinphoneAddress *parsed_url2=NULL;
        char *real_url=NULL;
-       LinphoneProxyConfig *dest_proxy=NULL;
        LinphoneCall *call;
        bool_t use_ice = FALSE;
 
@@ -2351,6 +2424,7 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const
        parsed_url2=linphone_address_new(from);
 
        call=linphone_call_new_outgoing(lc,parsed_url2,linphone_address_clone(addr),params);
+       call->dest_proxy=dest_proxy;
        sal_op_set_route(call->op,route);
 
        if(linphone_core_add_call(lc,call)!= 0)
@@ -2370,13 +2444,13 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const
                if (linphone_core_gather_ice_candidates(lc,call)<0) {
                        /* Ice candidates gathering failed, proceed with the call anyway. */
                        linphone_call_delete_ice_session(call);
-                       linphone_call_stop_media_streams(call);
+                       linphone_call_stop_media_streams_for_ice_gathering(call);
                } else {
                        use_ice = TRUE;
                }
        }
 
-       if (dest_proxy==NULL && lc->sip_conf.ping_with_options==TRUE){
+       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);
@@ -2384,7 +2458,7 @@ LinphoneCall * linphone_core_invite_address_with_params(LinphoneCore *lc, const
                sal_op_set_user_pointer(call->ping_op,call);
                call->start_time=time(NULL);
        }else{
-               if (use_ice==FALSE) linphone_core_start_invite(lc,call,dest_proxy);
+               if (use_ice==FALSE) linphone_core_start_invite(lc,call);
        }
 
        if (real_url!=NULL) ms_free(real_url);
@@ -2456,8 +2530,8 @@ void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){
        bool_t propose_early_media=lp_config_get_int(lc->config,"sip","incoming_calls_early_media",FALSE);
        const char *ringback_tone=linphone_core_get_remote_ringback_tone (lc);
 
-       if (call->ice_session != NULL)
-               linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session);
+       call->localdesc=create_local_media_description(lc,call);
+       sal_call_set_local_media_description(call->op,call->localdesc);
        md=sal_call_get_final_media_description(call->op);
        if (md && sal_media_description_empty(md)){
                sal_call_decline(call->op,SalReasonMedia,NULL);
@@ -2523,7 +2597,6 @@ void linphone_core_notify_incoming_call(LinphoneCore *lc, LinphoneCall *call){
 int linphone_core_start_update_call(LinphoneCore *lc, LinphoneCall *call){
        const char *subject;
        call->camera_active=call->params.has_video;
-       update_local_media_description(lc,call);
        if (call->ice_session != NULL)
                linphone_core_update_local_media_description_from_ice(call->localdesc, call->ice_session);
 
@@ -2555,6 +2628,7 @@ int linphone_core_start_update_call(LinphoneCore *lc, LinphoneCall *call){
 int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params){
        int err=0;
        if (params!=NULL){
+               linphone_call_set_state(call,LinphoneCallUpdating,"Updating call");
 #ifdef VIDEO_ENABLED
                bool_t has_video = call->params.has_video;
                if ((call->ice_session != NULL) && (call->videostream != NULL) && !params->has_video) {
@@ -2562,10 +2636,10 @@ int linphone_core_update_call(LinphoneCore *lc, LinphoneCall *call, const Linpho
                        call->videostream->ice_check_list = NULL;
                }
                call->params = *params;
-               if ((call->ice_session != NULL) && (ice_session_state(call->ice_session) != IS_Completed) && !has_video && params->has_video) {
+               update_local_media_description(lc, call);
+               if ((call->ice_session != NULL) && !has_video && call->params.has_video) {
                        /* Defer call update until the ICE candidates gathering process has finished. */
                        ms_message("Defer call update to gather ICE candidates");
-                       update_local_media_description(lc, call);
                        linphone_call_init_video_stream(call);
                        video_stream_prepare_video(call->videostream);
                        if (linphone_core_gather_ice_candidates(lc,call)<0) {
@@ -2650,7 +2724,9 @@ int linphone_core_start_accept_call_update(LinphoneCore *lc, LinphoneCall *call)
  * @return 0 if sucessful, -1 otherwise (actually when this function call is performed outside ot #LinphoneCallUpdatedByRemote state).
 **/
 int linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params){
+#ifdef VIDEO_ENABLED
        bool_t old_has_video = call->params.has_video;
+#endif
        if (call->state!=LinphoneCallUpdatedByRemote){
                ms_error("linphone_core_accept_update(): invalid state %s to call this function.",
                         linphone_call_state_to_string(call->state));
@@ -2661,10 +2737,15 @@ int linphone_core_accept_call_update(LinphoneCore *lc, LinphoneCall *call, const
        }else
                call->params=*params;
 
+       if (call->params.has_video && !linphone_core_video_enabled(lc)){
+               ms_warning("linphone_core_accept_call_update(): requested video but video support is globally disabled. Refusing video.");
+               call->params.has_video=FALSE;
+       }
        if (call->current_params.in_conference) {
                ms_warning("Video isn't supported in conference");
                call->params.has_video = FALSE;
        }
+       call->params.has_video &= linphone_core_media_description_contains_video_stream(sal_call_get_remote_media_description(call->op));
        call->camera_active=call->params.has_video;
        update_local_media_description(lc,call);
        if (call->ice_session != NULL) {
@@ -2718,7 +2799,7 @@ int linphone_core_accept_call(LinphoneCore *lc, LinphoneCall *call){
 **/
 int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallParams *params)
 {
-       LinphoneProxyConfig *cfg=NULL,*dest_proxy=NULL;
+       LinphoneProxyConfig *cfg=NULL;
        const char *contact=NULL;
        SalOp *replaced;
        SalMediaDescription *new_md;
@@ -2766,31 +2847,32 @@ int linphone_core_accept_call_with_params(LinphoneCore *lc, LinphoneCall *call,
        }
 
        linphone_core_get_default_proxy(lc,&cfg);
-       dest_proxy=cfg;
-       dest_proxy=linphone_core_lookup_known_proxy(lc,call->log->to);
+       call->dest_proxy=cfg;
+       call->dest_proxy=linphone_core_lookup_known_proxy(lc,call->log->to);
 
-       if (cfg!=dest_proxy && dest_proxy!=NULL) {
+       if (cfg!=call->dest_proxy && call->dest_proxy!=NULL) {
                ms_message("Overriding default proxy setting for this call:");
-               ms_message("The used identity will be %s",linphone_proxy_config_get_identity(dest_proxy));
+               ms_message("The used identity will be %s",linphone_proxy_config_get_identity(call->dest_proxy));
        }
        /*try to be best-effort in giving real local or routable contact address*/
-       contact=get_fixed_contact(lc,call,dest_proxy);
+       contact=get_fixed_contact(lc,call,call->dest_proxy);
        if (contact)
                sal_op_set_contact(call->op,contact);
 
-       if (call->audiostream==NULL)
-               linphone_call_init_media_streams(call);
-       if (!was_ringing && call->audiostream->ticker==NULL){
-               audio_stream_prepare_sound(call->audiostream,lc->sound_conf.play_sndcard,lc->sound_conf.capt_sndcard);
-       }
-
        if (params){
                call->params=*params;
+               call->params.has_video &= linphone_core_media_description_contains_video_stream(sal_call_get_remote_media_description(call->op));
                call->camera_active=call->params.has_video;
                update_local_media_description(lc,call);
                sal_call_set_local_media_description(call->op,call->localdesc);
        }
        
+       if (call->audiostream==NULL)
+               linphone_call_init_media_streams(call);
+       if (!was_ringing && call->audiostream->ticker==NULL){
+               audio_stream_prepare_sound(call->audiostream,lc->sound_conf.play_sndcard,lc->sound_conf.capt_sndcard);
+       }
+
        sal_call_accept(call->op);
        if (lc->vtable.display_status!=NULL)
                lc->vtable.display_status(lc,_("Connected."));
@@ -3815,7 +3897,10 @@ void linphone_core_enable_video(LinphoneCore *lc, bool_t vcap_enabled, bool_t di
 #endif
        lc->video_conf.capture=vcap_enabled;
        lc->video_conf.display=display_enabled;
-
+       if (linphone_core_ready(lc)){
+               lp_config_set_int(lc->config,"video","display",lc->video_conf.display);
+               lp_config_set_int(lc->config,"video","capture",lc->video_conf.capture);
+       }
        /* need to re-apply network bandwidth settings*/
        linphone_core_set_download_bandwidth(lc,
                linphone_core_get_download_bandwidth(lc));
@@ -3872,6 +3957,8 @@ const LinphoneVideoPolicy *linphone_core_get_video_policy(LinphoneCore *lc){
 **/
 void linphone_core_enable_video_preview(LinphoneCore *lc, bool_t val){
        lc->video_conf.show_local=val;
+       if (linphone_core_ready(lc))
+               lp_config_set_int(lc->config,"video","show_local",val);
 }
 
 /**
@@ -3897,6 +3984,9 @@ void linphone_core_enable_self_view(LinphoneCore *lc, bool_t val){
        if (call && call->videostream){
                video_stream_enable_self_view(call->videostream,val);
        }
+       if (linphone_core_ready(lc)){
+               lp_config_set_int(lc->config,"video","self_view",val);
+       }
 #endif
 }
 
@@ -4090,6 +4180,8 @@ void linphone_core_set_native_preview_window_id(LinphoneCore *lc, unsigned long
        LinphoneCall *call=linphone_core_get_current_call(lc);
        if (call!=NULL && call->videostream){
                video_stream_set_native_preview_window_id(call->videostream,id);
+       }else if (lc->previewstream){
+               video_preview_set_native_window_id(lc->previewstream,id);
        }
 #endif
 }
@@ -4520,8 +4612,16 @@ void sip_config_uninit(LinphoneCore *lc)
 void rtp_config_uninit(LinphoneCore *lc)
 {
        rtp_config_t *config=&lc->rtp_conf;
-       lp_config_set_int(lc->config,"rtp","audio_rtp_port",config->audio_rtp_port);
-       lp_config_set_int(lc->config,"rtp","video_rtp_port",config->video_rtp_port);
+       if (config->audio_rtp_min_port == config->audio_rtp_max_port) {
+               lp_config_set_int(lc->config, "rtp", "audio_rtp_port", config->audio_rtp_min_port);
+       } else {
+               lp_config_set_range(lc->config, "rtp", "audio_rtp_port", config->audio_rtp_min_port, config->audio_rtp_max_port);
+       }
+       if (config->video_rtp_min_port == config->video_rtp_max_port) {
+               lp_config_set_int(lc->config, "rtp", "video_rtp_port", config->video_rtp_min_port);
+       } else {
+               lp_config_set_range(lc->config, "rtp", "video_rtp_port", config->video_rtp_min_port, config->video_rtp_max_port);
+       }
        lp_config_set_int(lc->config,"rtp","audio_jitt_comp",config->audio_jitt_comp);
        lp_config_set_int(lc->config,"rtp","video_jitt_comp",config->video_jitt_comp);
        lp_config_set_int(lc->config,"rtp","nortp_timeout",config->nortp_timeout);
@@ -4529,7 +4629,7 @@ void rtp_config_uninit(LinphoneCore *lc)
        lp_config_set_int(lc->config,"rtp","video_jitt_comp_enabled",config->video_adaptive_jitt_comp_enabled);
 }
 
-void sound_config_uninit(LinphoneCore *lc)
+static void sound_config_uninit(LinphoneCore *lc)
 {
        sound_config_t *config=&lc->sound_conf;
        ms_free(config->cards);
@@ -4541,13 +4641,11 @@ void sound_config_uninit(LinphoneCore *lc)
        ms_snd_card_manager_destroy();
 }
 
-void video_config_uninit(LinphoneCore *lc)
+static void video_config_uninit(LinphoneCore *lc)
 {
        lp_config_set_string(lc->config,"video","size",video_size_get_name(linphone_core_get_preferred_video_size(lc)));
        lp_config_set_int(lc->config,"video","display",lc->video_conf.display);
        lp_config_set_int(lc->config,"video","capture",lc->video_conf.capture);
-       lp_config_set_int(lc->config,"video","show_local",linphone_core_video_preview_enabled(lc));
-       lp_config_set_int(lc->config,"video","self_view",linphone_core_self_view_enabled(lc));
        if (lc->video_conf.cams)
                ms_free(lc->video_conf.cams);
 }
@@ -5008,7 +5106,7 @@ bool_t linphone_core_sound_resources_locked(LinphoneCore *lc){
                        case LinphoneCallConnected:
                        case LinphoneCallRefered:
                        case LinphoneCallIncomingEarlyMedia:
-                       case LinphoneCallUpdated:
+                       case LinphoneCallUpdating:
                                return TRUE;
                        default:
                                break;
@@ -5079,34 +5177,11 @@ void linphone_core_set_media_encryption_mandatory(LinphoneCore *lc, bool_t m) {
 
 void linphone_core_init_default_params(LinphoneCore*lc, LinphoneCallParams *params) {
        params->has_video=linphone_core_video_enabled(lc) && lc->video_policy.automatically_initiate;
-       params->media_encryption=linphone_core_get_media_encryption(lc);        
+       params->media_encryption=linphone_core_get_media_encryption(lc);
        params->in_conference=FALSE;
 }
 
-void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, float* cy) {
-       VideoStream* vstream = call->videostream;
-       if (vstream) {
-               float zoom[3];
-               
-               if (zoom_factor < 1)
-                       zoom_factor = 1;
-               float halfsize = 0.5 * 1.0 / zoom_factor;
-
-               if ((*cx - halfsize) < 0)
-                       *cx = 0 + halfsize;
-               if ((*cx + halfsize) > 1)
-                       *cx = 1 - halfsize;
-               if ((*cy - halfsize) < 0)
-                       *cy = 0 + halfsize;
-               if ((*cy + halfsize) > 1)
-                       *cy = 1 - halfsize;
-       
-               zoom[0] = zoom_factor;
-               zoom[1] = *cx;
-               zoom[2] = *cy;
-               ms_filter_call_method(vstream->output, MS_VIDEO_DISPLAY_ZOOM, &zoom);
-       }else ms_warning("Could not apply zoom: video output wasn't activated.");
-}
+
 
 void linphone_core_set_device_identifier(LinphoneCore *lc,const char* device_id) {
        if (lc->device_id) ms_free(lc->device_id);
index ef24f2c78cbb3894e3a31637699641c9652fc83c..ad52c559f4955079f0276743ec6e1eb7b3daf843 100644 (file)
@@ -146,7 +146,7 @@ typedef struct _LinphoneCallLog{
        LinphoneCallStatus status; /**< The status of the call*/
        LinphoneAddress *from; /**<Originator of the call as a LinphoneAddress object*/
        LinphoneAddress *to; /**<Destination of the call as a LinphoneAddress object*/
-       char start_date[128]; /**<Human readable string containg the start date*/
+       char start_date[128]; /**<Human readable string containing the start date*/
        int duration; /**<Duration of the call in seconds*/
        char *refkey;
        void *user_pointer;
@@ -156,6 +156,7 @@ typedef struct _LinphoneCallLog{
     int video_enabled;
        struct _LinphoneCore *lc;
        time_t start_date_time; /**Start date of the call in seconds as expressed in a time_t */
+       const char* call_id; /**unique id of a call*/
 } LinphoneCallLog;
 
 
@@ -203,7 +204,14 @@ bool_t linphone_call_params_early_media_sending_enabled(const LinphoneCallParams
 bool_t linphone_call_params_local_conference_mode(const LinphoneCallParams *cp);
 void linphone_call_params_set_audio_bandwidth_limit(LinphoneCallParams *cp, int bw);
 void linphone_call_params_destroy(LinphoneCallParams *cp);
-
+/**
+ * @ingroup call_control
+ * Use to know if this call has been configured in low bandwidth mode.
+ * This mode can be automatically discovered thanks to a stun server when activate_edge_workarounds=1 in section [net] of configuration file
+ * <br> When enabled, this param may transform a call request with video in audio only mode.
+ * @return TRUE if low bandwidth has been configured/detected
+ */
+bool_t linphone_call_params_low_bandwidth_enabled(const LinphoneCallParams *cp);
 /**
  * Enum describing failure reasons.
  * @ingroup initializing
@@ -261,6 +269,25 @@ typedef struct _LinphoneCall LinphoneCall;
 #define LINPHONE_CALL_STATS_AUDIO 0
 #define LINPHONE_CALL_STATS_VIDEO 1
 
+/**
+ * Enum describing ICE states.
+ * @ingroup initializing
+**/
+enum _LinphoneIceState{
+       LinphoneIceStateNotActivated, /**< ICE has not been activated for this call */
+       LinphoneIceStateFailed, /**< ICE processing has failed */
+       LinphoneIceStateInProgress, /**< ICE process is in progress */
+       LinphoneIceStateHostConnection, /**< ICE has established a direct connection to the remote host */
+       LinphoneIceStateReflexiveConnection, /**< ICE has established a connection to the remote host through one or several NATs */
+       LinphoneIceStateRelayConnection /**< ICE has established a connection through a relay */
+};
+
+/**
+ * Enum describing Ice states.
+ * @ingroup initializing
+**/
+typedef enum _LinphoneIceState LinphoneIceState;
+
 /**
  * The LinphoneCallStats objects carries various statistic informations regarding quality of audio or video streams.
  *
@@ -285,6 +312,9 @@ struct _LinphoneCallStats {
        mblk_t*         received_rtcp; /**<Last RTCP packet received, as a mblk_t structure. See oRTP documentation for details how to extract information from it*/
        mblk_t*         sent_rtcp;/**<Last RTCP packet sent, as a mblk_t structure. See oRTP documentation for details how to extract information from it*/
        float           round_trip_delay; /**<Round trip propagation time in seconds if known, -1 if unknown.*/
+       LinphoneIceState        ice_state; /**< State of ICE processing. */
+       float download_bandwidth; /**<Download bandwidth measurement of received stream, expressed in kbit/s, including IP/UDP/RTP headers*/
+       float upload_bandwidth; /**<Download bandwidth measurement of sent stream, expressed in kbit/s, including IP/UDP/RTP headers*/
 };
 
 /**
@@ -321,7 +351,7 @@ typedef enum _LinphoneCallState{
        LinphoneCallPausedByRemote, /**<The call is paused by remote end*/
        LinphoneCallUpdatedByRemote, /**<The call's parameters change is requested by remote end, used for example when video is added by remote */
        LinphoneCallIncomingEarlyMedia, /**<We are proposing early media to an incoming call */
-       LinphoneCallUpdated, /**<The remote accepted the call update initiated by us */
+       LinphoneCallUpdating, /**<A call update has been initiated by us */
        LinphoneCallReleased /**< The call object is no more retained by the core */
 } LinphoneCallState;
 
@@ -360,6 +390,7 @@ void *linphone_call_get_user_pointer(LinphoneCall *call);
 void linphone_call_set_user_pointer(LinphoneCall *call, void *user_pointer);
 void linphone_call_set_next_video_frame_decoded_callback(LinphoneCall *call, LinphoneCallCbFunc cb, void* user_data);
 LinphoneCallState linphone_call_get_transfer_state(LinphoneCall *call);
+void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, float* cy);
 /**
  * Return TRUE if this call is currently part of a conference
  *@param call #LinphoneCall
@@ -877,11 +908,14 @@ void linphone_core_disable_logs(void);
 /*sets the user-agent string in sip messages, must be set before linphone_core_new() or linphone_core_init() */
 void linphone_core_set_user_agent(const char *ua_name, const char *version);
 const char *linphone_core_get_version(void);
+const char *linphone_core_get_user_agent_name(void);
+const char *linphone_core_get_user_agent_version(void);
 
 LinphoneCore *linphone_core_new(const LinphoneCoreVTable *vtable,
                                                const char *config_path, const char *factory_config, void* userdata);
 
 /* function to be periodically called in a main loop */
+/* For ICE to work properly it should be called every 20ms */
 void linphone_core_iterate(LinphoneCore *lc);
 #if 0 /*not implemented yet*/
 /**
@@ -1082,14 +1116,22 @@ void linphone_core_set_video_jittcomp(LinphoneCore *lc, int value);
 
 int linphone_core_get_audio_port(const LinphoneCore *lc);
 
+void linphone_core_get_audio_port_range(const LinphoneCore *lc, int *min_port, int *max_port);
+
 int linphone_core_get_video_port(const LinphoneCore *lc);
 
+void linphone_core_get_video_port_range(const LinphoneCore *lc, int *min_port, int *max_port);
+
 int linphone_core_get_nortp_timeout(const LinphoneCore *lc);
 
 void linphone_core_set_audio_port(LinphoneCore *lc, int port);
 
+void linphone_core_set_audio_port_range(LinphoneCore *lc, int min_port, int max_port);
+
 void linphone_core_set_video_port(LinphoneCore *lc, int port);
 
+void linphone_core_set_video_port_range(LinphoneCore *lc, int min_port, int max_port);
+
 void linphone_core_set_nortp_timeout(LinphoneCore *lc, int port);
 
 void linphone_core_set_use_info_for_dtmf(LinphoneCore *lc, bool_t use_info);
@@ -1387,8 +1429,6 @@ typedef struct LinphoneTunnel LinphoneTunnel;
 */
 LinphoneTunnel *linphone_core_get_tunnel(LinphoneCore *lc);
 
-void linphone_call_zoom_video(LinphoneCall* call, float zoom_factor, float* cx, float* cy);
-
 void linphone_core_set_sip_dscp(LinphoneCore *lc, int dscp);
 int linphone_core_get_sip_dscp(const LinphoneCore *lc);
 
@@ -1398,6 +1438,8 @@ int linphone_core_get_audio_dscp(const LinphoneCore *lc);
 void linphone_core_set_video_dscp(LinphoneCore *lc, int dscp);
 int linphone_core_get_video_dscp(const LinphoneCore *lc);
 
+
+
 #ifdef __cplusplus
 }
 #endif
index 440afcbc6df96d05f700e46de3ff878e4a023442..080c8b0091293c5776119d784afea2376ad439aa 100644 (file)
@@ -53,6 +53,9 @@ static JavaVM *jvm=0;
 #ifdef ANDROID
 static void linphone_android_log_handler(OrtpLogLevel lev, const char *fmt, va_list args){
        int prio;
+       char str[4096];
+       char *current;
+       char *next;
        switch(lev){
        case ORTP_DEBUG:        prio = ANDROID_LOG_DEBUG;       break;
        case ORTP_MESSAGE:      prio = ANDROID_LOG_INFO;        break;
@@ -61,7 +64,19 @@ static void linphone_android_log_handler(OrtpLogLevel lev, const char *fmt, va_l
        case ORTP_FATAL:        prio = ANDROID_LOG_FATAL;       break;
        default:                prio = ANDROID_LOG_DEFAULT;     break;
        }
-       __android_log_vprint(prio, LOG_DOMAIN, fmt, args);
+       vsnprintf(str, sizeof(str) - 1, fmt, args);
+       str[sizeof(str) - 1] = '\0';
+       if (strlen(str) < 512) {
+               __android_log_write(prio, LOG_DOMAIN, str);
+       } else {
+               current = str;
+               while ((next = strchr(current, '\n')) != NULL) {
+                       *next = '\0';
+                       __android_log_write(prio, LOG_DOMAIN, current);
+                       current = next + 1;
+               }
+               __android_log_write(prio, LOG_DOMAIN, current);
+       }
 }
 
 int dumbMethodForAllowingUsageOfCpuFeaturesFromStaticLibMediastream() {
@@ -110,8 +125,10 @@ public:
                vTable.call_encryption_changed = callEncryptionChange;
                vTable.text_received = text_received;
                vTable.message_received = message_received;
+               vTable.dtmf_received = dtmf_received;
                vTable.new_subscription_request = new_subscription_request;
                vTable.notify_presence_recv = notify_presence_recv;
+               vTable.call_stats_updated = callStatsUpdated;
 
                listenerClass = (jclass)env->NewGlobalRef(env->GetObjectClass( alistener));
 
@@ -133,6 +150,9 @@ public:
                callStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCall$State"));
                callStateFromIntId = env->GetStaticMethodID(callStateClass,"fromInt","(I)Lorg/linphone/core/LinphoneCall$State;");
 
+               /*callStatsUpdated(LinphoneCore lc, LinphoneCall call, LinphoneCallStats stats);*/
+               callStatsUpdatedId = env->GetMethodID(listenerClass, "callStatsUpdated", "(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCall;Lorg/linphone/core/LinphoneCallStats;)V");
+
                chatMessageStateClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneChatMessage$State"));
                chatMessageStateFromIntId = env->GetStaticMethodID(chatMessageStateClass,"fromInt","(I)Lorg/linphone/core/LinphoneChatMessage$State;");
 
@@ -152,7 +172,8 @@ public:
 
                /*void textReceived(LinphoneCore lc, LinphoneChatRoom cr,LinphoneAddress from,String message);*/
                textReceivedId = env->GetMethodID(listenerClass,"textReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneChatRoom;Lorg/linphone/core/LinphoneAddress;Ljava/lang/String;)V");
-               messageReceivedId = env->GetMethodID(listenerClass,"messageReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneChatRoom;Lorg/linphone/core/LinphoneAddress;Lorg/linphone/core/LinphoneChatMessage;)V");
+               messageReceivedId = env->GetMethodID(listenerClass,"messageReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneChatRoom;Lorg/linphone/core/LinphoneChatMessage;)V");
+               dtmfReceivedId = env->GetMethodID(listenerClass,"dtmfReceived","(Lorg/linphone/core/LinphoneCore;Lorg/linphone/core/LinphoneCall;I)V");
 
                proxyClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneProxyConfigImpl"));
                proxyCtrId = env->GetMethodID(proxyClass,"<init>", "(J)V");
@@ -161,7 +182,7 @@ public:
                callCtrId = env->GetMethodID(callClass,"<init>", "(J)V");
 
                chatMessageClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneChatMessageImpl"));
-               chatMessageCtrId = env->GetMethodID(chatMessageClass,"<init>", "(J)V");
+               if (chatMessageClass) chatMessageCtrId = env->GetMethodID(chatMessageClass,"<init>", "(J)V");
 
                chatRoomClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneChatRoomImpl"));
                chatRoomCtrId = env->GetMethodID(chatRoomClass,"<init>", "(J)V");
@@ -172,6 +193,10 @@ public:
                addressClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneAddressImpl"));
                addressCtrId =env->GetMethodID(addressClass,"<init>", "(J)V");
 
+               callStatsClass = (jclass)env->NewGlobalRef(env->FindClass("org/linphone/core/LinphoneCallStatsImpl"));
+               callStatsId = env->GetMethodID(callStatsClass, "<init>", "(JJ)V");
+               callSetAudioStatsId = env->GetMethodID(callClass, "setAudioStats", "(Lorg/linphone/core/LinphoneCallStats;)V");
+               callSetVideoStatsId = env->GetMethodID(callClass, "setVideoStats", "(Lorg/linphone/core/LinphoneCallStats;)V");
        }
 
        ~LinphoneCoreData() {
@@ -184,6 +209,7 @@ public:
                env->DeleteGlobalRef(globalStateClass);
                env->DeleteGlobalRef(registrationStateClass);
                env->DeleteGlobalRef(callStateClass);
+               env->DeleteGlobalRef(callStatsClass);
                env->DeleteGlobalRef(chatMessageStateClass);
                env->DeleteGlobalRef(proxyClass);
                env->DeleteGlobalRef(callClass);
@@ -202,6 +228,8 @@ public:
        jmethodID notifyPresenceReceivedId;
        jmethodID textReceivedId;
        jmethodID messageReceivedId;
+       jmethodID dtmfReceivedId;
+       jmethodID callStatsUpdatedId;
 
        jclass globalStateClass;
        jmethodID globalStateId;
@@ -215,6 +243,11 @@ public:
        jmethodID callStateId;
        jmethodID callStateFromIntId;
 
+       jclass callStatsClass;
+       jmethodID callStatsId;
+       jmethodID callSetAudioStatsId;
+       jmethodID callSetVideoStatsId;
+
        jclass chatMessageStateClass;
        jmethodID chatMessageStateFromIntId;
 
@@ -375,6 +408,20 @@ public:
                                                        ,env->NewObject(lcData->friendClass,lcData->friendCtrId,(jlong)my_friend)
                                                        ,url ? env->NewStringUTF(url) : NULL);
        }
+       static void dtmf_received(LinphoneCore *lc, LinphoneCall *call, int dtmf) {
+               JNIEnv *env = 0;
+               jint result = jvm->AttachCurrentThread(&env,NULL);
+               if (result != 0) {
+                       ms_error("cannot attach VM\n");
+                       return;
+               }
+               LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc);
+               env->CallVoidMethod(lcData->listener
+                                                       ,lcData->dtmfReceivedId
+                                                       ,lcData->core
+                                                       ,lcData->getCall(env,call)
+                                                       ,dtmf);
+       }
        static void text_received(LinphoneCore *lc, LinphoneChatRoom *room, const LinphoneAddress *from, const char *message) {
                JNIEnv *env = 0;
                jint result = jvm->AttachCurrentThread(&env,NULL);
@@ -402,7 +449,6 @@ public:
                                                                ,lcData->messageReceivedId
                                                                ,lcData->core
                                                                ,env->NewObject(lcData->chatRoomClass,lcData->chatRoomCtrId,(jlong)room)
-                                                               ,env->NewObject(lcData->addressClass,lcData->addressCtrId,(jlong)msg->from)
                                                                ,env->NewObject(lcData->chatMessageClass,lcData->chatMessageCtrId,(jlong)msg));
                }
        static void ecCalibrationStatus(LinphoneCore *lc, LinphoneEcCalibratorStatus status, int delay_ms, void *data) {
@@ -425,6 +471,24 @@ public:
                }
 
        }
+       static void callStatsUpdated(LinphoneCore *lc, LinphoneCall* call, const LinphoneCallStats *stats) {
+               JNIEnv *env = 0;
+               jobject statsobj;
+               jobject callobj;
+               jint result = jvm->AttachCurrentThread(&env,NULL);
+               if (result != 0) {
+                       ms_error("cannot attach VM\n");
+                       return;
+               }
+               LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data(lc);
+               statsobj = env->NewObject(lcData->callStatsClass, lcData->callStatsId, (jlong)call, (jlong)stats);
+               callobj = lcData->getCall(env, call);
+               if (stats->type == LINPHONE_CALL_STATS_AUDIO)
+                       env->CallVoidMethod(callobj, lcData->callSetAudioStatsId, statsobj);
+               else
+                       env->CallVoidMethod(callobj, lcData->callSetVideoStatsId, statsobj);
+               env->CallVoidMethod(lcData->listener, lcData->callStatsUpdatedId, lcData->core, callobj, statsobj);
+       }
 
 
 };
@@ -467,7 +531,7 @@ extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_newLinphoneCore(JNIEnv*
        if (factoryConfig) env->ReleaseStringUTFChars(jfactoryConfig, factoryConfig);
        return nativePtr;
 }
-extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_delete(JNIEnv*  env
+extern "C" void Java_org_linphone_core_LinphoneCoreImpl_delete(JNIEnv*  env
                ,jobject  thiz
                ,jlong lc) {
        LinphoneCoreData* lcData = (LinphoneCoreData*)linphone_core_get_user_data((LinphoneCore*)lc);
@@ -475,7 +539,7 @@ extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_delete(JNIEnv*  env
        delete lcData;
 }
 
-extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_clearProxyConfigs(JNIEnv* env, jobject thiz,jlong lc) {
+extern "C" void Java_org_linphone_core_LinphoneCoreImpl_clearProxyConfigs(JNIEnv* env, jobject thiz,jlong lc) {
        linphone_core_clear_proxy_config((LinphoneCore*)lc);
 }
 
@@ -509,7 +573,7 @@ extern "C" jlongArray Java_org_linphone_core_LinphoneCoreImpl_getProxyConfigList
        return jProxies;
 }
 
-extern "C" int Java_org_linphone_core_LinphoneCoreImpl_addProxyConfig( JNIEnv*  env
+extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_addProxyConfig(        JNIEnv*  env
                ,jobject  thiz
                ,jobject jproxyCfg
                ,jlong lc
@@ -517,10 +581,10 @@ extern "C" int Java_org_linphone_core_LinphoneCoreImpl_addProxyConfig(    JNIEnv*
        LinphoneProxyConfig* proxy = (LinphoneProxyConfig*)pc;
        linphone_proxy_config_set_user_data(proxy, env->NewGlobalRef(jproxyCfg));
 
-       return linphone_core_add_proxy_config((LinphoneCore*)lc,(LinphoneProxyConfig*)pc);
+       return (jint)linphone_core_add_proxy_config((LinphoneCore*)lc,(LinphoneProxyConfig*)pc);
 }
 
-extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_clearAuthInfos(JNIEnv* env, jobject thiz,jlong lc) {
+extern "C" void Java_org_linphone_core_LinphoneCoreImpl_clearAuthInfos(JNIEnv* env, jobject thiz,jlong lc) {
        linphone_core_clear_all_auth_info((LinphoneCore*)lc);
 }
 
@@ -573,13 +637,13 @@ extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_isInCall(     JNIEnv*  e
                ,jobject  thiz
                ,jlong lc) {
 
-       return linphone_core_in_call((LinphoneCore*)lc);
+       return (jboolean)linphone_core_in_call((LinphoneCore*)lc);
 }
 extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_isInComingInvitePending(   JNIEnv*  env
                ,jobject  thiz
                ,jlong lc) {
 
-       return linphone_core_inc_invite_pending((LinphoneCore*)lc);
+       return (jboolean)linphone_core_inc_invite_pending((LinphoneCore*)lc);
 }
 extern "C" void Java_org_linphone_core_LinphoneCoreImpl_acceptCall(    JNIEnv*  env
                ,jobject  thiz
@@ -621,7 +685,7 @@ extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_getCallLog(        JNIEnv*  en
 extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_getNumberOfCallLogs(   JNIEnv*  env
                ,jobject  thiz
                ,jlong lc) {
-               return ms_list_size(linphone_core_get_call_logs((LinphoneCore*)lc));
+               return (jint)ms_list_size(linphone_core_get_call_logs((LinphoneCore*)lc));
 }
 extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setNetworkStateReachable(      JNIEnv*  env
                ,jobject  thiz
@@ -633,7 +697,7 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setNetworkStateReachable
 extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_isNetworkStateReachable(   JNIEnv*  env
                ,jobject  thiz
                ,jlong lc) {
-               return linphone_core_is_network_reachable((LinphoneCore*)lc);
+               return (jboolean)linphone_core_is_network_reachable((LinphoneCore*)lc);
 }
 
 extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setPlaybackGain(       JNIEnv*  env
@@ -643,10 +707,10 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setPlaybackGain(  JNIEnv*
                linphone_core_set_playback_gain_db((LinphoneCore*)lc,gain);
 }
 
-extern "C" float Java_org_linphone_core_LinphoneCoreImpl_getPlaybackGain(      JNIEnv*  env
+extern "C" jfloat Java_org_linphone_core_LinphoneCoreImpl_getPlaybackGain(     JNIEnv*  env
                ,jobject  thiz
                ,jlong lc) {
-               return linphone_core_get_playback_gain_db((LinphoneCore*)lc);
+               return (jfloat)linphone_core_get_playback_gain_db((LinphoneCore*)lc);
 }
 
 extern "C" void Java_org_linphone_core_LinphoneCoreImpl_muteMic(       JNIEnv*  env
@@ -684,10 +748,10 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_stopDtmf( JNIEnv*  env
        linphone_core_stop_dtmf((LinphoneCore*)lc);
 }
 
-extern "C" void Java_org_linphone_core_LinphoneCoreImpl_getMissedCallsCount(JNIEnv*  env
+extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_getMissedCallsCount(JNIEnv*  env
                                                                                                                                                ,jobject  thiz
                                                                                                                                                ,jlong lc) {
-       linphone_core_get_missed_calls_count((LinphoneCore*)lc);
+       return (jint)linphone_core_get_missed_calls_count((LinphoneCore*)lc);
 }
 
 extern "C" void Java_org_linphone_core_LinphoneCoreImpl_resetMissedCallsCount(JNIEnv*  env
@@ -710,7 +774,7 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_clearCallLogs(JNIEnv*  e
 extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_isMicMuted(        JNIEnv*  env
                ,jobject  thiz
                ,jlong lc) {
-       return linphone_core_is_mic_muted((LinphoneCore*)lc);
+       return (jboolean)linphone_core_is_mic_muted((LinphoneCore*)lc);
 }
 extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_findPayloadType(JNIEnv*  env
                                                                                                                                                        ,jobject  thiz
@@ -759,12 +823,12 @@ extern "C" jlongArray Java_org_linphone_core_LinphoneCoreImpl_listAudioPayloadTy
        return jCodecs;
 }
 
-extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_enablePayloadType(JNIEnv*  env
+extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_enablePayloadType(JNIEnv*  env
                                                                                                                                                        ,jobject  thiz
                                                                                                                                                        ,jlong lc
                                                                                                                                                        ,jlong pt
                                                                                                                                                        ,jboolean enable) {
-       return linphone_core_enable_payload_type((LinphoneCore*)lc,(PayloadType*)pt,enable);
+       return (jint)linphone_core_enable_payload_type((LinphoneCore*)lc,(PayloadType*)pt,enable);
 }
 extern "C" void Java_org_linphone_core_LinphoneCoreImpl_enableEchoCancellation(JNIEnv*  env
                                                                                                                                                        ,jobject  thiz
@@ -782,14 +846,14 @@ extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_isEchoCancellationEn
                                                                                                                                                        ,jobject  thiz
                                                                                                                                                        ,jlong lc
                                                                                                                                                        ) {
-       return linphone_core_echo_cancellation_enabled((LinphoneCore*)lc);
+       return (jboolean)linphone_core_echo_cancellation_enabled((LinphoneCore*)lc);
 }
 
 extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_isEchoLimiterEnabled(JNIEnv*  env
                                                                                                                                                        ,jobject  thiz
                                                                                                                                                        ,jlong lc
                                                                                                                                                        ) {
-       return linphone_core_echo_limiter_enabled((LinphoneCore*)lc);
+       return (jboolean)linphone_core_echo_limiter_enabled((LinphoneCore*)lc);
 }
 
 extern "C" jobject Java_org_linphone_core_LinphoneCoreImpl_getCurrentCall(JNIEnv*  env
@@ -818,7 +882,7 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setPresenceInfo(JNIEnv*
        if (alternative_contact) env->ReleaseStringUTFChars(jalternative_contact, alternative_contact);
 }
 
-extern "C" long Java_org_linphone_core_LinphoneCoreImpl_createChatRoom(JNIEnv*  env
+extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_createChatRoom(JNIEnv*  env
                                                                                                                                                        ,jobject  thiz
                                                                                                                                                        ,jlong lc
                                                                                                                                                        ,jstring jto) {
@@ -826,7 +890,7 @@ extern "C" long Java_org_linphone_core_LinphoneCoreImpl_createChatRoom(JNIEnv*
        const char* to = env->GetStringUTFChars(jto, NULL);
        LinphoneChatRoom* lResult = linphone_core_create_chat_room((LinphoneCore*)lc,to);
        env->ReleaseStringUTFChars(jto, to);
-       return (long)lResult;
+       return (jlong)lResult;
 }
 
 extern "C" void Java_org_linphone_core_LinphoneCoreImpl_enableVideo(JNIEnv*  env
@@ -840,7 +904,7 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_enableVideo(JNIEnv*  env
 extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_isVideoEnabled(JNIEnv*  env
                                                                                                                                                        ,jobject  thiz
                                                                                                                                                        ,jlong lc) {
-       return linphone_core_video_enabled((LinphoneCore*)lc);
+       return (jboolean)linphone_core_video_enabled((LinphoneCore*)lc);
 }
 extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setPlayFile(JNIEnv*  env
                                                                                                                                                        ,jobject  thiz
@@ -887,59 +951,45 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_enableKeepAlive(JNIEnv*
 extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_isKeepAliveEnabled(JNIEnv*  env
                                                                                                                                ,jobject  thiz
                                                                                                                                ,jlong lc) {
-       return linphone_core_keep_alive_enabled((LinphoneCore*)lc);
+       return (jboolean)linphone_core_keep_alive_enabled((LinphoneCore*)lc);
 
 }
 extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_startEchoCalibration(JNIEnv*  env
                                                                                                                                                                ,jobject  thiz
                                                                                                                                                                ,jlong lc
                                                                                                                                                                ,jobject data) {
-       return linphone_core_start_echo_calibration((LinphoneCore*)lc
+       return (jint)linphone_core_start_echo_calibration((LinphoneCore*)lc
                                                                                                        , LinphoneCoreData::ecCalibrationStatus
                                                                                                        , data?env->NewGlobalRef(data):NULL);
 
 }
 
-extern "C" int Java_org_linphone_core_LinphoneCoreImpl_getMediaEncryption(JNIEnv*  env
+extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_getMediaEncryption(JNIEnv*  env
                                                                                                                                                        ,jobject  thiz
                                                                                                                                                        ,jlong lc
                                                                                                                                                        ) {
-       return (int)linphone_core_get_media_encryption((LinphoneCore*)lc);
+       return (jint)linphone_core_get_media_encryption((LinphoneCore*)lc);
 }
 
 extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setMediaEncryption(JNIEnv*  env
                                                                                                                                                        ,jobject  thiz
                                                                                                                                                        ,jlong lc
-                                                                                                                                                       ,int menc) {
+                                                                                                                                                       ,jint menc) {
        linphone_core_set_media_encryption((LinphoneCore*)lc,(LinphoneMediaEncryption)menc);
 }
 
-extern "C" int Java_org_linphone_core_LinphoneCallParamsImpl_getMediaEncryption(JNIEnv*  env
-                                                                                                                                                       ,jobject  thiz
-                                                                                                                                                       ,jlong cp
-                                                                                                                                                       ) {
-       return (int)linphone_call_params_get_media_encryption((LinphoneCallParams*)cp);
-}
-
 extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_mediaEncryptionSupported(JNIEnv*  env
                                                                                                                                                        ,jobject  thiz
                                                                                                                                                        ,jlong lc, jint menc
                                                                                                                                                        ) {
-       return linphone_core_media_encryption_supported((LinphoneCore*)lc,(LinphoneMediaEncryption)menc);
+       return (jboolean)linphone_core_media_encryption_supported((LinphoneCore*)lc,(LinphoneMediaEncryption)menc);
 }
 
-extern "C" void Java_org_linphone_core_LinphoneCallParamsImpl_setMediaEncryption(JNIEnv*  env
-                                                                                                                                                       ,jobject  thiz
-                                                                                                                                                       ,jlong cp
-                                                                                                                                                       ,int jmenc) {
-       linphone_call_params_set_media_encryption((LinphoneCallParams*)cp,(LinphoneMediaEncryption)jmenc);
-}
-
-extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_getMediaEncryptionMandatory(JNIEnv*  env
+extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_isMediaEncryptionMandatory(JNIEnv*  env
                                                                                                                                                        ,jobject  thiz
                                                                                                                                                        ,jlong lc
                                                                                                                                                        ) {
-       return linphone_core_is_media_encryption_mandatory((LinphoneCore*)lc);
+       return (jboolean)linphone_core_is_media_encryption_mandatory((LinphoneCore*)lc);
 }
 
 extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setMediaEncryptionMandatory(JNIEnv*  env
@@ -973,9 +1023,9 @@ extern "C" jstring Java_org_linphone_core_LinphoneProxyConfigImpl_getIdentity(JN
                return NULL;
        }
 }
-extern "C" int Java_org_linphone_core_LinphoneProxyConfigImpl_setProxy(JNIEnv* env,jobject thiz,jlong proxyCfg,jstring jproxy) {
+extern "C" jint Java_org_linphone_core_LinphoneProxyConfigImpl_setProxy(JNIEnv* env,jobject thiz,jlong proxyCfg,jstring jproxy) {
        const char* proxy = env->GetStringUTFChars(jproxy, NULL);
-       int err=linphone_proxy_config_set_server_addr((LinphoneProxyConfig*)proxyCfg,proxy);
+       jint err=linphone_proxy_config_set_server_addr((LinphoneProxyConfig*)proxyCfg,proxy);
        env->ReleaseStringUTFChars(jproxy, proxy);
        return err;
 }
@@ -992,14 +1042,14 @@ extern "C" void Java_org_linphone_core_LinphoneProxyConfigImpl_setContactParamet
        linphone_proxy_config_set_contact_parameters((LinphoneProxyConfig*)proxyCfg, params);
        env->ReleaseStringUTFChars(jparams, params);
 }
-extern "C" int Java_org_linphone_core_LinphoneProxyConfigImpl_setRoute(JNIEnv* env,jobject thiz,jlong proxyCfg,jstring jroute) {
+extern "C" jint Java_org_linphone_core_LinphoneProxyConfigImpl_setRoute(JNIEnv* env,jobject thiz,jlong proxyCfg,jstring jroute) {
        if (jroute != NULL) {
                const char* route = env->GetStringUTFChars(jroute, NULL);
-               int err=linphone_proxy_config_set_route((LinphoneProxyConfig*)proxyCfg,route);
+               jint err=linphone_proxy_config_set_route((LinphoneProxyConfig*)proxyCfg,route);
                env->ReleaseStringUTFChars(jroute, route);
                return err;
        } else {
-               return linphone_proxy_config_set_route((LinphoneProxyConfig*)proxyCfg,NULL);
+               return (jint)linphone_proxy_config_set_route((LinphoneProxyConfig*)proxyCfg,NULL);
        }
 }
 extern "C" jstring Java_org_linphone_core_LinphoneProxyConfigImpl_getRoute(JNIEnv* env,jobject thiz,jlong proxyCfg) {
@@ -1015,10 +1065,10 @@ extern "C" void Java_org_linphone_core_LinphoneProxyConfigImpl_enableRegister(JN
        linphone_proxy_config_enable_register((LinphoneProxyConfig*)proxyCfg,enableRegister);
 }
 extern "C" jboolean Java_org_linphone_core_LinphoneProxyConfigImpl_isRegistered(JNIEnv* env,jobject thiz,jlong proxyCfg) {
-       return linphone_proxy_config_is_registered((LinphoneProxyConfig*)proxyCfg);
+       return (jboolean)linphone_proxy_config_is_registered((LinphoneProxyConfig*)proxyCfg);
 }
 extern "C" jboolean Java_org_linphone_core_LinphoneProxyConfigImpl_isRegisterEnabled(JNIEnv* env,jobject thiz,jlong proxyCfg) {
-       return linphone_proxy_config_register_enabled((LinphoneProxyConfig*)proxyCfg);
+       return (jboolean)linphone_proxy_config_register_enabled((LinphoneProxyConfig*)proxyCfg);
 }
 extern "C" void Java_org_linphone_core_LinphoneProxyConfigImpl_edit(JNIEnv* env,jobject thiz,jlong proxyCfg) {
        linphone_proxy_config_edit((LinphoneProxyConfig*)proxyCfg);
@@ -1042,6 +1092,12 @@ extern "C" jstring Java_org_linphone_core_LinphoneProxyConfigImpl_normalizePhone
        env->ReleaseStringUTFChars(jnumber, number);
        return normalizedNumber;
 }
+extern "C" jint Java_org_linphone_core_LinphoneProxyConfigImpl_lookupCCCFromIso(JNIEnv* env, jobject thiz, jlong proxyCfg, jstring jiso) {
+       const char* iso = env->GetStringUTFChars(jiso, NULL);
+       int prefix = linphone_dial_plan_lookup_ccc_from_iso(iso);
+       env->ReleaseStringUTFChars(jiso, iso);
+       return (jint) prefix;
+}
 extern "C" jstring Java_org_linphone_core_LinphoneProxyConfigImpl_getDomain(JNIEnv* env
                                                                                                                                                        ,jobject thiz
                                                                                                                                                        ,jlong proxyCfg) {
@@ -1071,7 +1127,7 @@ extern "C" void Java_org_linphone_core_LinphoneProxyConfigImpl_enablePublish(JNI
        linphone_proxy_config_enable_publish((LinphoneProxyConfig*)proxyCfg,val);
 }
 extern "C" jboolean Java_org_linphone_core_LinphoneProxyConfigImpl_publishEnabled(JNIEnv* env,jobject thiz,jlong proxyCfg) {
-       return linphone_proxy_config_publish_enabled((LinphoneProxyConfig*)proxyCfg);
+       return (jboolean)linphone_proxy_config_publish_enabled((LinphoneProxyConfig*)proxyCfg);
 }
 
 //Auth Info
@@ -1085,11 +1141,17 @@ extern "C" jlong Java_org_linphone_core_LinphoneAuthInfoImpl_newLinphoneAuthInfo
                , jstring jrealm) {
 
        const char* username = env->GetStringUTFChars(jusername, NULL);
+       const char* userid = env->GetStringUTFChars(juserid, NULL);
        const char* password = env->GetStringUTFChars(jpassword, NULL);
-       jlong auth = (jlong)linphone_auth_info_new(username,NULL,password,NULL,NULL);
+       const char* ha1 = env->GetStringUTFChars(jha1, NULL);
+       const char* realm = env->GetStringUTFChars(jrealm, NULL);
+       jlong auth = (jlong)linphone_auth_info_new(username,userid,password,ha1,realm);
 
        env->ReleaseStringUTFChars(jusername, username);
+       env->ReleaseStringUTFChars(juserid, userid);
        env->ReleaseStringUTFChars(jpassword, password);
+       env->ReleaseStringUTFChars(jha1, ha1);
+       env->ReleaseStringUTFChars(jrealm, realm);
        return auth;
 
 }
@@ -1129,7 +1191,7 @@ extern "C" jstring Java_org_linphone_core_LinphoneAddressImpl_getDisplayName(JNI
        if (displayName) {
                return env->NewStringUTF(displayName);
        } else {
-               return 0;
+               return NULL;
        }
 }
 extern "C" jstring Java_org_linphone_core_LinphoneAddressImpl_getUserName(JNIEnv*  env
@@ -1139,7 +1201,7 @@ extern "C" jstring Java_org_linphone_core_LinphoneAddressImpl_getUserName(JNIEnv
        if (userName) {
                return env->NewStringUTF(userName);
        } else {
-               return 0;
+               return NULL;
        }
 }
 extern "C" jstring Java_org_linphone_core_LinphoneAddressImpl_getDomain(JNIEnv*  env
@@ -1149,7 +1211,7 @@ extern "C" jstring Java_org_linphone_core_LinphoneAddressImpl_getDomain(JNIEnv*
        if (domain) {
                return env->NewStringUTF(domain);
        } else {
-               return 0;
+               return NULL;
        }
 }
 
@@ -1185,10 +1247,10 @@ extern "C" jlong Java_org_linphone_core_LinphoneCallLogImpl_getFrom(JNIEnv*  env
                                                                                                                                                ,jlong ptr) {
        return (jlong)((LinphoneCallLog*)ptr)->from;
 }
-extern "C" int Java_org_linphone_core_LinphoneCallLogImpl_getStatus(JNIEnv*  env
+extern "C" jint Java_org_linphone_core_LinphoneCallLogImpl_getStatus(JNIEnv*  env
                                                                                                                                                ,jobject  thiz
                                                                                                                                                ,jlong ptr) {
-       return (jlong)((LinphoneCallLog*)ptr)->status;
+       return (jint)((LinphoneCallLog*)ptr)->status;
 }
 extern "C" jlong Java_org_linphone_core_LinphoneCallLogImpl_getTo(JNIEnv*  env
                                                                                                                                                ,jobject  thiz
@@ -1209,7 +1271,131 @@ extern "C" jstring Java_org_linphone_core_LinphoneCallLogImpl_getStartDate(JNIEn
 extern "C" jint Java_org_linphone_core_LinphoneCallLogImpl_getCallDuration(JNIEnv*  env
                                                                                                                                                ,jobject  thiz
                                                                                                                                                ,jlong ptr) {
-       return ((LinphoneCallLog*)ptr)->duration;
+       return (jint)((LinphoneCallLog*)ptr)->duration;
+}
+
+/* CallStats */
+extern "C" jint Java_org_linphone_core_LinphoneCallStatsImpl_getMediaType(JNIEnv *env, jobject thiz, jlong stats_ptr) {
+       return (jint)((LinphoneCallStats *)stats_ptr)->type;
+}
+extern "C" jint Java_org_linphone_core_LinphoneCallStatsImpl_getIceState(JNIEnv *env, jobject thiz, jlong stats_ptr) {
+       return (jint)((LinphoneCallStats *)stats_ptr)->ice_state;
+}
+extern "C" jfloat Java_org_linphone_core_LinphoneCallStatsImpl_getDownloadBandwidth(JNIEnv *env, jobject thiz, jlong stats_ptr) {
+       return (jfloat)((LinphoneCallStats *)stats_ptr)->download_bandwidth;
+}
+extern "C" jfloat Java_org_linphone_core_LinphoneCallStatsImpl_getUploadBandwidth(JNIEnv *env, jobject thiz, jlong stats_ptr) {
+       return (jfloat)((LinphoneCallStats *)stats_ptr)->upload_bandwidth;
+}
+extern "C" jfloat Java_org_linphone_core_LinphoneCallStatsImpl_getSenderLossRate(JNIEnv *env, jobject thiz, jlong stats_ptr) {
+       const LinphoneCallStats *stats = (LinphoneCallStats *)stats_ptr;
+       const report_block_t *srb = NULL;
+
+       if (!stats || !stats->sent_rtcp)
+               return (jfloat)0.0;
+       /* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several mblk_t structure */
+       if (stats->sent_rtcp->b_cont != NULL)
+               msgpullup(stats->sent_rtcp, -1);
+       if (rtcp_is_SR(stats->sent_rtcp))
+               srb = rtcp_SR_get_report_block(stats->sent_rtcp, 0);
+       else if (rtcp_is_RR(stats->sent_rtcp))
+               srb = rtcp_RR_get_report_block(stats->sent_rtcp, 0);
+       if (!srb)
+               return (jfloat)0.0;
+       return (jfloat)(100.0 * report_block_get_fraction_lost(srb) / 256.0);
+}
+extern "C" jfloat Java_org_linphone_core_LinphoneCallStatsImpl_getReceiverLossRate(JNIEnv *env, jobject thiz, jlong stats_ptr) {
+       const LinphoneCallStats *stats = (LinphoneCallStats *)stats_ptr;
+       const report_block_t *rrb = NULL;
+
+       if (!stats || !stats->received_rtcp)
+               return (jfloat)0.0;
+       /* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several mblk_t structure */
+       if (stats->received_rtcp->b_cont != NULL)
+               msgpullup(stats->received_rtcp, -1);
+       if (rtcp_is_RR(stats->received_rtcp))
+               rrb = rtcp_RR_get_report_block(stats->received_rtcp, 0);
+       else if (rtcp_is_SR(stats->received_rtcp))
+               rrb = rtcp_SR_get_report_block(stats->received_rtcp, 0);
+       if (!rrb)
+               return (jfloat)0.0;
+       return (jfloat)(100.0 * report_block_get_fraction_lost(rrb) / 256.0);
+}
+extern "C" jfloat Java_org_linphone_core_LinphoneCallStatsImpl_getSenderInterarrivalJitter(JNIEnv *env, jobject thiz, jlong stats_ptr, jlong call_ptr) {
+       LinphoneCallStats *stats = (LinphoneCallStats *)stats_ptr;
+       const LinphoneCall *call = (LinphoneCall *)call_ptr;
+       const LinphoneCallParams *params;
+       const PayloadType *pt;
+       const report_block_t *srb = NULL;
+
+       if (!stats || !call || !stats->sent_rtcp)
+               return (jfloat)0.0;
+       params = linphone_call_get_current_params(call);
+       if (!params)
+               return (jfloat)0.0;
+       /* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several mblk_t structure */
+       if (stats->sent_rtcp->b_cont != NULL)
+               msgpullup(stats->sent_rtcp, -1);
+       if (rtcp_is_SR(stats->sent_rtcp))
+               srb = rtcp_SR_get_report_block(stats->sent_rtcp, 0);
+       else if (rtcp_is_RR(stats->sent_rtcp))
+               srb = rtcp_RR_get_report_block(stats->sent_rtcp, 0);
+       if (!srb)
+               return (jfloat)0.0;
+       if (stats->type == LINPHONE_CALL_STATS_AUDIO)
+               pt = linphone_call_params_get_used_audio_codec(params);
+       else
+               pt = linphone_call_params_get_used_video_codec(params);
+       return (jfloat)((float)report_block_get_interarrival_jitter(srb) / (float)pt->clock_rate);
+}
+extern "C" jfloat Java_org_linphone_core_LinphoneCallStatsImpl_getReceiverInterarrivalJitter(JNIEnv *env, jobject thiz, jlong stats_ptr, jlong call_ptr) {
+       LinphoneCallStats *stats = (LinphoneCallStats *)stats_ptr;
+       const LinphoneCall *call = (LinphoneCall *)call_ptr;
+       const LinphoneCallParams *params;
+       const PayloadType *pt;
+       const report_block_t *rrb = NULL;
+
+       if (!stats || !call || !stats->received_rtcp)
+               return (jfloat)0.0;
+       params = linphone_call_get_current_params(call);
+       if (!params)
+               return (jfloat)0.0;
+       /* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several mblk_t structure */
+       if (stats->received_rtcp->b_cont != NULL)
+               msgpullup(stats->received_rtcp, -1);
+       if (rtcp_is_SR(stats->received_rtcp))
+               rrb = rtcp_SR_get_report_block(stats->received_rtcp, 0);
+       else if (rtcp_is_RR(stats->received_rtcp))
+               rrb = rtcp_RR_get_report_block(stats->received_rtcp, 0);
+       if (!rrb)
+               return (jfloat)0.0;
+       if (stats->type == LINPHONE_CALL_STATS_AUDIO)
+               pt = linphone_call_params_get_used_audio_codec(params);
+       else
+               pt = linphone_call_params_get_used_video_codec(params);
+       return (jfloat)((float)report_block_get_interarrival_jitter(rrb) / (float)pt->clock_rate);
+}
+extern "C" jfloat Java_org_linphone_core_LinphoneCallStatsImpl_getRoundTripDelay(JNIEnv *env, jobject thiz, jlong stats_ptr) {
+       return (jfloat)((LinphoneCallStats *)stats_ptr)->round_trip_delay;
+}
+extern "C" jlong Java_org_linphone_core_LinphoneCallStatsImpl_getLatePacketsCumulativeNumber(JNIEnv *env, jobject thiz, jlong stats_ptr, jlong call_ptr) {
+       LinphoneCallStats *stats = (LinphoneCallStats *)stats_ptr;
+       LinphoneCall *call = (LinphoneCall *)call_ptr;
+       rtp_stats_t rtp_stats;
+
+       if (!stats || !call)
+               return (jlong)0;
+       memset(&rtp_stats, 0, sizeof(rtp_stats));
+       if (stats->type == LINPHONE_CALL_STATS_AUDIO)
+               audio_stream_get_local_rtp_stats(call->audiostream, &rtp_stats);
+#ifdef VIDEO_ENABLED
+       else
+               video_stream_get_local_rtp_stats(call->videostream, &rtp_stats);
+#endif
+       return (jlong)rtp_stats.outoftime;
+}
+extern "C" jfloat Java_org_linphone_core_LinphoneCallStatsImpl_getJitterBufferSize(JNIEnv *env, jobject thiz, jlong stats_ptr) {
+       return (jfloat)((LinphoneCallStats *)stats_ptr)->jitter_stats.jitter_buffer_size_ms;
 }
 
 /*payloadType*/
@@ -1230,7 +1416,7 @@ extern "C" jstring Java_org_linphone_core_PayloadTypeImpl_getMime(JNIEnv*  env,j
 }
 extern "C" jint Java_org_linphone_core_PayloadTypeImpl_getRate(JNIEnv*  env,jobject  thiz, jlong ptr) {
        PayloadType* pt = (PayloadType*)ptr;
-       return payload_type_get_rate(pt);
+       return (jint)payload_type_get_rate(pt);
 }
 
 //LinphoneCall
@@ -1286,7 +1472,7 @@ extern "C" void Java_org_linphone_core_LinphoneCallImpl_enableEchoCancellation(
 extern "C" jboolean Java_org_linphone_core_LinphoneCallImpl_isEchoCancellationEnabled( JNIEnv*  env
                                                                                                                                                ,jobject  thiz
                                                                                                                                                ,jlong ptr) {
-       return linphone_call_echo_cancellation_enabled((LinphoneCall*)ptr);
+       return (jboolean)linphone_call_echo_cancellation_enabled((LinphoneCall*)ptr);
 }
 
 extern "C" void Java_org_linphone_core_LinphoneCallImpl_enableEchoLimiter(     JNIEnv*  env
@@ -1298,7 +1484,7 @@ extern "C" void Java_org_linphone_core_LinphoneCallImpl_enableEchoLimiter(        JNIEn
 extern "C" jboolean Java_org_linphone_core_LinphoneCallImpl_isEchoLimiterEnabled(      JNIEnv*  env
                                                                                                                                                ,jobject  thiz
                                                                                                                                                ,jlong ptr) {
-       return linphone_call_echo_limiter_enabled((LinphoneCall*)ptr);
+       return (jboolean)linphone_call_echo_limiter_enabled((LinphoneCall*)ptr);
 }
 
 extern "C" jobject Java_org_linphone_core_LinphoneCallImpl_getReplacedCall(    JNIEnv*  env
@@ -1322,7 +1508,7 @@ extern "C" jfloat Java_org_linphone_core_LinphoneCallImpl_getAverageQuality(      JNI
 
 
 //LinphoneFriend
-extern "C" long Java_org_linphone_core_LinphoneFriendImpl_newLinphoneFriend(JNIEnv*  env
+extern "C" jlong Java_org_linphone_core_LinphoneFriendImpl_newLinphoneFriend(JNIEnv*  env
                                                                                                                                                ,jobject  thiz
                                                                                                                                                ,jstring jFriendUri) {
        LinphoneFriend* lResult;
@@ -1334,7 +1520,7 @@ extern "C" long Java_org_linphone_core_LinphoneFriendImpl_newLinphoneFriend(JNIE
        } else {
                lResult = linphone_friend_new();
        }
-       return (long)lResult;
+       return (jlong)lResult;
 }
 extern "C" void Java_org_linphone_core_LinphoneFriendImpl_setAddress(JNIEnv*  env
                                                                                                                                                ,jobject  thiz
@@ -1342,10 +1528,10 @@ extern "C" void Java_org_linphone_core_LinphoneFriendImpl_setAddress(JNIEnv*  en
                                                                                                                                                ,jlong linphoneAddress) {
        linphone_friend_set_addr((LinphoneFriend*)ptr,(LinphoneAddress*)linphoneAddress);
 }
-extern "C" long Java_org_linphone_core_LinphoneFriendImpl_getAddress(JNIEnv*  env
+extern "C" jlong Java_org_linphone_core_LinphoneFriendImpl_getAddress(JNIEnv*  env
                                                                                                                                                ,jobject  thiz
                                                                                                                                                ,jlong ptr) {
-       return (long)linphone_friend_get_address((LinphoneFriend*)ptr);
+       return (jlong)linphone_friend_get_address((LinphoneFriend*)ptr);
 }
 extern "C" void Java_org_linphone_core_LinphoneFriendImpl_setIncSubscribePolicy(JNIEnv*  env
                                                                                                                                                ,jobject  thiz
@@ -1356,7 +1542,7 @@ extern "C" void Java_org_linphone_core_LinphoneFriendImpl_setIncSubscribePolicy(
 extern "C" jint Java_org_linphone_core_LinphoneFriendImpl_getIncSubscribePolicy(JNIEnv*  env
                                                                                                                                                ,jobject  thiz
                                                                                                                                                ,jlong ptr) {
-       return linphone_friend_get_inc_subscribe_policy((LinphoneFriend*)ptr);
+       return (jint)linphone_friend_get_inc_subscribe_policy((LinphoneFriend*)ptr);
 }
 extern "C" void Java_org_linphone_core_LinphoneFriendImpl_enableSubscribes(JNIEnv*  env
                                                                                                                                                ,jobject  thiz
@@ -1367,12 +1553,12 @@ extern "C" void Java_org_linphone_core_LinphoneFriendImpl_enableSubscribes(JNIEn
 extern "C" jboolean Java_org_linphone_core_LinphoneFriendImpl_isSubscribesEnabled(JNIEnv*  env
                                                                                                                                                ,jobject  thiz
                                                                                                                                                ,jlong ptr) {
-       return linphone_friend_subscribes_enabled((LinphoneFriend*)ptr);
+       return (jboolean)linphone_friend_subscribes_enabled((LinphoneFriend*)ptr);
 }
-extern "C" jboolean Java_org_linphone_core_LinphoneFriendImpl_getStatus(JNIEnv*  env
+extern "C" jint Java_org_linphone_core_LinphoneFriendImpl_getStatus(JNIEnv*  env
                                                                                                                                                ,jobject  thiz
                                                                                                                                                ,jlong ptr) {
-       return linphone_friend_get_status((LinphoneFriend*)ptr);
+       return (jint)linphone_friend_get_status((LinphoneFriend*)ptr);
 }
 extern "C" void Java_org_linphone_core_LinphoneFriendImpl_edit(JNIEnv*  env
                                                                                                                                                ,jobject  thiz
@@ -1384,11 +1570,26 @@ extern "C" void Java_org_linphone_core_LinphoneFriendImpl_done(JNIEnv*  env
                                                                                                                                                ,jlong ptr) {
         linphone_friend_done((LinphoneFriend*)ptr);
 }
+extern "C" void Java_org_linphone_core_LinphoneCoreImpl_removeFriend(JNIEnv*  env
+                                                                                                                                               ,jobject  thiz
+                                                                                                                                               ,jlong ptr
+                                                                                                                                               ,jlong lf) {
+       linphone_core_remove_friend((LinphoneCore*)ptr, (LinphoneFriend*)lf);
+}
+extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_getFriendByAddress(JNIEnv*  env
+                                                                                                                                               ,jobject  thiz
+                                                                                                                                               ,jlong ptr
+                                                                                                                                               ,jstring jaddress) {
+       const char* address = env->GetStringUTFChars(jaddress, NULL);
+       LinphoneFriend *lf = linphone_core_get_friend_by_address((LinphoneCore*)ptr, address);
+       env->ReleaseStringUTFChars(jaddress, address);
+       return (jlong) lf;
+}
 //LinphoneChatRoom
-extern "C" long Java_org_linphone_core_LinphoneChatRoomImpl_getPeerAddress(JNIEnv*  env
+extern "C" jlong Java_org_linphone_core_LinphoneChatRoomImpl_getPeerAddress(JNIEnv*  env
                                                                                                                                                ,jobject  thiz
                                                                                                                                                ,jlong ptr) {
-       return (long) linphone_chat_room_get_peer_address((LinphoneChatRoom*)ptr);
+       return (jlong) linphone_chat_room_get_peer_address((LinphoneChatRoom*)ptr);
 }
 extern "C" jlong Java_org_linphone_core_LinphoneChatRoomImpl_createLinphoneChatMessage(JNIEnv*  env
                                                                                                                                                ,jobject  thiz
@@ -1426,10 +1627,15 @@ extern "C" void Java_org_linphone_core_LinphoneChatMessageImpl_setExternalBodyUr
        linphone_chat_message_set_external_body_url((LinphoneChatMessage *)ptr, url);
        env->ReleaseStringUTFChars(jurl, url);
 }
-extern "C" long Java_org_linphone_core_LinphoneChatMessageImpl_getPeerAddress(JNIEnv*  env
+extern "C" jlong Java_org_linphone_core_LinphoneChatMessageImpl_getFrom(JNIEnv*  env
+                                                                                                                                               ,jobject  thiz
+                                                                                                                                               ,jlong ptr) {
+       return (jlong) linphone_chat_message_get_from((LinphoneChatMessage*)ptr);
+}
+extern "C" jlong Java_org_linphone_core_LinphoneChatMessageImpl_getPeerAddress(JNIEnv*  env
                                                                                                                                                ,jobject  thiz
                                                                                                                                                ,jlong ptr) {
-       return (long) linphone_chat_message_get_peer_address((LinphoneChatMessage*)ptr);
+       return (jlong) linphone_chat_message_get_peer_address((LinphoneChatMessage*)ptr);
 }
 extern "C" void Java_org_linphone_core_LinphoneChatRoomImpl_sendMessage(JNIEnv*  env
                                                                                                                                                ,jobject  thiz
@@ -1508,12 +1714,12 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setDeviceRotation(JNIEnv
 }
 
 
-extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setFirewallPolicy(JNIEnv *env, jobject thiz, jlong lc, int enum_value){
+extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setFirewallPolicy(JNIEnv *env, jobject thiz, jlong lc, jint enum_value){
        linphone_core_set_firewall_policy((LinphoneCore*)lc,(LinphoneFirewallPolicy)enum_value);
 }
 
 extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_getFirewallPolicy(JNIEnv *env, jobject thiz, jlong lc){
-       return linphone_core_get_firewall_policy((LinphoneCore*)lc);
+       return (jint)linphone_core_get_firewall_policy((LinphoneCore*)lc);
 }
 
 extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setStunServer(JNIEnv *env, jobject thiz, jlong lc, jstring jserver){
@@ -1530,6 +1736,30 @@ extern "C" jstring Java_org_linphone_core_LinphoneCoreImpl_getStunServer(JNIEnv
        return jvalue;
 }
 
+//CallParams
+
+extern "C" jlong Java_org_linphone_core_LinphoneCallParamsImpl_getUsedAudioCodec(JNIEnv *env, jobject thiz, jlong cp) {
+       return (jlong)linphone_call_params_get_used_audio_codec((LinphoneCallParams *)cp);
+}
+
+extern "C" jlong Java_org_linphone_core_LinphoneCallParamsImpl_getUsedVideoCodec(JNIEnv *env, jobject thiz, jlong cp) {
+       return (jlong)linphone_call_params_get_used_video_codec((LinphoneCallParams *)cp);
+}
+
+extern "C" jint Java_org_linphone_core_LinphoneCallParamsImpl_getMediaEncryption(JNIEnv*  env
+                                                                                                                                                       ,jobject  thiz
+                                                                                                                                                       ,jlong cp
+                                                                                                                                                       ) {
+       return (jint)linphone_call_params_get_media_encryption((LinphoneCallParams*)cp);
+}
+
+extern "C" void Java_org_linphone_core_LinphoneCallParamsImpl_setMediaEncryption(JNIEnv*  env
+                                                                                                                                                       ,jobject  thiz
+                                                                                                                                                       ,jlong cp
+                                                                                                                                                       ,jint jmenc) {
+       linphone_call_params_set_media_encryption((LinphoneCallParams*)cp,(LinphoneMediaEncryption)jmenc);
+}
+
 extern "C" void Java_org_linphone_core_LinphoneCallParamsImpl_audioBandwidth(JNIEnv *env, jobject thiz, jlong lcp, jint bw){
        linphone_call_params_set_audio_bandwidth_limit((LinphoneCallParams*)lcp, bw);
 }
@@ -1539,11 +1769,11 @@ extern "C" void Java_org_linphone_core_LinphoneCallParamsImpl_enableVideo(JNIEnv
 }
 
 extern "C" jboolean Java_org_linphone_core_LinphoneCallParamsImpl_getVideoEnabled(JNIEnv *env, jobject thiz, jlong lcp){
-       return linphone_call_params_video_enabled((LinphoneCallParams*)lcp);
+       return (jboolean)linphone_call_params_video_enabled((LinphoneCallParams*)lcp);
 }
 
 extern "C" jboolean Java_org_linphone_core_LinphoneCallParamsImpl_localConferenceMode(JNIEnv *env, jobject thiz, jlong lcp){
-       return linphone_call_params_local_conference_mode((LinphoneCallParams*)lcp);
+       return (jboolean)linphone_call_params_local_conference_mode((LinphoneCallParams*)lcp);
 }
 
 extern "C" void Java_org_linphone_core_LinphoneCallParamsImpl_destroy(JNIEnv *env, jobject thiz, jlong lc){
@@ -1554,6 +1784,9 @@ extern "C" jlong Java_org_linphone_core_LinphoneCoreImpl_createDefaultCallParams
 }
 
 extern "C" jlong Java_org_linphone_core_LinphoneCallImpl_getRemoteParams(JNIEnv *env, jobject thiz, jlong lc){
+       if (linphone_call_get_remote_params((LinphoneCall*)lc) == NULL) {
+                       return (jlong) 0;
+       }
        return (jlong) linphone_call_params_copy(linphone_call_get_remote_params((LinphoneCall*)lc));
 }
 
@@ -1561,12 +1794,12 @@ extern "C" jlong Java_org_linphone_core_LinphoneCallImpl_getCurrentParamsCopy(JN
        return (jlong) linphone_call_params_copy(linphone_call_get_current_params((LinphoneCall*)lc));
 }
 
-extern "C" jlong Java_org_linphone_core_LinphoneCallImpl_enableCamera(JNIEnv *env, jobject thiz, jlong lc, jboolean b){
+extern "C" void Java_org_linphone_core_LinphoneCallImpl_enableCamera(JNIEnv *env, jobject thiz, jlong lc, jboolean b){
        linphone_call_enable_camera((LinphoneCall *)lc, (bool_t) b);
 }
 
 extern "C" jboolean Java_org_linphone_core_LinphoneCallImpl_cameraEnabled(JNIEnv *env, jobject thiz, jlong lc){
-       linphone_call_camera_enabled((LinphoneCall *)lc);
+       return (jboolean)linphone_call_camera_enabled((LinphoneCall *)lc);
 }
 
 extern "C" jobject Java_org_linphone_core_LinphoneCoreImpl_inviteAddressWithParams(JNIEnv *env, jobject thiz, jlong lc, jlong addr, jlong params){
@@ -1614,15 +1847,15 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setUploadPtime(JNIEnv *e
        linphone_core_set_upload_ptime((LinphoneCore *)lc, (int) ptime);
 }
 
-extern "C" int Java_org_linphone_core_LinphoneProxyConfigImpl_getState(JNIEnv*  env,jobject thiz,jlong ptr) {
-       return (int) linphone_proxy_config_get_state((const LinphoneProxyConfig *) ptr);
+extern "C" jint Java_org_linphone_core_LinphoneProxyConfigImpl_getState(JNIEnv*  env,jobject thiz,jlong ptr) {
+       return (jint) linphone_proxy_config_get_state((const LinphoneProxyConfig *) ptr);
 }
 extern "C" void Java_org_linphone_core_LinphoneProxyConfigImpl_setExpires(JNIEnv*  env,jobject thiz,jlong ptr,jint delay) {
        linphone_proxy_config_expires((LinphoneProxyConfig *) ptr, (int) delay);
 }
 
 extern "C" jint Java_org_linphone_core_LinphoneCallImpl_getDuration(JNIEnv*  env,jobject thiz,jlong ptr) {
-       linphone_call_get_duration((LinphoneCall *) ptr);
+       return (jint)linphone_call_get_duration((LinphoneCall *) ptr);
 }
 
 extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_getSignalingTransportPort(JNIEnv* env,jobject thiz,jlong ptr, jint code) {
@@ -1661,19 +1894,19 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_adjustSoftwareVolume(JNI
 }
 
 extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_pauseCall(JNIEnv *env,jobject thiz,jlong pCore, jlong pCall) {
-       return linphone_core_pause_call((LinphoneCore *) pCore, (LinphoneCall *) pCall);
+       return (jint)linphone_core_pause_call((LinphoneCore *) pCore, (LinphoneCall *) pCall);
 }
 extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_pauseAllCalls(JNIEnv *env,jobject thiz,jlong pCore) {
-       return linphone_core_pause_all_calls((LinphoneCore *) pCore);
+       return (jint)linphone_core_pause_all_calls((LinphoneCore *) pCore);
 }
 extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_resumeCall(JNIEnv *env,jobject thiz,jlong pCore, jlong pCall) {
-       return linphone_core_resume_call((LinphoneCore *) pCore, (LinphoneCall *) pCall);
+       return (jint)linphone_core_resume_call((LinphoneCore *) pCore, (LinphoneCall *) pCall);
 }
 extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_isInConference(JNIEnv *env,jobject thiz,jlong pCore) {
-       return linphone_core_is_in_conference((LinphoneCore *) pCore);
+       return (jboolean)linphone_core_is_in_conference((LinphoneCore *) pCore);
 }
 extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_enterConference(JNIEnv *env,jobject thiz,jlong pCore) {
-       return 0 == linphone_core_enter_conference((LinphoneCore *) pCore);
+       return (jboolean)(0 == linphone_core_enter_conference((LinphoneCore *) pCore));
 }
 extern "C" void Java_org_linphone_core_LinphoneCoreImpl_leaveConference(JNIEnv *env,jobject thiz,jlong pCore) {
        linphone_core_leave_conference((LinphoneCore *) pCore);
@@ -1692,7 +1925,7 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_terminateConference(JNIE
        linphone_core_terminate_conference((LinphoneCore *) pCore);
 }
 extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_getConferenceSize(JNIEnv *env,jobject thiz,jlong pCore) {
-       return linphone_core_get_conference_size((LinphoneCore *) pCore);
+       return (jint)linphone_core_get_conference_size((LinphoneCore *) pCore);
 }
 extern "C" void Java_org_linphone_core_LinphoneCoreImpl_terminateAllCalls(JNIEnv *env,jobject thiz,jlong pCore) {
        linphone_core_terminate_all_calls((LinphoneCore *) pCore);
@@ -1703,16 +1936,17 @@ extern "C" jobject Java_org_linphone_core_LinphoneCoreImpl_getCall(JNIEnv *env,j
        return lcd->getCall(env,lCall);
 }
 extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_getCallsNb(JNIEnv *env,jobject thiz,jlong pCore) {
-       return ms_list_size(linphone_core_get_calls((LinphoneCore *) pCore));
+       return (jint)ms_list_size(linphone_core_get_calls((LinphoneCore *) pCore));
 }
 
-extern "C" void Java_org_linphone_core_LinphoneCoreImpl_transferCall(JNIEnv *env,jobject thiz,jlong pCore, jlong pCall, jstring jReferTo) {
+extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_transferCall(JNIEnv *env,jobject thiz,jlong pCore, jlong pCall, jstring jReferTo) {
        const char* cReferTo=env->GetStringUTFChars(jReferTo, NULL);
-       linphone_core_transfer_call((LinphoneCore *) pCore, (LinphoneCall *) pCall, cReferTo);
+       jint err = linphone_core_transfer_call((LinphoneCore *) pCore, (LinphoneCall *) pCall, cReferTo);
        env->ReleaseStringUTFChars(jReferTo, cReferTo);
+       return err;
 }
-extern "C" void Java_org_linphone_core_LinphoneCoreImpl_transferCallToAnother(JNIEnv *env,jobject thiz,jlong pCore, jlong pCall, jlong pDestCall) {
-       linphone_core_transfer_call_to_another((LinphoneCore *) pCore, (LinphoneCall *) pCall, (LinphoneCall *) pDestCall);
+extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_transferCallToAnother(JNIEnv *env,jobject thiz,jlong pCore, jlong pCall, jlong pDestCall) {
+       return (jint)linphone_core_transfer_call_to_another((LinphoneCore *) pCore, (LinphoneCall *) pCall, (LinphoneCall *) pDestCall);
 }
 
 extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setZrtpSecretsCache(JNIEnv *env,jobject thiz,jlong pCore, jstring jFile) {
@@ -1747,7 +1981,7 @@ extern "C" jint Java_org_linphone_core_LinphoneCoreImpl_setVideoDevice(JNIEnv *e
                        break;
                ms_message("Existing device %d : %s\n", i, devices[i]);
                if (i==id) {
-                       return linphone_core_set_video_device(lc, devices[i]);
+                       return (jint)linphone_core_set_video_device(lc, devices[i]);
                }
        }
        return -1;
@@ -1783,7 +2017,7 @@ extern "C" jstring Java_org_linphone_core_LinphoneCallImpl_getAuthenticationToke
 }
 extern "C" jboolean Java_org_linphone_core_LinphoneCallImpl_isAuthenticationTokenVerified(JNIEnv*  env,jobject thiz,jlong ptr) {
        LinphoneCall *call = (LinphoneCall *) ptr;
-       return linphone_call_get_authentication_token_verified(call);
+       return (jboolean)linphone_call_get_authentication_token_verified(call);
 }
 extern "C" void Java_org_linphone_core_LinphoneCallImpl_setAuthenticationTokenVerified(JNIEnv*  env,jobject thiz,jlong ptr,jboolean verified) {
        LinphoneCall *call = (LinphoneCall *) ptr;
@@ -1792,11 +2026,11 @@ extern "C" void Java_org_linphone_core_LinphoneCallImpl_setAuthenticationTokenVe
 
 extern "C" jfloat Java_org_linphone_core_LinphoneCallImpl_getPlayVolume(JNIEnv* env, jobject thiz, jlong ptr) {
        LinphoneCall *call = (LinphoneCall *) ptr;
-       return linphone_call_get_play_volume(call);
+       return (jfloat)linphone_call_get_play_volume(call);
 }
 
 extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_soundResourcesLocked(JNIEnv* env,jobject thiz,jlong ptr){
-       return linphone_core_sound_resources_locked((LinphoneCore *) ptr);
+       return (jboolean)linphone_core_sound_resources_locked((LinphoneCore *) ptr);
 }
 
 // Needed by Galaxy S (can't switch to/from speaker while playing and still keep mic working)
@@ -1866,7 +2100,7 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setUserAgent(JNIEnv *env
 }
 
 extern "C" jboolean Java_org_linphone_core_LinphoneCoreImpl_isTunnelAvailable(JNIEnv *env,jobject thiz){
-       return linphone_core_tunnel_available();
+       return (jboolean)linphone_core_tunnel_available();
 }
 
 extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setVideoPolicy(JNIEnv *env, jobject thiz, jlong lc, jboolean autoInitiate, jboolean autoAccept){
@@ -1880,6 +2114,26 @@ extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setCpuCountNative(JNIEnv
        ms_set_cpu_count(count);
 }
 
+extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setAudioPort(JNIEnv *env, jobject thiz, jlong lc, jint port) {
+       linphone_core_set_audio_port((LinphoneCore *)lc, port);
+}
+
+extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setVideoPort(JNIEnv *env, jobject thiz, jlong lc, jint port) {
+       linphone_core_set_video_port((LinphoneCore *)lc, port);
+}
+
+extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setAudioPortRange(JNIEnv *env, jobject thiz, jlong lc, jint min_port, jint max_port) {
+       linphone_core_set_audio_port_range((LinphoneCore *)lc, min_port, max_port);
+}
+
+extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setVideoPortRange(JNIEnv *env, jobject thiz, jlong lc, jint min_port, jint max_port) {
+       linphone_core_set_video_port_range((LinphoneCore *)lc, min_port, max_port);
+}
+
+extern "C" void Java_org_linphone_core_LinphoneCoreImpl_setIncomingTimeout(JNIEnv *env, jobject thiz, jlong lc, jint timeout) {
+       linphone_core_set_inc_timeout((LinphoneCore *)lc, timeout);
+}
+
 extern "C" jstring Java_org_linphone_core_LinphoneCoreImpl_getVersion(JNIEnv*  env,jobject  thiz,jlong ptr) {
        jstring jvalue =env->NewStringUTF(linphone_core_get_version());
        return jvalue;
index 9643856832fae7d3c4fce6ff24e0db0e527a748c..fadfc1a3608bb25cf559c39927ecba02b488ac61 100644 (file)
@@ -56,9 +56,10 @@ void linphone_sound_daemon_destroy(LinphoneSoundDaemon *obj);
  * Enum describing the result of the echo canceller calibration process.
 **/
 typedef enum {
-       LinphoneEcCalibratorInProgress,
-       LinphoneEcCalibratorDone,
-       LinphoneEcCalibratorFailed
+       LinphoneEcCalibratorInProgress, /**< The echo canceller calibration process is on going. */
+       LinphoneEcCalibratorDone,       /**< The echo canceller calibration has been performed and produced an echo delay measure. */
+       LinphoneEcCalibratorFailed,     /**< The echo canceller calibration process has failed. */
+       LinphoneEcCalibratorDoneNoEcho  /**< The echo canceller calibration has been performed and no echo has been detected. */
 }LinphoneEcCalibratorStatus;
 
 
index 0efdc335e529e77777e369503b95801a1d1e3edc..bd2adfbb48147fdc02e04e064d71f05a97ea27c6 100644 (file)
@@ -184,10 +184,10 @@ void lp_config_parse(LpConfig *lpconfig, FILE *file){
                                        if (pos2==NULL) pos2=pos1+strlen(pos1);
                                        else {
                                                *pos2='\0'; /*replace the '\n' */
-                                               pos2--;
                                        }
                                        /* remove ending white spaces */
-                                       for (; pos2>pos1 && *pos2==' ';pos2--) *pos2='\0';
+                                       for (; pos2>pos1 && pos2[-1]==' ';pos2--) pos2[-1]='\0';
+
                                        if (pos2-pos1>=0){
                                                /* found a pair key,value */
                                                if (cur!=NULL){
@@ -198,7 +198,7 @@ void lp_config_parse(LpConfig *lpconfig, FILE *file){
                                                                ms_free(item->value);
                                                                item->value=strdup(pos1);
                                                        }
-                                                       /*printf("Found %s %s=%s\n",cur->name,key,pos1);*/
+                                                       /*printf("Found %s %s={%s}\n",cur->name,key,pos1);*/
                                                }else{
                                                        ms_warning("found key,item but no sections");
                                                }
@@ -271,6 +271,25 @@ const char *lp_config_get_string(LpConfig *lpconfig, const char *section, const
        return default_string;
 }
 
+bool_t lp_config_get_range(LpConfig *lpconfig, const char *section, const char *key, int *min, int *max, int default_min, int default_max) {
+       const char *str = lp_config_get_string(lpconfig, section, key, NULL);
+       if (str != NULL) {
+               char *minusptr = strchr(str, '-');
+               if ((minusptr == NULL) || (minusptr == str)) {
+                       *min = default_min;
+                       *max = default_max;
+                       return FALSE;
+               }
+               *min = atoi(str);
+               *max = atoi(minusptr + 1);
+               return TRUE;
+       } else {
+               *min = default_min;
+               *max = default_max;
+               return TRUE;
+       }
+}
+
 int lp_config_get_int(LpConfig *lpconfig,const char *section, const char *key, int default_value){
        const char *str=lp_config_get_string(lpconfig,section,key,NULL);
        if (str!=NULL) {
@@ -324,6 +343,12 @@ void lp_config_set_string(LpConfig *lpconfig,const char *section, const char *ke
        lpconfig->modified++;
 }
 
+void lp_config_set_range(LpConfig *lpconfig, const char *section, const char *key, int min_value, int max_value) {
+       char tmp[30];
+       snprintf(tmp, sizeof(tmp), "%i-%i", min_value, max_value);
+       lp_config_set_string(lpconfig, section, key, tmp);
+}
+
 void lp_config_set_int(LpConfig *lpconfig,const char *section, const char *key, int value){
        char tmp[30];
        snprintf(tmp,sizeof(tmp),"%i",value);
index a27f7e39a28327ed54fd12ea34f6b6b02a26434f..8f3cae0a11bcbbd11bf401052ed4d6227bfb9dda 100644 (file)
@@ -49,6 +49,20 @@ typedef struct _LpConfig LpConfig;
 extern "C" {
 #endif
 
+
+#define LP_CONFIG_DEFAULT_STRING(config, name, default) \
+       (config) ? (lp_config_get_string(config, "default_values", name, default)) : (default)
+
+#define LP_CONFIG_DEFAULT_INT(config, name, default) \
+       (config) ? (lp_config_get_int(config, "default_values", name, default)) : (default)
+
+#define LP_CONFIG_DEFAULT_INT64(config, name, default) \
+       (config) ? (lp_config_get_int64(config, "default_values", name, default)) : (default)
+
+#define LP_CONFIG_DEFAULT_FLOAT(config, name, default) \
+       (config) ? (lp_config_get_float(config, "default_values", name, default)) : (default)
+
+
 LpConfig * lp_config_new(const char *filename);
 int lp_config_read_file(LpConfig *lpconfig, const char *filename);
 /**
@@ -59,6 +73,14 @@ int lp_config_read_file(LpConfig *lpconfig, const char *filename);
 **/
 const char *lp_config_get_string(LpConfig *lpconfig, const char *section, const char *key, const char *default_string);
 int lp_config_read_file(LpConfig *lpconfig, const char *filename);
+/**
+ * Retrieves a configuration item as a range, given its section, key, and default min and max values.
+ *
+ * @ingroup misc
+ * @return TRUE if the value is successfully parsed as a range, FALSE otherwise.
+ * If FALSE is returned, min and max are filled respectively with default_min and default_max values.
+ */
+bool_t lp_config_get_range(LpConfig *lpconfig, const char *section, const char *key, int *min, int *max, int default_min, int default_max);
 /**
  * Retrieves a configuration item as an integer, given its section, key, and default value.
  * 
@@ -90,6 +112,12 @@ float lp_config_get_float(LpConfig *lpconfig,const char *section, const char *ke
  * @ingroup misc
 **/
 void lp_config_set_string(LpConfig *lpconfig,const char *section, const char *key, const char *value);
+/**
+ * Sets a range config item
+ *
+ * @ingroup misc
+ */
+void lp_config_set_range(LpConfig *lpconfig, const char *section, const char *key, int min_value, int max_value);
 /**
  * Sets an integer config item
  *
index 1e7676bfae7b035a13f1da80c15f6058b069f677..b9176ebd4ab65ef0f3ca5a7277411f9027b318a2 100644 (file)
@@ -467,8 +467,10 @@ static int recvStunResponse(ortp_socket_t sock, char *ipaddr, int *port, int *id
 }
 
 /* this functions runs a simple stun test and return the number of milliseconds to complete the tests, or -1 if the test were failed.*/
-int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call, StunCandidate *ac, StunCandidate *vc){
+int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call){
        const char *server=linphone_core_get_stun_server(lc);
+       StunCandidate *ac=&call->ac;
+       StunCandidate *vc=&call->vc;
        
        if (lc->sip_conf.ipv6_enabled){
                ms_warning("stun support is not implemented for ipv6");
@@ -584,7 +586,7 @@ void linphone_core_adapt_to_network(LinphoneCore *lc, int ping_time_ms, Linphone
                        params->up_bw=params->down_bw=edge_bw;
                        params->up_ptime=params->down_ptime=edge_ptime;
                        params->has_video=FALSE;
-                       
+                       params->low_bandwidth=TRUE;
                }/*else use default settings */
        }
 }
@@ -618,15 +620,20 @@ int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call)
                lc->vtable.display_status(lc, _("ICE local candidates gathering in progress..."));
 
        /* Gather local host candidates. */
-       if (linphone_core_get_local_ip_for(AF_INET, NULL, local_addr) < 0) {
+       if (linphone_core_get_local_ip_for(AF_INET, server, local_addr) < 0) {
                ms_error("Fail to get local ip");
                return -1;
        }
-       ice_add_local_candidate(audio_check_list, "host", local_addr, call->audio_port, 1, NULL);
-       ice_add_local_candidate(audio_check_list, "host", local_addr, call->audio_port + 1, 2, NULL);
-       if (call->params.has_video && (video_check_list != NULL)) {
+       if ((ice_check_list_state(audio_check_list) != ICL_Completed) && (ice_check_list_candidates_gathered(audio_check_list) == FALSE)) {
+               ice_add_local_candidate(audio_check_list, "host", local_addr, call->audio_port, 1, NULL);
+               ice_add_local_candidate(audio_check_list, "host", local_addr, call->audio_port + 1, 2, NULL);
+               call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateInProgress;
+       }
+       if (call->params.has_video && (video_check_list != NULL)
+               && (ice_check_list_state(video_check_list) != ICL_Completed) && (ice_check_list_candidates_gathered(video_check_list) == FALSE)) {
                ice_add_local_candidate(video_check_list, "host", local_addr, call->video_port, 1, NULL);
                ice_add_local_candidate(video_check_list, "host", local_addr, call->video_port + 1, 2, NULL);
+               call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateInProgress;
        }
 
        ms_message("ICE: gathering candidate from [%s]",server);
@@ -635,6 +642,66 @@ int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call)
        return 0;
 }
 
+void linphone_core_update_ice_state_in_call_stats(LinphoneCall *call)
+{
+       IceCheckList *audio_check_list;
+       IceCheckList *video_check_list;
+       IceSessionState session_state;
+
+       if (call->ice_session == NULL) return;
+       audio_check_list = ice_session_check_list(call->ice_session, 0);
+       video_check_list = ice_session_check_list(call->ice_session, 1);
+       if (audio_check_list == NULL) return;
+
+       session_state = ice_session_state(call->ice_session);
+       if ((session_state == IS_Completed) || ((session_state == IS_Failed) && (ice_session_has_completed_check_list(call->ice_session) == TRUE))) {
+               if (ice_check_list_state(audio_check_list) == ICL_Completed) {
+                       switch (ice_check_list_selected_valid_candidate_type(audio_check_list)) {
+                               case ICT_HostCandidate:
+                                       call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateHostConnection;
+                                       break;
+                               case ICT_ServerReflexiveCandidate:
+                               case ICT_PeerReflexiveCandidate:
+                                       call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateReflexiveConnection;
+                                       break;
+                               case ICT_RelayedCandidate:
+                                       call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateRelayConnection;
+                                       break;
+                       }
+               } else {
+                       call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateFailed;
+               }
+               if (call->params.has_video && (video_check_list != NULL)) {
+                       if (ice_check_list_state(video_check_list) == ICL_Completed) {
+                               switch (ice_check_list_selected_valid_candidate_type(video_check_list)) {
+                                       case ICT_HostCandidate:
+                                               call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateHostConnection;
+                                               break;
+                                       case ICT_ServerReflexiveCandidate:
+                                       case ICT_PeerReflexiveCandidate:
+                                               call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateReflexiveConnection;
+                                               break;
+                                       case ICT_RelayedCandidate:
+                                               call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateRelayConnection;
+                                               break;
+                               }
+                       } else {
+                               call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateFailed;
+                       }
+               }
+       } else if (session_state == IS_Running) {
+               call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateInProgress;
+               if (call->params.has_video && (video_check_list != NULL)) {
+                       call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateInProgress;
+               }
+       } else {
+               call->stats[LINPHONE_CALL_STATS_AUDIO].ice_state = LinphoneIceStateFailed;
+               if (call->params.has_video && (video_check_list != NULL)) {
+                       call->stats[LINPHONE_CALL_STATS_VIDEO].ice_state = LinphoneIceStateFailed;
+               }
+       }
+}
+
 void linphone_core_update_local_media_description_from_ice(SalMediaDescription *desc, IceSession *session)
 {
        const char *rtp_addr, *rtcp_addr;
@@ -645,8 +712,12 @@ void linphone_core_update_local_media_description_from_ice(SalMediaDescription *
 
        if (session_state == IS_Completed) {
                desc->ice_completed = TRUE;
-               ice_check_list_selected_valid_local_candidate(ice_session_check_list(session, 0), &rtp_addr, NULL, NULL, NULL);
-               strncpy(desc->addr, rtp_addr, sizeof(desc->addr));
+               result = ice_check_list_selected_valid_local_candidate(ice_session_check_list(session, 0), &rtp_addr, NULL, NULL, NULL);
+               if (result == TRUE) {
+                       strncpy(desc->addr, rtp_addr, sizeof(desc->addr));
+               } else {
+                       ms_warning("If ICE has completed successfully, rtp_addr should be set!");
+               }
        }
        else {
                desc->ice_completed = FALSE;
@@ -716,11 +787,19 @@ void linphone_core_update_local_media_description_from_ice(SalMediaDescription *
                if ((ice_check_list_state(cl) == ICL_Completed) && (ice_session_role(session) == IR_Controlling)) {
                        int rtp_port, rtcp_port;
                        memset(stream->ice_remote_candidates, 0, sizeof(stream->ice_remote_candidates));
-                       ice_check_list_selected_valid_remote_candidate(cl, &rtp_addr, &rtp_port, &rtcp_addr, &rtcp_port);
-                       strncpy(stream->ice_remote_candidates[0].addr, rtp_addr, sizeof(stream->ice_remote_candidates[0].addr));
-                       stream->ice_remote_candidates[0].port = rtp_port;
-                       strncpy(stream->ice_remote_candidates[1].addr, rtcp_addr, sizeof(stream->ice_remote_candidates[1].addr));
-                       stream->ice_remote_candidates[1].port = rtcp_port;
+                       if (ice_check_list_selected_valid_remote_candidate(cl, &rtp_addr, &rtp_port, &rtcp_addr, &rtcp_port) == TRUE) {
+                               strncpy(stream->ice_remote_candidates[0].addr, rtp_addr, sizeof(stream->ice_remote_candidates[0].addr));
+                               stream->ice_remote_candidates[0].port = rtp_port;
+                               strncpy(stream->ice_remote_candidates[1].addr, rtcp_addr, sizeof(stream->ice_remote_candidates[1].addr));
+                               stream->ice_remote_candidates[1].port = rtcp_port;
+                       } else {
+                               ms_error("ice: Selected valid remote candidates should be present if the check list is in the Completed state");
+                       }
+               } else {
+                       for (j = 0; j < SAL_MEDIA_DESCRIPTION_MAX_ICE_REMOTE_CANDIDATES; j++) {
+                               stream->ice_remote_candidates[j].addr[0] = '\0';
+                               stream->ice_remote_candidates[j].port = 0;
+                       }
                }
        }
 }
@@ -801,8 +880,10 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call,
                                                break;
                                }
                        }
-                       if ((stream->ice_mismatch == TRUE) || (stream->rtp_port == 0)) {
+                       if (stream->ice_mismatch == TRUE) {
                                ice_check_list_set_state(cl, ICL_Failed);
+                       } else if (stream->rtp_port == 0) {
+                               ice_session_remove_check_list(call->ice_session, cl);
                        } else {
                                if ((stream->ice_pwd[0] != '\0') && (stream->ice_ufrag[0] != '\0'))
                                        ice_check_list_set_remote_credentials(cl, stream->ice_ufrag, stream->ice_pwd);
@@ -828,6 +909,10 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call,
                                                int componentID = j + 1;
                                                if (candidate->addr[0] == '\0') break;
                                                get_default_addr_and_port(componentID, md, stream, &addr, &port);
+                                               if (j == 0) {
+                                                       /* If we receive a re-invite and we finished ICE processing on our side, use the candidates given by the remote. */
+                                                       ice_check_list_unselect_valid_pairs(cl);
+                                               }
                                                ice_add_losing_pair(cl, j + 1, candidate->addr, candidate->port, addr, port);
                                                losing_pairs_added = TRUE;
                                        }
@@ -839,21 +924,25 @@ void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call,
                        ice_session_remove_check_list(call->ice_session, ice_session_check_list(call->ice_session, i - 1));
                }
                ice_session_check_mismatch(call->ice_session);
+       } else {
+               /* Response from remote does not contain mandatory ICE attributes, delete the session. */
+               linphone_call_delete_ice_session(call);
+               return;
        }
        if (ice_session_nb_check_lists(call->ice_session) == 0) {
                linphone_call_delete_ice_session(call);
        }
 }
 
-void linphone_core_deactivate_ice_for_deactivated_media_streams(LinphoneCall *call, const SalMediaDescription *md)
+bool_t linphone_core_media_description_contains_video_stream(const SalMediaDescription *md)
 {
        int i;
+
        for (i = 0; i < md->nstreams; i++) {
-               IceCheckList *cl = ice_session_check_list(call->ice_session, i);
-               if (cl && (md->streams[i].rtp_port == 0)) {
-                       if (ice_check_list_state(cl) != ICL_Completed) ice_check_list_set_state(cl, ICL_Failed);
-               }
+               if ((md->streams[i].type == SalVideo) && (md->streams[i].rtp_port != 0))
+                       return TRUE;
        }
+       return FALSE;
 }
 
 LinphoneCall * is_a_linphone_call(void *user_pointer){
@@ -912,10 +1001,15 @@ static int get_local_ip_with_getifaddrs(int type, char *address, int size)
        if (getifaddrs(&ifpstart) < 0) {
                return -1;
        }
-
+#ifndef __linux
+       #define UP_FLAG IFF_UP /* interface is up */
+#else
+       #define UP_FLAG IFF_RUNNING /* resources allocated */
+#endif
+       
        for (ifp = ifpstart; ifp != NULL; ifp = ifp->ifa_next) {
                if (ifp->ifa_addr && ifp->ifa_addr->sa_family == type
-                       && (ifp->ifa_flags & IFF_RUNNING) && !(ifp->ifa_flags & IFF_LOOPBACK))
+                       && (ifp->ifa_flags & UP_FLAG) && !(ifp->ifa_flags & IFF_LOOPBACK))
                {
                        getnameinfo(ifp->ifa_addr,
                                                (type == AF_INET6) ?
index f26c6f106f218c97e6748c6eb327483914e3bc43..07fd1c689189766bd999982326ba06b9742de5e6 100644 (file)
@@ -79,7 +79,7 @@ struct _LinphoneCallParams{
        bool_t real_early_media; /*send real media even during early media (for outgoing calls)*/
        bool_t in_conference; /*in conference mode */
        bool_t pad;
-       
+       bool_t low_bandwidth;
 };
     
 typedef struct _CallCallbackObj
@@ -99,7 +99,13 @@ struct _LinphoneChatMessage {
        char* external_body_url;
        LinphoneAddress* from;
 };
-       
+
+typedef struct StunCandidate{
+       char addr[64];
+       int port;
+}StunCandidate;
+
+
 struct _LinphoneCall
 {
        int magic; /*used to distinguish from proxy config*/
@@ -119,10 +125,12 @@ struct _LinphoneCall
        LinphoneCallState       state;
        LinphoneCallState transfer_state; /*idle if no transfer*/
        LinphoneReason reason;
+       LinphoneProxyConfig *dest_proxy;
        int refcnt;
        void * user_pointer;
        int audio_port;
        int video_port;
+       StunCandidate ac,vc; /*audio video ip/port discovered by STUN*/
        struct _AudioStream *audiostream;  /**/
        struct _VideoStream *videostream;
        MSAudioEndpoint *endpoint; /*used for conferencing*/
@@ -132,27 +140,31 @@ struct _LinphoneCall
        LinphoneCallParams remote_params;
        int up_bw; /*upload bandwidth setting at the time the call is started. Used to detect if it changes during a call */
        int audio_bw;   /*upload bandwidth used by audio */
+       OrtpEvQueue *audiostream_app_evq;
+       char *auth_token;
+       OrtpEvQueue *videostream_app_evq;
+       CallCallbackObj nextVideoFrameDecoded;
+       LinphoneCallStats stats[2];
+       IceSession *ice_session;
+       LinphoneChatMessage* pending_message;
+       int ping_time;
        bool_t refer_pending;
        bool_t media_pending;
        bool_t audio_muted;
        bool_t camera_active;
+       
        bool_t all_muted; /*this flag is set during early medias*/
        bool_t playing_ringbacktone;
        bool_t owns_call_log;
        bool_t ringing_beep; /* whether this call is ringing through an already existent current call*/
-       OrtpEvQueue *audiostream_app_evq;
-       char *auth_token;
-       OrtpEvQueue *videostream_app_evq;
+       
        bool_t videostream_encrypted;
        bool_t audiostream_encrypted;
        bool_t auth_token_verified;
        bool_t defer_update;
+       
        bool_t was_automatically_paused;
        bool_t ping_replied;
-       CallCallbackObj nextVideoFrameDecoded;
-       LinphoneCallStats stats[2];
-       IceSession *ice_session;
-       LinphoneChatMessage* pending_message;
 };
 
 
@@ -233,17 +245,13 @@ MSList *linphone_find_friend(MSList *fl, const LinphoneAddress *fri, LinphoneFri
 void linphone_core_update_allocated_audio_bandwidth(LinphoneCore *lc);
 void linphone_core_update_allocated_audio_bandwidth_in_call(LinphoneCall *call, const PayloadType *pt);
 
-typedef struct StunCandidate{
-       char addr[64];
-       int port;
-}StunCandidate;
-
-int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call, StunCandidate *ac, StunCandidate *vc);
+int linphone_core_run_stun_tests(LinphoneCore *lc, LinphoneCall *call);
 void linphone_core_adapt_to_network(LinphoneCore *lc, int ping_time_ms, LinphoneCallParams *params);
 int linphone_core_gather_ice_candidates(LinphoneCore *lc, LinphoneCall *call);
+void linphone_core_update_ice_state_in_call_stats(LinphoneCall *call);
 void linphone_core_update_local_media_description_from_ice(SalMediaDescription *desc, IceSession *session);
 void linphone_core_update_ice_from_remote_media_description(LinphoneCall *call, const SalMediaDescription *md);
-void linphone_core_deactivate_ice_for_deactivated_media_streams(LinphoneCall *call, const SalMediaDescription *md);
+bool_t linphone_core_media_description_contains_video_stream(const SalMediaDescription *md);
 
 void linphone_core_send_initial_subscribes(LinphoneCore *lc);
 void linphone_core_write_friends_config(LinphoneCore* lc);
@@ -272,8 +280,11 @@ void linphone_call_init_video_stream(LinphoneCall *call);
 void linphone_call_init_media_streams(LinphoneCall *call);
 void linphone_call_start_media_streams(LinphoneCall *call, bool_t all_inputs_muted, bool_t send_ringbacktone);
 void linphone_call_start_media_streams_for_ice_gathering(LinphoneCall *call);
+void linphone_call_stop_audio_stream(LinphoneCall *call);
+void linphone_call_stop_video_stream(LinphoneCall *call);
 void linphone_call_stop_media_streams(LinphoneCall *call);
 void linphone_call_delete_ice_session(LinphoneCall *call);
+void linphone_call_stop_media_streams_for_ice_gathering(LinphoneCall *call);
 
 const char * linphone_core_get_identity(LinphoneCore *lc);
 const char * linphone_core_get_route(LinphoneCore *lc);
@@ -282,7 +293,7 @@ void linphone_core_update_progress(LinphoneCore *lc, const char *purpose, float
 void linphone_core_stop_waiting(LinphoneCore *lc);
 
 int linphone_core_proceed_with_invite_if_ready(LinphoneCore *lc, LinphoneCall *call, LinphoneProxyConfig *dest_proxy);
-int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call, LinphoneProxyConfig *dest_proxy);
+int linphone_core_start_invite(LinphoneCore *lc, LinphoneCall *call);
 int linphone_core_start_update_call(LinphoneCore *lc, LinphoneCall *call);
 int linphone_core_start_accept_call_update(LinphoneCore *lc, LinphoneCall *call);
 void linphone_core_start_refered_call(LinphoneCore *lc, LinphoneCall *call);
@@ -343,7 +354,6 @@ struct _LinphoneChatRoom{
        struct _LinphoneCore *lc;
        char  *peer;
        LinphoneAddress *peer_url;
-       SalOp *op;
        void * user_data;
 };
 
@@ -387,8 +397,10 @@ typedef struct sip_config
 
 typedef struct rtp_config
 {
-       int audio_rtp_port;
-       int video_rtp_port;
+       int audio_rtp_min_port;
+       int audio_rtp_max_port;
+       int video_rtp_min_port;
+       int video_rtp_max_port;
        int audio_jitt_comp;  /*jitter compensation*/
        int video_jitt_comp;  /*jitter compensation*/
        int nortp_timeout;
@@ -579,7 +591,8 @@ struct _EcCalibrator{
        ms_thread_t thread;
        MSSndCard *play_card,*capt_card;
        MSFilter *sndread,*det,*rec;
-       MSFilter *play, *gen, *sndwrite,*resampler;
+       MSFilter *play, *gen, *sndwrite;
+       MSFilter *read_resampler,*write_resampler;
        MSTicker *ticker;
        LinphoneEcCalibrationCallback cb;
        void *cb_data;
index ba9c0d75214865b524d689cbeade84a5ac81069c..718f7b0f5efcce4570a321cb91912f44900cf269 100644 (file)
@@ -41,17 +41,12 @@ void linphone_proxy_config_write_all_to_config_file(LinphoneCore *lc){
        lp_config_set_int(lc->config,"sip","default_proxy",linphone_core_get_default_proxy(lc,NULL));
 }
 
-#define DEFAULT_INT(config,name,default) \
-               config?lp_config_get_int(config,"default_values",#name,default):default
-#define DEFAULT_STRING(config,name,default) \
-       config?lp_config_get_string(config,"default_values",#name,default):default
-
 static void linphone_proxy_config_init(LinphoneCore* lc,LinphoneProxyConfig *obj){
        memset(obj,0,sizeof(LinphoneProxyConfig));
        obj->magic=linphone_proxy_config_magic;
-       obj->expires=DEFAULT_INT((lc?lc->config:NULL),reg_expires,3600);
-       obj->dial_prefix=ms_strdup(DEFAULT_STRING((lc?lc->config:NULL),dial_prefix,'\0'));
-       obj->dial_escape_plus=DEFAULT_INT((lc?lc->config:NULL),dial_escape_plus,0);
+       obj->expires=LP_CONFIG_DEFAULT_INT((lc?lc->config:NULL),"reg_expires",3600);
+       obj->dial_prefix=ms_strdup(LP_CONFIG_DEFAULT_STRING((lc?lc->config:NULL),"dial_prefix",'\0'));
+       obj->dial_escape_plus=LP_CONFIG_DEFAULT_INT((lc?lc->config:NULL),"dial_escape_plus",0);
 }
 
 /**
@@ -779,13 +774,13 @@ LinphoneProxyConfig *linphone_proxy_config_new_from_config_file(LpConfig *config
 
        linphone_proxy_config_set_contact_parameters(cfg,lp_config_get_string(config,key,"contact_parameters",NULL));
        
-       linphone_proxy_config_expires(cfg,lp_config_get_int(config,key,"reg_expires",DEFAULT_INT(config,reg_expires,600)));
+       linphone_proxy_config_expires(cfg,lp_config_get_int(config,key,"reg_expires",LP_CONFIG_DEFAULT_INT(config,"reg_expires",600)));
        linphone_proxy_config_enableregister(cfg,lp_config_get_int(config,key,"reg_sendregister",0));
        
        linphone_proxy_config_enable_publish(cfg,lp_config_get_int(config,key,"publish",0));
 
-       linphone_proxy_config_set_dial_escape_plus(cfg,lp_config_get_int(config,key,"dial_escape_plus",DEFAULT_INT(config,dial_escape_plus,0)));
-       linphone_proxy_config_set_dial_prefix(cfg,lp_config_get_string(config,key,"dial_prefix",DEFAULT_STRING(config,dial_prefix,NULL)));
+       linphone_proxy_config_set_dial_escape_plus(cfg,lp_config_get_int(config,key,"dial_escape_plus",LP_CONFIG_DEFAULT_INT(config,"dial_escape_plus",0)));
+       linphone_proxy_config_set_dial_prefix(cfg,lp_config_get_string(config,key,"dial_prefix",LP_CONFIG_DEFAULT_STRING(config,"dial_prefix",NULL)));
        
        tmp=lp_config_get_string(config,key,"type",NULL);
        if (tmp!=NULL && strlen(tmp)>0) 
index a7bb00e3e816d32c01433e75eef7d16c4be10af7..b349ad0a4e4efd002dbd701d607415a88c843fff 100644 (file)
@@ -269,7 +269,9 @@ const char *sal_op_get_proxy(const SalOp *op){
 const char *sal_op_get_network_origin(const SalOp *op){
        return ((SalOpBase*)op)->origin;
 }
-
+const char* sal_op_get_call_id(const SalOp *op) {
+       return  ((SalOpBase*)op)->call_id;
+}
 void __sal_op_init(SalOp *b, Sal *sal){
        memset(b,0,sizeof(SalOpBase));
        ((SalOpBase*)b)->root=sal;
@@ -310,6 +312,8 @@ void __sal_op_free(SalOp *op){
                sal_media_description_unref(b->local_media);
        if (b->remote_media)
                sal_media_description_unref(b->remote_media);
+       if (b->call_id)
+               ms_free((void*)b->call_id);
        ms_free(op);
 }
 
index 751cc653309df69c99762dc1a0fb9993c4704b6f..2913096caf5270b64e97eacf544dc25974f5fb7d 100644 (file)
@@ -207,6 +207,7 @@ typedef struct SalOpBase{
        SalMediaDescription *local_media;
        SalMediaDescription *remote_media;
        void *user_pointer;
+       const char* call_id;
 } SalOpBase;
 
 
@@ -339,6 +340,7 @@ unsigned int sal_get_keepalive_period(Sal *ctx);
 void sal_use_session_timers(Sal *ctx, int expires);
 void sal_use_double_registrations(Sal *ctx, bool_t enabled);
 void sal_expire_old_registration_contacts(Sal *ctx, bool_t enabled);
+void sal_use_dates(Sal *ctx, bool_t enabled);
 void sal_reuse_authorization(Sal *ctx, bool_t enabled);
 void sal_use_one_matching_codec_policy(Sal *ctx, bool_t one_matching_codec);
 void sal_use_rport(Sal *ctx, bool_t use_rports);
@@ -373,6 +375,7 @@ const char *sal_op_get_network_origin(const SalOp *op);
 /*returns far-end "User-Agent" string */
 const char *sal_op_get_remote_ua(const SalOp *op);
 void *sal_op_get_user_pointer(const SalOp *op);
+const char* sal_op_get_call_id(const SalOp *op);
 
 /*Call API*/
 int sal_call_set_local_media_description(SalOp *h, SalMediaDescription *desc);
index b09cae4ffc3da254eef78fd9d309219eb53caaff..b5f6cc10f6fbe5b250e8b03f6107a37478cb2285 100644 (file)
@@ -283,6 +283,7 @@ Sal * sal_init(){
        sal->rootCa = 0;
        sal->verify_server_certs=TRUE;
        sal->expire_old_contact=FALSE;
+       sal->add_dates=FALSE;
        sal->dscp=-1;
        return sal;
 }
@@ -460,6 +461,18 @@ void sal_expire_old_registration_contacts(Sal *ctx, bool_t enabled){
        ctx->expire_old_contact=enabled;
 }
 
+void sal_use_dates(Sal *ctx, bool_t enabled){
+       ctx->add_dates=enabled;
+#ifdef EXOSIP_OPT_REGISTER_WITH_DATE
+       {
+               int tmp=enabled;
+               eXosip_set_option(EXOSIP_OPT_REGISTER_WITH_DATE,&tmp);
+       }
+#else
+       if (enabled) ms_warning("Exosip does not support EXOSIP_OPT_REGISTER_WITH_DATE option.");
+#endif
+}
+
 void sal_use_rport(Sal *ctx, bool_t use_rports){
        ctx->use_rports=use_rports;
 }
@@ -603,6 +616,7 @@ int sal_call(SalOp *h, const char *from, const char *to){
        int err;
        const char *route;
        osip_message_t *invite=NULL;
+       osip_call_id_t *callid;
        sal_op_set_from(h,from);
        sal_op_set_to(h,to);
        sal_exosip_fix_route(h);
@@ -643,6 +657,8 @@ int sal_call(SalOp *h, const char *from, const char *to){
                ms_error("Fail to send invite ! Error code %d", err);
                return -1;
        }else{
+               callid=osip_message_get_call_id(invite);
+               osip_call_id_to_str(callid,(char **)(&h->base.call_id));
                sal_add_call(h->base.root,h);
        }
        return 0;
@@ -1018,6 +1034,8 @@ static void inc_new_call(Sal *sal, eXosip_event_t *ev){
        osip_call_info_t *call_info;
        char *tmp;
        sdp_message_t *sdp=eXosip_get_sdp_info(ev->request);
+       osip_call_id_t *callid=osip_message_get_call_id(ev->request);
+       osip_call_id_to_str(callid,(char**)(&op->base.call_id));
 
        set_network_origin(op,ev->request);
        set_remote_ua(op,ev->request);
@@ -1054,7 +1072,6 @@ static void inc_new_call(Sal *sal, eXosip_event_t *ev){
        op->tid=ev->tid;
        op->cid=ev->cid;
        op->did=ev->did;
-       
        sal_add_call(op->base.root,op);
        sal->callbacks.call_received(op);
 }
@@ -2211,6 +2228,7 @@ static void sal_register_add_route(osip_message_t *msg, const char *proxy){
        osip_message_set_route(msg,tmp);
 }
 
+
 int sal_register(SalOp *h, const char *proxy, const char *from, int expires){
        osip_message_t *msg;
        const char *contact=sal_op_get_contact(h);
@@ -2251,8 +2269,9 @@ int sal_register(SalOp *h, const char *proxy, const char *from, int expires){
                eXosip_register_build_register(h->rid,expires,&msg);
                sal_register_add_route(msg,proxy);
        }
-       if (msg)
+       if (msg){
                eXosip_register_send_register(h->rid,msg);
+       }
        eXosip_unlock();
        h->expires=expires;
        return (msg != NULL) ? 0 : -1;
index 71463854ca301abf1375d79d6947b535b77c2832..29eee78aecbd66fd5cd76eb9d87da2412ee6b890 100644 (file)
@@ -49,6 +49,7 @@ struct Sal{
        bool_t reuse_authorization;
        bool_t verify_server_certs;
        bool_t expire_old_contact;
+       bool_t add_dates;
 };
 
 struct SalOp{
index 70d4de886ae6e879b58af74beb004613e44b741e..78f5d0de7e22cc5b851500d0d3a2cbe9f53a8ad3 100644 (file)
@@ -9,7 +9,8 @@ UI_FILES=       about.ui \
                buddylookup.ui \
                tunnel_config.ui \
                waiting.ui \
-               dscp_settings.ui
+               dscp_settings.ui \
+               call_statistics.ui
 
 PIXMAPS=       \
                stock_people.png 
diff --git a/gtk/call_statistics.ui b/gtk/call_statistics.ui
new file mode 100644 (file)
index 0000000..4447104
--- /dev/null
@@ -0,0 +1,212 @@
+<?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" 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="can_focus">False</property>
+                    <property name="n_rows">6</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>
+                        <property name="x_options"></property>
+                      </packing>
+                    </child>
+                    <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>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                        <property name="x_options"></property>
+                      </packing>
+                    </child>
+                    <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>
+                        <property name="top_attach">2</property>
+                        <property name="bottom_attach">3</property>
+                        <property name="x_options"></property>
+                      </packing>
+                    </child>
+                    <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>
+                        <property name="right_attach">2</property>
+                      </packing>
+                    </child>
+                    <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>
+                        <property name="right_attach">2</property>
+                        <property name="top_attach">1</property>
+                        <property name="bottom_attach">2</property>
+                      </packing>
+                    </child>
+                    <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>
+                        <property name="right_attach">2</property>
+                        <property name="top_attach">2</property>
+                        <property name="bottom_attach">3</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLabel" id="label4">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="label" translatable="yes">Media connectivity</property>
+                      </object>
+                      <packing>
+                        <property name="top_attach">4</property>
+                        <property name="bottom_attach">5</property>
+                        <property name="x_options"></property>
+                      </packing>
+                    </child>
+                    <child>
+                      <placeholder/>
+                    </child>
+                    <child>
+                      <placeholder/>
+                    </child>
+                    <child>
+                      <object class="GtkLabel" id="media_connectivity">
+                        <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">4</property>
+                        <property name="bottom_attach">5</property>
+                      </packing>
+                    </child>
+                    <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>
+                        <property name="top_attach">3</property>
+                        <property name="bottom_attach">4</property>
+                        <property name="x_options"></property>
+                      </packing>
+                    </child>
+                    <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>
+                        <property name="right_attach">2</property>
+                        <property name="top_attach">3</property>
+                        <property name="bottom_attach">4</property>
+                      </packing>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+            <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>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="0">button1</action-widget>
+    </action-widgets>
+  </object>
+</interface>
index 4664768c67822df7e3dbf6d001fb500f25854177..22679a49b92cb8c4c7fd339d7526bb6e8cda60cd 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <interface>
-  <requires lib="gtk+" version="2.24"/>
+  <requires lib="gtk+" version="2.18"/>
   <!-- interface-naming-policy project-wide -->
   <object class="GtkDialog" id="dscp_settings">
     <property name="can_focus">False</property>
index 25ee2348a615051a665a73b680341308d9c744c9..346e8af6c61a99c427fdc47a1327a1e6ae323a1b 100644 (file)
@@ -190,6 +190,102 @@ void linphone_gtk_enable_conference_button(LinphoneCore *lc, gboolean value){
        }
 }
 
+static void show_used_codecs(GtkWidget *callstats, LinphoneCall *call){
+       const LinphoneCallParams *params=linphone_call_get_current_params(call);
+       if (params){
+               const PayloadType *acodec=linphone_call_params_get_used_audio_codec(params);
+               const PayloadType *vcodec=linphone_call_params_get_used_video_codec(params);
+               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);
+               }else gtk_label_set_label(GTK_LABEL(acodec_ui),_("Not used"));
+               if (vcodec){
+                       gtk_label_set_label(GTK_LABEL(vcodec_ui),vcodec->mime_type);
+               }else gtk_label_set_label(GTK_LABEL(vcodec_ui),_("Not used"));
+       }
+}
+
+static const char *ice_state_to_string(LinphoneIceState ice_state){
+       switch(ice_state){
+               case LinphoneIceStateNotActivated:
+                       return _("ICE not activated");
+               case LinphoneIceStateFailed:
+                       return _("ICE failed");
+               case LinphoneIceStateInProgress:
+                       return _("ICE in progress");
+               case LinphoneIceStateReflexiveConnection:
+                       return _("Going through one or more NATs");
+               case LinphoneIceStateHostConnection:
+                       return _("Direct");
+               case LinphoneIceStateRelayConnection:
+                       return _("Through a relay server");
+       }
+       return "invalid";
+}
+
+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);
+       LinphoneIceState ice_state=as->ice_state;
+       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);
+       gtk_label_set_markup(GTK_LABEL(linphone_gtk_get_widget(callstats,"video_bandwidth_usage")),tmp);
+       g_free(tmp);
+       gtk_label_set_text(GTK_LABEL(linphone_gtk_get_widget(callstats,"media_connectivity")),ice_state_to_string(ice_state));
+}
+
+static gboolean refresh_call_stats(GtkWidget *callstats){
+       LinphoneCall *call=(LinphoneCall*)g_object_get_data(G_OBJECT(callstats),"call");
+       switch (linphone_call_get_state(call)){
+               case LinphoneCallError:
+               case LinphoneCallEnd:
+               case LinphoneCallReleased:
+                       gtk_widget_destroy(callstats);
+                       return FALSE;
+               break;
+               case LinphoneCallStreamsRunning:
+                       _refresh_call_stats(callstats,call);
+               break;
+               default:
+               break;
+       }
+       return TRUE;
+}
+
+static void on_call_stats_destroyed(GtkWidget *call_view){
+       GtkWidget *call_stats=(GtkWidget*)g_object_get_data(G_OBJECT(call_view),"call_stats");
+       LinphoneCall *call=(LinphoneCall*)g_object_get_data(G_OBJECT(call_stats),"call");
+       g_source_remove(GPOINTER_TO_INT(g_object_get_data(G_OBJECT(call_stats),"tid")));
+       g_object_set_data(G_OBJECT(call_view),"call_stats",NULL);
+       linphone_call_unref(call);
+}
+
+static void linphone_gtk_show_call_stats(LinphoneCall *call){
+       GtkWidget *w=(GtkWidget*)linphone_call_get_user_pointer(call);
+       GtkWidget *call_stats=(GtkWidget*)g_object_get_data(G_OBJECT(w),"call_stats");
+       if (call_stats==NULL){
+               guint tid;
+               call_stats=linphone_gtk_create_window("call_statistics");
+               g_object_set_data(G_OBJECT(w),"call_stats",call_stats);
+               g_object_set_data(G_OBJECT(call_stats),"call",linphone_call_ref(call));
+               tid=g_timeout_add(1000,(GSourceFunc)refresh_call_stats,call_stats);
+               g_object_set_data(G_OBJECT(call_stats),"tid",GINT_TO_POINTER(tid));
+               g_signal_connect_swapped(G_OBJECT(call_stats),"destroy",(GCallback)on_call_stats_destroyed,(gpointer)w);
+               show_used_codecs(call_stats,call);
+               refresh_call_stats(call_stats);
+               gtk_widget_show(call_stats);
+       }
+       
+}
+
 void linphone_gtk_create_in_call_view(LinphoneCall *call){
        GtkWidget *call_view=linphone_gtk_create_widget("main","in_call_frame");
        GtkWidget *main_window=linphone_gtk_get_main_window ();
@@ -220,6 +316,7 @@ void linphone_gtk_create_in_call_view(LinphoneCall *call){
        gtk_button_set_label(GTK_BUTTON(button),_("Stop"));
        gtk_button_set_image(GTK_BUTTON(button),image);
        gtk_widget_show(image);
+       g_signal_connect_swapped(G_OBJECT(linphone_gtk_get_widget(call_view,"quality_indicator")),"button-press-event",(GCallback)linphone_gtk_show_call_stats,call);
 
 }
 
@@ -510,6 +607,7 @@ void linphone_gtk_in_call_view_set_in_call(LinphoneCall *call){
        GtkWidget *duration=linphone_gtk_get_widget(callview,"in_call_duration");
        guint taskid=GPOINTER_TO_INT(g_object_get_data(G_OBJECT(callview),"taskid"));
        gboolean in_conf=linphone_call_params_local_conference_mode(linphone_call_get_current_params(call));
+       GtkWidget *call_stats=(GtkWidget*)g_object_get_data(G_OBJECT(callview),"call_stats");
        
        display_peer_name_in_label(callee,linphone_call_get_remote_address (call));
 
@@ -528,6 +626,7 @@ void linphone_gtk_in_call_view_set_in_call(LinphoneCall *call){
        linphone_gtk_in_call_view_enable_audio_view(call, !in_conf);
        linphone_gtk_in_call_view_show_encryption(call);
        if (in_conf) linphone_gtk_set_in_conference(call);
+       if (call_stats) show_used_codecs(call_stats,call);
 }
 
 void linphone_gtk_in_call_view_set_paused(LinphoneCall *call){
@@ -682,3 +781,8 @@ void linphone_gtk_enable_hold_button(LinphoneCall *call, gboolean sensitive, gbo
        gtk_widget_set_visible(GTK_WIDGET(button),sensitive);
        linphone_gtk_draw_hold_button(GTK_BUTTON(button),!holdon);
 }
+
+void linphone_gtk_call_statistics_closed(GtkWidget *call_stats){
+       gtk_widget_destroy(call_stats);
+}
+
index 0acbf6d481c7bd91f29c055f8ada2db3fdfa6297..8ec303e288dde9e515fa52ab36c96e2725fd9cbf 100644 (file)
@@ -278,8 +278,10 @@ static void linphone_gtk_configure_window(GtkWidget *w, const char *window_name)
                linphone_gtk_visibility_set(shown,window_name,w,TRUE);
        if (icon_path) {
                GdkPixbuf *pbuf=create_pixbuf(icon_path);
-               gtk_window_set_icon(GTK_WINDOW(w),pbuf);
-               g_object_unref(G_OBJECT(pbuf));
+               if(pbuf != NULL) {
+                       gtk_window_set_icon(GTK_WINDOW(w),pbuf);
+                       g_object_unref(G_OBJECT(pbuf));
+               }
        }
 }
 
@@ -1530,8 +1532,10 @@ static void linphone_gtk_configure_main_window(){
        }
        if (search_icon){
                GdkPixbuf *pbuf=create_pixbuf(search_icon);
-               gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"directory_search_button_icon")),pbuf);
-               g_object_unref(G_OBJECT(pbuf));
+               if(pbuf != NULL) {
+                       gtk_image_set_from_pixbuf(GTK_IMAGE(linphone_gtk_get_widget(w,"directory_search_button_icon")),pbuf);
+                       g_object_unref(G_OBJECT(pbuf));
+               }
        }
        if (home){
                gchar *tmp;
index 1b147fed4518929ea2b0cbbd98178ae0498a1dd3..8731a495a1179caf036949ce90f5b826f55de8d5 100644 (file)
                 <property name="width_request">90</property>
                 <property name="visible">True</property>
                 <property name="can_focus">False</property>
+                <property name="events">GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_STRUCTURE_MASK</property>
                 <property name="tooltip_text" translatable="yes">Call quality rating</property>
               </object>
               <packing>
index c42ebb74019b6588240c2d7d2959f71f901b5394..35e173d5a802d1a454b827780f3aca081285e475 100644 (file)
@@ -21,7 +21,7 @@ package org.linphone.core;
 import java.util.Vector;
 
 /**
- * Object representing a Call. calls are created using {@link LinphoneCore#invite(LinphoneAddress)} or passed to the application by listener {@link LinphoneCoreListener#callState(LinphoneCore, LinphoneCall, State, String)}
+ * Object representing a call. Calls are created using {@link LinphoneCore#invite(LinphoneAddress)} or passed to the application by listener {@link LinphoneCoreListener#callState}
  * 
  */
 
@@ -159,6 +159,30 @@ public interface LinphoneCall {
         * @Return LinphoneCallLog
        **/
        LinphoneCallLog getCallLog();
+
+       /**
+        * Set the audio statistics associated with this call.
+        * @return LinphoneCallStats
+        */
+       void setAudioStats(LinphoneCallStats stats);
+
+       /**
+        * Set the video statistics associated with this call.
+        * @return LinphoneCallStats
+        */
+       void setVideoStats(LinphoneCallStats stats);
+
+       /**
+        * Get the audio statistics associated with this call.
+        * @return LinphoneCallStats
+        */
+       LinphoneCallStats getAudioStats();
+
+       /**
+        * Get the video statistics associated with this call.
+        * @return LinphoneCallStats
+        */
+       LinphoneCallStats getVideoStats();
        
        LinphoneCallParams getRemoteParams();
 
index 40299e6d95bdc3c129aeadb85702469ca4348371..1abdb7bed9acbcf3dbfb57d00b33942956276c92 100644 (file)
@@ -104,4 +104,8 @@ public interface LinphoneCallLog {
         * @return the call duration, in seconds
         */
        public int getCallDuration();
+       /**
+        * @return the call id from signaling
+        */
+       public int getCallId();
 }
index 5bf06733717f369069d9adad40a1f370351d7b3a..2dd497c9c346f4cf511a6d1448181ee24c3b0cdb 100644 (file)
@@ -34,7 +34,7 @@ public interface LinphoneCallParams {
         * @param value 0 to disable limitation
         */
        void setAudioBandwidth(int value);
-       
+
        /**
         * return selected media encryption
         * @return MediaEncryption.None MediaEncryption.SRTP or MediaEncryption.ZRTP
@@ -45,5 +45,16 @@ public interface LinphoneCallParams {
         * @params menc: MediaEncryption.None, MediaEncryption.SRTP or MediaEncryption.ZRTP
         */
        void setMediaEnctyption(MediaEncryption menc);
-       
+
+       /**
+        * Get the currently used audio codec
+        * @return PayloadType or null
+        */
+       PayloadType getUsedAudioCodec();
+
+       /**
+        * Get the currently used video codec
+        * @return PayloadType or null
+        */
+       PayloadType getUsedVideoCodec();
 }
diff --git a/java/common/org/linphone/core/LinphoneCallStats.java b/java/common/org/linphone/core/LinphoneCallStats.java
new file mode 100644 (file)
index 0000000..15b4cfb
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+LinPhoneCallStats.java
+Copyright (C) 2010  Belledonne Communications, Grenoble, France
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+package org.linphone.core;
+
+import java.util.Vector;
+
+
+public interface LinphoneCallStats {
+       static public class MediaType {
+               static private Vector values = new Vector();
+               /**
+                * Audio
+                */
+               static public MediaType Audio = new MediaType(0, "Audio");
+               /**
+                * Video
+                */
+               static public MediaType Video = new MediaType(1, "Video");
+               protected final int mValue;
+               private final String mStringValue;
+
+               private MediaType(int value, String stringValue) {
+                       mValue = value;
+                       values.addElement(this);
+                       mStringValue = stringValue;
+               }
+               public static MediaType fromInt(int value) {
+                       for (int i = 0; i < values.size(); i++) {
+                               MediaType mtype = (MediaType) values.elementAt(i);
+                               if (mtype.mValue == value) return mtype;
+                       }
+                       throw new RuntimeException("MediaType not found [" + value + "]");
+               }
+               public String toString() {
+                       return mStringValue;
+               }
+       }
+       static public class IceState {
+               static private Vector values = new Vector();
+               /**
+                * Not activated
+                */
+               static public IceState NotActivated = new IceState(0, "Not activated");
+               /**
+                * Failed
+                */
+               static public IceState Failed = new IceState(1, "Failed");
+               /**
+                * In progress
+                */
+               static public IceState InProgress = new IceState(2, "In progress");
+               /**
+                * Host connection
+                */
+               static public IceState HostConnection = new IceState(3, "Host connection");
+               /**
+                * Reflexive connection
+                */
+               static public IceState ReflexiveConnection = new IceState(4, "Reflexive connection");
+               /**
+                * Relay connection
+                */
+               static public IceState RelayConnection = new IceState(5, "Relay connection");
+               protected final int mValue;
+               private final String mStringValue;
+
+               private IceState(int value, String stringValue) {
+                       mValue = value;
+                       values.addElement(this);
+                       mStringValue = stringValue;
+               }
+               public static IceState fromInt(int value) {
+                       for (int i = 0; i < values.size(); i++) {
+                               IceState mstate = (IceState) values.elementAt(i);
+                               if (mstate.mValue == value) return mstate;
+                       }
+                       throw new RuntimeException("IceState not found [" + value + "]");
+               }
+               public String toString() {
+                       return mStringValue;
+               }
+       }
+
+       /**
+        * Get the stats media type
+        * @return MediaType
+        */
+       public MediaType getMediaType();
+
+       /**
+        * Get the ICE state
+        */
+       public IceState getIceState();
+
+       /**
+        * Get the download bandwidth in kbit/s
+        * @return The download bandwidth
+        */
+       public float getDownloadBandwidth();
+
+       /**
+        * Get the upload bandwidth in kbit/s
+        * @return The upload bandwidth
+        */
+       public float getUploadBandwidth();
+
+       /**
+        * Get the sender loss rate since last report
+        * @return The sender loss rate
+        */
+       public float getSenderLossRate();
+
+       /**
+        * Get the receiver loss rate since last report
+        * @return The receiver loss rate
+        */
+       public float getReceiverLossRate();
+
+       /**
+        * Get the sender interarrival jitter
+        * @return The interarrival jitter at last emitted sender report
+        */
+       public float getSenderInterarrivalJitter();
+
+       /**
+        * Get the receiver interarrival jitter
+        * @return The interarrival jitter at last received receiver report
+        */
+       public float getReceiverInterarrivalJitter();
+
+       /**
+        * Get the round trip delay
+        * @return The round trip delay in seconds, -1 if the information is not available
+        */
+       public float getRoundTripDelay();
+
+       /**
+        * Get the cumulative number of late packets
+        * @return The cumulative number of late packets
+        */
+       public long getLatePacketsCumulativeNumber();
+
+       /**
+        * Get the jitter buffer size
+        * @return The jitter buffer size in milliseconds
+        */
+       public float getJitterBufferSize();
+}
index 3b135fc6590b3c0048aa952ec24997375f928223..db75f91165ca5391f07076e1b8c5cee47ff87666 100644 (file)
@@ -74,6 +74,13 @@ public interface LinphoneChatMessage {
         */
        LinphoneAddress getPeerAddress();
        
+       /**
+        * get from address associated to this LinphoneChatMessage
+        *
+        * @return LinphoneAddress from address
+        */
+       LinphoneAddress getFrom();
+       
        /**
         * Linphone message can carry external body as defined by rfc2017
         * @param message #LinphoneChatMessage
index 102a03c217a1ad0e9453adcd8fc6661641900119..d6512f1707258e004e846cbea9dee97a646fad9f 100644 (file)
@@ -40,12 +40,6 @@ public interface LinphoneChatRoom {
         * @param chat message
         */
        void sendMessage(LinphoneChatMessage message, LinphoneChatMessage.StateListener listener);
-       /**
-        * DEPRECATED
-        * @param opaque
-        * @param message
-        */
-       void sendMessage(Object opaque, String message);
        
        /**
         * Create a LinphoneChatMessage
index dbe5611db88808a50acaa325541454fabb0fd247..562ae86cdf0884696955b7a76c6c2ddb99cd13d9 100644 (file)
@@ -20,9 +20,6 @@ package org.linphone.core;
 
 import java.util.Vector;
 
-import org.linphone.core.LinphoneCallLog;
-import org.linphone.core.LinphoneCallParams;
-
 /**
  * Linphone core main object created by method {@link LinphoneCoreFactory#createLinphoneCore(LinphoneCoreListener, String, String, Object)}.   
  *
@@ -234,21 +231,28 @@ public interface LinphoneCore {
        static public class EcCalibratorStatus {
                
                static private Vector values = new Vector();
+               /* Do not change the values of these constants or the strings associated with them to prevent breaking
+                  the collection of echo canceller calibration results during the wizard! */
                public static final int IN_PROGRESS_STATUS=0;
                public static final int DONE_STATUS=1;
                public static final int FAILED_STATUS=2;
+               public static final int DONE_NO_ECHO_STATUS=3;
                /**
                 * Calibration in progress
                 */
-               static public EcCalibratorStatus InProgress = new EcCalibratorStatus(IN_PROGRESS_STATUS,"InProgress");       
+               static public EcCalibratorStatus InProgress = new EcCalibratorStatus(IN_PROGRESS_STATUS,"InProgress");
                /**
-                * Calibration done
+                * Calibration done that produced an echo delay measure
                 */
-               static public EcCalibratorStatus Done  = new EcCalibratorStatus(DONE_STATUS,"Done");
+               static public EcCalibratorStatus Done = new EcCalibratorStatus(DONE_STATUS,"Done");
                /**
-                * Calibration in progress
+                * Calibration failed
                 */
                static public EcCalibratorStatus Failed = new EcCalibratorStatus(FAILED_STATUS,"Failed");
+               /**
+                * Calibration done with no echo detected
+                */
+               static public EcCalibratorStatus DoneNoEcho = new EcCalibratorStatus(DONE_NO_ECHO_STATUS, "DoneNoEcho");
 
                private final int mValue;
                private final String mStringValue;
@@ -373,7 +377,7 @@ public interface LinphoneCore {
         * Accept an incoming call.
         *
         * Basically the application is notified of incoming calls within the
-        * {@link LinphoneCoreListener#inviteReceived(LinphoneCore, String)} listener.
+        * {@link LinphoneCoreListener#callState} listener method.
         * The application can later respond positively to the call using
         * this method.
         * @throws LinphoneCoreException 
@@ -384,7 +388,7 @@ public interface LinphoneCore {
         * Accept an incoming call.
         *
         * Basically the application is notified of incoming calls within the
-        * {@link LinphoneCoreListener#inviteReceived(LinphoneCore, String)} listener.
+        * {@link LinphoneCoreListener#callState} listener method.
         * The application can later respond positively to the call using
         * this method.
         * @throws LinphoneCoreException 
@@ -395,7 +399,7 @@ public interface LinphoneCore {
         * Accept call modifications initiated by other end.
         *
         * Basically the application is notified of incoming calls within the
-        * {@link LinphoneCoreListener#inviteReceived(LinphoneCore, String)} listener.
+        * {@link LinphoneCoreListener#callState} listener method.
         * The application can later respond positively to the call using
         * this method.
         * @throws LinphoneCoreException 
@@ -407,7 +411,7 @@ public interface LinphoneCore {
         * Prevent LinphoneCore from performing an automatic answer
         *
         * Basically the application is notified of incoming calls within the
-        * {@link LinphoneCoreListener#inviteReceived(LinphoneCore, String)} listener.
+        * {@link LinphoneCoreListener#callState} listener method.
         * The application can later respond positively to the call using
         * this method.
         * @throws LinphoneCoreException 
@@ -491,11 +495,17 @@ public interface LinphoneCore {
         */
        void clearCallLogs();
        /***
-        * get payload type  from mime type an clock rate
+        * get payload type  from mime type, clock rate, and number of channels.-
         * 
         * return null if not found
         */
        PayloadType findPayloadType(String mime, int clockRate, int channels); 
+       /***
+        * get payload type  from mime type and clock rate..
+        * 
+        * return null if not found
+        */
+       PayloadType findPayloadType(String mime, int clockRate); 
        /**
         * not implemented yet
         * @param pt
@@ -677,6 +687,10 @@ public interface LinphoneCore {
        void startEchoCalibration(Object data) throws LinphoneCoreException;
 
        void enableIpv6(boolean enable);
+       /**
+        * @deprecated
+        * @param i
+        */
        void adjustSoftwareVolume(int i);
        
        boolean pauseCall(LinphoneCall call);
@@ -792,4 +806,41 @@ public interface LinphoneCore {
         * return the version code of linphone core
         */
        public String getVersion();
+       
+       /**
+        * remove a linphone friend from linphone core and linphonerc
+        */
+       void removeFriend(LinphoneFriend lf);
+       
+       /**
+        * return a linphone friend (if exists) that matches the sip address
+        */
+       LinphoneFriend findFriendByAddress(String sipUri);
+       
+       /**
+        * Sets the UDP port used for audio streaming.
+       **/
+       void setAudioPort(int port);
+       
+       /**
+        * Sets the UDP port range from which to randomly select the port used for audio streaming.
+        */
+       void setAudioPortRange(int minPort, int maxPort);
+       
+       /**
+        * Sets the UDP port used for video streaming.
+       **/
+       void setVideoPort(int port);
+       
+       /**
+        * Sets the UDP port range from which to randomly select the port used for video streaming.
+        */
+       void setVideoPortRange(int minPort, int maxPort);
+       
+       /**
+        * Set the incoming call timeout in seconds.
+        * If an incoming call isn't answered for this timeout period, it is
+        * automatically declined.
+       **/
+       void setIncomingTimeout(int timeout);
 }
index ab9dd1ac3cfb1481d45ab1e0e4703509391a1583..740bdc29c14bb20de8b90d1326436d385cb4781e 100644 (file)
@@ -24,27 +24,10 @@ package org.linphone.core;
  *This interface holds all callbacks that the application should implement. None is mandatory.
  */
 public interface LinphoneCoreListener {
-
-       /**< Notifies the application that it should show up
-        * @return */
-       void show(LinphoneCore lc);
-
        /**< Ask the application some authentication information 
         * @return */
        void authInfoRequested(LinphoneCore lc,String realm,String username); 
 
-       /**< Callback that notifies various events with human readable text.
-        * @return */
-       void displayStatus(LinphoneCore lc,String message);
-
-       /**< Callback to display a message to the user 
-        * @return */
-       void displayMessage(LinphoneCore lc,String message);
-
-       /** Callback to display a warning to the user 
-        * @return */
-       void displayWarning(LinphoneCore lc,String message);
-
        /** General State notification  
         * @param state LinphoneCore.State
         * @return 
@@ -57,6 +40,11 @@ public interface LinphoneCoreListener {
         * */           
        void callState(LinphoneCore lc, LinphoneCall call, LinphoneCall.State cstate,String message);
 
+       /**
+        * Call stats notification
+        */
+       void callStatsUpdated(LinphoneCore lc, LinphoneCall call, LinphoneCallStats stats);
+
        /**
         * Callback to display change in encryption state.
         * @param encrypted true if all streams of the call are encrypted
@@ -99,11 +87,18 @@ public interface LinphoneCoreListener {
         * invoked when a new linphone chat message is received
         * @param lc LinphoneCore
         * @param  room         LinphoneChatRoom involved in this conversation. Can be be created by the framework in case the from is not present in any chat room.
-        * @param from          LinphoneAddress from
         * @param message       incoming linphone chat message message
         */
-       void messageReceived(LinphoneCore lc, LinphoneChatRoom cr, LinphoneAddress from, LinphoneChatMessage message);
+       void messageReceived(LinphoneCore lc, LinphoneChatRoom cr, LinphoneChatMessage message);
 
+       /**
+        * invoked when a new dtmf is received
+        * @param lc    LinphoneCore
+        * @param call  LinphoneCall involved in the dtmf sending
+        * @param dtmf  value of the dtmf sent
+        */
+       void dtmfReceived(LinphoneCore lc, LinphoneCall call, int dtmf);
+       
        /**
         * Invoked when echo cancalation calibration is completed
         * @param lc LinphoneCore
@@ -121,5 +116,22 @@ public interface LinphoneCoreListener {
         *  
         */
        void notifyReceived(LinphoneCore lc, LinphoneCall call, LinphoneAddress from, byte[] event);
+
+       
+       /**< @Deprecated Notifies the application that it should show up
+        * @return */
+       void show(LinphoneCore lc);
+       /**< @Deprecated Callback that notifies various events with human readable text.
+        * @return */
+       void displayStatus(LinphoneCore lc,String message);
+
+       /**< @Deprecated Callback to display a message to the user 
+        * @return */
+       void displayMessage(LinphoneCore lc,String message);
+
+       /** @Deprecated Callback to display a warning to the user 
+        * @return */
+       void displayWarning(LinphoneCore lc,String message);
+
 }
 
index d4f0e7503ed6814459fb63ec244d532af5dfd5bc..e070f69214154bb6297ce2e65f29b463e0d4cdb8 100644 (file)
@@ -123,5 +123,8 @@ public interface LinphoneFriend {
         */
        String toString();
        
-
+       /**
+        * Return the native pointer for this object
+        */
+       long getNativePtr();
 }
index bf2907d2615e0cbe67f4e0e4ed4ada6baeedf367..eee58c9156572b148e0b4d8d20039bd5af72797a 100644 (file)
@@ -139,4 +139,10 @@ public interface LinphoneProxyConfig {
         * @param parameters to add
         */
        public void setContactParameters(String params);
+       
+       /**
+        * Return the international prefix for the given country
+        * @param country iso code
+        */
+       public int lookupCCCFromIso(String iso);
 }
index 65e82ddfe0db34b81c0d18960bd14e811f931bf9..f4ba3711b61f4e6ba8103db2a53f1f09cb9724a2 100644 (file)
@@ -41,14 +41,18 @@ Liblinphone is a high level library for bringing SIP video call functionnality i
 
 LibLinphone package is organized in submodules.
 <ul>
-  <li><a href="#proxy">Managing proxies</a>
+  <li><a href="#proxy">Managing proxies</a></li>
 </ul>
 <ul>
-  <li><a href="#buddy">Managing Buddies and buddy list and presence</a>
+  <li><a href="#buddy">Managing Buddies and buddy list and presence</a></li>
 </ul>
 <ul>
-  <li><a href="#chat">Chat room and Messaging</a>
+  <li><a href="#chat">Chat room and Messaging</a></li>
 </ul>
+<ul>
+  <li><a href="#echo">Sound and echo cancellation settings</a></li>
+</ul>
+
 
 <h2>Related Documentation</h2>
 
@@ -189,6 +193,109 @@ from a peer sip uri.
                System.out.println("Message ["+message+"] received from ["+from+"] ");
        }
 </code>
+</pre>
+
+<h3>
+<a name="echo">Sound and echo cancellation settings</a>
+</h3>
+<b>Sound levels</b>
+<br> 
+It is possible to tune the microphone input gain and speaker/receiver output gain by setting parameters into the linphonerc factory config file loaded when instanciating the {@link org.linphone.core.LinphoneCore LinphoneCore}. These gains are liblinphone's internal software gains and are unrelated to volume levels managed by the operating system. For example: <br>
+<pre>
+<code>
+[sound]
+#set the speaker or receiver playback gain in dbm0 (0 db = no change). 
+playback_gain_db=-3
+#set the microphone gain in linear scale:
+mic_gain=0.1
+</code>
+</pre>
+
+<br>
+
+<b>Echo cancellation</b>
+<br>
+On Android devices, there are two kind of situations regarding echo cancellation:<br>
+<ul>
+       <li>The new (after 2011) high end devices, on which manufacturers often include a hardware echo cancellation. If available, liblinphone will make use of it and no software correction is required. Source file linphone-android/submodules/linphone/mediastreamer2/java/src/org/linphone/mediastream/video/capture/hwconf/Hacks.java contains a method hasBuiltInEchoCanceller() that returns true if an hardware echo canceller is available, based on device model identifier. The current list is incomplete.</li>
+       <li>The other devices, for which it is recommended to enable the software echo canceller of liblinphone.</li>
+</ul>
+
+<br>
+<b>Echo calibration tool</b>
+<br>
+The echo calibration procedure is a five second audio test which consists in playing small beeps to the receiver while the microphone input is recorded.
+If the device is subject to echo (or doesn't have hardware echo cancellation), then beeps recorded by the microphone will be detected and a measurement of echo delay can be computed.
+Echo calibration procedure can be started by calling {@link org.linphone.core.LinphoneCore#startEchoCalibration LinphoneCore.startEchoCalibration}.
+The measurement of the echo delay is important to save CPU computations by restricting the temporal area where the software echo canceller has to perform.
+<br>
+
+<br>
+<b>Echo limiter</b>
+<br>
+The echo limiter is a liblinphone algorithm to clear out echo with a brute force method. It consists in cutting down the microphone signal when active signal is played by the speaker/receiver, to prevent voice to feed back into the microphone. This algorithm has disadvantages compared to the hardware or software echo cancellers because the remote user will be not hear any background noise when speaking, which is confusing. As a result the echo limiter method shall be used only under situation where echo canceller can't perform, that is loud signals with heavy saturations, which usually happens when using the device in speaker mode. Echo limiter can be enabled or disabled during a call with {@link org.linphone.core.LinphoneCall#enableEchoLimiter LinphoneCall.enableEchoLimiter()}.
+<br>
+
+<br>
+<b>Recommandations to applications for optimal audio performance</b>
+<br>
+
+<br>
+In order to benefit from the best echo cancellation solution, we recommend applications to run the following procedure, when they are run for the first time:<br>
+<ul>
+       <li>Use the Hacks.hasBuiltInEchoCanceller() method to first check if the device has hardware echo cancellation. If yes, then echo canceller must be turned off.</li>
+       <li>If hasBuiltInEchoCanceller() returned false, then it is recommended to run the echo calibration procedure. This procedure can produce the following results:
+               <ul>
+                       <li>success with no echo detected: it means that the device has an hardware echo canceller but is not (yet) referenced in our list of devices having hardware echo cancellation. Echo cancellation should be disabled with {@link org.linphone.core.LinphoneCore#enableEchoCancellation LinphoneCore.enableEchoCancellation(false)}</li>
+                       <li>success with an estimated echo delay: the echo canceller should be enabled.</li>
+                       <li>failure: it means that some echo has been detected but the delay could not be estimated. In this case it is recommended to activate the echo canceller. A typical for android minimum delay of 250 ms will be used as default.</li>
+               </ul>
+       </li>
+</ul>
+
+During calls, the echo limiter should be disabled while using the receiver, but enabled while using the hands-free speaker. It is also recommended to disable echo canceller while using the echo limiter, because the first one would be useless. Therefore you should have the following situations:
+<ul>
+       <li>While using the receiver</li>
+               <ul>
+                       <li>Echo canceller enabled, unless the device has hardware echo cancellation</li>
+                       <li>Echo limiter disabled</li>
+               </ul>
+       <li>While using the hands-free speaker</li>
+               <ul>
+                       <li>Echo canceller disabled</li>
+                       <li>Echo limiter enabled, unless the device has hardware echo cancellation.</li>
+               </ul>
+       </li>
+</ul>
+Controlling echo limiter during a call has to be done with {@link org.linphone.core.LinphoneCall#enableEchoLimiter LinphoneCall.enableEchoLimiter()}.
+Controlling echo canceller during a call has to be done with {@link org.linphone.core.LinphoneCall#enableEchoCancellation LinphoneCall.enableEchoCancellation()}.
+
+
+<br><br>
+<b>Echo limiter settings</b>
+<br>
+Echo limiter requires settings to be defined in linphonerc factory config file for correction operation.
+Typical settings are:
 <pre>
+<code>
+[sound]
+el_type=mic
+#speaker energy threshold (linear scale) above which echo limiter decreases mic gain.
+el_thres=0.03
+#attenuation applied to mic gain (linear scale)
+el_force=100000
+#minimum time in milliseconds during which attenuation is applied
+el_sustain=600
+#double talk detection: threshold of ratio mic-energy/speaker-energy above which mic input is sent anyway.
+el_transmit_thres=1.7
+#noise gate floorgain (gain applied when no voice is detected).
+ng_floorgain=0.01
+</code>
+</pre>
+
+Up to date settings must be found from linphone-android/res/raw/linphonerc file.
+
+<br>
+
 </body>
 </html>
\ No newline at end of file
diff --git a/java/impl/org/linphone/core/LinphoneAddressImpl.java b/java/impl/org/linphone/core/LinphoneAddressImpl.java
new file mode 100644 (file)
index 0000000..b9d2909
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+LinphoneAddressImpl.java
+Copyright (C) 2010  Belledonne Communications, Grenoble, France
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+package org.linphone.core;
+
+
+
+public class LinphoneAddressImpl implements LinphoneAddress {
+       protected final long nativePtr;
+       boolean ownPtr = false;
+       private native long newLinphoneAddressImpl(String uri,String displayName);
+       private native void  delete(long ptr);
+       private native String getDisplayName(long ptr);
+       private native String getUserName(long ptr);
+       private native String getDomain(long ptr);
+       private native String toUri(long ptr);
+       private native void setDisplayName(long ptr,String name);
+       private native String toString(long ptr);
+       
+       protected LinphoneAddressImpl(String identity)  {
+               nativePtr = newLinphoneAddressImpl(identity, null);
+       }
+       
+       protected LinphoneAddressImpl(String username,String domain,String displayName)  {
+               nativePtr = newLinphoneAddressImpl("sip:"+username+"@"+domain, displayName);
+       }
+       protected LinphoneAddressImpl(long aNativePtr,boolean javaOwnPtr)  {
+               nativePtr = aNativePtr;
+               ownPtr=javaOwnPtr;
+       }
+       protected LinphoneAddressImpl(long aNativePtr)  {
+               nativePtr = aNativePtr;
+               ownPtr=false;
+       }
+       protected void finalize() throws Throwable {
+               if (ownPtr) delete(nativePtr);
+       }
+       public String getDisplayName() {
+               return getDisplayName(nativePtr);
+       }
+       public String getDomain() {
+               return getDomain(nativePtr);
+       }
+       public String getUserName() {
+               return getUserName(nativePtr);
+       }
+       
+       public String toString() {
+               return toString(nativePtr);
+       }
+       public String toUri() {
+               return toUri(nativePtr);        
+       }
+       public void setDisplayName(String name) {
+               setDisplayName(nativePtr,name);
+       }
+       public String asString() {
+               return toString();
+       }
+       public String asStringUriOnly() {
+               return toUri(nativePtr);
+       }
+       public void clean() {
+               throw new RuntimeException("Not implemented");
+       }
+       public String getPort() {
+               return String.valueOf(getPortInt());
+       }
+       public int getPortInt() {
+               return getPortInt();
+       }
+       public void setDomain(String domain) {
+               throw new RuntimeException("Not implemented");
+       }
+       public void setPort(String port) {
+               throw new RuntimeException("Not implemented");
+       }
+       public void setPortInt(int port) {
+               throw new RuntimeException("Not implemented");
+       }
+       public void setUserName(String username) {
+               throw new RuntimeException("Not implemented");
+       }
+}
diff --git a/java/impl/org/linphone/core/LinphoneAuthInfoImpl.java b/java/impl/org/linphone/core/LinphoneAuthInfoImpl.java
new file mode 100644 (file)
index 0000000..45fd8a4
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+LinphoneAuthInfoImpl.java
+Copyright (C) 2010  Belledonne Communications, Grenoble, France
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+package org.linphone.core;
+
+class LinphoneAuthInfoImpl implements LinphoneAuthInfo {
+       protected final long nativePtr;
+       private native long newLinphoneAuthInfo(String username, String userid, String passwd, String ha1,String realm);
+       private native void  delete(long ptr);
+       protected LinphoneAuthInfoImpl(String username,String password, String realm)  {
+               nativePtr = newLinphoneAuthInfo(username,"",password,"","");
+       }
+       protected void finalize() throws Throwable {
+               delete(nativePtr);
+       }
+       public String getPassword() {
+               // TODO Auto-generated method stub
+               throw new RuntimeException("not implemeneted yet");
+       }
+       public String getRealm() {
+               // TODO Auto-generated method stub
+               throw new RuntimeException("not implemeneted yet");
+       }
+       public String getUsername() {
+               // TODO Auto-generated method stub
+               throw new RuntimeException("not implemeneted yet");
+       }
+       public void setPassword(String password) {
+               // TODO Auto-generated method stub
+               throw new RuntimeException("not implemeneted yet");
+       }
+       public void setRealm(String realm) {
+               // TODO Auto-generated method stub
+               throw new RuntimeException("not implemeneted yet");
+       }
+       public void setUsername(String username) {
+               // TODO Auto-generated method stub
+               throw new RuntimeException("not implemeneted yet");
+       }
+}
diff --git a/java/impl/org/linphone/core/LinphoneCallImpl.java b/java/impl/org/linphone/core/LinphoneCallImpl.java
new file mode 100644 (file)
index 0000000..7e39ceb
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+LinphoneCallImpl.java
+Copyright (C) 2010  Belledonne Communications, Grenoble, France
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+package org.linphone.core;
+
+
+class LinphoneCallImpl implements LinphoneCall {
+       protected final long nativePtr;
+       boolean ownPtr = false;
+       private LinphoneCallStats audioStats;
+       private LinphoneCallStats videoStats;
+
+       native private void finalize(long nativePtr);
+       native private long  getCallLog(long nativePtr);
+       private native boolean isIncoming(long nativePtr);
+       native private long getRemoteAddress(long nativePtr);
+       native private int getState(long nativePtr);
+       private native long getCurrentParamsCopy(long nativePtr);
+       private native long getRemoteParams(long nativePtr);
+       private native void enableCamera(long nativePtr, boolean enabled);
+       private native boolean cameraEnabled(long nativePtr);
+       private native void enableEchoCancellation(long nativePtr,boolean enable);
+       private native boolean isEchoCancellationEnabled(long nativePtr) ;
+       private native void enableEchoLimiter(long nativePtr,boolean enable);
+       private native boolean isEchoLimiterEnabled(long nativePtr);
+       private native Object getReplacedCall(long nativePtr);
+       private native int getDuration(long nativePtr);
+       private native float getCurrentQuality(long nativePtr);
+       private native float getAverageQuality(long nativePtr);
+       
+       /*
+        * This method must always be called from JNI, nothing else.
+        */
+       private LinphoneCallImpl(long aNativePtr)  {
+               nativePtr = aNativePtr;
+       }
+       protected void finalize() throws Throwable {
+               finalize(nativePtr);
+       }
+       public LinphoneCallLog getCallLog() {
+               long lNativePtr = getCallLog(nativePtr);
+               if (lNativePtr!=0) {
+                       return new LinphoneCallLogImpl(lNativePtr); 
+               } else {
+                       return null;
+               }
+       }
+       public void setAudioStats(LinphoneCallStats stats) {
+               audioStats = stats;
+       }
+       public void setVideoStats(LinphoneCallStats stats) {
+               videoStats = stats;
+       }
+       public LinphoneCallStats getAudioStats() {
+               return audioStats;
+       }
+       public LinphoneCallStats getVideoStats() {
+               return videoStats;
+       }
+       public CallDirection getDirection() {
+               return isIncoming(nativePtr)?CallDirection.Incoming:CallDirection.Outgoing;
+       }
+       public LinphoneAddress getRemoteAddress() {
+               long lNativePtr = getRemoteAddress(nativePtr);
+               if (lNativePtr!=0) {
+                       return new LinphoneAddressImpl(lNativePtr); 
+               } else {
+                       return null;
+               }
+       }
+       public State getState() {
+               return LinphoneCall.State.fromInt(getState(nativePtr));
+       }
+       public LinphoneCallParams getCurrentParamsCopy() {
+               return new LinphoneCallParamsImpl(getCurrentParamsCopy(nativePtr));
+       }
+       public LinphoneCallParams getRemoteParams() {
+               long remoteParamsPtr = getRemoteParams(nativePtr);
+               if (remoteParamsPtr == 0) {
+                       return null;
+               }
+               return new LinphoneCallParamsImpl(remoteParamsPtr);
+       }
+       public void enableCamera(boolean enabled) {
+               enableCamera(nativePtr, enabled);
+       }
+       public boolean cameraEnabled() {
+               return cameraEnabled(nativePtr);
+       }
+
+       @Override
+       public boolean equals(Object call) {
+               if (this == call) return true;
+               if (call == null) return false;
+               if (!(call instanceof LinphoneCallImpl)) return false;
+               return nativePtr == ((LinphoneCallImpl)call).nativePtr;
+       }
+
+       @Override
+       public int hashCode() {
+               int result = 17;
+               result = 31 * result + (int) (nativePtr ^ (nativePtr >>> 32));
+               return result;
+       }
+       public void enableEchoCancellation(boolean enable) {
+               enableEchoCancellation(nativePtr,enable);
+               
+       }
+       public boolean isEchoCancellationEnabled() {
+               return isEchoCancellationEnabled(nativePtr);
+       }
+       public void enableEchoLimiter(boolean enable) {
+               enableEchoLimiter(nativePtr,enable);
+       }
+       public boolean isEchoLimiterEnabled() {
+               return isEchoLimiterEnabled(nativePtr);
+       }
+       public LinphoneCall getReplacedCall(){
+               return (LinphoneCall)getReplacedCall(nativePtr);
+       }
+
+       public int getDuration() {
+               return getDuration(nativePtr);
+       }
+       public float getAverageQuality() {
+               return getAverageQuality(nativePtr);
+       }
+       public float getCurrentQuality() {
+               return getCurrentQuality(nativePtr);
+       }
+
+       private native String getAuthenticationToken(long nativePtr);
+       public String getAuthenticationToken(){
+               return getAuthenticationToken(nativePtr);
+       }
+
+       private native boolean isAuthenticationTokenVerified(long nativePtr);
+       public boolean isAuthenticationTokenVerified(){
+               return isAuthenticationTokenVerified(nativePtr);
+       }
+
+       private native void setAuthenticationTokenVerified(long nativePtr, boolean verified);
+       public void setAuthenticationTokenVerified(boolean verified){
+               setAuthenticationTokenVerified(nativePtr, verified);
+       }
+
+       public boolean isInConference() {
+               LinphoneCallParamsImpl params = new LinphoneCallParamsImpl(getCurrentParamsCopy(nativePtr));
+               return params.localConferenceMode();
+       }
+
+       @Override
+       public String toString() {
+               return "Call " + nativePtr;
+       }
+
+       private native float getPlayVolume(long nativePtr);
+       public float getPlayVolume() {
+               return getPlayVolume(nativePtr);
+       }
+       
+       private native void takeSnapshot(long nativePtr, String path);
+       public void takeSnapshot(String path) {
+               takeSnapshot(nativePtr, path);
+       }
+
+       private native void zoomVideo(long nativePtr, float factor, float cx, float cy);
+       public void zoomVideo(float factor, float cx, float cy) {
+               zoomVideo(nativePtr, factor, cx, cy);
+       }
+}
diff --git a/java/impl/org/linphone/core/LinphoneCallLogImpl.java b/java/impl/org/linphone/core/LinphoneCallLogImpl.java
new file mode 100644 (file)
index 0000000..0546862
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+LinPhoneCallLogImpl.java
+Copyright (C) 2010  Belledonne Communications, Grenoble, France
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+package org.linphone.core;
+
+
+class LinphoneCallLogImpl implements LinphoneCallLog {
+
+       protected final long nativePtr;
+       
+       private native long getFrom(long nativePtr);
+       private native long getTo(long nativePtr);
+       private native boolean isIncoming(long nativePtr);
+       private native int getStatus(long nativePtr);
+       private native String getStartDate(long nativePtr);
+       private native int getCallDuration(long nativePtr);
+       private native int getCallId(long nativePtr);
+       
+       LinphoneCallLogImpl(long aNativePtr)  {
+               nativePtr = aNativePtr;
+       }
+       
+       public CallDirection getDirection() {
+               return isIncoming(nativePtr)?CallDirection.Incoming:CallDirection.Outgoing;
+       }
+
+       public LinphoneAddress getFrom() {
+               return new LinphoneAddressImpl(getFrom(nativePtr));
+       }
+
+       public LinphoneAddress getTo() {
+               return new LinphoneAddressImpl(getTo(nativePtr));
+       }
+       public CallStatus getStatus() {
+               return LinphoneCallLog.CallStatus.fromInt(getStatus(nativePtr));
+       }
+
+       public long getNativePtr() {
+               return nativePtr;
+       }
+       
+       public String getStartDate() {
+               return getStartDate(nativePtr);
+       }
+
+       public int getCallDuration() {
+               return getCallDuration(nativePtr);
+       }
+       public int getCallId() {
+               return getCallId(nativePtr);
+       }
+}
diff --git a/java/impl/org/linphone/core/LinphoneCallParamsImpl.java b/java/impl/org/linphone/core/LinphoneCallParamsImpl.java
new file mode 100644 (file)
index 0000000..3c45140
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+LinphoneCallParamsImpl.java
+Copyright (C) 2010  Belledonne Communications, Grenoble, France
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+package org.linphone.core;
+
+import org.linphone.core.LinphoneCore.MediaEncryption;
+
+public class LinphoneCallParamsImpl implements LinphoneCallParams {
+       protected final long nativePtr;
+       
+       public LinphoneCallParamsImpl(long nativePtr) {
+               this.nativePtr = nativePtr;
+       }
+
+       private native void enableVideo(long nativePtr, boolean b);
+       private native boolean getVideoEnabled(long nativePtr);
+       private native void audioBandwidth(long nativePtr, int bw);
+       private native void setMediaEncryption(long nativePtr, int menc);
+       private native int getMediaEncryption(long nativePtr);
+       private native long getUsedAudioCodec(long nativePtr);
+       private native long getUsedVideoCodec(long nativePtr);
+       private native void destroy(long nativePtr);
+       
+       
+       public boolean getVideoEnabled() {
+               return getVideoEnabled(nativePtr);
+       }
+
+       public void setVideoEnabled(boolean b) {
+               enableVideo(nativePtr, b);
+       }
+       
+       @Override
+       protected void finalize() throws Throwable {
+               destroy(nativePtr);
+               super.finalize();
+       }
+
+       public void setAudioBandwidth(int value) {
+               audioBandwidth(nativePtr, value);
+       }
+       
+       public MediaEncryption getMediaEncryption() {
+               return MediaEncryption.fromInt(getMediaEncryption(nativePtr));
+       }
+       
+       public void setMediaEnctyption(MediaEncryption menc) {
+               setMediaEncryption(nativePtr, menc.mValue);
+       }
+
+       public PayloadType getUsedAudioCodec() {
+               long ptr = getUsedAudioCodec(nativePtr);
+               if (ptr == 0) return null;
+               return new PayloadTypeImpl(ptr);
+       }
+
+       public PayloadType getUsedVideoCodec() {
+               long ptr = getUsedVideoCodec(nativePtr);
+               if (ptr == 0) return null;
+               return new PayloadTypeImpl(ptr);
+       }
+
+       private native boolean localConferenceMode(long nativePtr);
+       public boolean localConferenceMode() {
+               return localConferenceMode(nativePtr);
+       }
+}
diff --git a/java/impl/org/linphone/core/LinphoneCallStatsImpl.java b/java/impl/org/linphone/core/LinphoneCallStatsImpl.java
new file mode 100644 (file)
index 0000000..53fcb5f
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+LinPhoneCallStatsImpl.java
+Copyright (C) 2010  Belledonne Communications, Grenoble, France
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+package org.linphone.core;
+
+
+class LinphoneCallStatsImpl implements LinphoneCallStats {
+       private int mediaType;
+       private int iceState;
+       private float downloadBandwidth;
+       private float uploadBandwidth;
+       private float senderLossRate;
+       private float receiverLossRate;
+       private float senderInterarrivalJitter;
+       private float receiverInterarrivalJitter;
+       private float roundTripDelay;
+       private long latePacketsCumulativeNumber;
+       private float jitterBufferSize;
+
+       private native int getMediaType(long nativeStatsPtr);
+       private native int getIceState(long nativeStatsPtr);
+       private native float getDownloadBandwidth(long nativeStatsPtr);
+       private native float getUploadBandwidth(long nativeStatsPtr);
+       private native float getSenderLossRate(long nativeStatsPtr);
+       private native float getReceiverLossRate(long nativeStatsPtr);
+       private native float getSenderInterarrivalJitter(long nativeStatsPtr, long nativeCallPtr);
+       private native float getReceiverInterarrivalJitter(long nativeStatsPtr, long nativeCallPtr);
+       private native float getRoundTripDelay(long nativeStatsPtr);
+       private native long getLatePacketsCumulativeNumber(long nativeStatsPtr, long nativeCallPtr);
+       private native float getJitterBufferSize(long nativeStatsPtr);
+
+       protected LinphoneCallStatsImpl(long nativeCallPtr, long nativeStatsPtr) {
+               mediaType = getMediaType(nativeStatsPtr);
+               iceState = getIceState(nativeStatsPtr);
+               downloadBandwidth = getDownloadBandwidth(nativeStatsPtr);
+               uploadBandwidth = getUploadBandwidth(nativeStatsPtr);
+               senderLossRate = getSenderLossRate(nativeStatsPtr);
+               receiverLossRate = getReceiverLossRate(nativeStatsPtr);
+               senderInterarrivalJitter = getSenderInterarrivalJitter(nativeStatsPtr, nativeCallPtr);
+               receiverInterarrivalJitter = getReceiverInterarrivalJitter(nativeStatsPtr, nativeCallPtr);
+               roundTripDelay = getRoundTripDelay(nativeStatsPtr);
+               latePacketsCumulativeNumber = getLatePacketsCumulativeNumber(nativeStatsPtr, nativeCallPtr);
+               jitterBufferSize = getJitterBufferSize(nativeStatsPtr);
+       }
+
+       public MediaType getMediaType() {
+               return MediaType.fromInt(mediaType);
+       }
+
+       public IceState getIceState() {
+               return IceState.fromInt(iceState);
+       }
+
+       public float getDownloadBandwidth() {
+               return downloadBandwidth;
+       }
+
+       public float getUploadBandwidth() {
+               return uploadBandwidth;
+       }
+
+       public float getSenderLossRate() {
+               return senderLossRate;
+       }
+
+       public float getReceiverLossRate() {
+               return receiverLossRate;
+       }
+
+       public float getSenderInterarrivalJitter() {
+               return senderInterarrivalJitter;
+       }
+
+       public float getReceiverInterarrivalJitter() {
+               return receiverInterarrivalJitter;
+       }
+
+       public float getRoundTripDelay() {
+               return roundTripDelay;
+       }
+
+       public long getLatePacketsCumulativeNumber() {
+               return latePacketsCumulativeNumber;
+       }
+
+       public float getJitterBufferSize() {
+               return jitterBufferSize;
+       }
+}
diff --git a/java/impl/org/linphone/core/LinphoneChatMessageImpl.java b/java/impl/org/linphone/core/LinphoneChatMessageImpl.java
new file mode 100644 (file)
index 0000000..62fac1d
--- /dev/null
@@ -0,0 +1,56 @@
+package org.linphone.core;
+
+public class LinphoneChatMessageImpl implements LinphoneChatMessage {
+       protected final long nativePtr;
+       private native void setUserData(long ptr);
+       private native String getMessage(long ptr);
+       private native long getPeerAddress(long ptr);
+       private native String getExternalBodyUrl(long ptr);
+       private native void setExternalBodyUrl(long ptr, String url);
+       private native long getFrom(long ptr);
+       
+       protected LinphoneChatMessageImpl(long aNativePtr)  {
+               nativePtr = aNativePtr;
+               setUserData();
+       }
+       
+       public long getNativePtr() {
+               return nativePtr;
+       }
+       
+       @Override
+       public Object getUserData() {
+               // TODO Auto-generated method stub
+               return null;
+       }
+
+       @Override
+       public void setUserData() {
+               setUserData(nativePtr);
+       }
+
+       @Override
+       public String getMessage() {
+               return getMessage(nativePtr);
+       }
+       
+       @Override
+       public LinphoneAddress getPeerAddress() {
+               return new LinphoneAddressImpl(getPeerAddress(nativePtr));
+       }
+       
+       @Override
+       public String getExternalBodyUrl() {
+               return getExternalBodyUrl(nativePtr);
+       }
+       
+       @Override
+       public void setExternalBodyUrl(String url) {
+               setExternalBodyUrl(nativePtr, url);
+       }
+       
+       @Override
+       public LinphoneAddress getFrom() {
+               return new LinphoneAddressImpl(getFrom(nativePtr));
+       }
+}
diff --git a/java/impl/org/linphone/core/LinphoneChatRoomImpl.java b/java/impl/org/linphone/core/LinphoneChatRoomImpl.java
new file mode 100644 (file)
index 0000000..83141ad
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+LinphoneChatRoomImpl.java
+Copyright (C) 2010  Belledonne Communications, Grenoble, France
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+package org.linphone.core;
+
+import org.linphone.core.LinphoneChatMessage.StateListener;
+
+class LinphoneChatRoomImpl implements LinphoneChatRoom {
+       protected final long nativePtr;
+       private native long createLinphoneChatMessage(long ptr, String message);
+       private native long getPeerAddress(long ptr);
+       private native void sendMessage(long ptr, String message);
+       private native void sendMessage2(long ptr, long message, StateListener listener);
+
+       protected LinphoneChatRoomImpl(long aNativePtr)  {
+               nativePtr = aNativePtr;
+       }
+
+       public LinphoneAddress getPeerAddress() {
+               return new LinphoneAddressImpl(getPeerAddress(nativePtr));
+       }
+
+       public void sendMessage(String message) {
+               sendMessage(nativePtr,message);
+       }
+       
+       @Override
+       public void sendMessage(LinphoneChatMessage message, StateListener listener) {
+               sendMessage2(nativePtr, message.getNativePtr(), listener);
+               
+       }
+
+       @Override
+       public LinphoneChatMessage createLinphoneChatMessage(String message) {
+               return new LinphoneChatMessageImpl(createLinphoneChatMessage(nativePtr, message));
+       }
+}
diff --git a/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java b/java/impl/org/linphone/core/LinphoneCoreFactoryImpl.java
new file mode 100644 (file)
index 0000000..a99509f
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+LinphoneCoreFactoryImpl.java
+Copyright (C) 2010  Belledonne Communications, Grenoble, France
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+package org.linphone.core;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.linphone.mediastream.Version;
+
+import android.util.Log;
+
+public class LinphoneCoreFactoryImpl extends LinphoneCoreFactory {
+
+       private static boolean loadOptionalLibrary(String s) {
+               try {
+                       System.loadLibrary(s);
+                       return true;
+               } catch (Throwable e) {
+                       Log.w("Unable to load optional library lib", s);
+               }
+               return false;
+       }
+
+       static {
+               // FFMPEG (audio/video)
+               loadOptionalLibrary("avutil");
+               loadOptionalLibrary("swscale");
+               loadOptionalLibrary("avcore");
+               
+               if (!hasNeonInCpuFeatures()) {
+                       boolean noNeonLibrariesLoaded = loadOptionalLibrary("avcodecnoneon");
+                       if (!noNeonLibrariesLoaded) {
+                               loadOptionalLibrary("avcodec");
+                       }
+               } else {
+                       loadOptionalLibrary("avcodec");
+               }
+               // OPENSSL (cryptography)
+               // lin prefix avoids collision with libs in /system/lib
+               loadOptionalLibrary("lincrypto");
+               loadOptionalLibrary("linssl");
+
+               // Secure RTP and key negotiation
+               loadOptionalLibrary("srtp");
+               loadOptionalLibrary("zrtpcpp"); // GPLv3+
+
+               // Tunnel
+               loadOptionalLibrary("tunnelclient");
+               
+               // g729 A implementation
+               loadOptionalLibrary("bcg729");
+
+               //Main library
+               if (!hasNeonInCpuFeatures()) {
+                       try {
+                               if (!isArmv7() && !Version.isX86()) {
+                                       System.loadLibrary("linphonearmv5"); 
+                               } else {
+                                       System.loadLibrary("linphonenoneon"); 
+                               }
+                               Log.w("linphone", "No-neon liblinphone loaded");
+                       } catch (UnsatisfiedLinkError ule) {
+                               Log.w("linphone", "Failed to load no-neon liblinphone, loading neon liblinphone");
+                               System.loadLibrary("linphone"); 
+                       }
+               } else {
+                       System.loadLibrary("linphone"); 
+               }
+
+               Version.dumpCapabilities();
+       }
+       @Override
+       public LinphoneAuthInfo createAuthInfo(String username, String password,
+                       String realm) {
+               return new LinphoneAuthInfoImpl(username,password,realm);
+       }
+
+       @Override
+       public LinphoneAddress createLinphoneAddress(String username,
+                       String domain, String displayName) {
+               return new LinphoneAddressImpl(username,domain,displayName);
+       }
+
+       @Override
+       public LinphoneAddress createLinphoneAddress(String identity) {
+               return new LinphoneAddressImpl(identity);
+       }
+
+       @Override
+       public LinphoneCore createLinphoneCore(LinphoneCoreListener listener,
+                       String userConfig, String factoryConfig, Object userdata)
+                       throws LinphoneCoreException {
+               try {
+                       return new LinphoneCoreImpl(listener,new File(userConfig),new File(factoryConfig),userdata);
+               } catch (IOException e) {
+                       throw new LinphoneCoreException("Cannot create LinphoneCore",e);
+               }
+       }
+
+       @Override
+       public LinphoneCore createLinphoneCore(LinphoneCoreListener listener) throws LinphoneCoreException {
+               try {
+                       return new LinphoneCoreImpl(listener);
+               } catch (IOException e) {
+                       throw new LinphoneCoreException("Cannot create LinphoneCore",e);
+               }
+       }
+
+       @Override
+       public LinphoneProxyConfig createProxyConfig(String identity, String proxy,
+                       String route, boolean enableRegister) throws LinphoneCoreException {
+               return new LinphoneProxyConfigImpl(identity,proxy,route,enableRegister);
+       }
+
+       @Override
+       public native void setDebugMode(boolean enable);
+
+       @Override
+       public void setLogHandler(LinphoneLogHandler handler) {
+               //not implemented on Android
+               
+       }
+
+       @Override
+       public LinphoneFriend createLinphoneFriend(String friendUri) {
+               return new LinphoneFriendImpl(friendUri);
+       }
+
+       @Override
+       public LinphoneFriend createLinphoneFriend() {
+               return createLinphoneFriend(null);
+       }
+
+       public static boolean hasNeonInCpuFeatures()
+       {
+               ProcessBuilder cmd;
+               boolean result = false;
+               
+               try {
+                       String[] args = {"/system/bin/cat", "/proc/cpuinfo"};
+                       cmd = new ProcessBuilder(args);
+       
+                  Process process = cmd.start();
+                  InputStream in = process.getInputStream();
+                  byte[] re = new byte[1024];
+                  while(in.read(re) != -1){
+                          String line = new String(re);
+                          if (line.contains("Features")) {
+                                  result = line.contains("neon");
+                                  break;
+                          }
+                  }
+                  in.close();
+               } catch(IOException ex){
+                       ex.printStackTrace();
+               }
+               return result;
+       }
+       
+       public static boolean isArmv7()
+       {
+               return System.getProperty("os.arch").contains("armv7");
+       }
+}
diff --git a/java/impl/org/linphone/core/LinphoneCoreImpl.java b/java/impl/org/linphone/core/LinphoneCoreImpl.java
new file mode 100644 (file)
index 0000000..6059915
--- /dev/null
@@ -0,0 +1,785 @@
+/*
+LinphoneCoreImpl.java
+Copyright (C) 2010  Belledonne Communications, Grenoble, France
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+package org.linphone.core;
+
+import java.io.File;
+import java.io.IOException;
+
+
+class LinphoneCoreImpl implements LinphoneCore {
+
+       private final  LinphoneCoreListener mListener; //to make sure to keep a reference on this object
+       private long nativePtr = 0;
+       private native long newLinphoneCore(LinphoneCoreListener listener,String userConfig,String factoryConfig,Object  userdata);
+       private native void iterate(long nativePtr);
+       private native long getDefaultProxyConfig(long nativePtr);
+
+       private native void setDefaultProxyConfig(long nativePtr,long proxyCfgNativePtr);
+       private native int addProxyConfig(LinphoneProxyConfig jprtoxyCfg,long nativePtr,long proxyCfgNativePtr);
+       private native void clearAuthInfos(long nativePtr);
+       
+       private native void clearProxyConfigs(long nativePtr);
+       private native void addAuthInfo(long nativePtr,long authInfoNativePtr);
+       private native Object invite(long nativePtr,String uri);
+       private native void terminateCall(long nativePtr, long call);
+       private native long getRemoteAddress(long nativePtr);
+       private native boolean  isInCall(long nativePtr);
+       private native boolean isInComingInvitePending(long nativePtr);
+       private native void acceptCall(long nativePtr, long call);
+       private native long getCallLog(long nativePtr,int position);
+       private native int getNumberOfCallLogs(long nativePtr);
+       private native void delete(long nativePtr);
+       private native void setNetworkStateReachable(long nativePtr,boolean isReachable);
+       private native boolean isNetworkStateReachable(long nativePtr);
+       private native void setPlaybackGain(long nativeptr, float gain);
+       private native float getPlaybackGain(long nativeptr);
+       private native void muteMic(long nativePtr,boolean isMuted);
+       private native long interpretUrl(long nativePtr,String destination);
+       private native Object inviteAddress(long nativePtr,long to);
+       private native Object inviteAddressWithParams(long nativePtrLc,long to, long nativePtrParam);
+       private native void sendDtmf(long nativePtr,char dtmf);
+       private native void clearCallLogs(long nativePtr);
+       private native boolean isMicMuted(long nativePtr);
+       private native long findPayloadType(long nativePtr, String mime, int clockRate, int channels);
+       private native int enablePayloadType(long nativePtr, long payloadType,  boolean enable);
+       private native void enableEchoCancellation(long nativePtr,boolean enable);
+       private native boolean isEchoCancellationEnabled(long nativePtr);
+       private native Object getCurrentCall(long nativePtr) ;
+       private native void playDtmf(long nativePtr,char dtmf,int duration);
+       private native void stopDtmf(long nativePtr);
+       private native void setVideoWindowId(long nativePtr, Object wid);
+       private native void setPreviewWindowId(long nativePtr, Object wid);
+       private native void setDeviceRotation(long nativePtr, int rotation);
+       private native void addFriend(long nativePtr,long friend);
+       private native void setPresenceInfo(long nativePtr,int minute_away, String alternative_contact,int status);
+       private native long createChatRoom(long nativePtr,String to);
+       private native void enableVideo(long nativePtr,boolean vcap_enabled,boolean display_enabled);
+       private native boolean isVideoEnabled(long nativePtr);
+       private native void setFirewallPolicy(long nativePtr, int enum_value);
+       private native int getFirewallPolicy(long nativePtr);
+       private native void setStunServer(long nativePtr, String stun_server);
+       private native String getStunServer(long nativePtr);
+       private native long createDefaultCallParams(long nativePtr);
+       private native int updateCall(long ptrLc, long ptrCall, long ptrParams);
+       private native void setUploadBandwidth(long nativePtr, int bw);
+       private native void setDownloadBandwidth(long nativePtr, int bw);
+       private native void setPreferredVideoSize(long nativePtr, int width, int heigth);
+       private native int[] getPreferredVideoSize(long nativePtr);
+       private native void setRing(long nativePtr, String path);
+       private native String getRing(long nativePtr);
+       private native void setRootCA(long nativePtr, String path);
+       private native long[] listVideoPayloadTypes(long nativePtr);
+       private native long[] getProxyConfigList(long nativePtr);
+       private native long[] listAudioPayloadTypes(long nativePtr);
+       private native void enableKeepAlive(long nativePtr,boolean enable);
+       private native boolean isKeepAliveEnabled(long nativePtr);
+       private native int startEchoCalibration(long nativePtr,Object data);
+       private native int getSignalingTransportPort(long nativePtr, int code);
+       private native void setSignalingTransportPorts(long nativePtr, int udp, int tcp, int tls);
+       private native void enableIpv6(long nativePtr,boolean enable);
+       private native int pauseCall(long nativePtr, long callPtr);
+       private native int pauseAllCalls(long nativePtr);
+       private native int resumeCall(long nativePtr, long callPtr);
+       private native void setUploadPtime(long nativePtr, int ptime);
+       private native void setDownloadPtime(long nativePtr, int ptime);
+       private native void setZrtpSecretsCache(long nativePtr, String file);
+       private native void enableEchoLimiter(long nativePtr2, boolean val);
+       private native int setVideoDevice(long nativePtr2, int id);
+       private native int getVideoDevice(long nativePtr2);
+       private native int getMediaEncryption(long nativePtr);
+       private native void setMediaEncryption(long nativePtr, int menc);
+       private native boolean isMediaEncryptionMandatory(long nativePtr);
+       private native void setMediaEncryptionMandatory(long nativePtr, boolean yesno);
+       private native void removeCallLog(long nativePtr, long callLogPtr);
+       private native int getMissedCallsCount(long nativePtr);
+       private native void resetMissedCallsCount(long nativePtr);
+       private native String getVersion(long nativePtr);
+       private native void setAudioPort(long nativePtr, int port);
+       private native void setVideoPort(long nativePtr, int port);
+       private native void setAudioPortRange(long nativePtr, int minPort, int maxPort);
+       private native void setVideoPortRange(long nativePtr, int minPort, int maxPort);
+       private native void setIncomingTimeout(long nativePtr, int timeout);
+       
+       LinphoneCoreImpl(LinphoneCoreListener listener, File userConfig,File factoryConfig,Object  userdata) throws IOException {
+               mListener=listener;
+               nativePtr = newLinphoneCore(listener,userConfig.getCanonicalPath(),factoryConfig.getCanonicalPath(),userdata);
+       }
+       LinphoneCoreImpl(LinphoneCoreListener listener) throws IOException {
+               mListener=listener;
+               nativePtr = newLinphoneCore(listener,null,null,null);
+       }
+       
+       protected void finalize() throws Throwable {
+               
+       }
+       
+       public synchronized void addAuthInfo(LinphoneAuthInfo info) {
+               isValid();
+               addAuthInfo(nativePtr,((LinphoneAuthInfoImpl)info).nativePtr);
+       }
+
+
+
+       public synchronized LinphoneProxyConfig getDefaultProxyConfig() {
+               isValid();
+               long lNativePtr = getDefaultProxyConfig(nativePtr);
+               if (lNativePtr!=0) {
+                       return new LinphoneProxyConfigImpl(lNativePtr); 
+               } else {
+                       return null;
+               }
+       }
+
+       public synchronized LinphoneCall invite(String uri) {
+               isValid();
+               return (LinphoneCall)invite(nativePtr,uri);
+       }
+
+       public synchronized void iterate() {
+               isValid();
+               iterate(nativePtr);
+       }
+
+       public synchronized void setDefaultProxyConfig(LinphoneProxyConfig proxyCfg) {
+               isValid();
+               setDefaultProxyConfig(nativePtr,((LinphoneProxyConfigImpl)proxyCfg).nativePtr);
+       }
+       public synchronized void addProxyConfig(LinphoneProxyConfig proxyCfg) throws LinphoneCoreException{
+               isValid();
+               if (addProxyConfig(proxyCfg,nativePtr,((LinphoneProxyConfigImpl)proxyCfg).nativePtr) !=0) {
+                       throw new LinphoneCoreException("bad proxy config");
+               }
+       }
+       public synchronized void clearAuthInfos() {
+               isValid();
+               clearAuthInfos(nativePtr);
+               
+       }
+       public synchronized void clearProxyConfigs() {
+               isValid();
+               clearProxyConfigs(nativePtr);
+       }
+       public synchronized void terminateCall(LinphoneCall aCall) {
+               isValid();
+               if (aCall!=null)terminateCall(nativePtr,((LinphoneCallImpl)aCall).nativePtr);
+       }
+       public synchronized LinphoneAddress getRemoteAddress() {
+               isValid();
+               long ptr = getRemoteAddress(nativePtr);
+               if (ptr==0) {
+                       return null;
+               } else {
+                       return new LinphoneAddressImpl(ptr);
+               }
+       }
+       public synchronized  boolean isIncall() {
+               isValid();
+               return isInCall(nativePtr);
+       }
+       public synchronized boolean isInComingInvitePending() {
+               isValid();
+               return isInComingInvitePending(nativePtr);
+       }
+       public synchronized void acceptCall(LinphoneCall aCall) {
+               isValid();
+               acceptCall(nativePtr,((LinphoneCallImpl)aCall).nativePtr);
+               
+       }
+       public synchronized LinphoneCallLog[] getCallLogs() {
+               isValid();
+               LinphoneCallLog[] logs = new LinphoneCallLog[getNumberOfCallLogs(nativePtr)]; 
+               for (int i=0;i < getNumberOfCallLogs(nativePtr);i++) {
+                       logs[i] = new LinphoneCallLogImpl(getCallLog(nativePtr, i));
+               }
+               return logs;
+       }
+       public synchronized void destroy() {
+               isValid();
+               delete(nativePtr);
+               nativePtr = 0;
+       }
+       
+       private void isValid() {
+               if (nativePtr == 0) {
+                       throw new RuntimeException("object already destroyed");
+               }
+       }
+       public synchronized void setNetworkReachable(boolean isReachable) {
+               setNetworkStateReachable(nativePtr,isReachable);
+       }
+       public synchronized void setPlaybackGain(float gain) {
+               setPlaybackGain(nativePtr,gain);
+               
+       }
+       public synchronized float getPlaybackGain() {
+               return getPlaybackGain(nativePtr);
+       }
+       public synchronized void muteMic(boolean isMuted) {
+               muteMic(nativePtr,isMuted);
+       }
+       public synchronized LinphoneAddress interpretUrl(String destination) throws LinphoneCoreException {
+               long lAddress = interpretUrl(nativePtr,destination);
+               if (lAddress != 0) {
+                       return new LinphoneAddressImpl(lAddress,true);
+               } else {
+                       throw new LinphoneCoreException("Cannot interpret ["+destination+"]");
+               }
+       }
+       public synchronized LinphoneCall invite(LinphoneAddress to) throws LinphoneCoreException { 
+               LinphoneCall call = (LinphoneCall)inviteAddress(nativePtr,((LinphoneAddressImpl)to).nativePtr);
+               if (call!=null) {
+                       return call;
+               } else {
+                       throw new LinphoneCoreException("Unable to invite address " + to.asString());
+               }
+       }
+
+       public synchronized void sendDtmf(char number) {
+               sendDtmf(nativePtr,number);
+       }
+       public synchronized void clearCallLogs() {
+               clearCallLogs(nativePtr);
+       }
+       public synchronized boolean isMicMuted() {
+               return isMicMuted(nativePtr);
+       }
+       public synchronized PayloadType findPayloadType(String mime, int clockRate, int channels) {
+               isValid();
+               long playLoadType = findPayloadType(nativePtr, mime, clockRate, channels);
+               if (playLoadType == 0) {
+                       return null;
+               } else {
+                       return new PayloadTypeImpl(playLoadType);
+               }
+       }
+       public synchronized void enablePayloadType(PayloadType pt, boolean enable)
+                       throws LinphoneCoreException {
+               isValid();
+               if (enablePayloadType(nativePtr,((PayloadTypeImpl)pt).nativePtr,enable) != 0) {
+                       throw new LinphoneCoreException("cannot enable payload type ["+pt+"]");
+               }
+               
+       }
+       public synchronized void enableEchoCancellation(boolean enable) {
+               isValid();
+               enableEchoCancellation(nativePtr, enable);
+       }
+       public synchronized boolean isEchoCancellationEnabled() {
+               isValid();
+               return isEchoCancellationEnabled(nativePtr);
+               
+       }
+
+       public synchronized LinphoneCall getCurrentCall() {
+               isValid();
+               return (LinphoneCall)getCurrentCall(nativePtr);
+       }
+       
+       public int getPlayLevel() {
+               // TODO Auto-generated method stub
+               return 0;
+       }
+       public void setPlayLevel(int level) {
+               // TODO Auto-generated method stub
+               
+       }
+       public void enableSpeaker(boolean value) {
+               // TODO Auto-generated method stub
+               
+       }
+       public boolean isSpeakerEnabled() {
+               // TODO Auto-generated method stub
+               return false;
+       }
+       public synchronized void playDtmf(char number, int duration) {
+               playDtmf(nativePtr,number, duration);
+               
+       }
+       public synchronized void stopDtmf() {
+               stopDtmf(nativePtr);
+       }
+       
+       public synchronized void addFriend(LinphoneFriend lf) throws LinphoneCoreException {
+               addFriend(nativePtr,((LinphoneFriendImpl)lf).nativePtr);
+               
+       }
+       public synchronized void setPresenceInfo(int minute_away, String alternative_contact,
+                       OnlineStatus status) {
+               setPresenceInfo(nativePtr,minute_away,alternative_contact,status.mValue);
+               
+       }
+       public synchronized LinphoneChatRoom createChatRoom(String to) {
+               return new LinphoneChatRoomImpl(createChatRoom(nativePtr,to));
+       }
+       public synchronized void setPreviewWindow(Object w) {
+               setPreviewWindowId(nativePtr,w);
+       }
+       public synchronized void setVideoWindow(Object w) {
+               setVideoWindowId(nativePtr, w);
+       }
+       public synchronized void setDeviceRotation(int rotation) {
+               setDeviceRotation(nativePtr, rotation);
+       }
+       
+       public synchronized void enableVideo(boolean vcap_enabled, boolean display_enabled) {
+               enableVideo(nativePtr,vcap_enabled, display_enabled);
+       }
+       public synchronized boolean isVideoEnabled() {
+               return isVideoEnabled(nativePtr);
+       }
+       public synchronized FirewallPolicy getFirewallPolicy() {
+               return FirewallPolicy.fromInt(getFirewallPolicy(nativePtr));
+       }
+       public synchronized String getStunServer() {
+               return getStunServer(nativePtr);
+       }
+       public synchronized void setFirewallPolicy(FirewallPolicy pol) {
+               setFirewallPolicy(nativePtr,pol.value());
+       }
+       public synchronized void setStunServer(String stunServer) {
+               setStunServer(nativePtr,stunServer);
+       }
+       
+       public synchronized LinphoneCallParams createDefaultCallParameters() {
+               return new LinphoneCallParamsImpl(createDefaultCallParams(nativePtr));
+       }
+       
+       public synchronized LinphoneCall inviteAddressWithParams(LinphoneAddress to, LinphoneCallParams params) throws LinphoneCoreException {
+               long ptrDestination = ((LinphoneAddressImpl)to).nativePtr;
+               long ptrParams =((LinphoneCallParamsImpl)params).nativePtr;
+               
+               LinphoneCall call = (LinphoneCall)inviteAddressWithParams(nativePtr, ptrDestination, ptrParams);
+               if (call!=null) {
+                       return call;
+               } else {
+                       throw new LinphoneCoreException("Unable to invite with params " + to.asString());
+               }
+       }
+
+       public synchronized int updateCall(LinphoneCall call, LinphoneCallParams params) {
+               long ptrCall = ((LinphoneCallImpl) call).nativePtr;
+               long ptrParams = params!=null ? ((LinphoneCallParamsImpl)params).nativePtr : 0;
+
+               return updateCall(nativePtr, ptrCall, ptrParams);
+       }
+       public synchronized void setUploadBandwidth(int bw) {
+               setUploadBandwidth(nativePtr, bw);
+       }
+
+       public synchronized void setDownloadBandwidth(int bw) {
+               setDownloadBandwidth(nativePtr, bw);
+       }
+
+       public synchronized void setPreferredVideoSize(VideoSize vSize) {
+               setPreferredVideoSize(nativePtr, vSize.width, vSize.height);
+       }
+
+       public synchronized VideoSize getPreferredVideoSize() {
+               int[] nativeSize = getPreferredVideoSize(nativePtr);
+
+               VideoSize vSize = new VideoSize();
+               vSize.width = nativeSize[0];
+               vSize.height = nativeSize[1];
+               return vSize;
+       }
+       public synchronized void setRing(String path) {
+               setRing(nativePtr, path);
+       }
+       public synchronized String getRing() {
+               return getRing(nativePtr);
+       }
+       
+       public synchronized void setRootCA(String path) {
+               setRootCA(nativePtr, path);
+       }
+       
+       public synchronized LinphoneProxyConfig[] getProxyConfigList() {
+               long[] typesPtr = getProxyConfigList(nativePtr);
+               if (typesPtr == null) return null;
+               
+               LinphoneProxyConfig[] proxies = new LinphoneProxyConfig[typesPtr.length];
+
+               for (int i=0; i < proxies.length; i++) {
+                       proxies[i] = new LinphoneProxyConfigImpl(typesPtr[i]);
+               }
+
+               return proxies;
+       }
+       
+       public synchronized PayloadType[] getVideoCodecs() {
+               long[] typesPtr = listVideoPayloadTypes(nativePtr);
+               if (typesPtr == null) return null;
+               
+               PayloadType[] codecs = new PayloadType[typesPtr.length];
+
+               for (int i=0; i < codecs.length; i++) {
+                       codecs[i] = new PayloadTypeImpl(typesPtr[i]);
+               }
+
+               return codecs;
+       }
+       public synchronized PayloadType[] getAudioCodecs() {
+               long[] typesPtr = listAudioPayloadTypes(nativePtr);
+               if (typesPtr == null) return null;
+               
+               PayloadType[] codecs = new PayloadType[typesPtr.length];
+
+               for (int i=0; i < codecs.length; i++) {
+                       codecs[i] = new PayloadTypeImpl(typesPtr[i]);
+               }
+
+               return codecs;
+       }
+       public synchronized boolean isNetworkReachable() {
+               return isNetworkStateReachable(nativePtr);
+       }
+       
+       public synchronized void enableKeepAlive(boolean enable) {
+               enableKeepAlive(nativePtr,enable);
+               
+       }
+       public synchronized boolean isKeepAliveEnabled() {
+               return isKeepAliveEnabled(nativePtr);
+       }
+       public synchronized void startEchoCalibration(Object data) throws LinphoneCoreException {
+               startEchoCalibration(nativePtr, data);
+       }
+       
+       public synchronized Transports getSignalingTransportPorts() {
+               Transports transports = new Transports();
+               transports.udp = getSignalingTransportPort(nativePtr, 0);
+               transports.tcp = getSignalingTransportPort(nativePtr, 1);
+               transports.tls = getSignalingTransportPort(nativePtr, 3);
+               // See C struct LCSipTransports in linphonecore.h
+               // Code is the index in the structure
+               return transports;
+       }
+       public synchronized void setSignalingTransportPorts(Transports transports) {
+               setSignalingTransportPorts(nativePtr, transports.udp, transports.tcp, transports.tls);
+       }
+
+       public synchronized void enableIpv6(boolean enable) {
+               enableIpv6(nativePtr,enable);
+       }
+       public synchronized void adjustSoftwareVolume(int i) {
+               //deprecated, does the same as setPlaybackGain().
+       }
+
+       public synchronized boolean pauseCall(LinphoneCall call) {
+               return 0 == pauseCall(nativePtr, ((LinphoneCallImpl) call).nativePtr);
+       }
+       public synchronized boolean resumeCall(LinphoneCall call) {
+               return 0 == resumeCall(nativePtr, ((LinphoneCallImpl) call).nativePtr);
+       }
+       public synchronized boolean pauseAllCalls() {
+               return 0 == pauseAllCalls(nativePtr);
+       }
+       public synchronized void setDownloadPtime(int ptime) {
+               setDownloadPtime(nativePtr,ptime);
+               
+       }
+       public synchronized void setUploadPtime(int ptime) {
+               setUploadPtime(nativePtr,ptime);
+       }
+
+       public synchronized void setZrtpSecretsCache(String file) {
+               setZrtpSecretsCache(nativePtr,file);
+       }
+       public synchronized void enableEchoLimiter(boolean val) {
+               enableEchoLimiter(nativePtr,val);
+       }
+       public void setVideoDevice(int id) {
+               Log.i("Setting camera id :", id);
+               if (setVideoDevice(nativePtr, id) != 0) {
+                       Log.e("Failed to set video device to id:", id);
+               }
+       }
+       public int getVideoDevice() {
+               return getVideoDevice(nativePtr);
+       }
+
+
+       private native void leaveConference(long nativePtr);    
+       public synchronized void leaveConference() {
+               leaveConference(nativePtr);
+       }
+
+       private native boolean enterConference(long nativePtr); 
+       public synchronized boolean enterConference() {
+               return enterConference(nativePtr);
+       }
+
+       private native boolean isInConference(long nativePtr);
+       public synchronized boolean isInConference() {
+               return isInConference(nativePtr);
+       }
+
+       private native void terminateConference(long nativePtr);
+       public synchronized void terminateConference() {
+               terminateConference(nativePtr);
+       }
+       private native int getConferenceSize(long nativePtr);
+       public synchronized int getConferenceSize() {
+               return getConferenceSize(nativePtr);
+       }
+       private native int getCallsNb(long nativePtr);
+       public synchronized int getCallsNb() {
+               return getCallsNb(nativePtr);
+       }
+       private native void terminateAllCalls(long nativePtr);
+       public synchronized void terminateAllCalls() {
+               terminateAllCalls(nativePtr);
+       }
+       private native Object getCall(long nativePtr, int position);
+       public synchronized LinphoneCall[] getCalls() {
+               int size = getCallsNb(nativePtr);
+               LinphoneCall[] calls = new LinphoneCall[size];
+               for (int i=0; i < size; i++) {
+                       calls[i]=((LinphoneCall)getCall(nativePtr, i));
+               }
+               return calls;
+       }
+       private native void addAllToConference(long nativePtr);
+       public synchronized void addAllToConference() {
+               addAllToConference(nativePtr);
+               
+       }
+       private native void addToConference(long nativePtr, long nativePtrLcall);
+       public synchronized void addToConference(LinphoneCall call) {
+               addToConference(nativePtr, getCallPtr(call));
+               
+       }
+       private native void removeFromConference(long nativePtr, long nativeCallPtr);
+       public synchronized void removeFromConference(LinphoneCall call) {
+               removeFromConference(nativePtr,getCallPtr(call));
+       }
+
+       private long getCallPtr(LinphoneCall call) {
+               return ((LinphoneCallImpl)call).nativePtr;
+       }
+       
+       private long getCallParamsPtr(LinphoneCallParams callParams) {
+               return ((LinphoneCallParamsImpl)callParams).nativePtr;
+       }
+
+       private native int transferCall(long nativePtr, long callPtr, String referTo);
+       public synchronized void transferCall(LinphoneCall call, String referTo) {
+               transferCall(nativePtr, getCallPtr(call), referTo);
+       }
+
+       private native int transferCallToAnother(long nativePtr, long callPtr, long destPtr);
+       public synchronized void transferCallToAnother(LinphoneCall call, LinphoneCall dest) {
+               transferCallToAnother(nativePtr, getCallPtr(call), getCallPtr(dest));
+       }
+
+       private native Object findCallFromUri(long nativePtr, String uri);
+       @Override
+       public synchronized LinphoneCall findCallFromUri(String uri) {
+               return (LinphoneCall) findCallFromUri(nativePtr, uri);
+       }
+
+       public synchronized MediaEncryption getMediaEncryption() {
+               return MediaEncryption.fromInt(getMediaEncryption(nativePtr));
+       }
+       public synchronized boolean isMediaEncryptionMandatory() {
+               return isMediaEncryptionMandatory(nativePtr);
+       }
+       public synchronized void setMediaEncryption(MediaEncryption menc) {
+               setMediaEncryption(nativePtr, menc.mValue);     
+       }
+       public synchronized void setMediaEncryptionMandatory(boolean yesno) {
+               setMediaEncryptionMandatory(nativePtr, yesno);
+       }
+
+       private native int getMaxCalls(long nativePtr);
+       public synchronized int getMaxCalls() {
+               return getMaxCalls(nativePtr);
+       }
+       @Override
+       public boolean isMyself(String uri) {
+               LinphoneProxyConfig lpc = getDefaultProxyConfig();
+               if (lpc == null) return false;
+               return uri.equals(lpc.getIdentity());
+       }
+
+       private native boolean soundResourcesLocked(long nativePtr);
+       public synchronized boolean soundResourcesLocked() {
+               return soundResourcesLocked(nativePtr);
+       }
+
+       private native void setMaxCalls(long nativePtr, int max);
+       @Override
+       public synchronized void setMaxCalls(int max) {
+               setMaxCalls(nativePtr, max);
+       }
+       private native boolean isEchoLimiterEnabled(long nativePtr);
+       @Override
+       public synchronized boolean isEchoLimiterEnabled() {
+               return isEchoLimiterEnabled(nativePtr);
+       }
+       private native boolean mediaEncryptionSupported(long nativePtr, int menc);
+       @Override
+       public synchronized boolean mediaEncryptionSupported(MediaEncryption menc) {
+               return mediaEncryptionSupported(nativePtr,menc.mValue);
+       }
+
+       private native void setPlayFile(long nativePtr, String path);
+
+       @Override
+       public synchronized void setPlayFile(String path) {
+               setPlayFile(nativePtr, path);
+       }
+
+
+       private native void tunnelAddServerAndMirror(long nativePtr, String host, int port, int mirror, int ms);
+       @Override
+       public synchronized void tunnelAddServerAndMirror(String host, int port, int mirror, int ms) {
+               tunnelAddServerAndMirror(nativePtr, host, port, mirror, ms);
+       }
+
+       private native void tunnelAutoDetect(long nativePtr);
+       @Override
+       public synchronized void tunnelAutoDetect() {
+               tunnelAutoDetect(nativePtr);
+       }
+
+       private native void tunnelCleanServers(long nativePtr);
+       @Override
+       public synchronized void tunnelCleanServers() {
+               tunnelCleanServers(nativePtr);
+       }
+
+       private native void tunnelEnable(long nativePtr, boolean enable);
+       @Override
+       public synchronized void tunnelEnable(boolean enable) {
+               tunnelEnable(nativePtr, enable);
+       }
+
+       @Override
+       public native boolean isTunnelAvailable();
+       
+       private native void acceptCallWithParams(long nativePtr, long aCall,
+                       long params);
+       @Override
+       public synchronized void acceptCallWithParams(LinphoneCall aCall,
+                       LinphoneCallParams params) throws LinphoneCoreException {
+               acceptCallWithParams(nativePtr, getCallPtr(aCall), getCallParamsPtr(params));
+       }
+       
+       private native void acceptCallUpdate(long nativePtr, long aCall, long params);
+       @Override
+       public synchronized void acceptCallUpdate(LinphoneCall aCall, LinphoneCallParams params)
+                       throws LinphoneCoreException {
+               acceptCallUpdate(nativePtr, getCallPtr(aCall), getCallParamsPtr(params));               
+       }
+       
+       private native void deferCallUpdate(long nativePtr, long aCall);
+       @Override
+       public synchronized void deferCallUpdate(LinphoneCall aCall)
+                       throws LinphoneCoreException {
+               deferCallUpdate(nativePtr, getCallPtr(aCall));
+       }
+       
+       private native void setVideoPolicy(long nativePtr, boolean autoInitiate, boolean autoAccept);
+       public synchronized void setVideoPolicy(boolean autoInitiate, boolean autoAccept) {
+               setVideoPolicy(nativePtr, autoInitiate, autoAccept);
+       }
+       private native void setUserAgent(long nativePtr, String name, String version);
+       @Override
+       public void setUserAgent(String name, String version) {
+               setUserAgent(nativePtr,name,version);
+       }
+
+       private native void setCpuCountNative(int count);
+       public void setCpuCount(int count)
+       {
+               setCpuCountNative(count);
+       }
+       
+       public int getMissedCallsCount() {
+               return getMissedCallsCount(nativePtr);
+       }
+       
+       public void removeCallLog(LinphoneCallLog log) {
+               removeCallLog(nativePtr, ((LinphoneCallLogImpl) log).getNativePtr());
+       }
+
+       public void resetMissedCallsCount() {
+               resetMissedCallsCount(nativePtr);
+       }
+       
+       private native void tunnelSetHttpProxy(long nativePtr, String proxy_host, int port,
+                       String username, String password);
+       @Override
+       public void tunnelSetHttpProxy(String proxy_host, int port,
+                       String username, String password) {
+               tunnelSetHttpProxy(nativePtr, proxy_host, port, username, password);
+       }
+       
+       private native void refreshRegisters(long nativePtr);
+       public void refreshRegisters() {
+               refreshRegisters(nativePtr);
+       }
+       
+       @Override
+       public String getVersion() {
+               return getVersion(nativePtr);
+       }
+       
+       @Override
+       public PayloadType findPayloadType(String mime, int clockRate) {
+               return null;
+       }
+       
+       private native void removeFriend(long ptr, long lf);
+       @Override
+       public void removeFriend(LinphoneFriend lf) {
+               removeFriend(nativePtr, lf.getNativePtr());
+       }
+       
+       private native long getFriendByAddress(long ptr, String sipUri);
+       @Override
+       public LinphoneFriend findFriendByAddress(String sipUri) {
+               long ptr = getFriendByAddress(nativePtr, sipUri);
+               if (ptr == 0) {
+                       return null;
+               }
+               return new LinphoneFriendImpl(ptr);
+       }
+       
+       public void setAudioPort(int port) {
+               setAudioPort(nativePtr, port);
+       }
+       
+       public void setVideoPort(int port) {
+               setVideoPort(nativePtr, port);
+       }
+       
+       public void setAudioPortRange(int minPort, int maxPort) {
+               setAudioPortRange(nativePtr, minPort, maxPort);
+       }
+       
+       public void setVideoPortRange(int minPort, int maxPort) {
+               setVideoPortRange(nativePtr, minPort, maxPort);
+       }
+       
+       public void setIncomingTimeout(int timeout) {
+               setIncomingTimeout(nativePtr, timeout);
+       }
+}
diff --git a/java/impl/org/linphone/core/LinphoneFriendImpl.java b/java/impl/org/linphone/core/LinphoneFriendImpl.java
new file mode 100644 (file)
index 0000000..6e7aa2d
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+LinphoneFriendImpl.java
+Copyright (C) 2010  Belledonne Communications, Grenoble, France
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+package org.linphone.core;
+
+import java.io.Serializable;
+
+class LinphoneFriendImpl implements LinphoneFriend, Serializable {
+       protected final long nativePtr;
+       private native long newLinphoneFriend(String friendUri);
+       private native void setAddress(long nativePtr,long friend);
+       private native long getAddress(long nativePtr);
+       private native void setIncSubscribePolicy(long nativePtr,int enumValue);
+       private native int  getIncSubscribePolicy(long nativePtr);
+       private native void enableSubscribes(long nativePtr,boolean value);
+       private native boolean isSubscribesEnabled(long nativePtr);
+       private native int getStatus(long nativePtr);
+       private native void edit(long nativePtr);
+       private native void done(long nativePtr);
+       
+       private native void  delete(long ptr);
+       boolean ownPtr = false;
+       protected LinphoneFriendImpl()  {
+               nativePtr = newLinphoneFriend(null);
+       }       
+       protected LinphoneFriendImpl(String friendUri)  {
+               nativePtr = newLinphoneFriend(friendUri);
+       }
+       protected LinphoneFriendImpl(long aNativePtr)  {
+               nativePtr = aNativePtr;
+               ownPtr=false;
+       }
+       protected void finalize() throws Throwable {
+               if (ownPtr) delete(nativePtr);
+       }
+       public void setAddress(LinphoneAddress anAddress) {
+               this.setAddress(nativePtr, ((LinphoneAddressImpl)anAddress).nativePtr);
+       }
+       public LinphoneAddress getAddress() {
+               return new LinphoneAddressImpl(getAddress(nativePtr));
+       }
+       public void setIncSubscribePolicy(SubscribePolicy policy) {
+               setIncSubscribePolicy(nativePtr,policy.mValue);
+       }
+       public SubscribePolicy getIncSubscribePolicy() {
+               return SubscribePolicy.fromInt(getIncSubscribePolicy(nativePtr)) ;
+       }
+       public void enableSubscribes(boolean enable) {
+               enableSubscribes(nativePtr, enable);
+       }
+       public boolean isSubscribesEnabled() {
+               return isSubscribesEnabled(nativePtr);
+       }
+       public OnlineStatus getStatus() {
+               return OnlineStatus.fromInt(getStatus(nativePtr));
+       }
+       public void edit() {
+               edit(nativePtr);
+       }
+       public void done() {
+               done(nativePtr);
+       }
+       public long getNativePtr() {
+               return nativePtr;
+       }
+}
diff --git a/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java b/java/impl/org/linphone/core/LinphoneProxyConfigImpl.java
new file mode 100644 (file)
index 0000000..2295bce
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+LinphoneProxyConfigImpl.java
+Copyright (C) 2010  Belledonne Communications, Grenoble, France
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+package org.linphone.core;
+
+import org.linphone.core.LinphoneCore.RegistrationState;
+
+
+
+
+
+class LinphoneProxyConfigImpl implements LinphoneProxyConfig {
+
+       protected final long nativePtr;
+       
+       private native int getState(long nativePtr);
+       private native void setExpires(long nativePtr, int delay);
+
+       boolean ownPtr = false;
+       protected LinphoneProxyConfigImpl(String identity,String proxy,String route, boolean enableRegister) throws LinphoneCoreException {
+               nativePtr = newLinphoneProxyConfig();
+               setIdentity(identity);
+               setProxy(proxy);
+               enableRegister(enableRegister);
+               ownPtr=true;
+       }
+       protected LinphoneProxyConfigImpl(long aNativePtr)  {
+               nativePtr = aNativePtr;
+               ownPtr=false;
+       }
+       protected void finalize() throws Throwable {
+               //Log.e(LinphoneService.TAG,"fixme, should release underlying proxy config");
+               if (ownPtr) delete(nativePtr);
+       }
+       private native long newLinphoneProxyConfig();
+       private native void  delete(long ptr);
+
+       private native void edit(long ptr);
+       private native void done(long ptr);
+       
+       private native void setIdentity(long ptr,String identity);
+       private native String getIdentity(long ptr);
+       private native int setProxy(long ptr,String proxy);
+       private native String getProxy(long ptr);
+       
+
+       private native void enableRegister(long ptr,boolean value);
+       private native boolean isRegisterEnabled(long ptr);
+       
+       private native boolean isRegistered(long ptr);
+       private native void setDialPrefix(long ptr, String prefix);
+       
+       private native String normalizePhoneNumber(long ptr,String number);
+       
+       private native String getDomain(long ptr);
+       
+       private native void setDialEscapePlus(long ptr, boolean value);
+       
+       private native String getRoute(long ptr);
+       private native int setRoute(long ptr,String uri);
+       private native void enablePublish(long ptr,boolean enable);
+       private native boolean publishEnabled(long ptr);
+       private native void setContactParameters(long ptr, String params);
+       
+       private native int lookupCCCFromIso(long nativePtr, String iso);
+       
+       public void enableRegister(boolean value) {
+               enableRegister(nativePtr,value);
+       }
+
+       public void done() {
+               done(nativePtr);
+       }
+
+       public void edit() {
+               edit(nativePtr);
+       }
+
+       public void setIdentity(String identity) throws LinphoneCoreException {
+               setIdentity(nativePtr,identity);
+       }
+
+       public void setProxy(String proxyUri) throws LinphoneCoreException {
+               if (setProxy(nativePtr,proxyUri)!=0) {
+                       throw new LinphoneCoreException("Bad proxy address ["+proxyUri+"]");
+               }
+       }
+       public String normalizePhoneNumber(String number) {
+               return normalizePhoneNumber(nativePtr,number);
+       }
+       public void setDialPrefix(String prefix) {
+               setDialPrefix(nativePtr, prefix);
+       }
+       public String getDomain() {
+               return getDomain(nativePtr);
+       }
+       public void setDialEscapePlus(boolean value) {
+                setDialEscapePlus(nativePtr,value);
+       }
+       public String getIdentity() {
+               return getIdentity(nativePtr);
+       }
+       public String getProxy() {
+               return getProxy(nativePtr);
+       }
+       public boolean isRegistered() {
+               return isRegistered(nativePtr);
+       }
+       public boolean registerEnabled() {
+               return isRegisterEnabled(nativePtr);
+       }
+       public String getRoute() {
+               return getRoute(nativePtr);
+       }
+       public void setRoute(String routeUri) throws LinphoneCoreException {
+               if (setRoute(nativePtr, routeUri) != 0) {
+                       throw new LinphoneCoreException("cannot set route ["+routeUri+"]");
+               }
+       }
+       public void enablePublish(boolean enable) {
+               enablePublish(nativePtr,enable);
+       }
+       public RegistrationState getState() {
+               return RegistrationState.fromInt(getState(nativePtr));
+       }
+
+       public void setExpires(int delay) {
+               setExpires(nativePtr, delay);
+       }
+       public boolean publishEnabled() {
+               return publishEnabled(nativePtr); 
+       }
+       @Override
+       public void setContactParameters(String params) {
+               setContactParameters(nativePtr, params);
+       }
+       @Override
+       public int lookupCCCFromIso(String iso) {
+               return lookupCCCFromIso(nativePtr, iso);
+       }
+}
diff --git a/java/impl/org/linphone/core/Log.java b/java/impl/org/linphone/core/Log.java
new file mode 100644 (file)
index 0000000..b70b659
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+Log.java
+Copyright (C) 2011  Belledonne Communications, Grenoble, France
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+package org.linphone.core;
+
+import static android.util.Log.DEBUG;
+import static android.util.Log.ERROR;
+import static android.util.Log.INFO;
+import static android.util.Log.WARN;
+
+/**
+ * Convenient wrapper for Android logs.
+ *
+ * @author Guillaume Beraudo
+ */
+public final class Log {
+
+       public static final String TAG = "Linphone";
+       private static final boolean useIsLoggable = false;
+
+       @SuppressWarnings(value="all")
+       private static boolean isLoggable(int level) {
+               return !useIsLoggable || android.util.Log.isLoggable(TAG, level);
+       }
+
+       public static void i(Object...objects) {
+               if (isLoggable(INFO)) {
+                       android.util.Log.i(TAG, toString(objects));
+               }
+       }
+       public static void i(Throwable t, Object...objects) {
+               if (isLoggable(INFO)) {
+                       android.util.Log.i(TAG, toString(objects), t);
+               }
+       }
+
+       
+       public static void d(Object...objects) {
+               if (isLoggable(DEBUG)) {
+                       android.util.Log.d(TAG, toString(objects));
+               }
+       }
+       public static void d(Throwable t, Object...objects) {
+               if (isLoggable(DEBUG)) {
+                       android.util.Log.d(TAG, toString(objects), t);
+               }
+       }
+       
+       public static void w(Object...objects) {
+               if (isLoggable(WARN)) {
+                       android.util.Log.w(TAG, toString(objects));
+               }
+       }
+       public static void w(Throwable t, Object...objects) {
+               if (isLoggable(WARN)) {
+                       android.util.Log.w(TAG, toString(objects), t);
+               }
+       }
+       
+       public static void e(Object...objects) {
+               if (isLoggable(ERROR)) {
+                       android.util.Log.e(TAG, toString(objects));
+               }
+       }
+       public static void e(Throwable t, Object...objects) {
+               if (isLoggable(ERROR)) {
+                       android.util.Log.e(TAG, toString(objects), t);
+               }
+       }
+
+       /**
+        * @throws RuntimeException always throw after logging the error message.
+        */
+       public static void f(Object...objects) {
+               if (isLoggable(ERROR)) {
+                       android.util.Log.e(TAG, toString(objects));
+                       throw new RuntimeException("Fatal error : " + toString(objects));
+               }
+       }
+       /**
+        * @throws RuntimeException always throw after logging the error message.
+        */
+       public static void f(Throwable t, Object...objects) {
+               if (isLoggable(ERROR)) {
+                       android.util.Log.e(TAG, toString(objects), t);
+                       throw new RuntimeException("Fatal error : " + toString(objects), t);
+               }
+       }
+
+       private static String toString(Object...objects) {
+               StringBuilder sb = new StringBuilder();
+               for (Object o : objects) {
+                       sb.append(o);
+               }
+               return sb.toString();
+       }
+}
diff --git a/java/impl/org/linphone/core/PayloadTypeImpl.java b/java/impl/org/linphone/core/PayloadTypeImpl.java
new file mode 100644 (file)
index 0000000..864b094
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+PayloadTypeImpl.java
+Copyright (C) 2010  Belledonne Communications, Grenoble, France
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+
+package org.linphone.core;
+
+class PayloadTypeImpl implements PayloadType {
+
+       protected final long nativePtr;
+       
+       private native String toString(long ptr);
+       private native String getMime(long ptr);
+       private native int getRate(long ptr);
+
+       protected PayloadTypeImpl(long aNativePtr)  {
+               nativePtr = aNativePtr;
+       }
+       
+       public int getRate() {
+               return getRate(nativePtr);
+       }
+
+       public String getMime() {
+               return getMime(nativePtr);
+       }
+       
+       public String toString() {
+               return toString(nativePtr);
+       }
+}
diff --git a/java/impl/org/linphone/core/video/VideoUtil.java b/java/impl/org/linphone/core/video/VideoUtil.java
new file mode 100644 (file)
index 0000000..065557b
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+VideoUtil.java
+Copyright (C) 2011  Belledonne Communications, Grenoble, France
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+*/
+package org.linphone.core.video;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.linphone.core.VideoSize;
+
+import android.hardware.Camera.Size;
+
+/**
+ * @author Guillaume Beraudo
+ */
+final class VideoUtil {
+
+       private VideoUtil() {}
+
+       public static List<VideoSize> createList(List<Size> supportedVideoSizes) {
+               List<VideoSize> converted = new ArrayList<VideoSize>(supportedVideoSizes.size());
+               for (Size s : supportedVideoSizes) {
+                       converted.add(new VideoSize(s.width, s.height));
+               }
+               return converted;
+       }
+}
index 129b28570a3ee72c21f6a6ea2d5d69dd57fd6e60..aa4b7a9c304a095830301916f356d5225d561e44 100644 (file)
@@ -5,13 +5,7 @@ AC_REQUIRE([LP_CHECK_OSIP2])
 
 
 case $host_alias in
-       i386-apple*)
-               OSIP_LIBS="$OSIP_LIBS  -framework CoreFoundation -framework CFNetwork -lresolv"
-       ;;
-       armv6-apple*)
-               OSIP_LIBS="$OSIP_LIBS  -framework CoreFoundation -framework CFNetwork -lresolv"
-       ;;
-       armv7-apple*)
+       i386-apple*|armv6-apple*|armv7-apple*|armv7s-apple*)
                OSIP_LIBS="$OSIP_LIBS  -framework CoreFoundation -framework CFNetwork -lresolv"
        ;;
        x86_64-apple*)
index 13a217fda4dbdec5062b78cb449dc16f5d7846c9..ebb7656cd00dfc159e1f3384a72abeec5311d655 100644 (file)
@@ -22,15 +22,22 @@ if test "$readline_prefix" != "none"; then
        AC_CHECK_HEADERS(readline.h readline/readline.h, readline_h_found=yes)
        AC_CHECK_HEADERS(history.h readline/history.h)
        
-       AC_CHECK_LIB(readline, readline, [readline_libs_found=yes],[],[])
-       
+       for termcap_lib in "" -ltermcap -lcurses -lncurses; do
+               unset ac_cv_lib_readline_readline
+               AC_CHECK_LIB(readline, readline, [readline_libs_found=yes],[],[$termcap_lib])
+               if test "x$readline_libs_found" = "xyes" ; then
+                       READLINE_LIBS="$READLINE_LIBS -lreadline $termcap_lib"
+                       break
+               fi
+       done
+
        LIBS=$LIBS_save
        CPPFLAGS=$CPPFLAGS_save
        
        if test "$readline_libs_found$readline_h_found" != "yesyes" ; then
                AC_MSG_WARN([Could not find libreadline headers or library, linphonec will have limited prompt features])
        else
-               READLINE_LIBS="$READLINE_LIBS -lreadline "
+               AC_DEFINE([HAVE_READLINE],1,[defined when compiling with readline support])
        fi
        
        
index a457709df8daa72544fc36283c0053c4f09d0249..23c75b19523c172c97ba89c76cf7672fc804b14a 160000 (submodule)
@@ -1 +1 @@
-Subproject commit a457709df8daa72544fc36283c0053c4f09d0249
+Subproject commit 23c75b19523c172c97ba89c76cf7672fc804b14a
diff --git a/oRTP b/oRTP
index cbe444a6098346311b412a5723190107e77d9c42..ddc4f7d041967305483761fc9c643d3bb290a5f1 160000 (submodule)
--- a/oRTP
+++ b/oRTP
@@ -1 +1 @@
-Subproject commit cbe444a6098346311b412a5723190107e77d9c42
+Subproject commit ddc4f7d041967305483761fc9c643d3bb290a5f1
index 683f1492fdb1d2e53790933cf60b35a4cbd6e500..1af3423bb9eff9d70c158f1f5fb704ce08876c70 100644 (file)
@@ -24,6 +24,7 @@ gtk/loginframe.c
 [type: gettext/glade]gtk/buddylookup.ui
 [type: gettext/glade]gtk/waiting.ui
 [type: gettext/glade]gtk/dscp_settings.ui
+[type: gettext/glade]gtk/call_statistics.ui
 [type: gettext/glade]gtk/tunnel_config.ui
 coreapi/linphonecore.c
 coreapi/misc.c