1feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk/*
2feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk * Copyright (C) 2014 The Android Open Source Project
3feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk *
4feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk * Licensed under the Apache License, Version 2.0 (the "License");
5feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk * you may not use this file except in compliance with the License.
6feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk * You may obtain a copy of the License at
7feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk *
8feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk *      http://www.apache.org/licenses/LICENSE-2.0
9feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk *
10feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk * Unless required by applicable law or agreed to in writing, software
11feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk * distributed under the License is distributed on an "AS IS" BASIS,
12feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk * See the License for the specific language governing permissions and
14feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk * limitations under the License.
15feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk */
16feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
17feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkpackage android.hardware.camera2.legacy;
18feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
19feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport android.graphics.SurfaceTexture;
204aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunkimport android.hardware.camera2.impl.CameraDeviceImpl;
21feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport android.os.ConditionVariable;
22feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport android.os.Handler;
23feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport android.os.Message;
24feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport android.util.Log;
25f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunkimport android.util.Pair;
26f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunkimport android.util.Size;
27feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport android.view.Surface;
28feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
29feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport java.util.Collection;
30feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
3191838ded36131525312739c0929913b215519c2aRuben Brunkimport static com.android.internal.util.Preconditions.*;
3291838ded36131525312739c0929913b215519c2aRuben Brunk
33feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk/**
34feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk * GLThreadManager handles the thread used for rendering into the configured output surfaces.
35feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk */
36feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkpublic class GLThreadManager {
37feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private final String TAG;
38a78791f22af6c6985d186494737468bb19b69540Eino-Ville Talvala    private static final boolean DEBUG = false;
39feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
40feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private static final int MSG_NEW_CONFIGURATION = 1;
41feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private static final int MSG_NEW_FRAME = 2;
42feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private static final int MSG_CLEANUP = 3;
43feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private static final int MSG_DROP_FRAMES = 4;
44feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private static final int MSG_ALLOW_FRAMES = 5;
45feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
4691838ded36131525312739c0929913b215519c2aRuben Brunk    private CaptureCollector mCaptureCollector;
4791838ded36131525312739c0929913b215519c2aRuben Brunk
484aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk    private final CameraDeviceState mDeviceState;
494aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk
50feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private final SurfaceTextureRenderer mTextureRenderer;
51feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
52feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private final RequestHandlerThread mGLHandlerThread;
53feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
54feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private final RequestThreadManager.FpsCounter mPrevCounter =
55feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            new RequestThreadManager.FpsCounter("GL Preview Producer");
56feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
57feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    /**
58feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * Container object for Configure messages.
59feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     */
60feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private static class ConfigureHolder {
61feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        public final ConditionVariable condition;
62f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk        public final Collection<Pair<Surface, Size>> surfaces;
6391838ded36131525312739c0929913b215519c2aRuben Brunk        public final CaptureCollector collector;
64feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
65f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk        public ConfigureHolder(ConditionVariable condition, Collection<Pair<Surface,
66f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk                Size>> surfaces, CaptureCollector collector) {
67feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            this.condition = condition;
68feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            this.surfaces = surfaces;
6991838ded36131525312739c0929913b215519c2aRuben Brunk            this.collector = collector;
70feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
71feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
72feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
73feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private final Handler.Callback mGLHandlerCb = new Handler.Callback() {
74feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        private boolean mCleanup = false;
75feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        private boolean mConfigured = false;
76feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        private boolean mDroppingFrames = false;
77feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
78feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        @SuppressWarnings("unchecked")
79feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        @Override
80feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        public boolean handleMessage(Message msg) {
81feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            if (mCleanup) {
82feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                return true;
83feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            }
844aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk            try {
854aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk                switch (msg.what) {
864aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk                    case MSG_NEW_CONFIGURATION:
874aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk                        ConfigureHolder configure = (ConfigureHolder) msg.obj;
884aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk                        mTextureRenderer.cleanupEGLContext();
894aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk                        mTextureRenderer.configureSurfaces(configure.surfaces);
904aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk                        mCaptureCollector = checkNotNull(configure.collector);
914aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk                        configure.condition.open();
924aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk                        mConfigured = true;
934aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk                        break;
944aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk                    case MSG_NEW_FRAME:
954aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk                        if (mDroppingFrames) {
964aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk                            Log.w(TAG, "Ignoring frame.");
974aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk                            break;
984aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk                        }
994aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk                        if (DEBUG) {
1004aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk                            mPrevCounter.countAndLog();
1014aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk                        }
1024aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk                        if (!mConfigured) {
1034aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk                            Log.e(TAG, "Dropping frame, EGL context not configured!");
1044aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk                        }
1054aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk                        mTextureRenderer.drawIntoSurfaces(mCaptureCollector);
1064aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk                        break;
1074aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk                    case MSG_CLEANUP:
1084aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk                        mTextureRenderer.cleanupEGLContext();
1094aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk                        mCleanup = true;
1104aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk                        mConfigured = false;
1114aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk                        break;
1124aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk                    case MSG_DROP_FRAMES:
1134aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk                        mDroppingFrames = true;
1144aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk                        break;
1154aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk                    case MSG_ALLOW_FRAMES:
1164aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk                        mDroppingFrames = false;
1174aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk                        break;
11851dcfd65a6742884e07182dd7d13b916fd4e0305Igor Murashkin                    case RequestHandlerThread.MSG_POKE_IDLE_HANDLER:
11951dcfd65a6742884e07182dd7d13b916fd4e0305Igor Murashkin                        // OK: Ignore message.
12051dcfd65a6742884e07182dd7d13b916fd4e0305Igor Murashkin                        break;
1214aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk                    default:
1224aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk                        Log.e(TAG, "Unhandled message " + msg.what + " on GLThread.");
123feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                        break;
1244aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk                }
1254aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk            } catch (Exception e) {
1264aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk                Log.e(TAG, "Received exception on GL render thread: ", e);
1274aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk                mDeviceState.setError(CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE);
128feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            }
129feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            return true;
130feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
131feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    };
132feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
133feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    /**
134feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * Create a new GL thread and renderer.
135feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     *
136feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * @param cameraId the camera id for this thread.
137b68dd5c8b92d376540ac4ae6ed59671db641685eRuben Brunk     * @param facing direction the camera is facing.
1384aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk     * @param state {@link CameraDeviceState} to use for error handling.
139feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     */
1404aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk    public GLThreadManager(int cameraId, int facing, CameraDeviceState state) {
141b68dd5c8b92d376540ac4ae6ed59671db641685eRuben Brunk        mTextureRenderer = new SurfaceTextureRenderer(facing);
142feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        TAG = String.format("CameraDeviceGLThread-%d", cameraId);
143feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mGLHandlerThread = new RequestHandlerThread(TAG, mGLHandlerCb);
1444aed87a9ed31a1ea7fd1ac8fd9ae538d9ecbef7eRuben Brunk        mDeviceState = state;
145feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
146feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
147feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    /**
148feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * Start the thread.
149feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     *
150feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * <p>
151feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * This must be called before queueing new frames.
152feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * </p>
153feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     */
154feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    public void start() {
155feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mGLHandlerThread.start();
156feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
157feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
158feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    /**
159feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * Wait until the thread has started.
160feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     */
161feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    public void waitUntilStarted() {
162feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mGLHandlerThread.waitUntilStarted();
163feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
164feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
165feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    /**
166feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * Quit the thread.
167feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     *
168feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * <p>
169feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * No further methods can be called after this.
170feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * </p>
171feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     */
172feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    public void quit() {
173feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        Handler handler = mGLHandlerThread.getHandler();
174feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        handler.sendMessageAtFrontOfQueue(handler.obtainMessage(MSG_CLEANUP));
175feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mGLHandlerThread.quitSafely();
176d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk        try {
177d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk            mGLHandlerThread.join();
178d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk        } catch (InterruptedException e) {
179d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk            Log.e(TAG, String.format("Thread %s (%d) interrupted while quitting.",
180d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                    mGLHandlerThread.getName(), mGLHandlerThread.getId()));
181d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk        }
182feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
183feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
184feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    /**
18591838ded36131525312739c0929913b215519c2aRuben Brunk     * Queue a new call to draw into the surfaces specified in the next available preview
18691838ded36131525312739c0929913b215519c2aRuben Brunk     * request from the {@link CaptureCollector} passed to
18791838ded36131525312739c0929913b215519c2aRuben Brunk     * {@link #setConfigurationAndWait(java.util.Collection, CaptureCollector)};
188feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     */
18991838ded36131525312739c0929913b215519c2aRuben Brunk    public void queueNewFrame() {
190feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        Handler handler = mGLHandlerThread.getHandler();
191feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
192feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        /**
193feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk         * Avoid queuing more than one new frame.  If we are not consuming faster than frames
194feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk         * are produced, drop frames rather than allowing the queue to back up.
195feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk         */
196feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        if (!handler.hasMessages(MSG_NEW_FRAME)) {
19791838ded36131525312739c0929913b215519c2aRuben Brunk            handler.sendMessage(handler.obtainMessage(MSG_NEW_FRAME));
198feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        } else {
199feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            Log.e(TAG, "GLThread dropping frame.  Not consuming frames quickly enough!");
200feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
201feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
202feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
203feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    /**
204feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * Configure the GL renderer for the given set of output surfaces, and block until
205feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * this configuration has been applied.
206feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     *
207f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk     * @param surfaces a collection of pairs of {@link android.view.Surface}s and their
208f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk     *                 corresponding sizes to configure.
20991838ded36131525312739c0929913b215519c2aRuben Brunk     * @param collector a {@link CaptureCollector} to retrieve requests from.
210feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     */
211f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk    public void setConfigurationAndWait(Collection<Pair<Surface, Size>> surfaces,
212f4a637d0be2e028d1e78c8bf90ad17ec3f84b5f3Ruben Brunk                                        CaptureCollector collector) {
21391838ded36131525312739c0929913b215519c2aRuben Brunk        checkNotNull(collector, "collector must not be null");
214feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        Handler handler = mGLHandlerThread.getHandler();
215feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
216feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        final ConditionVariable condition = new ConditionVariable(/*closed*/false);
21791838ded36131525312739c0929913b215519c2aRuben Brunk        ConfigureHolder configure = new ConfigureHolder(condition, surfaces, collector);
218feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
219feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        Message m = handler.obtainMessage(MSG_NEW_CONFIGURATION, /*arg1*/0, /*arg2*/0, configure);
220feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        handler.sendMessage(m);
221feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
222feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        // Block until configuration applied.
223feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        condition.block();
224feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
225feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
226feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    /**
227feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * Get the underlying surface to produce frames from.
228feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     *
229feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * <p>
230feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * This returns the surface that is drawn into the set of surfaces passed in for each frame.
231feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * This method should only be called after a call to
232feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * {@link #setConfigurationAndWait(java.util.Collection)}.  Calling this before the first call
233feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * to {@link #setConfigurationAndWait(java.util.Collection)}, after {@link #quit()}, or
234feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * concurrently to one of these calls may result in an invalid
235feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * {@link android.graphics.SurfaceTexture} being returned.
236feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * </p>
237feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     *
238feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * @return an {@link android.graphics.SurfaceTexture} to draw to.
239feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     */
240feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    public SurfaceTexture getCurrentSurfaceTexture() {
241feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        return mTextureRenderer.getSurfaceTexture();
242feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
243feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
244feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    /**
245feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * Ignore any subsequent calls to {@link #queueNewFrame(java.util.Collection)}.
246feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     */
247feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    public void ignoreNewFrames() {
248feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mGLHandlerThread.getHandler().sendEmptyMessage(MSG_DROP_FRAMES);
249feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
250feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
251feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    /**
252feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * Wait until no messages are queued.
253feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     */
254feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    public void waitUntilIdle() {
255feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mGLHandlerThread.waitUntilIdle();
256feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
257feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
258feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    /**
259feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * Re-enable drawing new frames after a call to {@link #ignoreNewFrames()}.
260feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     */
261feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    public void allowNewFrames() {
262feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mGLHandlerThread.getHandler().sendEmptyMessage(MSG_ALLOW_FRAMES);
263feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
264feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk}
265