Commit c476c7ec authored by Ghislain MARY's avatar Ghislain MARY
Browse files

Add JNI to access call statistics.

parent b67d2dd4
......@@ -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){}
......
......@@ -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){}
......
......@@ -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){}
......
......@@ -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){}
......
......@@ -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;
......
......@@ -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();
......
/*
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();
}
......@@ -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
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment