Index: talk/app/webrtc/java/android/org/webrtc/SurfaceViewRenderer.java |
diff --git a/talk/app/webrtc/java/android/org/webrtc/SurfaceViewRenderer.java b/talk/app/webrtc/java/android/org/webrtc/SurfaceViewRenderer.java |
index fe3300c85f6dfdce1f1a11ca615ed2a3145e9b48..7e56e700c2e6f62acbb4bb4bc7f12d7b09d67ea1 100644 |
--- a/talk/app/webrtc/java/android/org/webrtc/SurfaceViewRenderer.java |
+++ b/talk/app/webrtc/java/android/org/webrtc/SurfaceViewRenderer.java |
@@ -54,11 +54,11 @@ public class SurfaceViewRenderer extends SurfaceView |
implements SurfaceHolder.Callback, VideoRenderer.Callbacks { |
private static final String TAG = "SurfaceViewRenderer"; |
- // These variables are synchronized on |threadLock|. |
- private final Object threadLock = new Object(); |
// Dedicated render thread. |
private HandlerThread renderThread; |
- // Handler for inter-thread communication. |
+ // |renderThreadHandler| is a handler for communicating with |renderThread|, and is synchronized |
+ // on |handlerLock|. |
+ private final Object handlerLock = new Object(); |
private Handler renderThreadHandler; |
// EGL and GL resources for drawing YUV/OES textures. After initilization, these are only accessed |
@@ -156,11 +156,13 @@ public class SurfaceViewRenderer extends SurfaceView |
} |
/** |
- * Release all resources. This needs to be done manually, otherwise the resources are leaked. You |
- * should call this before the Activity is destroyed, while the EGLContext is still valid. |
+ * Block until any pending frame is returned and all GL resources released, even if an interrupt |
+ * occurs. If an interrupt occurs during release(), the interrupt flag will be set. This function |
+ * should be called before the Activity is destroyed and the EGLContext is still valid. If you |
+ * don't call this function, the GL resources might leak. |
*/ |
public void release() { |
- synchronized (threadLock) { |
+ synchronized (handlerLock) { |
if (renderThreadHandler == null) { |
Logging.d(TAG, "Already released"); |
return; |
@@ -169,7 +171,7 @@ public class SurfaceViewRenderer extends SurfaceView |
// TODO(magjed): This might not be necessary - all OpenGL resources are automatically deleted |
// when the EGL context is lost. It might be dangerous to delete them manually in |
// Activity.onDestroy(). |
- renderThreadHandler.post(new Runnable() { |
+ renderThreadHandler.postAtFrontOfQueue(new Runnable() { |
@Override public void run() { |
drawer.release(); |
drawer = null; |
@@ -181,19 +183,35 @@ public class SurfaceViewRenderer extends SurfaceView |
eglBase = null; |
} |
}); |
- // Don't accept any more messages to the render thread. |
+ // Don't accept any more frames or messages to the render thread. |
renderThreadHandler = null; |
- // Quit safely to make sure the EGL/GL cleanup posted above is executed. |
- renderThread.quitSafely(); |
- renderThread = null; |
} |
- getHolder().removeCallback(this); |
+ // Quit safely to make sure the EGL/GL cleanup posted above is executed. |
+ renderThread.quitSafely(); |
synchronized (frameLock) { |
if (pendingFrame != null) { |
VideoRenderer.renderFrameDone(pendingFrame); |
pendingFrame = null; |
} |
} |
+ // The |renderThread| cleanup is not safe to cancel and we need to wait until it's done. |
+ boolean wasInterrupted = false; |
+ while (true) { |
+ try { |
+ renderThread.join(); |
+ renderThread = null; |
+ break; |
+ } catch (InterruptedException e) { |
+ // Someone is asking us to return early at our convenience. We can't cancel this cleanup, |
+ // but we should preserve the information and pass it along. Any rendering in progress |
+ // should complete in a few ms. |
+ wasInterrupted = true; |
+ } |
+ } |
+ // Pass interruption information along. |
+ if (wasInterrupted) { |
+ Thread.currentThread().interrupt(); |
+ } |
} |
/** |
@@ -220,7 +238,7 @@ public class SurfaceViewRenderer extends SurfaceView |
synchronized (statisticsLock) { |
++framesReceived; |
} |
- synchronized (threadLock) { |
+ synchronized (handlerLock) { |
if (renderThreadHandler == null) { |
Logging.d(TAG, "Dropping frame - SurfaceViewRenderer not initialized or already released."); |
} else { |
@@ -322,7 +340,7 @@ public class SurfaceViewRenderer extends SurfaceView |
* Private helper function to post tasks safely. |
*/ |
private void runOnRenderThread(Runnable runnable) { |
- synchronized (threadLock) { |
+ synchronized (handlerLock) { |
if (renderThreadHandler != null) { |
renderThreadHandler.post(runnable); |
} |