OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 package org.chromium.media; | |
6 | |
7 import android.content.Context; | |
8 import android.os.Handler; | |
9 import android.os.HandlerThread; | |
10 import android.os.IBinder; | |
11 | |
12 import org.chromium.base.ContextUtils; | |
13 import org.chromium.base.annotations.CalledByNative; | |
14 import org.chromium.base.annotations.JNINamespace; | |
15 | |
16 /** | |
17 * Singleton class to create and manage DialogSurface. Normally, you won't need | |
18 * to access this directly. Instead, see the native wrappers in | |
19 * dialog_surface_manager.cc for usage. | |
20 * | |
21 * The wrappers do roughly the following on the gpu side: | |
22 * - Create an IDialogSurfaceCallback. For native, DialogSurfaceCallback hides | |
23 * the threading issues and provides the java peer. | |
24 * - Get an IDialogSurfaceManager from the browser via ChildProcessCallback . | |
25 * - dialogSurface = IDialogSurfaceManager.createSurface(callback) | |
26 * This calls into the browser, and returns an IDialogSurface IBinder. | |
27 * - Wrap the DialogSurface in a DialogSurfaceWrapper. This provides the JNI | |
28 * bindings for native. | |
29 * - Expect callbacks on the callback to let you know when the underlying | |
30 * android surface state changes. | |
31 * - Use the surface. | |
32 * - Call IDialogSurface::release() to destroy the surface when done. | |
33 */ | |
34 @JNINamespace("media") | |
35 public class DialogSurfaceManagerImpl extends IDialogSurfaceManager.Stub { | |
36 private static final String TAG = "cr_media"; | |
37 private static DialogSurfaceManagerImpl sInstance; | |
38 private static final Object sLock = new Object(); | |
39 | |
40 private final Context mContext; | |
41 | |
42 // We maintain a thread with a Looper for the DialogSurfaces to use, | |
43 // since Dialog requires one. We don't want this to be the native thread | |
44 // that's used to create them, because it probably also has a native message | |
45 // loop. Including a looper on it is not a good idea. | |
boliu
2017/01/04 23:14:39
the browser UI thread does have a java looper, so
liberato (no reviews please)
2017/01/11 22:17:57
i want to avoid that so that synchronous callbacks
boliu
2017/01/12 20:24:19
Ahh, I was curious what surface view implement, bu
liberato (no reviews please)
2017/02/03 21:28:32
i'll have to dig up where it does this, but CVV do
| |
46 private final Object mLock = new Object(); | |
47 private HandlerThread mThread; | |
48 private Handler mHandler; | |
49 // TODO(liberato): why does this have to be a binder interface? i suppose | |
50 // it has to live in the browser process. however, it's a lot more | |
51 // convenient if we don't need a binder object for it to call back on. | |
52 // maybe we should just make it a normal interface with inner client. | |
53 private final DialogSurfaceWindowTokenProvider mTokenProvider; | |
54 | |
55 // Number of DialogSurfaces that have been created but not released. | |
56 private int mNumSurfaces; | |
57 | |
58 // Maximum number of concurrent surfaces we allow. | |
59 private static final int MAX_SURFACES = 1; | |
60 | |
61 private DialogSurfaceManagerImpl(DialogSurfaceWindowTokenProvider tokenProvi der) { | |
62 mContext = ContextUtils.getApplicationContext(); | |
63 mTokenProvider = tokenProvider; | |
64 mNumSurfaces = 0; | |
65 } | |
66 | |
67 // Return the singleton instance, as a convenience. | |
68 public static IBinder instance(DialogSurfaceWindowTokenProvider tokenProvide r) { | |
69 synchronized (sLock) { | |
70 if (sInstance == null) sInstance = new DialogSurfaceManagerImpl(toke nProvider); | |
71 | |
72 return sInstance.asBinder(); | |
73 } | |
74 } | |
75 | |
76 @Override | |
77 @CalledByNative | |
boliu
2017/01/04 01:48:44
this class doesn't generate jni code?
liberato (no reviews please)
2017/01/11 22:17:57
whoops. thanks.
| |
78 public IDialogSurface createSurface(int rendererPid, int renderFrameId, | |
79 IDialogSurfaceCallback callback, int x, int y, int width, int height ) { | |
80 // Note that we may be called on any random binder thread, so lock. | |
81 synchronized (mLock) { | |
82 // Limit the number of concurrent surfaces. | |
83 if (mNumSurfaces >= MAX_SURFACES) return null; | |
84 | |
85 startThreadIfNeededLocked(); | |
86 | |
87 mNumSurfaces++; | |
88 } | |
89 | |
90 return new DialogSurfaceImpl(rendererPid, renderFrameId, mContext, this, mHandler, callback, | |
91 x, y, width, height); | |
92 } | |
93 | |
94 /** | |
95 * Called by DialogSurfaces when they no longer need the thread. | |
96 * Called on some random thread. | |
97 */ | |
98 public void notifyReleased() { | |
99 synchronized (mLock) { | |
100 if (mNumSurfaces > 0) mNumSurfaces--; | |
boliu
2017/01/04 01:48:44
this should be an assert? (which works as DCHECKs
liberato (no reviews please)
2017/01/11 22:17:57
Done.
| |
101 | |
102 // We don't stop the looper thread here, else android can get mad wh en | |
103 // it tries to send a message from the dialog on this thread. | |
104 // DialogSurface might have to notify us separately to tell us | |
105 // when it's done with the thread, if we don't want to wait until th en | |
106 // to start creating a new SV. | |
107 // Instead, we just avoid shutting down the thread at all for now. | |
108 } | |
109 } | |
110 | |
111 /** | |
112 * Make sure that mThread and mHandler are ready for use. Do nothing if | |
113 * they already are. | |
114 */ | |
115 private void startThreadIfNeededLocked() { | |
116 // Called with mLock held only. | |
117 if (mThread != null) return; | |
118 | |
119 mThread = new HandlerThread("DialogSurfaceThread"); | |
120 mThread.start(); | |
121 mHandler = new Handler(mThread.getLooper()); | |
122 } | |
123 | |
124 /** | |
125 * Return the window token provider. | |
126 */ | |
127 public DialogSurfaceWindowTokenProvider getWindowTokenProvider() { | |
128 return mTokenProvider; | |
129 } | |
130 } | |
OLD | NEW |