Chromium Code Reviews| 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 |