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 #include "media/base/android/android_overlay_callback.h" | |
6 | |
7 #include <map> | |
8 | |
9 #include "base/android/jni_android.h" | |
10 #include "base/bind.h" | |
11 #include "base/location.h" | |
12 #include "base/synchronization/lock.h" | |
13 #include "base/synchronization/waitable_event.h" | |
14 #include "base/threading/thread_task_runner_handle.h" | |
15 #include "jni/AndroidOverlayCallback_jni.h" | |
16 | |
17 using base::android::AttachCurrentThread; | |
18 | |
19 namespace media { | |
20 | |
21 static long next_id_ = 1; | |
22 | |
23 scoped_refptr<base::SingleThreadTaskRunner> | |
24 AndroidOverlayCallback::task_runner_; | |
25 | |
26 // Map of ids to AndroidOverlayCallbacks. This is called from multiple threads. | |
27 class AndroidOverlayCallbackmap { | |
28 public: | |
29 // Associate |thiz| with |id| from any thread. | |
30 void Insert(long id, AndroidOverlayCallback* thiz) { | |
31 base::AutoLock _l(lock_); | |
32 DCHECK(map_.find(id) == map_.end()); | |
33 map_[id] = thiz; | |
34 } | |
35 | |
36 // Forget about |id| from any thread. It's okay if it's not present. | |
37 // if it's not present. | |
38 void Erase(long id) { | |
39 base::AutoLock _l(lock_); | |
40 map_.erase(id); | |
41 } | |
42 | |
43 // Return the associated callback for |id|, or null, from any thread. | |
44 AndroidOverlayCallback* Lookup(long id) { | |
45 base::AutoLock _l(lock_); | |
46 return LookupLocked(id); | |
47 } | |
48 | |
49 private: | |
50 // Lookup |id|. The caller must hold |lock_|. | |
51 AndroidOverlayCallback* LookupLocked(long id) { | |
52 lock_.AssertAcquired(); | |
53 AndroidOverlayCallback* thiz = nullptr; | |
54 Map::const_iterator it = map_.find(id); | |
55 if (it != map_.end()) | |
56 thiz = it->second; | |
57 | |
58 return thiz; | |
59 } | |
60 | |
61 // Alternatively, we could put in a callback that is bound to the correct | |
62 // thread, and use a weak ref. However, since we still need a default | |
63 // action when the weak ref is cleared to unblock the callback, it ends up | |
64 // not being any simpler. | |
65 using Map = std::map<long, AndroidOverlayCallback*>; | |
66 Map map_; | |
67 | |
68 base::Lock lock_; | |
69 }; | |
70 | |
71 static base::LazyInstance<AndroidOverlayCallbackmap>::Leaky g_map = | |
72 LAZY_INSTANCE_INITIALIZER; | |
73 | |
74 AndroidOverlayCallback::AndroidOverlayCallback( | |
75 const AndroidOverlayProxy::Callback& callback) | |
76 : id_(next_id_++), callback_(callback) { | |
77 if (!task_runner_) | |
78 task_runner_ = base::ThreadTaskRunnerHandle::Get(); | |
boliu
2017/02/08 00:01:58
else DCHECK it's still the same thread?
| |
79 | |
80 JNIEnv* env = AttachCurrentThread(); | |
81 j_surface_callback_.Reset(Java_AndroidOverlayCallback_create(env, id_)); | |
82 | |
83 g_map.Pointer()->Insert(id_, this); | |
84 } | |
85 | |
86 AndroidOverlayCallback::~AndroidOverlayCallback() { | |
87 DCHECK(thread_checker_.CalledOnValidThread()); | |
88 g_map.Pointer()->Erase(id_); | |
89 } | |
90 | |
91 void AndroidOverlayCallback::SetAndroidSurfaceCB( | |
92 const AndroidSurfaceCB& android_surface_cb) { | |
93 android_surface_cb_ = android_surface_cb; | |
94 } | |
95 | |
96 bool AndroidOverlayCallback::RegisterAndroidOverlayCallback(JNIEnv* env) { | |
97 return RegisterNativesImpl(env); | |
98 } | |
99 | |
100 scoped_refptr<base::SingleThreadTaskRunner> | |
101 AndroidOverlayCallback::GetTaskRunner() { | |
102 // May be called on any thread. | |
103 return task_runner_; | |
104 } | |
105 | |
106 bool AndroidOverlayCallback::CalledOnValidThread() const { | |
107 return thread_checker_.CalledOnValidThread(); | |
108 } | |
109 | |
110 void AndroidOverlayCallback::OnCallbackProperThread( | |
111 long id, | |
112 AndroidOverlayProxy::CallbackOp what, | |
113 base::android::ScopedJavaGlobalRef<jobject> jobject_opt, | |
114 base::android::ScopedJavaGlobalRef<jobject> jcompletion_opt) { | |
115 // A callback has happened on some other thread. We're run on the correct | |
116 // thread in response to it. | |
117 AndroidOverlayCallback* thiz = g_map.Pointer()->Lookup(id); | |
118 // |thiz| cannot be deleted here, since we're on the main thread. However, | |
119 // it might have been deleted earlier, so it can be null. | |
120 | |
121 if (thiz) { | |
122 // If this is SURFACE_DESTROYED, then no further callbacks are permitted. | |
123 // Erase the map entry in case the IAndroidOverlay decides to send another. | |
124 if (what == AndroidOverlayProxy::CallbackOp::SURFACE_DESTROYED) | |
125 g_map.Pointer()->Erase(id); | |
126 | |
127 DCHECK(thiz->CalledOnValidThread()); | |
128 // Send the java surface to the AndroidOverlay before the callback. | |
129 if (what == AndroidOverlayProxy::CallbackOp::SURFACE_CREATED && | |
130 !thiz->android_surface_cb_.is_null()) { | |
131 thiz->android_surface_cb_.Run(jobject_opt); | |
132 } | |
133 | |
134 // Run the client-supplied callback. | |
135 thiz->callback_.Run(what); | |
136 } | |
137 | |
138 // If this is a synchronous callback, then signal that we've completed. | |
139 if (!jcompletion_opt.is_null()) { | |
140 JNIEnv* env = AttachCurrentThread(); | |
141 Java_AndroidOverlayCallback_signalCompletion(env, jcompletion_opt); | |
142 } | |
143 } | |
144 | |
145 void OnAndroidOverlayCallbackCreated( | |
146 JNIEnv* env, | |
147 const base::android::JavaParamRef<jclass>& jcaller, | |
148 jlong id, | |
149 const base::android::JavaParamRef<jobject>& jsurface) { | |
150 // Called from some random thread in java. | |
151 // Post back to the main thread. We get a strong ref here to the task | |
152 // runner, so that it's okay if the controller is deleted. Holding the | |
153 // lock during the callback is not safe; the caller might require it to | |
154 // complete the callback. | |
155 // Remember that we're on a random thread, but |g_map| is thread safe. | |
156 base::Closure cb = base::Bind( | |
157 &AndroidOverlayCallback::OnCallbackProperThread, id, | |
158 AndroidOverlayProxy::CallbackOp::SURFACE_CREATED, | |
159 base::android::ScopedJavaGlobalRef<jobject>(jsurface), nullptr); | |
160 #if 1 | |
161 AndroidOverlayCallback::GetTaskRunner()->PostTask(FROM_HERE, cb); | |
162 #else | |
163 // DO NOT COMMIT -- just so that picture buffer manager can wait. | |
164 // (I'll remove this before landing) | |
165 LOG(ERROR) << "AVDA: DO NOT COMMIT"; | |
166 cb.Run(); | |
167 #endif | |
168 } | |
169 | |
170 void OnAndroidOverlayCallbackDestroyed( | |
171 JNIEnv* env, | |
172 const base::android::JavaParamRef<jclass>& jcaller, | |
173 jlong id, | |
174 const base::android::JavaParamRef<jobject>& jcompletion) { | |
175 // Called from some random thread in java. | |
176 base::Closure cb = | |
177 base::Bind(&AndroidOverlayCallback::OnCallbackProperThread, id, | |
178 AndroidOverlayProxy::CallbackOp::SURFACE_DESTROYED, nullptr, | |
179 base::android::ScopedJavaGlobalRef<jobject>(jcompletion)); | |
180 AndroidOverlayCallback::GetTaskRunner()->PostTask(FROM_HERE, cb); | |
181 } | |
182 | |
183 } // namespace media | |
OLD | NEW |