Add Java binding for new getStats implementation.
Very similar to the current interface, but matches the new C++ structure, and exposes the stats values as Objects which can be downcast to more specific types (where the previous API only exposed the values as strings). BUG=webrtc:6871 Review-Url: https://codereview.webrtc.org/2807933003 Cr-Commit-Position: refs/heads/master@{#17746}
This commit is contained in:
@ -42,6 +42,8 @@ rtc_static_library("libjingle_peerconnection_jni") {
|
|||||||
"src/jni/native_handle_impl.cc",
|
"src/jni/native_handle_impl.cc",
|
||||||
"src/jni/native_handle_impl.h",
|
"src/jni/native_handle_impl.h",
|
||||||
"src/jni/peerconnection_jni.cc",
|
"src/jni/peerconnection_jni.cc",
|
||||||
|
"src/jni/rtcstatscollectorcallbackwrapper.cc",
|
||||||
|
"src/jni/rtcstatscollectorcallbackwrapper.h",
|
||||||
"src/jni/surfacetexturehelper_jni.cc",
|
"src/jni/surfacetexturehelper_jni.cc",
|
||||||
"src/jni/surfacetexturehelper_jni.h",
|
"src/jni/surfacetexturehelper_jni.h",
|
||||||
]
|
]
|
||||||
@ -159,6 +161,9 @@ android_library("libjingle_peerconnection_java") {
|
|||||||
"api/org/webrtc/PeerConnection.java",
|
"api/org/webrtc/PeerConnection.java",
|
||||||
"api/org/webrtc/PeerConnectionFactory.java",
|
"api/org/webrtc/PeerConnectionFactory.java",
|
||||||
"api/org/webrtc/RendererCommon.java",
|
"api/org/webrtc/RendererCommon.java",
|
||||||
|
"api/org/webrtc/RTCStats.java",
|
||||||
|
"api/org/webrtc/RTCStatsCollectorCallback.java",
|
||||||
|
"api/org/webrtc/RTCStatsReport.java",
|
||||||
"api/org/webrtc/RtpParameters.java",
|
"api/org/webrtc/RtpParameters.java",
|
||||||
"api/org/webrtc/RtpReceiver.java",
|
"api/org/webrtc/RtpReceiver.java",
|
||||||
"api/org/webrtc/RtpSender.java",
|
"api/org/webrtc/RtpSender.java",
|
||||||
|
|||||||
@ -265,8 +265,16 @@ public class PeerConnection {
|
|||||||
return Collections.unmodifiableList(receivers);
|
return Collections.unmodifiableList(receivers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Older, non-standard implementation of getStats.
|
||||||
|
@Deprecated
|
||||||
public boolean getStats(StatsObserver observer, MediaStreamTrack track) {
|
public boolean getStats(StatsObserver observer, MediaStreamTrack track) {
|
||||||
return nativeGetStats(observer, (track == null) ? 0 : track.nativeTrack);
|
return nativeOldGetStats(observer, (track == null) ? 0 : track.nativeTrack);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gets stats using the new stats collection API, see webrtc/api/stats/. These
|
||||||
|
// will replace old stats collection API when the new API has matured enough.
|
||||||
|
public void getStats(RTCStatsCollectorCallback callback) {
|
||||||
|
nativeNewGetStats(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Starts recording an RTC event log. Ownership of the file is transfered to
|
// Starts recording an RTC event log. Ownership of the file is transfered to
|
||||||
@ -328,7 +336,9 @@ public class PeerConnection {
|
|||||||
|
|
||||||
private native void nativeRemoveLocalStream(long nativeStream);
|
private native void nativeRemoveLocalStream(long nativeStream);
|
||||||
|
|
||||||
private native boolean nativeGetStats(StatsObserver observer, long nativeTrack);
|
private native boolean nativeOldGetStats(StatsObserver observer, long nativeTrack);
|
||||||
|
|
||||||
|
private native void nativeNewGetStats(RTCStatsCollectorCallback callback);
|
||||||
|
|
||||||
private native RtpSender nativeCreateSender(String kind, String stream_id);
|
private native RtpSender nativeCreateSender(String kind, String stream_id);
|
||||||
|
|
||||||
|
|||||||
105
webrtc/sdk/android/api/org/webrtc/RTCStats.java
Normal file
105
webrtc/sdk/android/api/org/webrtc/RTCStats.java
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2017 The WebRTC project authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by a BSD-style license
|
||||||
|
* that can be found in the LICENSE file in the root of the source
|
||||||
|
* tree. An additional intellectual property rights grant can be found
|
||||||
|
* in the file PATENTS. All contributing project authors may
|
||||||
|
* be found in the AUTHORS file in the root of the source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.webrtc;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Java version of webrtc::RTCStats. Represents an RTCStats object, as
|
||||||
|
* described in https://w3c.github.io/webrtc-stats/. The |id|, |timestampUs|
|
||||||
|
* and |type| accessors have the same meaning for this class as for the
|
||||||
|
* RTCStats dictionary. Each RTCStatsReport produced by getStats contains
|
||||||
|
* multiple RTCStats objects; one for each underlying object (codec, stream,
|
||||||
|
* transport, etc.) that was inspected to produce the stats.
|
||||||
|
*/
|
||||||
|
public class RTCStats {
|
||||||
|
private final long timestampUs;
|
||||||
|
private final String type;
|
||||||
|
private final String id;
|
||||||
|
private final Map<String, Object> members;
|
||||||
|
|
||||||
|
public RTCStats(long timestampUs, String type, String id, Map<String, Object> members) {
|
||||||
|
this.timestampUs = timestampUs;
|
||||||
|
this.type = type;
|
||||||
|
this.id = id;
|
||||||
|
this.members = members;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Timestamp in microseconds.
|
||||||
|
public double getTimestampUs() {
|
||||||
|
return timestampUs;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Equivalent to RTCStatsType in the stats spec. Indicates the type of the
|
||||||
|
// object that was inspected to produce the stats.
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unique ID representing this stats object. May be referred to by members of
|
||||||
|
// other stats objects.
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns map of member names to values. Returns as an ordered map so that
|
||||||
|
* the stats object can be serialized with a consistent ordering.
|
||||||
|
*
|
||||||
|
* Values will be one of the following objects:
|
||||||
|
* - Boolean
|
||||||
|
* - Integer (for 32-bit signed integers)
|
||||||
|
* - Long (for 32-bit unsigned and 64-bit signed integers)
|
||||||
|
* - BigInteger (for 64-bit unsigned integers)
|
||||||
|
* - Double
|
||||||
|
* - String
|
||||||
|
* - The array form of any of the above (e.g., Integer[])
|
||||||
|
*/
|
||||||
|
public Map<String, Object> getMembers() {
|
||||||
|
return members;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
builder.append("{ timestampUs: ")
|
||||||
|
.append(timestampUs)
|
||||||
|
.append(", type: ")
|
||||||
|
.append(type)
|
||||||
|
.append(", id: ")
|
||||||
|
.append(id);
|
||||||
|
boolean first = true;
|
||||||
|
for (Map.Entry<String, Object> entry : members.entrySet()) {
|
||||||
|
builder.append(", ").append(entry.getKey()).append(": ");
|
||||||
|
appendValue(builder, entry.getValue());
|
||||||
|
}
|
||||||
|
builder.append(" }");
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void appendValue(StringBuilder builder, Object value) {
|
||||||
|
if (value instanceof Object[]) {
|
||||||
|
Object[] arrayValue = (Object[]) value;
|
||||||
|
builder.append('[');
|
||||||
|
for (int i = 0; i < arrayValue.length; ++i) {
|
||||||
|
if (i != 0) {
|
||||||
|
builder.append(", ");
|
||||||
|
}
|
||||||
|
appendValue(builder, arrayValue[i]);
|
||||||
|
}
|
||||||
|
builder.append(']');
|
||||||
|
} else if (value instanceof String) {
|
||||||
|
// Enclose strings in quotes to make it clear they're strings.
|
||||||
|
builder.append('"').append(value).append('"');
|
||||||
|
} else {
|
||||||
|
builder.append(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2017 The WebRTC project authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by a BSD-style license
|
||||||
|
* that can be found in the LICENSE file in the root of the source
|
||||||
|
* tree. An additional intellectual property rights grant can be found
|
||||||
|
* in the file PATENTS. All contributing project authors may
|
||||||
|
* be found in the AUTHORS file in the root of the source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.webrtc;
|
||||||
|
|
||||||
|
/** Interface for receiving stats reports (see webrtc::RTCStatsCollectorCallback). */
|
||||||
|
public interface RTCStatsCollectorCallback {
|
||||||
|
/** Called when the stats report is ready. */
|
||||||
|
public void onStatsDelivered(RTCStatsReport report);
|
||||||
|
}
|
||||||
54
webrtc/sdk/android/api/org/webrtc/RTCStatsReport.java
Normal file
54
webrtc/sdk/android/api/org/webrtc/RTCStatsReport.java
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2017 The WebRTC project authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by a BSD-style license
|
||||||
|
* that can be found in the LICENSE file in the root of the source
|
||||||
|
* tree. An additional intellectual property rights grant can be found
|
||||||
|
* in the file PATENTS. All contributing project authors may
|
||||||
|
* be found in the AUTHORS file in the root of the source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.webrtc;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Java version of webrtc::RTCStatsReport. Each RTCStatsReport produced by
|
||||||
|
* getStats contains multiple RTCStats objects; one for each underlying object
|
||||||
|
* (codec, stream, transport, etc.) that was inspected to produce the stats.
|
||||||
|
*/
|
||||||
|
public class RTCStatsReport {
|
||||||
|
private final long timestampUs;
|
||||||
|
private final Map<String, RTCStats> stats;
|
||||||
|
|
||||||
|
public RTCStatsReport(long timestampUs, Map<String, RTCStats> stats) {
|
||||||
|
this.timestampUs = timestampUs;
|
||||||
|
this.stats = stats;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Timestamp in microseconds.
|
||||||
|
public double getTimestampUs() {
|
||||||
|
return timestampUs;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map of stats object IDs to stats objects. Can be used to easily look up
|
||||||
|
// other stats objects, when they refer to each other by ID.
|
||||||
|
public Map<String, RTCStats> getStatsMap() {
|
||||||
|
return stats;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
builder.append("{ timestampUs: ").append(timestampUs).append(", stats: [\n");
|
||||||
|
boolean first = true;
|
||||||
|
for (RTCStats stat : stats.values()) {
|
||||||
|
if (!first) {
|
||||||
|
builder.append(",\n");
|
||||||
|
}
|
||||||
|
builder.append(stat);
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
builder.append(" ] }");
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -53,7 +53,7 @@ public class PeerConnectionTest {
|
|||||||
|
|
||||||
private static class ObserverExpectations
|
private static class ObserverExpectations
|
||||||
implements PeerConnection.Observer, VideoRenderer.Callbacks, DataChannel.Observer,
|
implements PeerConnection.Observer, VideoRenderer.Callbacks, DataChannel.Observer,
|
||||||
StatsObserver, RtpReceiver.Observer {
|
StatsObserver, RTCStatsCollectorCallback, RtpReceiver.Observer {
|
||||||
private final String name;
|
private final String name;
|
||||||
private int expectedIceCandidates = 0;
|
private int expectedIceCandidates = 0;
|
||||||
private int expectedErrors = 0;
|
private int expectedErrors = 0;
|
||||||
@ -77,7 +77,8 @@ public class PeerConnectionTest {
|
|||||||
private LinkedList<DataChannel.State> expectedStateChanges =
|
private LinkedList<DataChannel.State> expectedStateChanges =
|
||||||
new LinkedList<DataChannel.State>();
|
new LinkedList<DataChannel.State>();
|
||||||
private LinkedList<String> expectedRemoteDataChannelLabels = new LinkedList<String>();
|
private LinkedList<String> expectedRemoteDataChannelLabels = new LinkedList<String>();
|
||||||
private int expectedStatsCallbacks = 0;
|
private int expectedOldStatsCallbacks = 0;
|
||||||
|
private int expectedNewStatsCallbacks = 0;
|
||||||
private LinkedList<StatsReport[]> gotStatsReports = new LinkedList<StatsReport[]>();
|
private LinkedList<StatsReport[]> gotStatsReports = new LinkedList<StatsReport[]>();
|
||||||
private final HashSet<MediaStream> gotRemoteStreams = new HashSet<MediaStream>();
|
private final HashSet<MediaStream> gotRemoteStreams = new HashSet<MediaStream>();
|
||||||
private int expectedFirstAudioPacket = 0;
|
private int expectedFirstAudioPacket = 0;
|
||||||
@ -270,14 +271,23 @@ public class PeerConnectionTest {
|
|||||||
expectedStateChanges.add(state);
|
expectedStateChanges.add(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Old getStats callback.
|
||||||
@Override
|
@Override
|
||||||
public synchronized void onComplete(StatsReport[] reports) {
|
public synchronized void onComplete(StatsReport[] reports) {
|
||||||
if (--expectedStatsCallbacks < 0) {
|
if (--expectedOldStatsCallbacks < 0) {
|
||||||
throw new RuntimeException("Unexpected stats report: " + reports);
|
throw new RuntimeException("Unexpected stats report: " + reports);
|
||||||
}
|
}
|
||||||
gotStatsReports.add(reports);
|
gotStatsReports.add(reports);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// New getStats callback.
|
||||||
|
@Override
|
||||||
|
public synchronized void onStatsDelivered(RTCStatsReport report) {
|
||||||
|
if (--expectedNewStatsCallbacks < 0) {
|
||||||
|
throw new RuntimeException("Unexpected stats report: " + report);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void onFirstPacketReceived(MediaStreamTrack.MediaType mediaType) {
|
public synchronized void onFirstPacketReceived(MediaStreamTrack.MediaType mediaType) {
|
||||||
if (mediaType == MediaStreamTrack.MediaType.MEDIA_TYPE_AUDIO) {
|
if (mediaType == MediaStreamTrack.MediaType.MEDIA_TYPE_AUDIO) {
|
||||||
@ -295,8 +305,12 @@ public class PeerConnectionTest {
|
|||||||
expectedFirstVideoPacket = 1;
|
expectedFirstVideoPacket = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void expectStatsCallback() {
|
public synchronized void expectOldStatsCallback() {
|
||||||
++expectedStatsCallbacks;
|
++expectedOldStatsCallbacks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void expectNewStatsCallback() {
|
||||||
|
++expectedNewStatsCallbacks;
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized LinkedList<StatsReport[]> takeStatsReports() {
|
public synchronized LinkedList<StatsReport[]> takeStatsReports() {
|
||||||
@ -348,8 +362,11 @@ public class PeerConnectionTest {
|
|||||||
stillWaitingForExpectations.add(
|
stillWaitingForExpectations.add(
|
||||||
"expectedRemoteDataChannelLabels: " + expectedRemoteDataChannelLabels.size());
|
"expectedRemoteDataChannelLabels: " + expectedRemoteDataChannelLabels.size());
|
||||||
}
|
}
|
||||||
if (expectedStatsCallbacks != 0) {
|
if (expectedOldStatsCallbacks != 0) {
|
||||||
stillWaitingForExpectations.add("expectedStatsCallbacks: " + expectedStatsCallbacks);
|
stillWaitingForExpectations.add("expectedOldStatsCallbacks: " + expectedOldStatsCallbacks);
|
||||||
|
}
|
||||||
|
if (expectedNewStatsCallbacks != 0) {
|
||||||
|
stillWaitingForExpectations.add("expectedNewStatsCallbacks: " + expectedNewStatsCallbacks);
|
||||||
}
|
}
|
||||||
if (expectedFirstAudioPacket > 0) {
|
if (expectedFirstAudioPacket > 0) {
|
||||||
stillWaitingForExpectations.add("expectedFirstAudioPacket: " + expectedFirstAudioPacket);
|
stillWaitingForExpectations.add("expectedFirstAudioPacket: " + expectedFirstAudioPacket);
|
||||||
@ -1035,14 +1052,25 @@ public class PeerConnectionTest {
|
|||||||
expectations.dataChannel.unregisterObserver();
|
expectations.dataChannel.unregisterObserver();
|
||||||
expectations.dataChannel.dispose();
|
expectations.dataChannel.dispose();
|
||||||
}
|
}
|
||||||
expectations.expectStatsCallback();
|
|
||||||
|
// Call getStats (old implementation) before shutting down PC.
|
||||||
|
expectations.expectOldStatsCallback();
|
||||||
assertTrue(pc.getStats(expectations, null));
|
assertTrue(pc.getStats(expectations, null));
|
||||||
assertTrue(expectations.waitForAllExpectationsToBeSatisfied(TIMEOUT_SECONDS));
|
assertTrue(expectations.waitForAllExpectationsToBeSatisfied(TIMEOUT_SECONDS));
|
||||||
|
|
||||||
|
// Call the new getStats implementation as well.
|
||||||
|
expectations.expectNewStatsCallback();
|
||||||
|
pc.getStats(expectations);
|
||||||
|
assertTrue(expectations.waitForAllExpectationsToBeSatisfied(TIMEOUT_SECONDS));
|
||||||
|
|
||||||
expectations.expectIceConnectionChange(IceConnectionState.CLOSED);
|
expectations.expectIceConnectionChange(IceConnectionState.CLOSED);
|
||||||
expectations.expectSignalingChange(SignalingState.CLOSED);
|
expectations.expectSignalingChange(SignalingState.CLOSED);
|
||||||
pc.close();
|
pc.close();
|
||||||
assertTrue(expectations.waitForAllExpectationsToBeSatisfied(TIMEOUT_SECONDS));
|
assertTrue(expectations.waitForAllExpectationsToBeSatisfied(TIMEOUT_SECONDS));
|
||||||
expectations.expectStatsCallback();
|
|
||||||
|
// Call getStats (old implementation) after calling close(). Should still
|
||||||
|
// work.
|
||||||
|
expectations.expectOldStatsCallback();
|
||||||
assertTrue(pc.getStats(expectations, null));
|
assertTrue(pc.getStats(expectations, null));
|
||||||
assertTrue(expectations.waitForAllExpectationsToBeSatisfied(TIMEOUT_SECONDS));
|
assertTrue(expectations.waitForAllExpectationsToBeSatisfied(TIMEOUT_SECONDS));
|
||||||
|
|
||||||
|
|||||||
@ -45,8 +45,15 @@ void FreeGlobalClassReferenceHolder() {
|
|||||||
|
|
||||||
ClassReferenceHolder::ClassReferenceHolder(JNIEnv* jni) {
|
ClassReferenceHolder::ClassReferenceHolder(JNIEnv* jni) {
|
||||||
LoadClass(jni, "android/graphics/SurfaceTexture");
|
LoadClass(jni, "android/graphics/SurfaceTexture");
|
||||||
|
LoadClass(jni, "java/lang/Boolean");
|
||||||
|
LoadClass(jni, "java/lang/Double");
|
||||||
|
LoadClass(jni, "java/lang/Integer");
|
||||||
|
LoadClass(jni, "java/lang/Long");
|
||||||
|
LoadClass(jni, "java/lang/String");
|
||||||
|
LoadClass(jni, "java/math/BigInteger");
|
||||||
LoadClass(jni, "java/nio/ByteBuffer");
|
LoadClass(jni, "java/nio/ByteBuffer");
|
||||||
LoadClass(jni, "java/util/ArrayList");
|
LoadClass(jni, "java/util/ArrayList");
|
||||||
|
LoadClass(jni, "java/util/LinkedHashMap");
|
||||||
LoadClass(jni, "org/webrtc/AudioTrack");
|
LoadClass(jni, "org/webrtc/AudioTrack");
|
||||||
LoadClass(jni, "org/webrtc/Camera1Enumerator");
|
LoadClass(jni, "org/webrtc/Camera1Enumerator");
|
||||||
LoadClass(jni, "org/webrtc/Camera2Enumerator");
|
LoadClass(jni, "org/webrtc/Camera2Enumerator");
|
||||||
@ -86,6 +93,8 @@ ClassReferenceHolder::ClassReferenceHolder(JNIEnv* jni) {
|
|||||||
LoadClass(jni, "org/webrtc/PeerConnection$CandidateNetworkPolicy");
|
LoadClass(jni, "org/webrtc/PeerConnection$CandidateNetworkPolicy");
|
||||||
LoadClass(jni, "org/webrtc/PeerConnection$KeyType");
|
LoadClass(jni, "org/webrtc/PeerConnection$KeyType");
|
||||||
LoadClass(jni, "org/webrtc/PeerConnection$SignalingState");
|
LoadClass(jni, "org/webrtc/PeerConnection$SignalingState");
|
||||||
|
LoadClass(jni, "org/webrtc/RTCStats");
|
||||||
|
LoadClass(jni, "org/webrtc/RTCStatsReport");
|
||||||
LoadClass(jni, "org/webrtc/RtpReceiver");
|
LoadClass(jni, "org/webrtc/RtpReceiver");
|
||||||
LoadClass(jni, "org/webrtc/RtpSender");
|
LoadClass(jni, "org/webrtc/RtpSender");
|
||||||
LoadClass(jni, "org/webrtc/SessionDescription");
|
LoadClass(jni, "org/webrtc/SessionDescription");
|
||||||
|
|||||||
@ -73,6 +73,7 @@
|
|||||||
#include "webrtc/sdk/android/src/jni/classreferenceholder.h"
|
#include "webrtc/sdk/android/src/jni/classreferenceholder.h"
|
||||||
#include "webrtc/sdk/android/src/jni/jni_helpers.h"
|
#include "webrtc/sdk/android/src/jni/jni_helpers.h"
|
||||||
#include "webrtc/sdk/android/src/jni/native_handle_impl.h"
|
#include "webrtc/sdk/android/src/jni/native_handle_impl.h"
|
||||||
|
#include "webrtc/sdk/android/src/jni/rtcstatscollectorcallbackwrapper.h"
|
||||||
#include "webrtc/system_wrappers/include/field_trial_default.h"
|
#include "webrtc/system_wrappers/include/field_trial_default.h"
|
||||||
#include "webrtc/system_wrappers/include/logcat_trace_context.h"
|
#include "webrtc/system_wrappers/include/logcat_trace_context.h"
|
||||||
#include "webrtc/system_wrappers/include/trace.h"
|
#include "webrtc/system_wrappers/include/trace.h"
|
||||||
@ -2123,8 +2124,8 @@ JOW(jobject, PeerConnection_nativeGetReceivers)(JNIEnv* jni, jobject j_pc) {
|
|||||||
return j_receivers;
|
return j_receivers;
|
||||||
}
|
}
|
||||||
|
|
||||||
JOW(bool, PeerConnection_nativeGetStats)(
|
JOW(bool, PeerConnection_nativeOldGetStats)
|
||||||
JNIEnv* jni, jobject j_pc, jobject j_observer, jlong native_track) {
|
(JNIEnv* jni, jobject j_pc, jobject j_observer, jlong native_track) {
|
||||||
rtc::scoped_refptr<StatsObserverWrapper> observer(
|
rtc::scoped_refptr<StatsObserverWrapper> observer(
|
||||||
new rtc::RefCountedObject<StatsObserverWrapper>(jni, j_observer));
|
new rtc::RefCountedObject<StatsObserverWrapper>(jni, j_observer));
|
||||||
return ExtractNativePC(jni, j_pc)->GetStats(
|
return ExtractNativePC(jni, j_pc)->GetStats(
|
||||||
@ -2133,6 +2134,14 @@ JOW(bool, PeerConnection_nativeGetStats)(
|
|||||||
PeerConnectionInterface::kStatsOutputLevelStandard);
|
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)(
|
JOW(bool, PeerConnection_nativeStartRtcEventLog)(
|
||||||
JNIEnv* jni, jobject j_pc, int file_descriptor, int max_size_bytes) {
|
JNIEnv* jni, jobject j_pc, int file_descriptor, int max_size_bytes) {
|
||||||
return ExtractNativePC(jni, j_pc)->StartRtcEventLog(file_descriptor,
|
return ExtractNativePC(jni, j_pc)->StartRtcEventLog(file_descriptor,
|
||||||
|
|||||||
267
webrtc/sdk/android/src/jni/rtcstatscollectorcallbackwrapper.cc
Normal file
267
webrtc/sdk/android/src/jni/rtcstatscollectorcallbackwrapper.cc
Normal file
@ -0,0 +1,267 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2017 The WebRTC project authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by a BSD-style license
|
||||||
|
* that can be found in the LICENSE file in the root of the source
|
||||||
|
* tree. An additional intellectual property rights grant can be found
|
||||||
|
* in the file PATENTS. All contributing project authors may
|
||||||
|
* be found in the AUTHORS file in the root of the source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "webrtc/sdk/android/src/jni/rtcstatscollectorcallbackwrapper.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "webrtc/sdk/android/src/jni/classreferenceholder.h"
|
||||||
|
|
||||||
|
namespace webrtc_jni {
|
||||||
|
|
||||||
|
RTCStatsCollectorCallbackWrapper::RTCStatsCollectorCallbackWrapper(
|
||||||
|
JNIEnv* jni,
|
||||||
|
jobject j_callback)
|
||||||
|
: j_callback_global_(jni, j_callback),
|
||||||
|
j_callback_class_(jni, GetObjectClass(jni, j_callback)),
|
||||||
|
j_stats_report_class_(FindClass(jni, "org/webrtc/RTCStatsReport")),
|
||||||
|
j_stats_report_ctor_(GetMethodID(jni,
|
||||||
|
j_stats_report_class_,
|
||||||
|
"<init>",
|
||||||
|
"(JLjava/util/Map;)V")),
|
||||||
|
j_stats_class_(FindClass(jni, "org/webrtc/RTCStats")),
|
||||||
|
j_stats_ctor_(GetMethodID(
|
||||||
|
jni,
|
||||||
|
j_stats_class_,
|
||||||
|
"<init>",
|
||||||
|
"(JLjava/lang/String;Ljava/lang/String;Ljava/util/Map;)V")),
|
||||||
|
j_linked_hash_map_class_(FindClass(jni, "java/util/LinkedHashMap")),
|
||||||
|
j_linked_hash_map_ctor_(
|
||||||
|
GetMethodID(jni, j_linked_hash_map_class_, "<init>", "()V")),
|
||||||
|
j_linked_hash_map_put_(GetMethodID(
|
||||||
|
jni,
|
||||||
|
j_linked_hash_map_class_,
|
||||||
|
"put",
|
||||||
|
"(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;")),
|
||||||
|
j_boolean_class_(FindClass(jni, "java/lang/Boolean")),
|
||||||
|
j_boolean_ctor_(GetMethodID(jni, j_boolean_class_, "<init>", "(Z)V")),
|
||||||
|
j_integer_class_(FindClass(jni, "java/lang/Integer")),
|
||||||
|
j_integer_ctor_(GetMethodID(jni, j_integer_class_, "<init>", "(I)V")),
|
||||||
|
j_long_class_(FindClass(jni, "java/lang/Long")),
|
||||||
|
j_long_ctor_(GetMethodID(jni, j_long_class_, "<init>", "(J)V")),
|
||||||
|
j_big_integer_class_(FindClass(jni, "java/math/BigInteger")),
|
||||||
|
j_big_integer_ctor_(GetMethodID(jni,
|
||||||
|
j_big_integer_class_,
|
||||||
|
"<init>",
|
||||||
|
"(Ljava/lang/String;)V")),
|
||||||
|
j_double_class_(FindClass(jni, "java/lang/Double")),
|
||||||
|
j_double_ctor_(GetMethodID(jni, j_double_class_, "<init>", "(D)V")),
|
||||||
|
j_string_class_(FindClass(jni, "java/lang/String")) {}
|
||||||
|
|
||||||
|
void RTCStatsCollectorCallbackWrapper::OnStatsDelivered(
|
||||||
|
const rtc::scoped_refptr<const webrtc::RTCStatsReport>& report) {
|
||||||
|
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";
|
||||||
|
}
|
||||||
|
|
||||||
|
jobject RTCStatsCollectorCallbackWrapper::ReportToJava(
|
||||||
|
JNIEnv* jni,
|
||||||
|
const rtc::scoped_refptr<const webrtc::RTCStatsReport>& report) {
|
||||||
|
jobject j_stats_map =
|
||||||
|
jni->NewObject(j_linked_hash_map_class_, j_linked_hash_map_ctor_);
|
||||||
|
CHECK_EXCEPTION(jni) << "error during NewObject";
|
||||||
|
for (const webrtc::RTCStats& stats : *report) {
|
||||||
|
// Create a local reference frame for each RTCStats, since there is a
|
||||||
|
// maximum number of references that can be created in one frame.
|
||||||
|
ScopedLocalRefFrame local_ref_frame(jni);
|
||||||
|
jstring j_id = JavaStringFromStdString(jni, stats.id());
|
||||||
|
jobject j_stats = StatsToJava(jni, stats);
|
||||||
|
jni->CallObjectMethod(j_stats_map, j_linked_hash_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 RTCStatsCollectorCallbackWrapper::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_linked_hash_map_class_, j_linked_hash_map_ctor_);
|
||||||
|
for (const webrtc::RTCStatsMemberInterface* member : stats.Members()) {
|
||||||
|
if (!member->is_defined()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Create a local reference frame for each member as well.
|
||||||
|
ScopedLocalRefFrame local_ref_frame(jni);
|
||||||
|
jstring j_name = JavaStringFromStdString(jni, member->name());
|
||||||
|
jobject j_member = MemberToJava(jni, member);
|
||||||
|
jni->CallObjectMethod(j_members, j_linked_hash_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 RTCStatsCollectorCallbackWrapper::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;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace webrtc_jni
|
||||||
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2017 The WebRTC project authors. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by a BSD-style license
|
||||||
|
* that can be found in the LICENSE file in the root of the source
|
||||||
|
* tree. An additional intellectual property rights grant can be found
|
||||||
|
* in the file PATENTS. All contributing project authors may
|
||||||
|
* be found in the AUTHORS file in the root of the source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef WEBRTC_SDK_ANDROID_SRC_JNI_RTCSTATSCOLLECTORCALLBACKWRAPPER_H_
|
||||||
|
#define WEBRTC_SDK_ANDROID_SRC_JNI_RTCSTATSCOLLECTORCALLBACKWRAPPER_H_
|
||||||
|
|
||||||
|
#include <jni.h>
|
||||||
|
|
||||||
|
#include "webrtc/api/peerconnectioninterface.h"
|
||||||
|
#include "webrtc/sdk/android/src/jni/jni_helpers.h"
|
||||||
|
|
||||||
|
namespace webrtc_jni {
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
void OnStatsDelivered(
|
||||||
|
const rtc::scoped_refptr<const webrtc::RTCStatsReport>& report) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Helper functions for converting C++ RTCStatsReport to Java equivalent.
|
||||||
|
jobject ReportToJava(
|
||||||
|
JNIEnv* jni,
|
||||||
|
const rtc::scoped_refptr<const webrtc::RTCStatsReport>& report);
|
||||||
|
jobject StatsToJava(JNIEnv* jni, const webrtc::RTCStats& stats);
|
||||||
|
jobject MemberToJava(JNIEnv* jni,
|
||||||
|
const webrtc::RTCStatsMemberInterface* member);
|
||||||
|
|
||||||
|
const ScopedGlobalRef<jobject> j_callback_global_;
|
||||||
|
const ScopedGlobalRef<jclass> j_callback_class_;
|
||||||
|
const jclass j_stats_report_class_;
|
||||||
|
const jmethodID j_stats_report_ctor_;
|
||||||
|
const jclass j_stats_class_;
|
||||||
|
const jmethodID j_stats_ctor_;
|
||||||
|
const jclass j_linked_hash_map_class_;
|
||||||
|
const jmethodID j_linked_hash_map_ctor_;
|
||||||
|
const jmethodID j_linked_hash_map_put_;
|
||||||
|
const jclass j_boolean_class_;
|
||||||
|
const jmethodID j_boolean_ctor_;
|
||||||
|
const jclass j_integer_class_;
|
||||||
|
const jmethodID j_integer_ctor_;
|
||||||
|
const jclass j_long_class_;
|
||||||
|
const jmethodID j_long_ctor_;
|
||||||
|
const jclass j_big_integer_class_;
|
||||||
|
const jmethodID j_big_integer_ctor_;
|
||||||
|
const jclass j_double_class_;
|
||||||
|
const jmethodID j_double_ctor_;
|
||||||
|
const jclass j_string_class_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace webrtc_jni
|
||||||
|
|
||||||
|
#endif // WEBRTC_SDK_ANDROID_SRC_JNI_RTCSTATSCOLLECTORCALLBACKWRAPPER_H_
|
||||||
Reference in New Issue
Block a user