| Index: media/base/android/media_drm_bridge.cc
|
| diff --git a/media/base/android/media_drm_bridge.cc b/media/base/android/media_drm_bridge.cc
|
| index 14bdbda03f0ac81e2f32ea958d02103f3b91e3d1..d436d4e73efe3f7edbf7635b3110531ed274c40d 100644
|
| --- a/media/base/android/media_drm_bridge.cc
|
| +++ b/media/base/android/media_drm_bridge.cc
|
| @@ -9,6 +9,7 @@
|
| #include "base/android/build_info.h"
|
| #include "base/android/jni_array.h"
|
| #include "base/android/jni_string.h"
|
| +#include "base/bind.h"
|
| #include "base/callback_helpers.h"
|
| #include "base/containers/hash_tables.h"
|
| #include "base/lazy_instance.h"
|
| @@ -24,6 +25,7 @@
|
| #include "jni/MediaDrmBridge_jni.h"
|
| #include "media/base/android/media_client_android.h"
|
| #include "media/base/android/media_drm_bridge_delegate.h"
|
| +#include "media/base/android/media_task_runner.h"
|
| #include "media/base/cdm_key_information.h"
|
|
|
| #include "widevine_cdm_version.h" // In SHARED_INTERMEDIATE_DIR.
|
| @@ -32,6 +34,7 @@ using base::android::AttachCurrentThread;
|
| using base::android::ConvertUTF8ToJavaString;
|
| using base::android::ConvertJavaStringToUTF8;
|
| using base::android::JavaByteArrayToByteVector;
|
| +using base::android::ScopedJavaGlobalRef;
|
| using base::android::ScopedJavaLocalRef;
|
|
|
| namespace media {
|
| @@ -254,6 +257,7 @@ bool MediaDrmBridge::IsKeySystemSupportedWithType(
|
| return IsKeySystemSupportedWithTypeImpl(key_system, container_mime_type);
|
| }
|
|
|
| +// static
|
| bool MediaDrmBridge::RegisterMediaDrmBridge(JNIEnv* env) {
|
| return RegisterNativesImpl(env);
|
| }
|
| @@ -270,7 +274,13 @@ MediaDrmBridge::MediaDrmBridge(
|
| session_closed_cb_(session_closed_cb),
|
| legacy_session_error_cb_(legacy_session_error_cb),
|
| session_keys_change_cb_(session_keys_change_cb),
|
| - session_expiration_update_cb_(session_expiration_update_cb) {
|
| + session_expiration_update_cb_(session_expiration_update_cb),
|
| + ui_task_runner_(base::ThreadTaskRunnerHandle::Get()),
|
| + use_media_thread_(UseMediaThreadForMediaPlayback()),
|
| + media_weak_factory_(this),
|
| + ui_weak_factory_(this) {
|
| + DVLOG(1) << __FUNCTION__;
|
| +
|
| JNIEnv* env = AttachCurrentThread();
|
| CHECK(env);
|
|
|
| @@ -280,22 +290,43 @@ MediaDrmBridge::MediaDrmBridge(
|
| env, j_scheme_uuid.obj(), reinterpret_cast<intptr_t>(this)));
|
| }
|
|
|
| -MediaDrmBridge::~MediaDrmBridge() {
|
| +void MediaDrmBridge::DeleteOnCorrectThread() {
|
| + DCHECK(ui_task_runner_->BelongsToCurrentThread());
|
| + DVLOG(1) << __FUNCTION__;
|
| +
|
| JNIEnv* env = AttachCurrentThread();
|
| - player_tracker_.NotifyCdmUnset();
|
| if (!j_media_drm_.is_null())
|
| Java_MediaDrmBridge_destroy(env, j_media_drm_.obj());
|
| +
|
| + // After the call to Java_MediaDrmBridge_destroy() Java won't call native
|
| + // methods anymore, this is ensured by MediaDrmBridge.java.
|
| +
|
| + // Post deletion onto Media thread if we use it.
|
| + if (use_media_thread_) {
|
| + ui_weak_factory_.InvalidateWeakPtrs();
|
| + GetMediaTaskRunner()->DeleteSoon(FROM_HERE, this);
|
| + } else {
|
| + delete this;
|
| + }
|
| +}
|
| +
|
| +MediaDrmBridge::~MediaDrmBridge() {
|
| + DVLOG(1) << __FUNCTION__;
|
| +
|
| + DCHECK(!use_media_thread_ || GetMediaTaskRunner()->BelongsToCurrentThread());
|
| +
|
| + player_tracker_.NotifyCdmUnset();
|
| }
|
|
|
| // static
|
| -scoped_ptr<MediaDrmBridge> MediaDrmBridge::Create(
|
| +scoped_ptr<MediaDrmBridge, BrowserCdmDeleter> MediaDrmBridge::Create(
|
| const std::string& key_system,
|
| const SessionMessageCB& session_message_cb,
|
| const SessionClosedCB& session_closed_cb,
|
| const LegacySessionErrorCB& legacy_session_error_cb,
|
| const SessionKeysChangeCB& session_keys_change_cb,
|
| const SessionExpirationUpdateCB& session_expiration_update_cb) {
|
| - scoped_ptr<MediaDrmBridge> media_drm_bridge;
|
| + scoped_ptr<MediaDrmBridge, BrowserCdmDeleter> media_drm_bridge;
|
| if (!IsAvailable())
|
| return media_drm_bridge.Pass();
|
|
|
| @@ -315,8 +346,8 @@ scoped_ptr<MediaDrmBridge> MediaDrmBridge::Create(
|
| }
|
|
|
| // static
|
| -scoped_ptr<MediaDrmBridge> MediaDrmBridge::CreateWithoutSessionSupport(
|
| - const std::string& key_system) {
|
| +scoped_ptr<MediaDrmBridge, BrowserCdmDeleter>
|
| +MediaDrmBridge::CreateWithoutSessionSupport(const std::string& key_system) {
|
| return MediaDrmBridge::Create(
|
| key_system, SessionMessageCB(), SessionClosedCB(), LegacySessionErrorCB(),
|
| SessionKeysChangeCB(), SessionExpirationUpdateCB());
|
| @@ -464,15 +495,21 @@ CdmContext* MediaDrmBridge::GetCdmContext() {
|
|
|
| int MediaDrmBridge::RegisterPlayer(const base::Closure& new_key_cb,
|
| const base::Closure& cdm_unset_cb) {
|
| + DCHECK(!use_media_thread_ || GetMediaTaskRunner()->BelongsToCurrentThread());
|
| return player_tracker_.RegisterPlayer(new_key_cb, cdm_unset_cb);
|
| }
|
|
|
| void MediaDrmBridge::UnregisterPlayer(int registration_id) {
|
| + DCHECK(!use_media_thread_ || GetMediaTaskRunner()->BelongsToCurrentThread());
|
| player_tracker_.UnregisterPlayer(registration_id);
|
| }
|
|
|
| -void MediaDrmBridge::SetMediaCryptoReadyCB(const base::Closure& closure) {
|
| - if (closure.is_null()) {
|
| +void MediaDrmBridge::SetMediaCryptoReadyCB(
|
| + const MediaCryptoReadyCB& media_crypto_ready_cb) {
|
| + DCHECK(ui_task_runner_->BelongsToCurrentThread());
|
| + DVLOG(1) << __FUNCTION__;
|
| +
|
| + if (media_crypto_ready_cb.is_null()) {
|
| media_crypto_ready_cb_.Reset();
|
| return;
|
| }
|
| @@ -480,17 +517,52 @@ void MediaDrmBridge::SetMediaCryptoReadyCB(const base::Closure& closure) {
|
| DCHECK(media_crypto_ready_cb_.is_null());
|
|
|
| if (!GetMediaCrypto().is_null()) {
|
| - base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, closure);
|
| + PostMediaCryptoReadyOnCorrectThread(media_crypto_ready_cb, true);
|
| return;
|
| }
|
|
|
| - media_crypto_ready_cb_ = closure;
|
| + media_crypto_ready_cb_ = media_crypto_ready_cb;
|
| +}
|
| +
|
| +void MediaDrmBridge::OnMediaCryptoReady(JNIEnv* env, jobject j_media_drm) {
|
| + DCHECK(ui_task_runner_->BelongsToCurrentThread());
|
| + DVLOG(1) << __FUNCTION__;
|
| +
|
| + DCHECK(!GetMediaCrypto().is_null());
|
| +
|
| + if (media_crypto_ready_cb_.is_null())
|
| + return;
|
| +
|
| + PostMediaCryptoReadyOnCorrectThread(
|
| + base::ResetAndReturn(&media_crypto_ready_cb_), false);
|
| }
|
|
|
| -void MediaDrmBridge::OnMediaCryptoReady(JNIEnv* env, jobject) {
|
| +void MediaDrmBridge::PostMediaCryptoReadyOnCorrectThread(
|
| + const MediaCryptoReadyCB& cb,
|
| + bool always_post_on_ui_thread) {
|
| + DCHECK(ui_task_runner_->BelongsToCurrentThread());
|
| +
|
| + DCHECK(!cb.is_null());
|
| DCHECK(!GetMediaCrypto().is_null());
|
| - if (!media_crypto_ready_cb_.is_null())
|
| - base::ResetAndReturn(&media_crypto_ready_cb_).Run();
|
| +
|
| + // We can use scoped_ptr to pass ScopedJavaGlobalRef with a callback.
|
| + scoped_ptr<ScopedJavaGlobalRef<jobject>> j_object_ptr(
|
| + new ScopedJavaGlobalRef<jobject>());
|
| + j_object_ptr->Reset(AttachCurrentThread(), GetMediaCrypto().obj());
|
| +
|
| + bool needs_protected_surface = IsProtectedSurfaceRequired();
|
| +
|
| + if (use_media_thread_) {
|
| + GetMediaTaskRunner()->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(cb, base::Passed(&j_object_ptr), needs_protected_surface));
|
| + } else if (always_post_on_ui_thread) {
|
| + ui_task_runner_->PostTask(
|
| + FROM_HERE,
|
| + base::Bind(cb, base::Passed(&j_object_ptr), needs_protected_surface));
|
| + } else {
|
| + cb.Run(j_object_ptr.Pass(), needs_protected_surface);
|
| + }
|
| }
|
|
|
| void MediaDrmBridge::OnPromiseResolved(JNIEnv* env,
|
| @@ -545,7 +617,7 @@ void MediaDrmBridge::OnSessionKeysChange(JNIEnv* env,
|
| jobjectArray j_keys_info,
|
| bool has_additional_usable_key) {
|
| if (has_additional_usable_key)
|
| - player_tracker_.NotifyNewKey();
|
| + NotifyNewKeyOnCorrectThread();
|
|
|
| CdmKeysInfo cdm_keys_info;
|
|
|
| @@ -583,6 +655,21 @@ void MediaDrmBridge::OnSessionKeysChange(JNIEnv* env,
|
| has_additional_usable_key, cdm_keys_info.Pass());
|
| }
|
|
|
| +void MediaDrmBridge::NotifyNewKeyOnCorrectThread() {
|
| + // Repost this method onto the Media thread if |use_media_thread_| is true.
|
| + if (use_media_thread_ && !GetMediaTaskRunner()->BelongsToCurrentThread()) {
|
| + GetMediaTaskRunner()->PostTask(
|
| + FROM_HERE, base::Bind(&MediaDrmBridge::NotifyNewKeyOnCorrectThread,
|
| + media_weak_factory_.GetWeakPtr()));
|
| + return;
|
| + }
|
| +
|
| + DCHECK(!use_media_thread_ || GetMediaTaskRunner()->BelongsToCurrentThread());
|
| + DVLOG(1) << __FUNCTION__;
|
| +
|
| + player_tracker_.NotifyNewKey();
|
| +}
|
| +
|
| // According to MeidaDrm documentation [1], zero |expiry_time_ms| means the keys
|
| // will never expire. This will be translated into a NULL base::Time() [2],
|
| // which will then be mapped to a zero Java time [3]. The zero Java time is
|
| @@ -613,6 +700,8 @@ void MediaDrmBridge::OnLegacySessionError(JNIEnv* env,
|
| }
|
|
|
| ScopedJavaLocalRef<jobject> MediaDrmBridge::GetMediaCrypto() {
|
| + DCHECK(ui_task_runner_->BelongsToCurrentThread());
|
| +
|
| JNIEnv* env = AttachCurrentThread();
|
| return Java_MediaDrmBridge_getMediaCrypto(env, j_media_drm_.obj());
|
| }
|
| @@ -635,6 +724,10 @@ bool MediaDrmBridge::IsProtectedSurfaceRequired() {
|
| return true;
|
| }
|
|
|
| +base::WeakPtr<MediaDrmBridge> MediaDrmBridge::WeakPtrForUIThread() {
|
| + return ui_weak_factory_.GetWeakPtr();
|
| +}
|
| +
|
| void MediaDrmBridge::ResetDeviceCredentials(
|
| const ResetCredentialsCB& callback) {
|
| DCHECK(reset_credentials_cb_.is_null());
|
|
|