Index: webrtc/sdk/android/src/jni/peerconnection_jni.cc |
diff --git a/webrtc/sdk/android/src/jni/peerconnection_jni.cc b/webrtc/sdk/android/src/jni/peerconnection_jni.cc |
index 75b1bad20256dcafd288b6a953d8e686c8a216ca..d35813b540b60443e0d298f99ae1450b6571e0be 100644 |
--- a/webrtc/sdk/android/src/jni/peerconnection_jni.cc |
+++ b/webrtc/sdk/android/src/jni/peerconnection_jni.cc |
@@ -839,6 +839,275 @@ class StatsObserverWrapper : public StatsObserver { |
const jmethodID j_value_ctor_; |
}; |
+// Adapter for a Java RTCStatsCollectorCallback presenting a C++ |
+// RTCStatsCollectorCallback and dispatching the callback from C++ back to |
+// Java. |
+class RTCStatsCollectorCallbackWrapper |
+ : public webrtc::RTCStatsCollectorCallback { |
+ public: |
+ RTCStatsCollectorCallbackWrapper(JNIEnv* jni, jobject j_callback) |
+ : j_callback_global_(jni, j_callback), |
+ j_callback_class_(jni, GetObjectClass(jni, j_callback)), |
+ j_stats_report_class_(jni, FindClass(jni, "org/webrtc/RTCStatsReport")), |
+ j_stats_report_ctor_(GetMethodID(jni, |
+ *j_stats_report_class_, |
+ "<init>", |
+ "(JLjava/util/SortedMap;)V")), |
+ j_stats_class_(jni, FindClass(jni, "org/webrtc/RTCStats")), |
+ j_stats_ctor_(GetMethodID( |
+ jni, |
+ *j_stats_class_, |
+ "<init>", |
+ "(JLjava/lang/String;Ljava/lang/String;Ljava/util/SortedMap;)V")), |
+ j_tree_map_class_(jni, FindClass(jni, "java/util/TreeMap")), |
+ j_tree_map_ctor_(GetMethodID(jni, *j_tree_map_class_, "<init>", "()V")), |
+ j_tree_map_put_(GetMethodID( |
+ jni, |
+ *j_tree_map_class_, |
+ "put", |
+ "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;")), |
+ j_boolean_class_(jni, FindClass(jni, "java/lang/Boolean")), |
+ j_boolean_ctor_(GetMethodID(jni, *j_boolean_class_, "<init>", "(Z)V")), |
+ j_integer_class_(jni, FindClass(jni, "java/lang/Integer")), |
+ j_integer_ctor_(GetMethodID(jni, *j_integer_class_, "<init>", "(I)V")), |
+ j_long_class_(jni, FindClass(jni, "java/lang/Long")), |
+ j_long_ctor_(GetMethodID(jni, *j_long_class_, "<init>", "(J)V")), |
+ j_big_integer_class_(jni, FindClass(jni, "java/math/BigInteger")), |
+ j_big_integer_ctor_(GetMethodID(jni, |
+ *j_big_integer_class_, |
+ "<init>", |
+ "(Ljava/lang/String;)V")), |
+ j_double_class_(jni, FindClass(jni, "java/lang/Double")), |
+ j_double_ctor_(GetMethodID(jni, *j_double_class_, "<init>", "(D)V")), |
+ j_string_class_(jni, FindClass(jni, "java/lang/String")) {} |
+ |
+ void OnStatsDelivered( |
+ const rtc::scoped_refptr<const webrtc::RTCStatsReport>& report) override { |
+ JNIEnv* jni = AttachCurrentThreadIfNeeded(); |
+ ScopedLocalRefFrame local_ref_frame(jni); |
+ jobject j_report = ReportToJava(jni, report); |
+ jmethodID m = GetMethodID(jni, *j_callback_class_, "onStatsDelivered", |
+ "(Lorg/webrtc/RTCStatsReport;)V"); |
+ jni->CallVoidMethod(*j_callback_global_, m, j_report); |
+ CHECK_EXCEPTION(jni) << "error during CallVoidMethod"; |
+ } |
+ |
+ private: |
+ jobject ReportToJava( |
+ JNIEnv* jni, |
+ const rtc::scoped_refptr<const webrtc::RTCStatsReport>& report) { |
+ jobject j_stats_map = jni->NewObject(*j_tree_map_class_, j_tree_map_ctor_); |
+ CHECK_EXCEPTION(jni) << "error during NewObject"; |
+ for (const webrtc::RTCStats& stats : *report) { |
+ ScopedLocalRefFrame local_ref_frame(jni); |
hbos
2017/04/10 10:19:42
If we should use ScopedLocalRefFrame for each scop
Taylor Brandstetter
2017/04/10 23:59:33
Confession: I was just copying the pattern of the
hbos
2017/04/11 09:36:13
Confession: I was just guessing how this JNI stuff
|
+ jstring j_id = JavaStringFromStdString(jni, stats.id()); |
+ jobject j_stats = StatsToJava(jni, stats); |
+ jni->CallObjectMethod(j_stats_map, j_tree_map_put_, j_id, j_stats); |
+ CHECK_EXCEPTION(jni) << "error during CallObjectMethod"; |
+ } |
+ jobject j_report = |
+ jni->NewObject(*j_stats_report_class_, j_stats_report_ctor_, |
+ report->timestamp_us(), j_stats_map); |
+ CHECK_EXCEPTION(jni) << "error during NewObject"; |
+ return j_report; |
+ } |
+ |
+ jobject StatsToJava(JNIEnv* jni, const webrtc::RTCStats& stats) { |
+ jstring j_type = JavaStringFromStdString(jni, stats.type()); |
+ jstring j_id = JavaStringFromStdString(jni, stats.id()); |
+ jobject j_members = jni->NewObject(*j_tree_map_class_, j_tree_map_ctor_); |
+ for (const webrtc::RTCStatsMemberInterface* member : stats.Members()) { |
+ if (!member->is_defined()) { |
+ continue; |
+ } |
+ ScopedLocalRefFrame local_ref_frame(jni); |
+ jstring j_name = JavaStringFromStdString(jni, member->name()); |
+ jobject j_member = MemberToJava(jni, member); |
+ jni->CallObjectMethod(j_members, j_tree_map_put_, j_name, j_member); |
+ CHECK_EXCEPTION(jni) << "error during CallObjectMethod"; |
+ } |
+ jobject j_stats = |
+ jni->NewObject(*j_stats_class_, j_stats_ctor_, stats.timestamp_us(), |
+ j_type, j_id, j_members); |
+ CHECK_EXCEPTION(jni) << "error during NewObject"; |
+ return j_stats; |
+ } |
+ |
+ jobject MemberToJava(JNIEnv* jni, |
+ const webrtc::RTCStatsMemberInterface* member) { |
+ switch (member->type()) { |
+ case webrtc::RTCStatsMemberInterface::kBool: { |
+ jobject value = |
+ jni->NewObject(*j_boolean_class_, j_boolean_ctor_, |
+ *member->cast_to<webrtc::RTCStatsMember<bool>>()); |
+ CHECK_EXCEPTION(jni) << "error during NewObject"; |
+ return value; |
+ } |
+ case webrtc::RTCStatsMemberInterface::kInt32: { |
+ jobject value = |
+ jni->NewObject(*j_integer_class_, j_integer_ctor_, |
+ *member->cast_to<webrtc::RTCStatsMember<int32_t>>()); |
+ CHECK_EXCEPTION(jni) << "error during NewObject"; |
+ return value; |
+ } |
+ case webrtc::RTCStatsMemberInterface::kUint32: { |
+ jobject value = jni->NewObject( |
+ *j_long_class_, j_long_ctor_, |
+ (jlong)*member->cast_to<webrtc::RTCStatsMember<uint32_t>>()); |
+ CHECK_EXCEPTION(jni) << "error during NewObject"; |
+ return value; |
+ } |
+ case webrtc::RTCStatsMemberInterface::kInt64: { |
+ jobject value = |
+ jni->NewObject(*j_long_class_, j_long_ctor_, |
+ *member->cast_to<webrtc::RTCStatsMember<int64_t>>()); |
+ CHECK_EXCEPTION(jni) << "error during NewObject"; |
+ return value; |
+ } |
+ case webrtc::RTCStatsMemberInterface::kUint64: { |
+ jobject value = jni->NewObject( |
+ *j_big_integer_class_, j_big_integer_ctor_, |
+ JavaStringFromStdString(jni, member->ValueToString())); |
+ CHECK_EXCEPTION(jni) << "error during NewObject"; |
+ return value; |
+ } |
+ case webrtc::RTCStatsMemberInterface::kDouble: { |
+ jobject value = |
+ jni->NewObject(*j_double_class_, j_double_ctor_, |
+ *member->cast_to<webrtc::RTCStatsMember<double>>()); |
+ CHECK_EXCEPTION(jni) << "error during NewObject"; |
+ return value; |
+ } |
+ case webrtc::RTCStatsMemberInterface::kString: { |
+ return JavaStringFromStdString( |
+ jni, *member->cast_to<webrtc::RTCStatsMember<std::string>>()); |
+ } |
+ case webrtc::RTCStatsMemberInterface::kSequenceBool: { |
+ const std::vector<bool>& values = |
+ *member->cast_to<webrtc::RTCStatsMember<std::vector<bool>>>(); |
+ jobjectArray j_values = |
+ jni->NewObjectArray(values.size(), *j_boolean_class_, nullptr); |
+ CHECK_EXCEPTION(jni) << "error during NewObjectArray"; |
+ for (size_t i = 0; i < values.size(); ++i) { |
+ jobject value = |
+ jni->NewObject(*j_boolean_class_, j_boolean_ctor_, values[i]); |
+ jni->SetObjectArrayElement(j_values, i, value); |
+ CHECK_EXCEPTION(jni) << "error during SetObjectArrayElement"; |
+ } |
+ return j_values; |
+ } |
+ case webrtc::RTCStatsMemberInterface::kSequenceInt32: { |
+ const std::vector<int32_t>& values = |
+ *member->cast_to<webrtc::RTCStatsMember<std::vector<int32_t>>>(); |
+ jobjectArray j_values = |
+ jni->NewObjectArray(values.size(), *j_integer_class_, nullptr); |
+ CHECK_EXCEPTION(jni) << "error during NewObjectArray"; |
+ for (size_t i = 0; i < values.size(); ++i) { |
+ jobject value = |
+ jni->NewObject(*j_integer_class_, j_integer_ctor_, values[i]); |
+ jni->SetObjectArrayElement(j_values, i, value); |
+ CHECK_EXCEPTION(jni) << "error during SetObjectArrayElement"; |
+ } |
+ return j_values; |
+ } |
+ case webrtc::RTCStatsMemberInterface::kSequenceUint32: { |
+ const std::vector<uint32_t>& values = |
+ *member->cast_to<webrtc::RTCStatsMember<std::vector<uint32_t>>>(); |
+ jobjectArray j_values = |
+ jni->NewObjectArray(values.size(), *j_long_class_, nullptr); |
+ CHECK_EXCEPTION(jni) << "error during NewObjectArray"; |
+ for (size_t i = 0; i < values.size(); ++i) { |
+ jobject value = |
+ jni->NewObject(*j_long_class_, j_long_ctor_, values[i]); |
+ jni->SetObjectArrayElement(j_values, i, value); |
+ CHECK_EXCEPTION(jni) << "error during SetObjectArrayElement"; |
+ } |
+ return j_values; |
+ } |
+ case webrtc::RTCStatsMemberInterface::kSequenceInt64: { |
+ const std::vector<int64_t>& values = |
+ *member->cast_to<webrtc::RTCStatsMember<std::vector<int64_t>>>(); |
+ jobjectArray j_values = |
+ jni->NewObjectArray(values.size(), *j_long_class_, nullptr); |
+ CHECK_EXCEPTION(jni) << "error during NewObjectArray"; |
+ for (size_t i = 0; i < values.size(); ++i) { |
+ jobject value = |
+ jni->NewObject(*j_long_class_, j_long_ctor_, values[i]); |
+ jni->SetObjectArrayElement(j_values, i, value); |
+ CHECK_EXCEPTION(jni) << "error during SetObjectArrayElement"; |
+ } |
+ return j_values; |
+ } |
+ case webrtc::RTCStatsMemberInterface::kSequenceUint64: { |
+ const std::vector<uint64_t>& values = |
+ *member->cast_to<webrtc::RTCStatsMember<std::vector<uint64_t>>>(); |
+ jobjectArray j_values = |
+ jni->NewObjectArray(values.size(), *j_big_integer_class_, nullptr); |
+ CHECK_EXCEPTION(jni) << "error during NewObjectArray"; |
+ for (size_t i = 0; i < values.size(); ++i) { |
+ jobject value = jni->NewObject( |
+ *j_big_integer_class_, j_big_integer_ctor_, |
+ JavaStringFromStdString(jni, rtc::ToString(values[i]))); |
+ jni->SetObjectArrayElement(j_values, i, value); |
+ CHECK_EXCEPTION(jni) << "error during SetObjectArrayElement"; |
+ } |
+ return j_values; |
+ } |
+ case webrtc::RTCStatsMemberInterface::kSequenceDouble: { |
+ const std::vector<double>& values = |
+ *member->cast_to<webrtc::RTCStatsMember<std::vector<double>>>(); |
+ jobjectArray j_values = |
+ jni->NewObjectArray(values.size(), *j_double_class_, nullptr); |
+ CHECK_EXCEPTION(jni) << "error during NewObjectArray"; |
+ for (size_t i = 0; i < values.size(); ++i) { |
+ jobject value = |
+ jni->NewObject(*j_double_class_, j_double_ctor_, values[i]); |
+ jni->SetObjectArrayElement(j_values, i, value); |
+ CHECK_EXCEPTION(jni) << "error during SetObjectArrayElement"; |
+ } |
+ return j_values; |
+ } |
+ case webrtc::RTCStatsMemberInterface::kSequenceString: { |
+ const std::vector<std::string>& values = |
+ *member |
+ ->cast_to<webrtc::RTCStatsMember<std::vector<std::string>>>(); |
+ jobjectArray j_values = |
+ jni->NewObjectArray(values.size(), *j_string_class_, nullptr); |
+ CHECK_EXCEPTION(jni) << "error during NewObjectArray"; |
+ for (size_t i = 0; i < values.size(); ++i) { |
+ jni->SetObjectArrayElement(j_values, i, |
+ JavaStringFromStdString(jni, values[i])); |
+ CHECK_EXCEPTION(jni) << "error during SetObjectArrayElement"; |
+ } |
+ return j_values; |
+ } |
+ } |
+ RTC_NOTREACHED(); |
+ return nullptr; |
+ } |
+ |
+ const ScopedGlobalRef<jobject> j_callback_global_; |
+ const ScopedGlobalRef<jclass> j_callback_class_; |
+ const ScopedGlobalRef<jclass> j_stats_report_class_; |
+ const jmethodID j_stats_report_ctor_; |
+ const ScopedGlobalRef<jclass> j_stats_class_; |
+ const jmethodID j_stats_ctor_; |
+ const ScopedGlobalRef<jclass> j_tree_map_class_; |
+ const jmethodID j_tree_map_ctor_; |
+ const jmethodID j_tree_map_put_; |
+ const ScopedGlobalRef<jclass> j_boolean_class_; |
+ const jmethodID j_boolean_ctor_; |
+ const ScopedGlobalRef<jclass> j_integer_class_; |
+ const jmethodID j_integer_ctor_; |
+ const ScopedGlobalRef<jclass> j_long_class_; |
+ const jmethodID j_long_ctor_; |
+ const ScopedGlobalRef<jclass> j_big_integer_class_; |
+ const jmethodID j_big_integer_ctor_; |
+ const ScopedGlobalRef<jclass> j_double_class_; |
+ const jmethodID j_double_ctor_; |
+ const ScopedGlobalRef<jclass> j_string_class_; |
+}; |
+ |
// Wrapper dispatching rtc::VideoSinkInterface to a Java VideoRenderer |
// instance. |
class JavaVideoRendererWrapper |
@@ -2121,8 +2390,8 @@ JOW(jobject, PeerConnection_nativeGetReceivers)(JNIEnv* jni, jobject j_pc) { |
return j_receivers; |
} |
-JOW(bool, PeerConnection_nativeGetStats)( |
- JNIEnv* jni, jobject j_pc, jobject j_observer, jlong native_track) { |
+JOW(bool, PeerConnection_nativeOldGetStats) |
+(JNIEnv* jni, jobject j_pc, jobject j_observer, jlong native_track) { |
rtc::scoped_refptr<StatsObserverWrapper> observer( |
new rtc::RefCountedObject<StatsObserverWrapper>(jni, j_observer)); |
return ExtractNativePC(jni, j_pc)->GetStats( |
@@ -2131,6 +2400,14 @@ JOW(bool, PeerConnection_nativeGetStats)( |
PeerConnectionInterface::kStatsOutputLevelStandard); |
} |
+JOW(void, PeerConnection_nativeNewGetStats) |
+(JNIEnv* jni, jobject j_pc, jobject j_callback) { |
+ rtc::scoped_refptr<RTCStatsCollectorCallbackWrapper> callback( |
+ new rtc::RefCountedObject<RTCStatsCollectorCallbackWrapper>(jni, |
+ j_callback)); |
+ ExtractNativePC(jni, j_pc)->GetStats(callback); |
+} |
+ |
JOW(bool, PeerConnection_nativeStartRtcEventLog)( |
JNIEnv* jni, jobject j_pc, int file_descriptor, int max_size_bytes) { |
return ExtractNativePC(jni, j_pc)->StartRtcEventLog(file_descriptor, |