diff --git a/webrtc/api/androidtests/src/org/webrtc/SurfaceTextureHelperTest.java b/webrtc/api/androidtests/src/org/webrtc/SurfaceTextureHelperTest.java index e6a788f9f8..f2a8a6fc66 100644 --- a/webrtc/api/androidtests/src/org/webrtc/SurfaceTextureHelperTest.java +++ b/webrtc/api/androidtests/src/org/webrtc/SurfaceTextureHelperTest.java @@ -11,8 +11,6 @@ package org.webrtc; import android.graphics.SurfaceTexture; import android.opengl.GLES20; -import android.os.Handler; -import android.os.HandlerThread; import android.os.SystemClock; import android.test.ActivityTestCase; import android.test.suitebuilder.annotation.MediumTest; @@ -271,78 +269,6 @@ public final class SurfaceTextureHelperTest extends ActivityTestCase { surfaceTextureHelper.disconnect(); } - /** - * Test use SurfaceTextureHelper on a separate thread. A uniform texture frame is created and - * received on a thread separate from the test thread. - */ - @MediumTest - public static void testFrameOnSeparateThread() throws InterruptedException { - final HandlerThread thread = new HandlerThread("SurfaceTextureHelperTestThread"); - thread.start(); - final Handler handler = new Handler(thread.getLooper()); - - // Create SurfaceTextureHelper and listener. - final SurfaceTextureHelper surfaceTextureHelper = - SurfaceTextureHelper.create(null, handler); - // Create a mock listener and expect frames to be delivered on |thread|. - final MockTextureListener listener = new MockTextureListener(thread); - surfaceTextureHelper.setListener(listener); - - // Create resources for stubbing an OES texture producer. |eglOesBase| has the - // SurfaceTexture in |surfaceTextureHelper| as the target EGLSurface. - final EglBase eglOesBase = EglBase.create(null, EglBase.CONFIG_PLAIN); - eglOesBase.createSurface(surfaceTextureHelper.getSurfaceTexture()); - eglOesBase.makeCurrent(); - // Draw a frame onto the SurfaceTexture. - GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); - // swapBuffers() will ultimately trigger onTextureFrameAvailable(). - eglOesBase.swapBuffers(); - eglOesBase.release(); - - // Wait for an OES texture to arrive. - listener.waitForNewFrame(); - - // Return the frame from this thread. - surfaceTextureHelper.returnTextureFrame(); - surfaceTextureHelper.disconnect(handler); - } - - /** - * Test use SurfaceTextureHelper on a separate thread. A uniform texture frame is created and - * received on a thread separate from the test thread and returned after disconnect. - */ - @MediumTest - public static void testLateReturnFrameOnSeparateThread() throws InterruptedException { - final HandlerThread thread = new HandlerThread("SurfaceTextureHelperTestThread"); - thread.start(); - final Handler handler = new Handler(thread.getLooper()); - - // Create SurfaceTextureHelper and listener. - final SurfaceTextureHelper surfaceTextureHelper = - SurfaceTextureHelper.create(null, handler); - // Create a mock listener and expect frames to be delivered on |thread|. - final MockTextureListener listener = new MockTextureListener(thread); - surfaceTextureHelper.setListener(listener); - - // Create resources for stubbing an OES texture producer. |eglOesBase| has the - // SurfaceTexture in |surfaceTextureHelper| as the target EGLSurface. - final EglBase eglOesBase = EglBase.create(null, EglBase.CONFIG_PLAIN); - eglOesBase.createSurface(surfaceTextureHelper.getSurfaceTexture()); - eglOesBase.makeCurrent(); - // Draw a frame onto the SurfaceTexture. - GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); - // swapBuffers() will ultimately trigger onTextureFrameAvailable(). - eglOesBase.swapBuffers(); - eglOesBase.release(); - - // Wait for an OES texture to arrive. - listener.waitForNewFrame(); - - surfaceTextureHelper.disconnect(handler); - - surfaceTextureHelper.returnTextureFrame(); - } - @MediumTest public static void testTexturetoYUV() throws InterruptedException { final int width = 16; diff --git a/webrtc/api/java/android/org/webrtc/SurfaceTextureHelper.java b/webrtc/api/java/android/org/webrtc/SurfaceTextureHelper.java index 4b1dda61d0..1781047107 100644 --- a/webrtc/api/java/android/org/webrtc/SurfaceTextureHelper.java +++ b/webrtc/api/java/android/org/webrtc/SurfaceTextureHelper.java @@ -48,32 +48,23 @@ class SurfaceTextureHelper { int oesTextureId, float[] transformMatrix, long timestampNs); } - public static SurfaceTextureHelper create(EglBase.Context sharedContext) { - return create(sharedContext, null); - } - /** - * Construct a new SurfaceTextureHelper sharing OpenGL resources with |sharedContext|. If - * |handler| is non-null, the callback will be executed on that handler's thread. If |handler| is - * null, a dedicated private thread is created for the callbacks. + * Construct a new SurfaceTextureHelper sharing OpenGL resources with |sharedContext|. A dedicated + * thread and handler is created for handling the SurfaceTexture. */ - public static SurfaceTextureHelper create(final EglBase.Context sharedContext, - final Handler handler) { - final Handler finalHandler; - if (handler != null) { - finalHandler = handler; - } else { - final HandlerThread thread = new HandlerThread(TAG); - thread.start(); - finalHandler = new Handler(thread.getLooper()); - } + public static SurfaceTextureHelper create(final EglBase.Context sharedContext) { + final HandlerThread thread = new HandlerThread(TAG); + thread.start(); + final Handler handler = new Handler(thread.getLooper()); + // The onFrameAvailable() callback will be executed on the SurfaceTexture ctor thread. See: // http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.1.1_r1/android/graphics/SurfaceTexture.java#195. // Therefore, in order to control the callback thread on API lvl < 21, the SurfaceTextureHelper // is constructed on the |handler| thread. - return ThreadUtils.invokeUninterruptibly(finalHandler, new Callable() { - @Override public SurfaceTextureHelper call() { - return new SurfaceTextureHelper(sharedContext, finalHandler, (handler == null)); + return ThreadUtils.invokeUninterruptibly(handler, new Callable() { + @Override + public SurfaceTextureHelper call() { + return new SurfaceTextureHelper(sharedContext, handler); } }); } @@ -291,7 +282,6 @@ class SurfaceTextureHelper { } private final Handler handler; - private boolean isOwningThread; private final EglBase eglBase; private final SurfaceTexture surfaceTexture; private final int oesTextureId; @@ -303,13 +293,11 @@ class SurfaceTextureHelper { private volatile boolean isTextureInUse = false; private boolean isQuitting = false; - private SurfaceTextureHelper(EglBase.Context sharedContext, - Handler handler, boolean isOwningThread) { + private SurfaceTextureHelper(EglBase.Context sharedContext, Handler handler) { if (handler.getLooper().getThread() != Thread.currentThread()) { throw new IllegalStateException("SurfaceTextureHelper must be created on the handler thread"); } this.handler = handler; - this.isOwningThread = isOwningThread; eglBase = EglBase.create(sharedContext, EglBase.CONFIG_PIXEL_BUFFER); eglBase.createDummyPbufferSurface(); @@ -357,6 +345,14 @@ class SurfaceTextureHelper { return surfaceTexture; } + /** + * Retrieve the handler that calls onTextureFrameAvailable(). This handler is valid until + * disconnect() is called. + */ + public Handler getHandler() { + return handler; + } + /** * Call this function to signal that you are done with the frame received in * onTextureFrameAvailable(). Only one texture frame can be in flight at once, so you must call @@ -380,14 +376,11 @@ class SurfaceTextureHelper { } /** - * Call disconnect() to stop receiving frames. Resources are released when the texture frame has - * been returned by a call to returnTextureFrame(). You are guaranteed to not receive any more - * onTextureFrameAvailable() after this function returns. + * Call disconnect() to stop receiving frames. OpenGL resources are released and the handler is + * stopped when the texture frame has been returned by a call to returnTextureFrame(). You are + * guaranteed to not receive any more onTextureFrameAvailable() after this function returns. */ public void disconnect() { - if (!isOwningThread) { - throw new IllegalStateException("Must call disconnect(handler)."); - } if (handler.getLooper().getThread() == Thread.currentThread()) { isQuitting = true; if (!isTextureInUse) { @@ -408,20 +401,6 @@ class SurfaceTextureHelper { ThreadUtils.awaitUninterruptibly(barrier); } - /** - * Call disconnect() to stop receiving frames and quit the looper used by |handler|. - * Resources are released when the texture frame has been returned by a call to - * returnTextureFrame(). You are guaranteed to not receive any more - * onTextureFrameAvailable() after this function returns. - */ - public void disconnect(Handler handler) { - if (this.handler != handler) { - throw new IllegalStateException("Wrong handler."); - } - isOwningThread = true; - disconnect(); - } - public void textureToYUV(ByteBuffer buf, int width, int height, int stride, int textureId, float [] transformMatrix) { if (textureId != oesTextureId) diff --git a/webrtc/api/java/android/org/webrtc/VideoCapturerAndroid.java b/webrtc/api/java/android/org/webrtc/VideoCapturerAndroid.java index f0536c6d92..a696805b2a 100644 --- a/webrtc/api/java/android/org/webrtc/VideoCapturerAndroid.java +++ b/webrtc/api/java/android/org/webrtc/VideoCapturerAndroid.java @@ -12,7 +12,6 @@ package org.webrtc; import android.content.Context; import android.os.Handler; -import android.os.HandlerThread; import android.os.SystemClock; import android.view.Surface; import android.view.WindowManager; @@ -53,7 +52,7 @@ public class VideoCapturerAndroid implements private final static int CAMERA_FREEZE_REPORT_TIMOUT_MS = 6000; private android.hardware.Camera camera; // Only non-null while capturing. - private HandlerThread cameraThread; + private Thread cameraThread; private final Handler cameraThreadHandler; private Context applicationContext; // Synchronization lock for |id|. @@ -302,12 +301,11 @@ public class VideoCapturerAndroid implements EglBase.Context sharedContext) { this.id = cameraId; this.eventsHandler = eventsHandler; - cameraThread = new HandlerThread(TAG); - cameraThread.start(); - cameraThreadHandler = new Handler(cameraThread.getLooper()); isCapturingToTexture = (sharedContext != null); cameraStatistics = new CameraStatistics(); - surfaceHelper = SurfaceTextureHelper.create(sharedContext, cameraThreadHandler); + surfaceHelper = SurfaceTextureHelper.create(sharedContext); + cameraThreadHandler = surfaceHelper.getHandler(); + cameraThread = cameraThreadHandler.getLooper().getThread(); if (isCapturingToTexture) { surfaceHelper.setListener(this); } @@ -354,11 +352,11 @@ public class VideoCapturerAndroid implements } } }); - surfaceHelper.disconnect(cameraThreadHandler); + surfaceHelper.disconnect(); cameraThread = null; } - // Used for testing purposes to check if release() has been called. + // Used for testing purposes to check if dispose() has been called. public boolean isDisposed() { return (cameraThread == null); }