Index: talk/app/webrtc/java/android/org/webrtc/SurfaceTextureHelper.java |
diff --git a/talk/app/webrtc/java/android/org/webrtc/SurfaceTextureHelper.java b/talk/app/webrtc/java/android/org/webrtc/SurfaceTextureHelper.java |
index 4d5a2e62f12346bd2f340e3855aa705887ebc54f..175a00ed21b5660385733a42a1da90d8f8f3d6d5 100644 |
--- a/talk/app/webrtc/java/android/org/webrtc/SurfaceTextureHelper.java |
+++ b/talk/app/webrtc/java/android/org/webrtc/SurfaceTextureHelper.java |
@@ -36,6 +36,7 @@ import android.os.Handler; |
import android.os.HandlerThread; |
import android.os.SystemClock; |
+import java.util.concurrent.Callable; |
import java.util.concurrent.CountDownLatch; |
import java.util.concurrent.TimeUnit; |
@@ -63,7 +64,35 @@ final class SurfaceTextureHelper { |
int oesTextureId, float[] transformMatrix, long timestampNs); |
} |
- private final HandlerThread thread; |
+ public static SurfaceTextureHelper create(EGLContext 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. |
+ */ |
+ public static SurfaceTextureHelper create(final EGLContext 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()); |
+ } |
+ // 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<SurfaceTextureHelper>() { |
+ @Override public SurfaceTextureHelper call() { |
+ return new SurfaceTextureHelper(sharedContext, finalHandler, (handler == null)); |
+ } |
+ }); |
+ } |
+ |
private final Handler handler; |
private final boolean isOwningThread; |
private final EglBase eglBase; |
@@ -75,23 +104,12 @@ final class SurfaceTextureHelper { |
private boolean isTextureInUse = false; |
private boolean isQuitting = false; |
- /** |
- * Construct a new SurfaceTextureHelper sharing OpenGL resources with |sharedContext|. |
- */ |
- public SurfaceTextureHelper(EGLContext sharedContext) { |
- this(sharedContext, null); |
- } |
- |
- public SurfaceTextureHelper(EGLContext sharedContext, HandlerThread thread) { |
- if (thread == null) { |
- this.thread = new HandlerThread(TAG); |
- this.thread.start(); |
- this.isOwningThread = true; |
- } else { |
- this.thread = thread; |
- this.isOwningThread = false; |
+ private SurfaceTextureHelper(EGLContext sharedContext, Handler handler, boolean isOwningThread) { |
+ if (!handler.getLooper().isCurrentThread()) { |
+ throw new IllegalStateException("SurfaceTextureHelper must be created on the handler thread"); |
} |
- this.handler = new Handler(this.thread.getLooper()); |
+ this.handler = handler; |
+ this.isOwningThread = isOwningThread; |
eglBase = new EglBase(sharedContext, EglBase.ConfigType.PIXEL_BUFFER); |
eglBase.createDummyPbufferSurface(); |
@@ -99,9 +117,6 @@ final class SurfaceTextureHelper { |
oesTextureId = GlUtil.generateTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES); |
surfaceTexture = new SurfaceTexture(oesTextureId); |
- |
- // The EGL context will be re-attached to the private thread. |
- eglBase.detachCurrent(); |
} |
/** |
@@ -119,7 +134,7 @@ final class SurfaceTextureHelper { |
hasPendingTexture = true; |
tryDeliverTextureFrame(); |
} |
- }, handler); |
+ }); |
} |
/** |
@@ -154,7 +169,7 @@ final class SurfaceTextureHelper { |
* onTextureFrameAvailable() after this function returns. |
*/ |
public void disconnect() { |
- if (Thread.currentThread() == thread) { |
+ if (handler.getLooper().isCurrentThread()) { |
isQuitting = true; |
if (!isTextureInUse) { |
release(); |
@@ -175,7 +190,7 @@ final class SurfaceTextureHelper { |
} |
private void tryDeliverTextureFrame() { |
- if (Thread.currentThread() != thread) { |
+ if (!handler.getLooper().isCurrentThread()) { |
throw new IllegalStateException("Wrong thread."); |
} |
if (isQuitting || !hasPendingTexture || isTextureInUse) { |
@@ -196,7 +211,7 @@ final class SurfaceTextureHelper { |
} |
private void release() { |
- if (Thread.currentThread() != thread) { |
+ if (!handler.getLooper().isCurrentThread()) { |
throw new IllegalStateException("Wrong thread."); |
} |
if (isTextureInUse || !isQuitting) { |
@@ -207,7 +222,7 @@ final class SurfaceTextureHelper { |
surfaceTexture.release(); |
eglBase.release(); |
if (isOwningThread) { |
- thread.quitSafely(); |
+ handler.getLooper().quitSafely(); |
} |
} |
} |