Remove Java PC support.
This cl removes none Android Java support.
Review URL: https://codereview.webrtc.org/1652123002
Cr-Commit-Position: refs/heads/master@{#11522}
diff --git a/talk/app/webrtc/java/README b/talk/app/webrtc/java/README
index 454046c..f367556 100644
--- a/talk/app/webrtc/java/README
+++ b/talk/app/webrtc/java/README
@@ -2,22 +2,9 @@
well as the JNI glue C++ code that lets the Java implementation reuse the C++
implementation of the same API.
-To build the Java API and related tests, build with
-OS=linux or OS=android and include
-build_with_libjingle=1 build_with_chromium=0
-in $GYP_DEFINES.
+To build the Java API and related tests, build with OS=android in $GYP_DEFINES.
To use the Java API, start by looking at the public interface of
org.webrtc.PeerConnection{,Factory} and the org.webrtc.PeerConnectionTest.
To understand the implementation of the API, see the native code in jni/.
-
-An example command-line to build & run the unittest:
-cd path/to/trunk
-GYP_DEFINES="build_with_libjingle=1 build_with_chromium=0 java_home=path/to/JDK" gclient runhooks && \
- ninja -C out/Debug libjingle_peerconnection_java_unittest && \
- ./out/Debug/libjingle_peerconnection_java_unittest
-(where path/to/JDK should contain include/jni.h)
-
-During development it can be helpful to run the JVM with the -Xcheck:jni flag.
-
diff --git a/talk/app/webrtc/java/jni/classreferenceholder.cc b/talk/app/webrtc/java/jni/classreferenceholder.cc
index a7d36c2..0d52bc5 100644
--- a/talk/app/webrtc/java/jni/classreferenceholder.cc
+++ b/talk/app/webrtc/java/jni/classreferenceholder.cc
@@ -62,28 +62,21 @@
}
ClassReferenceHolder::ClassReferenceHolder(JNIEnv* jni) {
+ LoadClass(jni, "android/graphics/SurfaceTexture");
LoadClass(jni, "java/nio/ByteBuffer");
LoadClass(jni, "java/util/ArrayList");
LoadClass(jni, "org/webrtc/AudioTrack");
+ LoadClass(jni, "org/webrtc/CameraEnumerator");
+ LoadClass(jni, "org/webrtc/Camera2Enumerator");
+ LoadClass(jni, "org/webrtc/CameraEnumerationAndroid");
LoadClass(jni, "org/webrtc/DataChannel");
LoadClass(jni, "org/webrtc/DataChannel$Buffer");
LoadClass(jni, "org/webrtc/DataChannel$Init");
LoadClass(jni, "org/webrtc/DataChannel$State");
- LoadClass(jni, "org/webrtc/IceCandidate");
-#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
- LoadClass(jni, "android/graphics/SurfaceTexture");
- LoadClass(jni, "org/webrtc/CameraEnumerator");
- LoadClass(jni, "org/webrtc/Camera2Enumerator");
- LoadClass(jni, "org/webrtc/CameraEnumerationAndroid");
- LoadClass(jni, "org/webrtc/VideoCapturerAndroid");
- LoadClass(jni, "org/webrtc/VideoCapturerAndroid$NativeObserver");
LoadClass(jni, "org/webrtc/EglBase");
LoadClass(jni, "org/webrtc/EglBase$Context");
LoadClass(jni, "org/webrtc/EglBase14$Context");
- LoadClass(jni, "org/webrtc/NetworkMonitor");
- LoadClass(jni, "org/webrtc/NetworkMonitorAutoDetect$ConnectionType");
- LoadClass(jni, "org/webrtc/NetworkMonitorAutoDetect$IPAddress");
- LoadClass(jni, "org/webrtc/NetworkMonitorAutoDetect$NetworkInformation");
+ LoadClass(jni, "org/webrtc/IceCandidate");
LoadClass(jni, "org/webrtc/MediaCodecVideoEncoder");
LoadClass(jni, "org/webrtc/MediaCodecVideoEncoder$OutputBufferInfo");
LoadClass(jni, "org/webrtc/MediaCodecVideoEncoder$VideoCodecType");
@@ -91,11 +84,13 @@
LoadClass(jni, "org/webrtc/MediaCodecVideoDecoder$DecodedTextureBuffer");
LoadClass(jni, "org/webrtc/MediaCodecVideoDecoder$DecodedOutputBuffer");
LoadClass(jni, "org/webrtc/MediaCodecVideoDecoder$VideoCodecType");
- LoadClass(jni, "org/webrtc/SurfaceTextureHelper");
-#endif
LoadClass(jni, "org/webrtc/MediaSource$State");
LoadClass(jni, "org/webrtc/MediaStream");
LoadClass(jni, "org/webrtc/MediaStreamTrack$State");
+ LoadClass(jni, "org/webrtc/NetworkMonitor");
+ LoadClass(jni, "org/webrtc/NetworkMonitorAutoDetect$ConnectionType");
+ LoadClass(jni, "org/webrtc/NetworkMonitorAutoDetect$IPAddress");
+ LoadClass(jni, "org/webrtc/NetworkMonitorAutoDetect$NetworkInformation");
LoadClass(jni, "org/webrtc/PeerConnectionFactory");
LoadClass(jni, "org/webrtc/PeerConnection$BundlePolicy");
LoadClass(jni, "org/webrtc/PeerConnection$ContinualGatheringPolicy");
@@ -112,8 +107,10 @@
LoadClass(jni, "org/webrtc/SessionDescription$Type");
LoadClass(jni, "org/webrtc/StatsReport");
LoadClass(jni, "org/webrtc/StatsReport$Value");
+ LoadClass(jni, "org/webrtc/SurfaceTextureHelper");
+ LoadClass(jni, "org/webrtc/VideoCapturerAndroid");
+ LoadClass(jni, "org/webrtc/VideoCapturerAndroid$NativeObserver");
LoadClass(jni, "org/webrtc/VideoRenderer$I420Frame");
- LoadClass(jni, "org/webrtc/VideoCapturer");
LoadClass(jni, "org/webrtc/VideoTrack");
}
diff --git a/talk/app/webrtc/java/jni/peerconnection_jni.cc b/talk/app/webrtc/java/jni/peerconnection_jni.cc
index 3237cd3..bbbd77f 100644
--- a/talk/app/webrtc/java/jni/peerconnection_jni.cc
+++ b/talk/app/webrtc/java/jni/peerconnection_jni.cc
@@ -59,7 +59,12 @@
#include <limits>
#include <utility>
+#include "talk/app/webrtc/androidvideocapturer.h"
#include "talk/app/webrtc/dtlsidentitystore.h"
+#include "talk/app/webrtc/java/jni/androidmediadecoder_jni.h"
+#include "talk/app/webrtc/java/jni/androidmediaencoder_jni.h"
+#include "talk/app/webrtc/java/jni/androidvideocapturer_jni.h"
+#include "talk/app/webrtc/java/jni/androidnetworkmonitor_jni.h"
#include "talk/app/webrtc/java/jni/classreferenceholder.h"
#include "talk/app/webrtc/java/jni/jni_helpers.h"
#include "talk/app/webrtc/java/jni/native_handle_impl.h"
@@ -83,20 +88,10 @@
#include "webrtc/media/webrtc/webrtcvideodecoderfactory.h"
#include "webrtc/media/webrtc/webrtcvideoencoderfactory.h"
#include "webrtc/system_wrappers/include/field_trial_default.h"
+#include "webrtc/system_wrappers/include/logcat_trace_context.h"
#include "webrtc/system_wrappers/include/trace.h"
#include "webrtc/voice_engine/include/voe_base.h"
-#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
-#include "talk/app/webrtc/androidvideocapturer.h"
-#include "talk/app/webrtc/java/jni/androidmediadecoder_jni.h"
-#include "talk/app/webrtc/java/jni/androidmediaencoder_jni.h"
-#include "talk/app/webrtc/java/jni/androidnetworkmonitor_jni.h"
-#include "talk/app/webrtc/java/jni/androidvideocapturer_jni.h"
-#include "webrtc/modules/video_render/video_render_internal.h"
-#include "webrtc/system_wrappers/include/logcat_trace_context.h"
-using webrtc::LogcatTraceContext;
-#endif
-
using cricket::WebRtcVideoDecoderFactory;
using cricket::WebRtcVideoEncoderFactory;
using rtc::Bind;
@@ -112,6 +107,7 @@
using webrtc::DataChannelInterface;
using webrtc::DataChannelObserver;
using webrtc::IceCandidateInterface;
+using webrtc::LogcatTraceContext;
using webrtc::MediaConstraintsInterface;
using webrtc::MediaSourceInterface;
using webrtc::MediaStreamInterface;
@@ -137,11 +133,9 @@
// Field trials initialization string
static char *field_trials_init_string = NULL;
-#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
// Set in PeerConnectionFactory_initializeAndroidGlobals().
static bool factory_static_initialized = false;
static bool video_hw_acceleration_enabled = true;
-#endif
// Return the (singleton) Java Enum object corresponding to |index|;
// |state_class_fragment| is something like "MediaSource$State".
@@ -889,18 +883,14 @@
std::string path = JavaToStdString(jni, j_path);
if (nativeLevels != webrtc::kTraceNone) {
webrtc::Trace::set_level_filter(nativeLevels);
-#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
if (path != "logcat:") {
-#endif
RTC_CHECK_EQ(0, webrtc::Trace::SetTraceFile(path.c_str(), false))
<< "SetTraceFile failed";
-#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
} else {
// Intentionally leak this to avoid needing to reason about its lifecycle.
// It keeps no state and functions only as a dispatch point.
static LogcatTraceContext* g_trace_callback = new LogcatTraceContext();
}
-#endif
}
if (nativeSeverity >= rtc::LS_SENSITIVE && nativeSeverity <= rtc::LS_ERROR) {
rtc::LogMessage::LogToDebug(
@@ -940,10 +930,6 @@
delete reinterpret_cast<cricket::VideoCapturer*>(j_p);
}
-JOW(void, VideoRenderer_freeGuiVideoRenderer)(JNIEnv*, jclass, jlong j_p) {
- delete reinterpret_cast<VideoRendererWrapper*>(j_p);
-}
-
JOW(void, VideoRenderer_freeWrappedVideoRenderer)(JNIEnv*, jclass, jlong j_p) {
delete reinterpret_cast<JavaVideoRendererWrapper*>(j_p);
}
@@ -995,7 +981,6 @@
return (jlong)new PCOJava(jni, j_observer);
}
-#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
JOW(jboolean, PeerConnectionFactory_initializeAndroidGlobals)(
JNIEnv* jni, jclass, jobject context,
jboolean initialize_audio, jboolean initialize_video,
@@ -1005,7 +990,6 @@
AndroidNetworkMonitor::SetAndroidContext(jni, context);
if (!factory_static_initialized) {
if (initialize_video) {
- failure |= webrtc::SetRenderAndroidVM(GetJVM());
failure |= AndroidVideoCapturerJni::SetAndroidObjects(jni, context);
}
if (initialize_audio)
@@ -1014,7 +998,6 @@
}
return !failure;
}
-#endif // defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
JOW(void, PeerConnectionFactory_initializeFieldTrials)(
JNIEnv* jni, jclass, jstring j_trials_init_string) {
@@ -1185,7 +1168,7 @@
if (has_options) {
options = ParseOptionsFromJava(jni, joptions);
}
-#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
+
if (video_hw_acceleration_enabled) {
encoder_factory = new MediaCodecVideoEncoderFactory();
decoder_factory = new MediaCodecVideoDecoderFactory();
@@ -1196,7 +1179,7 @@
network_monitor_factory = new AndroidNetworkMonitorFactory();
rtc::NetworkMonitorFactory::SetFactory(network_monitor_factory);
}
-#endif
+
rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
webrtc::CreatePeerConnectionFactory(worker_thread,
signaling_thread,
@@ -1299,42 +1282,30 @@
JOW(jboolean, PeerConnectionFactory_nativeStartAecDump)(
JNIEnv* jni, jclass, jlong native_factory, jint file,
jint filesize_limit_bytes) {
-#if defined(ANDROID)
rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
factoryFromJava(native_factory));
return factory->StartAecDump(file, filesize_limit_bytes);
-#else
- return false;
-#endif
}
JOW(void, PeerConnectionFactory_nativeStopAecDump)(
JNIEnv* jni, jclass, jlong native_factory) {
-#if defined(ANDROID)
rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
factoryFromJava(native_factory));
factory->StopAecDump();
-#endif
}
JOW(jboolean, PeerConnectionFactory_nativeStartRtcEventLog)(
JNIEnv* jni, jclass, jlong native_factory, jint file) {
-#if defined(ANDROID)
rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
factoryFromJava(native_factory));
return factory->StartRtcEventLog(file);
-#else
- return false;
-#endif
}
JOW(void, PeerConnectionFactory_nativeStopRtcEventLog)(
JNIEnv* jni, jclass, jlong native_factory) {
-#if defined(ANDROID)
rtc::scoped_refptr<PeerConnectionFactoryInterface> factory(
factoryFromJava(native_factory));
factory->StopRtcEventLog();
-#endif
}
JOW(void, PeerConnectionFactory_nativeSetOptions)(
@@ -1359,7 +1330,6 @@
JOW(void, PeerConnectionFactory_nativeSetVideoHwAccelerationOptions)(
JNIEnv* jni, jclass, jlong native_factory, jobject local_egl_context,
jobject remote_egl_context) {
-#if defined(ANDROID) && !defined(WEBRTC_CHROMIUM_BUILD)
OwnedFactoryAndThreads* owned_factory =
reinterpret_cast<OwnedFactoryAndThreads*>(native_factory);
@@ -1383,7 +1353,6 @@
LOG(LS_INFO) << "Set EGL context for HW decoding.";
decoder_factory->SetEGLContext(jni, remote_egl_context);
}
-#endif
}
static PeerConnectionInterface::IceTransportsType
@@ -1893,75 +1862,6 @@
return JavaEnumFromIndex(jni, "MediaSource$State", p->state());
}
-JOW(jobject, VideoCapturer_nativeCreateVideoCapturer)(
- JNIEnv* jni, jclass, jstring j_device_name) {
-// Since we can't create platform specific java implementations in Java, we
-// defer the creation to C land.
-#if defined(ANDROID)
- // TODO(nisse): This case is intended to be deleted.
- jclass j_video_capturer_class(
- FindClass(jni, "org/webrtc/VideoCapturerAndroid"));
- const int camera_id = jni->CallStaticIntMethod(
- j_video_capturer_class,
- GetStaticMethodID(jni, j_video_capturer_class, "lookupDeviceName",
- "(Ljava/lang/String;)I"),
- j_device_name);
- CHECK_EXCEPTION(jni) << "error during VideoCapturerAndroid.lookupDeviceName";
- if (camera_id == -1)
- return nullptr;
- jobject j_video_capturer = jni->NewObject(
- j_video_capturer_class,
- GetMethodID(jni, j_video_capturer_class, "<init>", "(I)V"), camera_id);
- CHECK_EXCEPTION(jni) << "error during creation of VideoCapturerAndroid";
- jfieldID helper_fid = GetFieldID(jni, j_video_capturer_class, "surfaceHelper",
- "Lorg/webrtc/SurfaceTextureHelper;");
-
- rtc::scoped_refptr<webrtc::AndroidVideoCapturerDelegate> delegate =
- new rtc::RefCountedObject<AndroidVideoCapturerJni>(
- jni, j_video_capturer,
- GetObjectField(jni, j_video_capturer, helper_fid));
- rtc::scoped_ptr<cricket::VideoCapturer> capturer(
- new webrtc::AndroidVideoCapturer(delegate));
-
-#else
- std::string device_name = JavaToStdString(jni, j_device_name);
- scoped_ptr<cricket::DeviceManagerInterface> device_manager(
- cricket::DeviceManagerFactory::Create());
- RTC_CHECK(device_manager->Init()) << "DeviceManager::Init() failed";
- cricket::Device device;
- if (!device_manager->GetVideoCaptureDevice(device_name, &device)) {
- LOG(LS_ERROR) << "GetVideoCaptureDevice failed for " << device_name;
- return 0;
- }
- scoped_ptr<cricket::VideoCapturer> capturer(
- device_manager->CreateVideoCapturer(device));
-
- jclass j_video_capturer_class(
- FindClass(jni, "org/webrtc/VideoCapturer"));
- const jmethodID j_videocapturer_ctor(GetMethodID(
- jni, j_video_capturer_class, "<init>", "()V"));
- jobject j_video_capturer =
- jni->NewObject(j_video_capturer_class,
- j_videocapturer_ctor);
- CHECK_EXCEPTION(jni) << "error during creation of VideoCapturer";
-
-#endif
- const jmethodID j_videocapturer_set_native_capturer(GetMethodID(
- jni, j_video_capturer_class, "setNativeCapturer", "(J)V"));
- jni->CallVoidMethod(j_video_capturer,
- j_videocapturer_set_native_capturer,
- jlongFromPointer(capturer.release()));
- CHECK_EXCEPTION(jni) << "error during setNativeCapturer";
- return j_video_capturer;
-}
-
-JOW(jlong, VideoRenderer_nativeCreateGuiVideoRenderer)(
- JNIEnv* jni, jclass, int x, int y) {
- scoped_ptr<VideoRendererWrapper> renderer(VideoRendererWrapper::Create(
- cricket::VideoRendererFactory::CreateGuiVideoRenderer(x, y)));
- return (jlong)renderer.release();
-}
-
JOW(jlong, VideoRenderer_nativeWrapVideoRenderer)(
JNIEnv* jni, jclass, jobject j_callbacks) {
scoped_ptr<JavaVideoRendererWrapper> renderer(
diff --git a/talk/app/webrtc/java/src/org/webrtc/VideoCapturer.java b/talk/app/webrtc/java/src/org/webrtc/VideoCapturer.java
index 158cc34..ad41053 100644
--- a/talk/app/webrtc/java/src/org/webrtc/VideoCapturer.java
+++ b/talk/app/webrtc/java/src/org/webrtc/VideoCapturer.java
@@ -28,19 +28,13 @@
package org.webrtc;
/** Java version of cricket::VideoCapturer. */
+// TODO(perkj): Merge VideoCapturer and VideoCapturerAndroid.
public class VideoCapturer {
private long nativeVideoCapturer;
protected VideoCapturer() {
}
- public static VideoCapturer create(String deviceName) {
- Object capturer = nativeCreateVideoCapturer(deviceName);
- if (capturer != null)
- return (VideoCapturer) (capturer);
- return null;
- }
-
// Sets |nativeCapturer| to be owned by VideoCapturer.
protected void setNativeCapturer(long nativeCapturer) {
this.nativeVideoCapturer = nativeCapturer;
@@ -64,7 +58,5 @@
}
}
- private static native Object nativeCreateVideoCapturer(String deviceName);
-
private static native void free(long nativeVideoCapturer);
}
diff --git a/talk/app/webrtc/java/src/org/webrtc/VideoRenderer.java b/talk/app/webrtc/java/src/org/webrtc/VideoRenderer.java
index 2e307fc..c14802e 100644
--- a/talk/app/webrtc/java/src/org/webrtc/VideoRenderer.java
+++ b/talk/app/webrtc/java/src/org/webrtc/VideoRenderer.java
@@ -144,27 +144,14 @@
}
}
- // |this| either wraps a native (GUI) renderer or a client-supplied Callbacks
- // (Java) implementation; this is indicated by |isWrappedVideoRenderer|.
long nativeVideoRenderer;
- private final boolean isWrappedVideoRenderer;
-
- public static VideoRenderer createGui(int x, int y) {
- long nativeVideoRenderer = nativeCreateGuiVideoRenderer(x, y);
- if (nativeVideoRenderer == 0) {
- return null;
- }
- return new VideoRenderer(nativeVideoRenderer);
- }
public VideoRenderer(Callbacks callbacks) {
nativeVideoRenderer = nativeWrapVideoRenderer(callbacks);
- isWrappedVideoRenderer = true;
}
private VideoRenderer(long nativeVideoRenderer) {
this.nativeVideoRenderer = nativeVideoRenderer;
- isWrappedVideoRenderer = false;
}
public void dispose() {
@@ -172,19 +159,12 @@
// Already disposed.
return;
}
- if (!isWrappedVideoRenderer) {
- freeGuiVideoRenderer(nativeVideoRenderer);
- } else {
- freeWrappedVideoRenderer(nativeVideoRenderer);
- }
+
+ freeWrappedVideoRenderer(nativeVideoRenderer);
nativeVideoRenderer = 0;
}
- private static native long nativeCreateGuiVideoRenderer(int x, int y);
private static native long nativeWrapVideoRenderer(Callbacks callbacks);
-
- private static native void freeGuiVideoRenderer(long nativeVideoRenderer);
private static native void freeWrappedVideoRenderer(long nativeVideoRenderer);
-
private static native void releaseNativeFrame(long nativeFramePointer);
}
diff --git a/talk/app/webrtc/java/testcommon/src/org/webrtc/PeerConnectionTest.java b/talk/app/webrtc/java/testcommon/src/org/webrtc/PeerConnectionTest.java
deleted file mode 100644
index 50f4d73..0000000
--- a/talk/app/webrtc/java/testcommon/src/org/webrtc/PeerConnectionTest.java
+++ /dev/null
@@ -1,782 +0,0 @@
-/*
- * libjingle
- * Copyright 2013 Google Inc.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-package org.webrtc;
-
-import org.webrtc.PeerConnection.IceConnectionState;
-import org.webrtc.PeerConnection.IceGatheringState;
-import org.webrtc.PeerConnection.SignalingState;
-
-import java.io.File;
-import java.lang.ref.WeakReference;
-import java.nio.ByteBuffer;
-import java.nio.charset.Charset;
-import java.util.Arrays;
-import java.util.IdentityHashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.TreeSet;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-import static junit.framework.Assert.*;
-
-/** End-to-end tests for PeerConnection.java. */
-public class PeerConnectionTest {
- // Set to true to render video.
- private static final boolean RENDER_TO_GUI = false;
- private static final int TIMEOUT_SECONDS = 20;
- private TreeSet<String> threadsBeforeTest = null;
-
- private static class ObserverExpectations implements PeerConnection.Observer,
- VideoRenderer.Callbacks,
- DataChannel.Observer,
- StatsObserver {
- private final String name;
- private int expectedIceCandidates = 0;
- private int expectedErrors = 0;
- private int expectedRenegotiations = 0;
- private int previouslySeenWidth = 0;
- private int previouslySeenHeight = 0;
- private int expectedFramesDelivered = 0;
- private LinkedList<SignalingState> expectedSignalingChanges =
- new LinkedList<SignalingState>();
- private LinkedList<IceConnectionState> expectedIceConnectionChanges =
- new LinkedList<IceConnectionState>();
- private LinkedList<IceGatheringState> expectedIceGatheringChanges =
- new LinkedList<IceGatheringState>();
- private LinkedList<String> expectedAddStreamLabels =
- new LinkedList<String>();
- private LinkedList<String> expectedRemoveStreamLabels =
- new LinkedList<String>();
- private final LinkedList<IceCandidate> gotIceCandidates =
- new LinkedList<IceCandidate>();
- private Map<MediaStream, WeakReference<VideoRenderer>> renderers =
- new IdentityHashMap<MediaStream, WeakReference<VideoRenderer>>();
- private DataChannel dataChannel;
- private LinkedList<DataChannel.Buffer> expectedBuffers =
- new LinkedList<DataChannel.Buffer>();
- private LinkedList<DataChannel.State> expectedStateChanges =
- new LinkedList<DataChannel.State>();
- private LinkedList<String> expectedRemoteDataChannelLabels =
- new LinkedList<String>();
- private int expectedStatsCallbacks = 0;
- private LinkedList<StatsReport[]> gotStatsReports =
- new LinkedList<StatsReport[]>();
-
- public ObserverExpectations(String name) {
- this.name = name;
- }
-
- public synchronized void setDataChannel(DataChannel dataChannel) {
- assertNull(this.dataChannel);
- this.dataChannel = dataChannel;
- this.dataChannel.registerObserver(this);
- assertNotNull(this.dataChannel);
- }
-
- public synchronized void expectIceCandidates(int count) {
- expectedIceCandidates += count;
- }
-
- @Override
- public synchronized void onIceCandidate(IceCandidate candidate) {
- --expectedIceCandidates;
-
- // We don't assert expectedIceCandidates >= 0 because it's hard to know
- // how many to expect, in general. We only use expectIceCandidates to
- // assert a minimal count.
- synchronized (gotIceCandidates) {
- gotIceCandidates.add(candidate);
- gotIceCandidates.notifyAll();
- }
- }
-
- private synchronized void setSize(int width, int height) {
- assertFalse(RENDER_TO_GUI);
- // Because different camera devices (fake & physical) produce different
- // resolutions, we only sanity-check the set sizes,
- assertTrue(width > 0);
- assertTrue(height > 0);
- if (previouslySeenWidth > 0) {
- assertEquals(previouslySeenWidth, width);
- assertEquals(previouslySeenHeight, height);
- } else {
- previouslySeenWidth = width;
- previouslySeenHeight = height;
- }
- }
-
- public synchronized void expectFramesDelivered(int count) {
- assertFalse(RENDER_TO_GUI);
- expectedFramesDelivered += count;
- }
-
- @Override
- public synchronized void renderFrame(VideoRenderer.I420Frame frame) {
- setSize(frame.rotatedWidth(), frame.rotatedHeight());
- --expectedFramesDelivered;
- VideoRenderer.renderFrameDone(frame);
- }
-
- public synchronized void expectSignalingChange(SignalingState newState) {
- expectedSignalingChanges.add(newState);
- }
-
- @Override
- public synchronized void onSignalingChange(SignalingState newState) {
- assertEquals(expectedSignalingChanges.removeFirst(), newState);
- }
-
- public synchronized void expectIceConnectionChange(
- IceConnectionState newState) {
- expectedIceConnectionChanges.add(newState);
- }
-
- @Override
- public synchronized void onIceConnectionChange(
- IceConnectionState newState) {
- // TODO(bemasc): remove once delivery of ICECompleted is reliable
- // (https://code.google.com/p/webrtc/issues/detail?id=3021).
- if (newState.equals(IceConnectionState.COMPLETED)) {
- return;
- }
-
- if (expectedIceConnectionChanges.isEmpty()) {
- System.out.println(name + "Got an unexpected ice connection change " + newState);
- return;
- }
-
- assertEquals(expectedIceConnectionChanges.removeFirst(), newState);
- }
-
- @Override
- public synchronized void onIceConnectionReceivingChange(boolean receiving) {
- System.out.println(name + "Got an ice connection receiving change " + receiving);
- }
-
- public synchronized void expectIceGatheringChange(
- IceGatheringState newState) {
- expectedIceGatheringChanges.add(newState);
- }
-
- @Override
- public synchronized void onIceGatheringChange(IceGatheringState newState) {
- // It's fine to get a variable number of GATHERING messages before
- // COMPLETE fires (depending on how long the test runs) so we don't assert
- // any particular count.
- if (newState == IceGatheringState.GATHERING) {
- return;
- }
- assertEquals(expectedIceGatheringChanges.removeFirst(), newState);
- }
-
- public synchronized void expectAddStream(String label) {
- expectedAddStreamLabels.add(label);
- }
-
- @Override
- public synchronized void onAddStream(MediaStream stream) {
- assertEquals(expectedAddStreamLabels.removeFirst(), stream.label());
- assertEquals(1, stream.videoTracks.size());
- assertEquals(1, stream.audioTracks.size());
- assertTrue(stream.videoTracks.get(0).id().endsWith("VideoTrack"));
- assertTrue(stream.audioTracks.get(0).id().endsWith("AudioTrack"));
- assertEquals("video", stream.videoTracks.get(0).kind());
- assertEquals("audio", stream.audioTracks.get(0).kind());
- VideoRenderer renderer = createVideoRenderer(this);
- stream.videoTracks.get(0).addRenderer(renderer);
- assertNull(renderers.put(
- stream, new WeakReference<VideoRenderer>(renderer)));
- }
-
- public synchronized void expectRemoveStream(String label) {
- expectedRemoveStreamLabels.add(label);
- }
-
- @Override
- public synchronized void onRemoveStream(MediaStream stream) {
- assertEquals(expectedRemoveStreamLabels.removeFirst(), stream.label());
- WeakReference<VideoRenderer> renderer = renderers.remove(stream);
- assertNotNull(renderer);
- assertNotNull(renderer.get());
- assertEquals(1, stream.videoTracks.size());
- stream.videoTracks.get(0).removeRenderer(renderer.get());
- }
-
- public synchronized void expectDataChannel(String label) {
- expectedRemoteDataChannelLabels.add(label);
- }
-
- @Override
- public synchronized void onDataChannel(DataChannel remoteDataChannel) {
- assertEquals(expectedRemoteDataChannelLabels.removeFirst(),
- remoteDataChannel.label());
- setDataChannel(remoteDataChannel);
- assertEquals(DataChannel.State.CONNECTING, dataChannel.state());
- }
-
- public synchronized void expectRenegotiationNeeded() {
- ++expectedRenegotiations;
- }
-
- @Override
- public synchronized void onRenegotiationNeeded() {
- assertTrue(--expectedRenegotiations >= 0);
- }
-
- public synchronized void expectMessage(ByteBuffer expectedBuffer,
- boolean expectedBinary) {
- expectedBuffers.add(
- new DataChannel.Buffer(expectedBuffer, expectedBinary));
- }
-
- @Override
- public synchronized void onMessage(DataChannel.Buffer buffer) {
- DataChannel.Buffer expected = expectedBuffers.removeFirst();
- assertEquals(expected.binary, buffer.binary);
- assertTrue(expected.data.equals(buffer.data));
- }
-
- @Override
- public synchronized void onBufferedAmountChange(long previousAmount) {
- assertFalse(previousAmount == dataChannel.bufferedAmount());
- }
-
- @Override
- public synchronized void onStateChange() {
- assertEquals(expectedStateChanges.removeFirst(), dataChannel.state());
- }
-
- public synchronized void expectStateChange(DataChannel.State state) {
- expectedStateChanges.add(state);
- }
-
- @Override
- public synchronized void onComplete(StatsReport[] reports) {
- if (--expectedStatsCallbacks < 0) {
- throw new RuntimeException("Unexpected stats report: " + reports);
- }
- gotStatsReports.add(reports);
- }
-
- public synchronized void expectStatsCallback() {
- ++expectedStatsCallbacks;
- }
-
- public synchronized LinkedList<StatsReport[]> takeStatsReports() {
- LinkedList<StatsReport[]> got = gotStatsReports;
- gotStatsReports = new LinkedList<StatsReport[]>();
- return got;
- }
-
- // Return a set of expectations that haven't been satisfied yet, possibly
- // empty if no such expectations exist.
- public synchronized TreeSet<String> unsatisfiedExpectations() {
- TreeSet<String> stillWaitingForExpectations = new TreeSet<String>();
- if (expectedIceCandidates > 0) { // See comment in onIceCandidate.
- stillWaitingForExpectations.add("expectedIceCandidates");
- }
- if (expectedErrors != 0) {
- stillWaitingForExpectations.add("expectedErrors: " + expectedErrors);
- }
- if (expectedSignalingChanges.size() != 0) {
- stillWaitingForExpectations.add(
- "expectedSignalingChanges: " + expectedSignalingChanges.size());
- }
- if (expectedIceConnectionChanges.size() != 0) {
- stillWaitingForExpectations.add("expectedIceConnectionChanges: " +
- expectedIceConnectionChanges.size());
- }
- if (expectedIceGatheringChanges.size() != 0) {
- stillWaitingForExpectations.add("expectedIceGatheringChanges: " +
- expectedIceGatheringChanges.size());
- }
- if (expectedAddStreamLabels.size() != 0) {
- stillWaitingForExpectations.add(
- "expectedAddStreamLabels: " + expectedAddStreamLabels.size());
- }
- if (expectedRemoveStreamLabels.size() != 0) {
- stillWaitingForExpectations.add(
- "expectedRemoveStreamLabels: " + expectedRemoveStreamLabels.size());
- }
- if (expectedFramesDelivered > 0) {
- stillWaitingForExpectations.add(
- "expectedFramesDelivered: " + expectedFramesDelivered);
- }
- if (!expectedBuffers.isEmpty()) {
- stillWaitingForExpectations.add(
- "expectedBuffers: " + expectedBuffers.size());
- }
- if (!expectedStateChanges.isEmpty()) {
- stillWaitingForExpectations.add(
- "expectedStateChanges: " + expectedStateChanges.size());
- }
- if (!expectedRemoteDataChannelLabels.isEmpty()) {
- stillWaitingForExpectations.add("expectedRemoteDataChannelLabels: " +
- expectedRemoteDataChannelLabels.size());
- }
- if (expectedStatsCallbacks != 0) {
- stillWaitingForExpectations.add(
- "expectedStatsCallbacks: " + expectedStatsCallbacks);
- }
- return stillWaitingForExpectations;
- }
-
- public boolean waitForAllExpectationsToBeSatisfied(int timeoutSeconds) {
- // TODO(fischman): problems with this approach:
- // - come up with something better than a poll loop
- // - avoid serializing expectations explicitly; the test is not as robust
- // as it could be because it must place expectations between wait
- // statements very precisely (e.g. frame must not arrive before its
- // expectation, and expectation must not be registered so early as to
- // stall a wait). Use callbacks to fire off dependent steps instead of
- // explicitly waiting, so there can be just a single wait at the end of
- // the test.
- long endTime = System.currentTimeMillis() + 1000 * timeoutSeconds;
- TreeSet<String> prev = null;
- TreeSet<String> stillWaitingForExpectations = unsatisfiedExpectations();
- while (!stillWaitingForExpectations.isEmpty()) {
- if (!stillWaitingForExpectations.equals(prev)) {
- System.out.println(
- name + " still waiting at\n " +
- (new Throwable()).getStackTrace()[1] +
- "\n for: " +
- Arrays.toString(stillWaitingForExpectations.toArray()));
- }
- if (endTime < System.currentTimeMillis()) {
- System.out.println(name + " timed out waiting for: "
- + Arrays.toString(stillWaitingForExpectations.toArray()));
- return false;
- }
- try {
- Thread.sleep(10);
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- }
- prev = stillWaitingForExpectations;
- stillWaitingForExpectations = unsatisfiedExpectations();
- }
- if (prev == null) {
- System.out.println(name + " didn't need to wait at\n " +
- (new Throwable()).getStackTrace()[1]);
- }
- return true;
- }
-
- // This methods return a list of all currently gathered ice candidates or waits until
- // 1 candidate have been gathered.
- public List<IceCandidate> getAtLeastOneIceCandidate() throws InterruptedException {
- synchronized (gotIceCandidates) {
- while (gotIceCandidates.isEmpty()) {
- gotIceCandidates.wait();
- }
- return new LinkedList<IceCandidate>(gotIceCandidates);
- }
- }
- }
-
- private static class SdpObserverLatch implements SdpObserver {
- private boolean success = false;
- private SessionDescription sdp = null;
- private String error = null;
- private CountDownLatch latch = new CountDownLatch(1);
-
- public SdpObserverLatch() {}
-
- @Override
- public void onCreateSuccess(SessionDescription sdp) {
- this.sdp = sdp;
- onSetSuccess();
- }
-
- @Override
- public void onSetSuccess() {
- success = true;
- latch.countDown();
- }
-
- @Override
- public void onCreateFailure(String error) {
- onSetFailure(error);
- }
-
- @Override
- public void onSetFailure(String error) {
- this.error = error;
- latch.countDown();
- }
-
- public boolean await() {
- try {
- assertTrue(latch.await(1000, TimeUnit.MILLISECONDS));
- return getSuccess();
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
- public boolean getSuccess() {
- return success;
- }
-
- public SessionDescription getSdp() {
- return sdp;
- }
-
- public String getError() {
- return error;
- }
- }
-
- static int videoWindowsMapped = -1;
-
- private static VideoRenderer createVideoRenderer(
- VideoRenderer.Callbacks videoCallbacks) {
- if (!RENDER_TO_GUI) {
- return new VideoRenderer(videoCallbacks);
- }
- ++videoWindowsMapped;
- assertTrue(videoWindowsMapped < 4);
- int x = videoWindowsMapped % 2 != 0 ? 700 : 0;
- int y = videoWindowsMapped >= 2 ? 0 : 500;
- return VideoRenderer.createGui(x, y);
- }
-
- // Return a weak reference to test that ownership is correctly held by
- // PeerConnection, not by test code.
- private static WeakReference<MediaStream> addTracksToPC(
- PeerConnectionFactory factory, PeerConnection pc,
- VideoSource videoSource,
- String streamLabel, String videoTrackId, String audioTrackId,
- VideoRenderer.Callbacks videoCallbacks) {
- MediaStream lMS = factory.createLocalMediaStream(streamLabel);
- VideoTrack videoTrack =
- factory.createVideoTrack(videoTrackId, videoSource);
- assertNotNull(videoTrack);
- VideoRenderer videoRenderer = createVideoRenderer(videoCallbacks);
- assertNotNull(videoRenderer);
- videoTrack.addRenderer(videoRenderer);
- lMS.addTrack(videoTrack);
- // Just for fun, let's remove and re-add the track.
- lMS.removeTrack(videoTrack);
- lMS.addTrack(videoTrack);
- lMS.addTrack(factory.createAudioTrack(
- audioTrackId, factory.createAudioSource(new MediaConstraints())));
- pc.addStream(lMS);
- return new WeakReference<MediaStream>(lMS);
- }
-
- // Used for making sure thread handles are not leaked.
- // Call initializeThreadCheck before a test and finalizeThreadCheck after
- // a test.
- void initializeThreadCheck() {
- System.gc(); // Encourage any GC-related threads to start up.
- threadsBeforeTest = allThreads();
- }
-
- void finalizeThreadCheck() throws Exception {
- // TreeSet<String> threadsAfterTest = allThreads();
-
- // TODO(tommi): Figure out a more reliable way to do this test. As is
- // we're seeing three possible 'normal' situations:
- // 1. before and after sets are equal.
- // 2. before contains 3 threads that do not exist in after.
- // 3. after contains 3 threads that do not exist in before.
- //
- // Maybe it would be better to do the thread enumeration from C++ and get
- // the thread names as well, in order to determine what these 3 threads are.
-
- // assertEquals(threadsBeforeTest, threadsAfterTest);
- // Thread.sleep(100);
- }
-
- void doTest() throws Exception {
- // Allow loopback interfaces too since our Android devices often don't
- // have those.
- PeerConnectionFactory.Options options = new PeerConnectionFactory.Options();
- options.networkIgnoreMask = 0;
- PeerConnectionFactory factory = new PeerConnectionFactory(options);
- // Uncomment to get ALL WebRTC tracing and SENSITIVE libjingle logging.
- // NOTE: this _must_ happen while |factory| is alive!
- // Logging.enableTracing(
- // "/tmp/PeerConnectionTest-log.txt",
- // EnumSet.of(Logging.TraceLevel.TRACE_ALL),
- // Logging.Severity.LS_SENSITIVE);
-
- MediaConstraints pcConstraints = new MediaConstraints();
- pcConstraints.mandatory.add(
- new MediaConstraints.KeyValuePair("DtlsSrtpKeyAgreement", "true"));
-
- LinkedList<PeerConnection.IceServer> iceServers =
- new LinkedList<PeerConnection.IceServer>();
- iceServers.add(new PeerConnection.IceServer(
- "stun:stun.l.google.com:19302"));
- iceServers.add(new PeerConnection.IceServer(
- "turn:fake.example.com", "fakeUsername", "fakePassword"));
- ObserverExpectations offeringExpectations =
- new ObserverExpectations("PCTest:offerer");
- PeerConnection offeringPC = factory.createPeerConnection(
- iceServers, pcConstraints, offeringExpectations);
- assertNotNull(offeringPC);
-
- ObserverExpectations answeringExpectations =
- new ObserverExpectations("PCTest:answerer");
- PeerConnection answeringPC = factory.createPeerConnection(
- iceServers, pcConstraints, answeringExpectations);
- assertNotNull(answeringPC);
-
- // We want to use the same camera for offerer & answerer, so create it here
- // instead of in addTracksToPC.
- VideoSource videoSource = factory.createVideoSource(
- VideoCapturer.create(""), new MediaConstraints());
-
- offeringExpectations.expectRenegotiationNeeded();
- WeakReference<MediaStream> oLMS = addTracksToPC(
- factory, offeringPC, videoSource, "offeredMediaStream",
- "offeredVideoTrack", "offeredAudioTrack", offeringExpectations);
-
- offeringExpectations.expectRenegotiationNeeded();
- DataChannel offeringDC = offeringPC.createDataChannel(
- "offeringDC", new DataChannel.Init());
- assertEquals("offeringDC", offeringDC.label());
-
- offeringExpectations.setDataChannel(offeringDC);
- SdpObserverLatch sdpLatch = new SdpObserverLatch();
- offeringPC.createOffer(sdpLatch, new MediaConstraints());
- assertTrue(sdpLatch.await());
- SessionDescription offerSdp = sdpLatch.getSdp();
- assertEquals(offerSdp.type, SessionDescription.Type.OFFER);
- assertFalse(offerSdp.description.isEmpty());
-
- sdpLatch = new SdpObserverLatch();
- answeringExpectations.expectSignalingChange(
- SignalingState.HAVE_REMOTE_OFFER);
- answeringExpectations.expectAddStream("offeredMediaStream");
- // SCTP DataChannels are announced via OPEN messages over the established
- // connection (not via SDP), so answeringExpectations can only register
- // expecting the channel during ICE, below.
- answeringPC.setRemoteDescription(sdpLatch, offerSdp);
- assertEquals(
- PeerConnection.SignalingState.STABLE, offeringPC.signalingState());
- assertTrue(sdpLatch.await());
- assertNull(sdpLatch.getSdp());
-
- answeringExpectations.expectRenegotiationNeeded();
- WeakReference<MediaStream> aLMS = addTracksToPC(
- factory, answeringPC, videoSource, "answeredMediaStream",
- "answeredVideoTrack", "answeredAudioTrack", answeringExpectations);
-
- sdpLatch = new SdpObserverLatch();
- answeringPC.createAnswer(sdpLatch, new MediaConstraints());
- assertTrue(sdpLatch.await());
- SessionDescription answerSdp = sdpLatch.getSdp();
- assertEquals(answerSdp.type, SessionDescription.Type.ANSWER);
- assertFalse(answerSdp.description.isEmpty());
-
- offeringExpectations.expectIceCandidates(2);
- answeringExpectations.expectIceCandidates(2);
-
- offeringExpectations.expectIceGatheringChange(IceGatheringState.COMPLETE);
- answeringExpectations.expectIceGatheringChange(IceGatheringState.COMPLETE);
-
- sdpLatch = new SdpObserverLatch();
- answeringExpectations.expectSignalingChange(SignalingState.STABLE);
- answeringPC.setLocalDescription(sdpLatch, answerSdp);
- assertTrue(sdpLatch.await());
- assertNull(sdpLatch.getSdp());
-
- sdpLatch = new SdpObserverLatch();
- offeringExpectations.expectSignalingChange(SignalingState.HAVE_LOCAL_OFFER);
- offeringPC.setLocalDescription(sdpLatch, offerSdp);
- assertTrue(sdpLatch.await());
- assertNull(sdpLatch.getSdp());
- sdpLatch = new SdpObserverLatch();
- offeringExpectations.expectSignalingChange(SignalingState.STABLE);
- offeringExpectations.expectAddStream("answeredMediaStream");
-
- offeringExpectations.expectIceConnectionChange(
- IceConnectionState.CHECKING);
- offeringExpectations.expectIceConnectionChange(
- IceConnectionState.CONNECTED);
- // TODO(bemasc): uncomment once delivery of ICECompleted is reliable
- // (https://code.google.com/p/webrtc/issues/detail?id=3021).
- //
- // offeringExpectations.expectIceConnectionChange(
- // IceConnectionState.COMPLETED);
- answeringExpectations.expectIceConnectionChange(
- IceConnectionState.CHECKING);
- answeringExpectations.expectIceConnectionChange(
- IceConnectionState.CONNECTED);
-
- offeringPC.setRemoteDescription(sdpLatch, answerSdp);
- assertTrue(sdpLatch.await());
- assertNull(sdpLatch.getSdp());
-
- assertEquals(offeringPC.getLocalDescription().type, offerSdp.type);
- assertEquals(offeringPC.getRemoteDescription().type, answerSdp.type);
- assertEquals(answeringPC.getLocalDescription().type, answerSdp.type);
- assertEquals(answeringPC.getRemoteDescription().type, offerSdp.type);
-
- assertEquals(offeringPC.getSenders().size(), 2);
- assertEquals(offeringPC.getReceivers().size(), 2);
- assertEquals(answeringPC.getSenders().size(), 2);
- assertEquals(answeringPC.getReceivers().size(), 2);
-
- if (!RENDER_TO_GUI) {
- // Wait for at least some frames to be delivered at each end (number
- // chosen arbitrarily).
- offeringExpectations.expectFramesDelivered(10);
- answeringExpectations.expectFramesDelivered(10);
- }
-
- offeringExpectations.expectStateChange(DataChannel.State.OPEN);
- // See commentary about SCTP DataChannels above for why this is here.
- answeringExpectations.expectDataChannel("offeringDC");
- answeringExpectations.expectStateChange(DataChannel.State.OPEN);
-
- // Wait for at least one ice candidate from the offering PC and forward them to the answering
- // PC.
- for (IceCandidate candidate : offeringExpectations.getAtLeastOneIceCandidate()) {
- answeringPC.addIceCandidate(candidate);
- }
-
- // Wait for at least one ice candidate from the answering PC and forward them to the offering
- // PC.
- for (IceCandidate candidate : answeringExpectations.getAtLeastOneIceCandidate()) {
- offeringPC.addIceCandidate(candidate);
- }
-
- assertTrue(offeringExpectations.waitForAllExpectationsToBeSatisfied(TIMEOUT_SECONDS));
- assertTrue(answeringExpectations.waitForAllExpectationsToBeSatisfied(TIMEOUT_SECONDS));
-
- assertEquals(
- PeerConnection.SignalingState.STABLE, offeringPC.signalingState());
- assertEquals(
- PeerConnection.SignalingState.STABLE, answeringPC.signalingState());
-
- // Test send & receive UTF-8 text.
- answeringExpectations.expectMessage(
- ByteBuffer.wrap("hello!".getBytes(Charset.forName("UTF-8"))), false);
- DataChannel.Buffer buffer = new DataChannel.Buffer(
- ByteBuffer.wrap("hello!".getBytes(Charset.forName("UTF-8"))), false);
- assertTrue(offeringExpectations.dataChannel.send(buffer));
- assertTrue(answeringExpectations.waitForAllExpectationsToBeSatisfied(TIMEOUT_SECONDS));
-
- // Construct this binary message two different ways to ensure no
- // shortcuts are taken.
- ByteBuffer expectedBinaryMessage = ByteBuffer.allocateDirect(5);
- for (byte i = 1; i < 6; ++i) {
- expectedBinaryMessage.put(i);
- }
- expectedBinaryMessage.flip();
- offeringExpectations.expectMessage(expectedBinaryMessage, true);
- assertTrue(answeringExpectations.dataChannel.send(
- new DataChannel.Buffer(
- ByteBuffer.wrap(new byte[] { 1, 2, 3, 4, 5 }), true)));
- assertTrue(offeringExpectations.waitForAllExpectationsToBeSatisfied(TIMEOUT_SECONDS));
-
- offeringExpectations.expectStateChange(DataChannel.State.CLOSING);
- answeringExpectations.expectStateChange(DataChannel.State.CLOSING);
- offeringExpectations.expectStateChange(DataChannel.State.CLOSED);
- answeringExpectations.expectStateChange(DataChannel.State.CLOSED);
- answeringExpectations.dataChannel.close();
- offeringExpectations.dataChannel.close();
-
- if (RENDER_TO_GUI) {
- try {
- Thread.sleep(3000);
- } catch (Throwable t) {
- throw new RuntimeException(t);
- }
- }
-
- // TODO(fischman) MOAR test ideas:
- // - Test that PC.removeStream() works; requires a second
- // createOffer/createAnswer dance.
- // - audit each place that uses |constraints| for specifying non-trivial
- // constraints (and ensure they're honored).
- // - test error cases
- // - ensure reasonable coverage of _jni.cc is achieved. Coverage is
- // extra-important because of all the free-text (class/method names, etc)
- // in JNI-style programming; make sure no typos!
- // - Test that shutdown mid-interaction is crash-free.
-
- // Free the Java-land objects, collect them, and sleep a bit to make sure we
- // don't get late-arrival crashes after the Java-land objects have been
- // freed.
- shutdownPC(offeringPC, offeringExpectations);
- offeringPC = null;
- shutdownPC(answeringPC, answeringExpectations);
- answeringPC = null;
- videoSource.dispose();
- factory.dispose();
- System.gc();
- }
-
- private static void shutdownPC(
- PeerConnection pc, ObserverExpectations expectations) {
- expectations.dataChannel.unregisterObserver();
- expectations.dataChannel.dispose();
- expectations.expectStatsCallback();
- assertTrue(pc.getStats(expectations, null));
- assertTrue(expectations.waitForAllExpectationsToBeSatisfied(TIMEOUT_SECONDS));
- expectations.expectIceConnectionChange(IceConnectionState.CLOSED);
- expectations.expectSignalingChange(SignalingState.CLOSED);
- pc.close();
- assertTrue(expectations.waitForAllExpectationsToBeSatisfied(TIMEOUT_SECONDS));
- expectations.expectStatsCallback();
- assertTrue(pc.getStats(expectations, null));
- assertTrue(expectations.waitForAllExpectationsToBeSatisfied(TIMEOUT_SECONDS));
-
- System.out.println("FYI stats: ");
- int reportIndex = -1;
- for (StatsReport[] reports : expectations.takeStatsReports()) {
- System.out.println(" Report #" + (++reportIndex));
- for (int i = 0; i < reports.length; ++i) {
- System.out.println(" " + reports[i].toString());
- }
- }
- assertEquals(1, reportIndex);
- System.out.println("End stats.");
-
- pc.dispose();
- }
-
- // Returns a set of thread IDs belonging to this process, as Strings.
- private static TreeSet<String> allThreads() {
- TreeSet<String> threads = new TreeSet<String>();
- // This pokes at /proc instead of using the Java APIs because we're also
- // looking for libjingle/webrtc native threads, most of which won't have
- // attached to the JVM.
- for (String threadId : (new File("/proc/self/task")).list()) {
- threads.add(threadId);
- }
- return threads;
- }
-}