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));
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;");
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() {
env->DeleteGlobalRef(globalStateClass);
env->DeleteGlobalRef(registrationStateClass);
env->DeleteGlobalRef(callStateClass);
+ env->DeleteGlobalRef(callStatsClass);
env->DeleteGlobalRef(chatMessageStateClass);
env->DeleteGlobalRef(proxyClass);
env->DeleteGlobalRef(callClass);
jmethodID notifyPresenceReceivedId;
jmethodID textReceivedId;
jmethodID messageReceivedId;
+ jmethodID callStatsUpdatedId;
jclass globalStateClass;
jmethodID globalStateId;
jmethodID callStateId;
jmethodID callStateFromIntId;
+ jclass callStatsClass;
+ jmethodID callStatsId;
+ jmethodID callSetAudioStatsId;
+ jmethodID callSetVideoStatsId;
+
jclass chatMessageStateClass;
jmethodID chatMessageStateFromIntId;
}
}
+ 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);
+ }
};
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;
--- /dev/null
+/*
+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();
+}