]> sjero.net Git - linphone/commitdiff
Add JNI to access call statistics.
authorGhislain MARY <ghislain.mary@belledonne-communications.com>
Wed, 19 Sep 2012 11:38:02 +0000 (13:38 +0200)
committerGhislain MARY <ghislain.mary@belledonne-communications.com>
Fri, 21 Sep 2012 13:40:40 +0000 (15:40 +0200)
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/linphonecore_jni.cc
java/common/org/linphone/core/LinphoneCall.java
java/common/org/linphone/core/LinphoneCallStats.java [new file with mode: 0644]
java/common/org/linphone/core/LinphoneCoreListener.java

index 1d86d482bd64b0dbd94ce945e1aed204109f44ef..bf253b727223b50876ae56f7898f6251cff82556 100644 (file)
@@ -20,6 +20,7 @@ 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;
@@ -97,6 +98,7 @@ 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){}
index 91dc0f247ff5fe6f727ab03b87f9082c329e02d6..7514a1ddc50750ac19a6cd40cfa3652449d0a75c 100644 (file)
@@ -20,6 +20,7 @@ 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;
@@ -75,6 +76,7 @@ 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){}
index 354f9750157ca6bca611fc30bb564ff96935690c..4b63e88133f0101a5334aeb019d3033968966ea9 100644 (file)
@@ -20,6 +20,7 @@ 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;
@@ -69,6 +70,7 @@ 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){}
index 48e473d61fe58a1918b9c92285b605fca2408f63..86b3001438c232ae75f4c7571103395cb4d3d21f 100644 (file)
@@ -20,6 +20,7 @@ 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;
@@ -80,6 +81,7 @@ 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){}
index 16d44390c458b93e7e4928ee0612282eb6acc14c..38d36ae42f442c4d82c36be4487540ea2a7baa1a 100644 (file)
@@ -112,6 +112,7 @@ public:
                vTable.message_received = message_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 +134,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;");
 
@@ -172,6 +176,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 +192,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 +211,7 @@ public:
        jmethodID notifyPresenceReceivedId;
        jmethodID textReceivedId;
        jmethodID messageReceivedId;
+       jmethodID callStatsUpdatedId;
 
        jclass globalStateClass;
        jmethodID globalStateId;
@@ -215,6 +225,11 @@ public:
        jmethodID callStateId;
        jmethodID callStateFromIntId;
 
+       jclass callStatsClass;
+       jmethodID callStatsId;
+       jmethodID callSetAudioStatsId;
+       jmethodID callSetVideoStatsId;
+
        jclass chatMessageStateClass;
        jmethodID chatMessageStateFromIntId;
 
@@ -424,6 +439,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);
+       }
 
 
 };
@@ -1211,6 +1244,113 @@ extern "C" jint Java_org_linphone_core_LinphoneCallLogImpl_getCallDuration(JNIEn
        return ((LinphoneCallLog*)ptr)->duration;
 }
 
+/* CallStats */
+extern "C" int Java_org_linphone_core_LinphoneCallStatsImpl_getMediaType(JNIEnv *env, jobject thiz, jlong stats_ptr) {
+       return (int)((LinphoneCallStats *)stats_ptr)->type;
+}
+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->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->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 = linphone_call_get_current_params(call);
+       const PayloadType *pt;
+       const report_block_t *srb = NULL;
+
+       if (!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;
+       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 = linphone_call_get_current_params(call);
+       const PayloadType *pt;
+       const report_block_t *rrb = NULL;
+
+       if (!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_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;
+
+       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*/
 extern "C" jstring Java_org_linphone_core_PayloadTypeImpl_toString(JNIEnv*  env,jobject  thiz,jlong ptr) {
        PayloadType* pt = (PayloadType*)ptr;
index 6fe6704ded9412b7354be5eb22a5b364b8c530d1..35e173d5a802d1a454b827780f3aca081285e475 100644 (file)
@@ -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();
 
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..f391b2a
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+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;
+               }
+       }
+
+       /**
+        * Get the stats media type
+        * @return MediaType
+        */
+       public MediaType getMediaType();
+
+       /**
+        * 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 a84f736d2c164099a546d4febb793689aff98420..c81dafec4d921341ef4149e2196185a503fe1c48 100644 (file)
@@ -40,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