summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
Diffstat (limited to 'media')
-rw-r--r--media/base/BUILD.gn2
-rw-r--r--media/base/android/browser_cdm_factory_android.cc14
-rw-r--r--media/base/android/browser_cdm_factory_android.h2
-rw-r--r--media/base/android/media_codec_player.cc65
-rw-r--r--media/base/android/media_codec_player.h11
-rw-r--r--media/base/android/media_drm_bridge.cc128
-rw-r--r--media/base/android/media_drm_bridge.h65
-rw-r--r--media/base/android/media_drm_bridge_unittest.cc2
-rw-r--r--media/base/android/media_player_android.cc2
-rw-r--r--media/base/android/media_player_android.h4
-rw-r--r--media/base/android/media_source_player.cc49
-rw-r--r--media/base/android/media_source_player.h9
-rw-r--r--media/base/browser_cdm.cc20
-rw-r--r--media/base/browser_cdm.h40
-rw-r--r--media/base/browser_cdm_factory.cc6
-rw-r--r--media/base/browser_cdm_factory.h11
-rw-r--r--media/base/cdm_factory.h2
-rw-r--r--media/base/cdm_initialized_promise.cc10
-rw-r--r--media/base/cdm_initialized_promise.h8
-rw-r--r--media/base/media_keys.cc9
-rw-r--r--media/base/media_keys.h62
-rw-r--r--media/base/player_tracker.h3
-rw-r--r--media/blink/cdm_session_adapter.cc11
-rw-r--r--media/blink/cdm_session_adapter.h4
-rw-r--r--media/cdm/aes_decryptor.h3
-rw-r--r--media/cdm/aes_decryptor_unittest.cc54
-rw-r--r--media/cdm/default_cdm_factory.cc4
-rw-r--r--media/cdm/player_tracker_impl.cc42
-rw-r--r--media/cdm/player_tracker_impl.h13
-rw-r--r--media/cdm/ppapi/external_clear_key/clear_key_cdm.cc25
-rw-r--r--media/cdm/ppapi/external_clear_key/clear_key_cdm.h2
-rw-r--r--media/cdm/proxy_decryptor.cc6
-rw-r--r--media/cdm/proxy_decryptor.h5
-rw-r--r--media/media.gyp2
-rw-r--r--media/mojo/services/mojo_cdm.cc13
-rw-r--r--media/mojo/services/mojo_cdm.h4
-rw-r--r--media/mojo/services/mojo_cdm_service.cc4
-rw-r--r--media/mojo/services/mojo_cdm_service.h5
-rw-r--r--media/test/pipeline_integration_test.cc24
39 files changed, 350 insertions, 395 deletions
diff --git a/media/base/BUILD.gn b/media/base/BUILD.gn
index d3a3a69..c6705a0 100644
--- a/media/base/BUILD.gn
+++ b/media/base/BUILD.gn
@@ -240,8 +240,6 @@ source_set("base") {
if (enable_browser_cdms) {
sources += [
- "browser_cdm.cc",
- "browser_cdm.h",
"browser_cdm_factory.cc",
"browser_cdm_factory.h",
]
diff --git a/media/base/android/browser_cdm_factory_android.cc b/media/base/android/browser_cdm_factory_android.cc
index 66912bc..9b43379 100644
--- a/media/base/android/browser_cdm_factory_android.cc
+++ b/media/base/android/browser_cdm_factory_android.cc
@@ -13,7 +13,7 @@
namespace media {
-ScopedBrowserCdmPtr BrowserCdmFactoryAndroid::CreateBrowserCdm(
+scoped_refptr<MediaKeys> BrowserCdmFactoryAndroid::CreateBrowserCdm(
const std::string& key_system,
bool use_hw_secure_codecs,
const SessionMessageCB& session_message_cb,
@@ -23,16 +23,16 @@ ScopedBrowserCdmPtr BrowserCdmFactoryAndroid::CreateBrowserCdm(
const SessionExpirationUpdateCB& session_expiration_update_cb) {
if (!MediaDrmBridge::IsKeySystemSupported(key_system)) {
NOTREACHED() << "Key system not supported unexpectedly: " << key_system;
- return ScopedBrowserCdmPtr();
+ return nullptr;
}
- ScopedMediaDrmBridgePtr cdm(
+ scoped_refptr<MediaDrmBridge> cdm(
MediaDrmBridge::Create(key_system, session_message_cb, session_closed_cb,
legacy_session_error_cb, session_keys_change_cb,
session_expiration_update_cb));
if (!cdm) {
NOTREACHED() << "MediaDrmBridge cannot be created for " << key_system;
- return ScopedBrowserCdmPtr();
+ return nullptr;
}
if (key_system == kWidevineKeySystem) {
@@ -41,7 +41,7 @@ ScopedBrowserCdmPtr BrowserCdmFactoryAndroid::CreateBrowserCdm(
: MediaDrmBridge::SECURITY_LEVEL_3;
if (!cdm->SetSecurityLevel(security_level)) {
DVLOG(1) << "failed to set security level " << security_level;
- return ScopedBrowserCdmPtr();
+ return nullptr;
}
} else {
// Assume other key systems require hardware-secure codecs and thus do not
@@ -50,11 +50,11 @@ ScopedBrowserCdmPtr BrowserCdmFactoryAndroid::CreateBrowserCdm(
NOTREACHED()
<< key_system
<< " may require use_video_overlay_for_embedded_encrypted_video";
- return ScopedBrowserCdmPtr();
+ return nullptr;
}
}
- return cdm.Pass();
+ return cdm;
}
} // namespace media
diff --git a/media/base/android/browser_cdm_factory_android.h b/media/base/android/browser_cdm_factory_android.h
index df6ca19..babae75 100644
--- a/media/base/android/browser_cdm_factory_android.h
+++ b/media/base/android/browser_cdm_factory_android.h
@@ -16,7 +16,7 @@ class MEDIA_EXPORT BrowserCdmFactoryAndroid : public BrowserCdmFactory {
BrowserCdmFactoryAndroid() {}
~BrowserCdmFactoryAndroid() final {};
- ScopedBrowserCdmPtr CreateBrowserCdm(
+ scoped_refptr<MediaKeys> CreateBrowserCdm(
const std::string& key_system,
bool use_hw_secure_codecs,
const SessionMessageCB& session_message_cb,
diff --git a/media/base/android/media_codec_player.cc b/media/base/android/media_codec_player.cc
index b444b11..a58ac27b 100644
--- a/media/base/android/media_codec_player.cc
+++ b/media/base/android/media_codec_player.cc
@@ -6,6 +6,7 @@
#include "base/barrier_closure.h"
#include "base/bind.h"
+#include "base/bind_helpers.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/thread_task_runner_handle.h"
@@ -49,7 +50,6 @@ MediaCodecPlayer::MediaCodecPlayer(
interpolator_(&default_tick_clock_),
pending_start_(false),
pending_seek_(kNoTimestamp()),
- drm_bridge_(nullptr),
cdm_registration_id_(0),
key_is_required_(false),
key_is_added_(false),
@@ -99,9 +99,10 @@ MediaCodecPlayer::~MediaCodecPlayer()
media_stat_->StopAndReport(GetInterpolatedTime());
- if (drm_bridge_) {
+ if (cdm_) {
DCHECK(cdm_registration_id_);
- drm_bridge_->UnregisterPlayer(cdm_registration_id_);
+ static_cast<MediaDrmBridge*>(cdm_.get())
+ ->UnregisterPlayer(cdm_registration_id_);
}
}
@@ -410,7 +411,8 @@ bool MediaCodecPlayer::IsPlayerReady() {
return true;
}
-void MediaCodecPlayer::SetCdm(BrowserCdm* cdm) {
+void MediaCodecPlayer::SetCdm(const scoped_refptr<MediaKeys>& cdm) {
+ DCHECK(cdm);
RUN_ON_MEDIA_THREAD(SetCdm, cdm);
DVLOG(1) << __FUNCTION__;
@@ -423,27 +425,31 @@ void MediaCodecPlayer::SetCdm(BrowserCdm* cdm) {
return;
}
- if (drm_bridge_) {
+ if (cdm_) {
NOTREACHED() << "Currently we do not support resetting CDM.";
return;
}
- DCHECK(cdm);
- drm_bridge_ = static_cast<MediaDrmBridge*>(cdm);
+ cdm_ = cdm;
- DCHECK(drm_bridge_);
+ // Only MediaDrmBridge will be set on MediaCodecPlayer.
+ MediaDrmBridge* drm_bridge = static_cast<MediaDrmBridge*>(cdm_.get());
- cdm_registration_id_ = drm_bridge_->RegisterPlayer(
- base::Bind(&MediaCodecPlayer::OnKeyAdded, media_weak_this_),
- base::Bind(&MediaCodecPlayer::OnCdmUnset, media_weak_this_));
+ // Register CDM callbacks. The callbacks registered will be posted back to the
+ // media thread via BindToCurrentLoop.
- MediaDrmBridge::MediaCryptoReadyCB cb = BindToCurrentLoop(
- base::Bind(&MediaCodecPlayer::OnMediaCryptoReady, media_weak_this_));
+ // Since |this| holds a reference to the |cdm_|, by the time the CDM is
+ // destructed, UnregisterPlayer() must have been called and |this| has been
+ // destructed as well. So the |cdm_unset_cb| will never have a chance to be
+ // called.
+ // TODO(xhwang): Remove |cdm_unset_cb| after it's not used on all platforms.
+ cdm_registration_id_ = drm_bridge->RegisterPlayer(
+ BindToCurrentLoop(
+ base::Bind(&MediaCodecPlayer::OnKeyAdded, media_weak_this_)),
+ base::Bind(&base::DoNothing));
- // Post back to MediaDrmBridge's default thread.
- ui_task_runner_->PostTask(FROM_HERE,
- base::Bind(&MediaDrmBridge::SetMediaCryptoReadyCB,
- drm_bridge_->WeakPtr(), cb));
+ drm_bridge->SetMediaCryptoReadyCB(BindToCurrentLoop(
+ base::Bind(&MediaCodecPlayer::OnMediaCryptoReady, media_weak_this_)));
}
// Callbacks from Demuxer.
@@ -965,31 +971,6 @@ void MediaCodecPlayer::OnKeyAdded() {
}
}
-void MediaCodecPlayer::OnCdmUnset() {
- DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread());
- DVLOG(1) << __FUNCTION__;
-
- // This comment is copied from MediaSourcePlayer::OnCdmUnset().
- // TODO(xhwang): Currently this is only called during teardown. Support full
- // detachment of CDM during playback. This will be needed when we start to
- // support setMediaKeys(0) (see http://crbug.com/330324), or when we release
- // MediaDrm when the video is paused, or when the device goes to sleep (see
- // http://crbug.com/272421).
-
- if (audio_decoder_) {
- audio_decoder_->SetNeedsReconfigure();
- }
-
- if (video_decoder_) {
- video_decoder_->SetProtectedSurfaceRequired(false);
- video_decoder_->SetNeedsReconfigure();
- }
-
- cdm_registration_id_ = 0;
- drm_bridge_ = nullptr;
- media_crypto_.reset();
-}
-
// State machine operations, called on Media thread
void MediaCodecPlayer::SetState(PlayerState new_state) {
diff --git a/media/base/android/media_codec_player.h b/media/base/android/media_codec_player.h
index 376c2e4..fff4129 100644
--- a/media/base/android/media_codec_player.h
+++ b/media/base/android/media_codec_player.h
@@ -157,7 +157,6 @@
namespace media {
-class BrowserCdm;
class MediaCodecAudioDecoder;
class MediaCodecVideoDecoder;
@@ -214,7 +213,7 @@ class MEDIA_EXPORT MediaCodecPlayer : public MediaPlayerAndroid,
bool CanSeekForward() override;
bool CanSeekBackward() override;
bool IsPlayerReady() override;
- void SetCdm(BrowserCdm* cdm) override;
+ void SetCdm(const scoped_refptr<MediaKeys>& cdm) override;
// DemuxerAndroidClient implementation.
void OnDemuxerConfigsAvailable(const DemuxerConfigs& params) override;
@@ -300,11 +299,10 @@ class MEDIA_EXPORT MediaCodecPlayer : public MediaPlayerAndroid,
// Callbacks from video decoder
void OnVideoResolutionChanged(const gfx::Size& size);
- // Callbacks from CDM
+ // Callbacks from MediaDrmBridge.
void OnMediaCryptoReady(MediaDrmBridge::JavaObjectPtr media_crypto,
bool needs_protected_surface);
void OnKeyAdded();
- void OnCdmUnset();
// Operations called from the state machine.
void SetState(PlayerState new_state);
@@ -395,10 +393,11 @@ class MEDIA_EXPORT MediaCodecPlayer : public MediaPlayerAndroid,
// For testing only.
DecodersTimeCallback decoders_time_cb_;
- // DRM
+ // Holds a ref-count to the CDM to keep |media_crypto_| valid.
+ scoped_refptr<MediaKeys> cdm_;
+
MediaDrmBridge::JavaObjectPtr media_crypto_;
- MediaDrmBridge* drm_bridge_;
int cdm_registration_id_;
// The flag is set when the player receives the error from decoder that the
diff --git a/media/base/android/media_drm_bridge.cc b/media/base/android/media_drm_bridge.cc
index 2de3f21..47822bf 100644
--- a/media/base/android/media_drm_bridge.cc
+++ b/media/base/android/media_drm_bridge.cc
@@ -25,7 +25,6 @@
#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.
@@ -214,37 +213,6 @@ std::string GetSecurityLevelString(
} // namespace
-MediaDrmBridge::~MediaDrmBridge() {
- DVLOG(1) << __FUNCTION__;
-
- DCHECK(!use_media_thread_ || GetMediaTaskRunner()->BelongsToCurrentThread());
-
- player_tracker_.NotifyCdmUnset();
-}
-
-void MediaDrmBridge::DeleteOnCorrectThread() {
- DCHECK(task_runner_->BelongsToCurrentThread());
- DVLOG(1) << __FUNCTION__;
-
- JNIEnv* env = AttachCurrentThread();
- 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.
-
- // CdmPromiseAdapter must be destroyed on the UI thread.
- cdm_promise_adapter_.reset();
-
- // Post deletion onto Media thread if we use it.
- if (use_media_thread_) {
- weak_factory_.InvalidateWeakPtrs();
- GetMediaTaskRunner()->DeleteSoon(FROM_HERE, this);
- } else {
- delete this;
- }
-}
-
// static
bool MediaDrmBridge::IsAvailable() {
if (base::android::BuildInfo::GetInstance()->sdk_int() < 19)
@@ -286,7 +254,7 @@ std::vector<std::string> MediaDrmBridge::GetPlatformKeySystemNames() {
}
// static
-ScopedMediaDrmBridgePtr MediaDrmBridge::Create(
+scoped_refptr<MediaDrmBridge> MediaDrmBridge::Create(
const std::string& key_system,
const SessionMessageCB& session_message_cb,
const SessionClosedCB& session_closed_cb,
@@ -295,37 +263,32 @@ ScopedMediaDrmBridgePtr MediaDrmBridge::Create(
const SessionExpirationUpdateCB& session_expiration_update_cb) {
DVLOG(1) << __FUNCTION__;
- scoped_ptr<MediaDrmBridge, BrowserCdmDeleter> media_drm_bridge;
if (!IsAvailable())
- return media_drm_bridge.Pass();
+ return nullptr;
UUID scheme_uuid = g_key_system_manager.Get().GetUUID(key_system);
if (scheme_uuid.empty())
- return media_drm_bridge.Pass();
+ return nullptr;
- media_drm_bridge.reset(
+ scoped_refptr<MediaDrmBridge> media_drm_bridge(
new MediaDrmBridge(scheme_uuid, session_message_cb, session_closed_cb,
legacy_session_error_cb, session_keys_change_cb,
session_expiration_update_cb));
if (media_drm_bridge->j_media_drm_.is_null())
- media_drm_bridge.reset();
+ media_drm_bridge = nullptr;
- return media_drm_bridge.Pass();
+ return media_drm_bridge;
}
// static
-ScopedMediaDrmBridgePtr MediaDrmBridge::CreateWithoutSessionSupport(
+scoped_refptr<MediaDrmBridge> MediaDrmBridge::CreateWithoutSessionSupport(
const std::string& key_system) {
return MediaDrmBridge::Create(
key_system, SessionMessageCB(), SessionClosedCB(), LegacySessionErrorCB(),
SessionKeysChangeCB(), SessionExpirationUpdateCB());
}
-base::WeakPtr<MediaDrmBridge> MediaDrmBridge::WeakPtr() {
- return weak_factory_.GetWeakPtr();
-}
-
void MediaDrmBridge::SetServerCertificate(
const std::vector<uint8_t>& certificate,
scoped_ptr<media::SimpleCdmPromise> promise) {
@@ -452,14 +415,25 @@ CdmContext* MediaDrmBridge::GetCdmContext() {
return nullptr;
}
+void MediaDrmBridge::DeleteOnCorrectThread() const {
+ DVLOG(1) << __FUNCTION__;
+
+ if (!task_runner_->BelongsToCurrentThread()) {
+ // When DeleteSoon returns false, |this| will be leaked, which is okay.
+ task_runner_->DeleteSoon(FROM_HERE, this);
+ } else {
+ delete this;
+ }
+}
+
int MediaDrmBridge::RegisterPlayer(const base::Closure& new_key_cb,
const base::Closure& cdm_unset_cb) {
- DCHECK(!use_media_thread_ || GetMediaTaskRunner()->BelongsToCurrentThread());
+ // |player_tracker_| can be accessed from any thread.
return player_tracker_.RegisterPlayer(new_key_cb, cdm_unset_cb);
}
void MediaDrmBridge::UnregisterPlayer(int registration_id) {
- DCHECK(!use_media_thread_ || GetMediaTaskRunner()->BelongsToCurrentThread());
+ // |player_tracker_| can be accessed from any thread.
player_tracker_.UnregisterPlayer(registration_id);
}
@@ -527,7 +501,14 @@ ScopedJavaLocalRef<jobject> MediaDrmBridge::GetMediaCrypto() {
void MediaDrmBridge::SetMediaCryptoReadyCB(
const MediaCryptoReadyCB& media_crypto_ready_cb) {
- DCHECK(task_runner_->BelongsToCurrentThread());
+ if (!task_runner_->BelongsToCurrentThread()) {
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&MediaDrmBridge::SetMediaCryptoReadyCB,
+ weak_factory_.GetWeakPtr(), media_crypto_ready_cb));
+ return;
+ }
+
DVLOG(1) << __FUNCTION__;
if (media_crypto_ready_cb.is_null()) {
@@ -558,25 +539,27 @@ void MediaDrmBridge::OnMediaCryptoReady(JNIEnv* env, jobject j_media_drm) {
return;
task_runner_->PostTask(
- FROM_HERE, base::Bind(&MediaDrmBridge::NotifyMediaCryptoReady, WeakPtr(),
+ FROM_HERE, base::Bind(&MediaDrmBridge::NotifyMediaCryptoReady,
+ weak_factory_.GetWeakPtr(),
base::ResetAndReturn(&media_crypto_ready_cb_)));
}
void MediaDrmBridge::OnPromiseResolved(JNIEnv* env,
jobject j_media_drm,
jint j_promise_id) {
- task_runner_->PostTask(FROM_HERE, base::Bind(&MediaDrmBridge::ResolvePromise,
- WeakPtr(), j_promise_id));
+ task_runner_->PostTask(FROM_HERE,
+ base::Bind(&MediaDrmBridge::ResolvePromise,
+ weak_factory_.GetWeakPtr(), j_promise_id));
}
void MediaDrmBridge::OnPromiseResolvedWithSession(JNIEnv* env,
jobject j_media_drm,
jint j_promise_id,
jbyteArray j_session_id) {
- task_runner_->PostTask(
- FROM_HERE,
- base::Bind(&MediaDrmBridge::ResolvePromiseWithSession, WeakPtr(),
- j_promise_id, GetSessionId(env, j_session_id)));
+ task_runner_->PostTask(FROM_HERE,
+ base::Bind(&MediaDrmBridge::ResolvePromiseWithSession,
+ weak_factory_.GetWeakPtr(), j_promise_id,
+ GetSessionId(env, j_session_id)));
}
void MediaDrmBridge::OnPromiseRejected(JNIEnv* env,
@@ -585,8 +568,8 @@ void MediaDrmBridge::OnPromiseRejected(JNIEnv* env,
jstring j_error_message) {
task_runner_->PostTask(
FROM_HERE,
- base::Bind(&MediaDrmBridge::RejectPromise, WeakPtr(), j_promise_id,
- ConvertJavaStringToUTF8(env, j_error_message)));
+ base::Bind(&MediaDrmBridge::RejectPromise, weak_factory_.GetWeakPtr(),
+ j_promise_id, ConvertJavaStringToUTF8(env, j_error_message)));
}
void MediaDrmBridge::OnSessionMessage(JNIEnv* env,
@@ -626,7 +609,7 @@ void MediaDrmBridge::OnSessionKeysChange(JNIEnv* env,
DVLOG(2) << __FUNCTION__;
if (has_additional_usable_key)
- NotifyNewKeyOnCorrectThread();
+ player_tracker_.NotifyNewKey();
CdmKeysInfo cdm_keys_info;
@@ -722,8 +705,6 @@ MediaDrmBridge::MediaDrmBridge(
session_expiration_update_cb_(session_expiration_update_cb),
cdm_promise_adapter_(new CdmPromiseAdapter()),
task_runner_(base::ThreadTaskRunnerHandle::Get()),
- use_media_thread_(UseMediaThreadForMediaPlayback()),
- media_weak_factory_(this),
weak_factory_(this) {
DVLOG(1) << __FUNCTION__;
@@ -736,6 +717,20 @@ MediaDrmBridge::MediaDrmBridge(
env, j_scheme_uuid.obj(), reinterpret_cast<intptr_t>(this)));
}
+MediaDrmBridge::~MediaDrmBridge() {
+ DCHECK(task_runner_->BelongsToCurrentThread());
+ DVLOG(1) << __FUNCTION__;
+
+ JNIEnv* env = AttachCurrentThread();
+
+ // After the call to Java_MediaDrmBridge_destroy() Java won't call native
+ // methods anymore, this is ensured by MediaDrmBridge.java.
+ if (!j_media_drm_.is_null())
+ Java_MediaDrmBridge_destroy(env, j_media_drm_.obj());
+
+ player_tracker_.NotifyCdmUnset();
+}
+
// TODO(ddorwin): This is specific to Widevine. http://crbug.com/459400
// static
bool MediaDrmBridge::IsSecureDecoderRequired(SecurityLevel security_level) {
@@ -752,21 +747,6 @@ MediaDrmBridge::SecurityLevel MediaDrmBridge::GetSecurityLevel() {
return GetSecurityLevelFromString(security_level_str);
}
-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();
-}
-
void MediaDrmBridge::NotifyMediaCryptoReady(const MediaCryptoReadyCB& cb) {
DCHECK(task_runner_->BelongsToCurrentThread());
diff --git a/media/base/android/media_drm_bridge.h b/media/base/android/media_drm_bridge.h
index a525f83..90aec56 100644
--- a/media/base/android/media_drm_bridge.h
+++ b/media/base/android/media_drm_bridge.h
@@ -13,9 +13,10 @@
#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
-#include "media/base/browser_cdm.h"
#include "media/base/cdm_promise_adapter.h"
#include "media/base/media_export.h"
+#include "media/base/media_keys.h"
+#include "media/base/player_tracker.h"
#include "media/cdm/player_tracker_impl.h"
#include "url/gurl.h"
@@ -23,12 +24,15 @@ class GURL;
namespace media {
-class MediaDrmBridge;
+// Implements a CDM using Android MediaDrm API.
+//
+// Thread Safety:
+//
+// This class lives on the thread where it is created. All methods must be
+// called on the |task_runner_| except for the PlayerTracker methods and
+// SetMediaCryptoReadyCB(), which can be called on any thread.
-using ScopedMediaDrmBridgePtr = scoped_ptr<MediaDrmBridge, BrowserCdmDeleter>;
-
-// This class provides DRM services for android EME implementation.
-class MEDIA_EXPORT MediaDrmBridge : public BrowserCdm {
+class MEDIA_EXPORT MediaDrmBridge : public MediaKeys, public PlayerTracker {
public:
// TODO(ddorwin): These are specific to Widevine. http://crbug.com/459400
enum SecurityLevel {
@@ -48,10 +52,6 @@ class MEDIA_EXPORT MediaDrmBridge : public BrowserCdm {
using MediaCryptoReadyCB = base::Callback<void(JavaObjectPtr media_crypto,
bool needs_protected_surface)>;
- ~MediaDrmBridge() override;
-
- void DeleteOnCorrectThread() override;
-
// Checks whether MediaDRM is available.
// All other static methods check IsAvailable() internally. There's no need
// to check IsAvailable() explicitly before calling them.
@@ -75,7 +75,7 @@ class MEDIA_EXPORT MediaDrmBridge : public BrowserCdm {
// Returns a MediaDrmBridge instance if |key_system| is supported, or a NULL
// pointer otherwise.
// TODO(xhwang): Is it okay not to update session expiration info?
- static ScopedMediaDrmBridgePtr Create(
+ static scoped_refptr<MediaDrmBridge> Create(
const std::string& key_system,
const SessionMessageCB& session_message_cb,
const SessionClosedCB& session_closed_cb,
@@ -86,13 +86,10 @@ class MEDIA_EXPORT MediaDrmBridge : public BrowserCdm {
// Returns a MediaDrmBridge instance if |key_system| is supported, or a NULL
// otherwise. No session callbacks are provided. This is used when we need to
// use MediaDrmBridge without creating any sessions.
- static ScopedMediaDrmBridgePtr CreateWithoutSessionSupport(
+ static scoped_refptr<MediaDrmBridge> CreateWithoutSessionSupport(
const std::string& key_system);
- // Returns a WeakPtr to be used on the |task_runner_|.
- base::WeakPtr<MediaDrmBridge> WeakPtr();
-
- // MediaKeys (via BrowserCdm) implementation.
+ // MediaKeys implementation.
void SetServerCertificate(
const std::vector<uint8_t>& certificate,
scoped_ptr<media::SimpleCdmPromise> promise) override;
@@ -112,8 +109,14 @@ class MEDIA_EXPORT MediaDrmBridge : public BrowserCdm {
void RemoveSession(const std::string& session_id,
scoped_ptr<media::SimpleCdmPromise> promise) override;
CdmContext* GetCdmContext() override;
-
- // PlayerTracker (via BrowserCdm) implementation.
+ void DeleteOnCorrectThread() const override;
+
+ // PlayerTracker implementation. Can be called on any thread.
+ // The registered callbacks will be fired on |task_runner_|. The caller
+ // should make sure that the callbacks are posted to the correct thread.
+ //
+ // Note: RegisterPlayer() should be called before SetMediaCryptoReadyCB() to
+ // avoid missing any new key notifications.
int RegisterPlayer(const base::Closure& new_key_cb,
const base::Closure& cdm_unset_cb) override;
void UnregisterPlayer(int registration_id) override;
@@ -144,8 +147,11 @@ class MEDIA_EXPORT MediaDrmBridge : public BrowserCdm {
// otherwise.
base::android::ScopedJavaLocalRef<jobject> GetMediaCrypto();
- // Sets callback which will be called when MediaCrypto is ready. If
- // |media_crypto_ready_cb| is null, previously set callback will be cleared.
+ // Registers a callback which will be called when MediaCrypto is ready.
+ // Can be called on any thread. Only one callback should be registered.
+ // The registered callbacks will be fired on |task_runner_|. The caller
+ // should make sure that the callbacks are posted to the correct thread.
+ // TODO(xhwang): Move this up to be close to RegisterPlayer().
void SetMediaCryptoReadyCB(const MediaCryptoReadyCB& media_crypto_ready_cb);
// All the OnXxx functions below are called from Java. The implementation must
@@ -212,6 +218,9 @@ class MEDIA_EXPORT MediaDrmBridge : public BrowserCdm {
void OnResetDeviceCredentialsCompleted(JNIEnv* env, jobject, bool success);
private:
+ // For DeleteSoon() in DeleteOnCorrectThread().
+ friend class base::DeleteHelper<MediaDrmBridge>;
+
MediaDrmBridge(const std::vector<uint8>& scheme_uuid,
const SessionMessageCB& session_message_cb,
const SessionClosedCB& session_closed_cb,
@@ -219,14 +228,13 @@ class MEDIA_EXPORT MediaDrmBridge : public BrowserCdm {
const SessionKeysChangeCB& session_keys_change_cb,
const SessionExpirationUpdateCB& session_expiration_update_cb);
+ ~MediaDrmBridge() override;
+
static bool IsSecureDecoderRequired(SecurityLevel security_level);
// Get the security level of the media.
SecurityLevel GetSecurityLevel();
- // A helper method that calls a |player_tracker_| method on correct thread.
- void NotifyNewKeyOnCorrectThread();
-
// A helper method that calculates the |media_crypto_ready_cb_| arguments and
// run this callback.
void NotifyMediaCryptoReady(const MediaCryptoReadyCB& cb);
@@ -248,24 +256,15 @@ class MEDIA_EXPORT MediaDrmBridge : public BrowserCdm {
ResetCredentialsCB reset_credentials_cb_;
- // The |player_tracker_| must be accessed by one thread only. It is accessed
- // by the Media thread when |use_media_thread_| is true.
PlayerTrackerImpl player_tracker_;
+ // TODO(xhwang): Host a CdmPromiseAdapter directly. No need to use scoped_ptr.
scoped_ptr<CdmPromiseAdapter> cdm_promise_adapter_;
// Default task runner.
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
- // This flag is set when we use media thread for certain callbacks.
- const bool use_media_thread_;
-
// NOTE: Weak pointers must be invalidated before all other member variables.
-
- // WeakPtrFactory to generate weak pointers to be used on the media thread.
- base::WeakPtrFactory<MediaDrmBridge> media_weak_factory_;
-
- // Default WeakPtrFactory.
base::WeakPtrFactory<MediaDrmBridge> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(MediaDrmBridge);
diff --git a/media/base/android/media_drm_bridge_unittest.cc b/media/base/android/media_drm_bridge_unittest.cc
index f215a42..233dc75 100644
--- a/media/base/android/media_drm_bridge_unittest.cc
+++ b/media/base/android/media_drm_bridge_unittest.cc
@@ -90,7 +90,7 @@ TEST(MediaDrmBridgeTest, CreateWithoutSessionSupport_InvalidKeySystem) {
TEST(MediaDrmBridgeTest, SetSecurityLevel_Widevine) {
base::MessageLoop message_loop_;
- scoped_ptr<MediaDrmBridge, BrowserCdmDeleter> media_drm_bridge =
+ scoped_refptr<MediaDrmBridge> media_drm_bridge =
MediaDrmBridge::CreateWithoutSessionSupport(kWidevineKeySystem);
EXPECT_TRUE_IF_WIDEVINE_AVAILABLE(media_drm_bridge);
if (!media_drm_bridge)
diff --git a/media/base/android/media_player_android.cc b/media/base/android/media_player_android.cc
index c08c259..9bde3de 100644
--- a/media/base/android/media_player_android.cc
+++ b/media/base/android/media_player_android.cc
@@ -42,7 +42,7 @@ GURL MediaPlayerAndroid::GetFirstPartyForCookies() {
return GURL();
}
-void MediaPlayerAndroid::SetCdm(BrowserCdm* /* cdm */) {
+void MediaPlayerAndroid::SetCdm(const scoped_refptr<MediaKeys>& /* cdm */) {
// Players that support EME should override this.
LOG(ERROR) << "EME not supported on base MediaPlayerAndroid class.";
return;
diff --git a/media/base/android/media_player_android.h b/media/base/android/media_player_android.h
index e24ad6c..24fb599 100644
--- a/media/base/android/media_player_android.h
+++ b/media/base/android/media_player_android.h
@@ -19,7 +19,7 @@
namespace media {
-class BrowserCdm;
+class MediaKeys;
class MediaPlayerManager;
// This class serves as the base class for different media player
@@ -78,7 +78,7 @@ class MEDIA_EXPORT MediaPlayerAndroid {
virtual GURL GetFirstPartyForCookies();
// Associates the |cdm| with this player.
- virtual void SetCdm(BrowserCdm* cdm);
+ virtual void SetCdm(const scoped_refptr<MediaKeys>& cdm);
// Requests playback permission from MediaPlayerManager.
// Overridden in MediaCodecPlayer to pass data between threads.
diff --git a/media/base/android/media_source_player.cc b/media/base/android/media_source_player.cc
index d4408b3..fd52bba 100644
--- a/media/base/android/media_source_player.cc
+++ b/media/base/android/media_source_player.cc
@@ -11,6 +11,7 @@
#include "base/barrier_closure.h"
#include "base/basictypes.h"
#include "base/bind.h"
+#include "base/bind_helpers.h"
#include "base/callback_helpers.h"
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
@@ -39,7 +40,6 @@ MediaSourcePlayer::MediaSourcePlayer(
interpolator_(&default_tick_clock_),
doing_browser_seek_(false),
pending_seek_(false),
- drm_bridge_(NULL),
cdm_registration_id_(0),
is_waiting_for_key_(false),
key_added_while_decode_pending_(false),
@@ -69,9 +69,10 @@ MediaSourcePlayer::MediaSourcePlayer(
MediaSourcePlayer::~MediaSourcePlayer() {
Release();
- DCHECK_EQ(!drm_bridge_, !cdm_registration_id_);
- if (drm_bridge_) {
- drm_bridge_->UnregisterPlayer(cdm_registration_id_);
+ DCHECK_EQ(!cdm_, !cdm_registration_id_);
+ if (cdm_) {
+ static_cast<MediaDrmBridge*>(cdm_.get())
+ ->UnregisterPlayer(cdm_registration_id_);
cdm_registration_id_ = 0;
}
}
@@ -267,13 +268,15 @@ void MediaSourcePlayer::OnMediaCryptoReady(
bool /* needs_protected_surface */) {
// Callback parameters are ignored in this player. They are intended for
// MediaCodecPlayer which uses a different threading scheme.
- DCHECK(!drm_bridge_->GetMediaCrypto().is_null());
+ DCHECK(!static_cast<MediaDrmBridge*>(cdm_.get())->GetMediaCrypto().is_null());
// Retry decoder creation if the decoders are waiting for MediaCrypto.
RetryDecoderCreation(true, true);
}
-void MediaSourcePlayer::SetCdm(BrowserCdm* cdm) {
+void MediaSourcePlayer::SetCdm(const scoped_refptr<MediaKeys>& cdm) {
+ DCHECK(cdm);
+
// Currently we don't support DRM change during the middle of playback, even
// if the player is paused.
// TODO(qinmin): support DRM change after playback has started.
@@ -283,25 +286,29 @@ void MediaSourcePlayer::SetCdm(BrowserCdm* cdm) {
<< "This is not well supported!";
}
- if (drm_bridge_) {
+ if (cdm_) {
NOTREACHED() << "Currently we do not support resetting CDM.";
return;
}
+ cdm_ = cdm;
+
// Only MediaDrmBridge will be set on MediaSourcePlayer.
- drm_bridge_ = static_cast<MediaDrmBridge*>(cdm);
+ MediaDrmBridge* drm_bridge = static_cast<MediaDrmBridge*>(cdm_.get());
- cdm_registration_id_ = drm_bridge_->RegisterPlayer(
+ // No need to set |cdm_unset_cb| since |this| holds a reference to the |cdm_|.
+ cdm_registration_id_ = drm_bridge->RegisterPlayer(
base::Bind(&MediaSourcePlayer::OnKeyAdded, weak_this_),
- base::Bind(&MediaSourcePlayer::OnCdmUnset, weak_this_));
+ base::Bind(&base::DoNothing));
- audio_decoder_job_->SetDrmBridge(drm_bridge_);
- video_decoder_job_->SetDrmBridge(drm_bridge_);
+ audio_decoder_job_->SetDrmBridge(drm_bridge);
+ video_decoder_job_->SetDrmBridge(drm_bridge);
- if (drm_bridge_->GetMediaCrypto().is_null()) {
+ if (drm_bridge->GetMediaCrypto().is_null()) {
+ // Use BindToCurrentLoop to avoid reentrancy.
MediaDrmBridge::MediaCryptoReadyCB cb = BindToCurrentLoop(
base::Bind(&MediaSourcePlayer::OnMediaCryptoReady, weak_this_));
- drm_bridge_->SetMediaCryptoReadyCB(cb);
+ drm_bridge->SetMediaCryptoReadyCB(cb);
return;
}
@@ -835,18 +842,4 @@ void MediaSourcePlayer::ResumePlaybackAfterKeyAdded() {
StartInternal();
}
-void MediaSourcePlayer::OnCdmUnset() {
- DVLOG(1) << __FUNCTION__;
- DCHECK(drm_bridge_);
- // TODO(xhwang): Currently this is only called during teardown. Support full
- // detachment of CDM during playback. This will be needed when we start to
- // support setMediaKeys(0) (see http://crbug.com/330324), or when we release
- // MediaDrm when the video is paused, or when the device goes to sleep (see
- // http://crbug.com/272421).
- audio_decoder_job_->SetDrmBridge(NULL);
- video_decoder_job_->SetDrmBridge(NULL);
- cdm_registration_id_ = 0;
- drm_bridge_ = NULL;
-}
-
} // namespace media
diff --git a/media/base/android/media_source_player.h b/media/base/android/media_source_player.h
index 7e4d706..0cfcfd0 100644
--- a/media/base/android/media_source_player.h
+++ b/media/base/android/media_source_player.h
@@ -63,7 +63,7 @@ class MEDIA_EXPORT MediaSourcePlayer : public MediaPlayerAndroid,
bool CanSeekForward() override;
bool CanSeekBackward() override;
bool IsPlayerReady() override;
- void SetCdm(BrowserCdm* cdm) override;
+ void SetCdm(const scoped_refptr<MediaKeys>& cdm) override;
// DemuxerAndroidClient implementation.
void OnDemuxerConfigsAvailable(const DemuxerConfigs& params) override;
@@ -165,9 +165,6 @@ class MEDIA_EXPORT MediaSourcePlayer : public MediaPlayerAndroid,
// available.
void ResumePlaybackAfterKeyAdded();
- // Called when the CDM is detached.
- void OnCdmUnset();
-
// Test-only method to setup hook for the completion of the next decode cycle.
// This callback state is cleared when it is next run.
// Prevent usage creep by only calling this from the
@@ -245,7 +242,9 @@ class MEDIA_EXPORT MediaSourcePlayer : public MediaPlayerAndroid,
// elapses.
base::CancelableClosure decoder_starvation_callback_;
- MediaDrmBridge* drm_bridge_;
+ // Holds a ref-count to the CDM.
+ scoped_refptr<MediaKeys> cdm_;
+
int cdm_registration_id_;
// No decryption key available to decrypt the encrypted buffer. In this case,
diff --git a/media/base/browser_cdm.cc b/media/base/browser_cdm.cc
deleted file mode 100644
index 45a2ea2..0000000
--- a/media/base/browser_cdm.cc
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "media/base/browser_cdm.h"
-
-namespace media {
-
-BrowserCdm::BrowserCdm() {
-}
-
-BrowserCdm::~BrowserCdm() {
-}
-
-// For most subclasses we can delete on the caller thread.
-void BrowserCdm::DeleteOnCorrectThread() {
- delete this;
-}
-
-} // namespace media
diff --git a/media/base/browser_cdm.h b/media/base/browser_cdm.h
deleted file mode 100644
index 5e4cb28..0000000
--- a/media/base/browser_cdm.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MEDIA_BASE_BROWSER_CDM_H_
-#define MEDIA_BASE_BROWSER_CDM_H_
-
-#include "base/memory/scoped_ptr.h"
-#include "media/base/media_export.h"
-#include "media/base/media_keys.h"
-#include "media/base/player_tracker.h"
-
-namespace media {
-
-// Interface for browser side CDMs.
-class MEDIA_EXPORT BrowserCdm : public MediaKeys, public PlayerTracker {
- public:
- ~BrowserCdm() override;
-
- // Virtual destructor. For most subclasses we can delete on the caller thread.
- virtual void DeleteOnCorrectThread();
-
- protected:
- BrowserCdm();
-
- private:
- DISALLOW_COPY_AND_ASSIGN(BrowserCdm);
-};
-
-struct MEDIA_EXPORT BrowserCdmDeleter {
- inline void operator()(BrowserCdm* ptr) const {
- ptr->DeleteOnCorrectThread();
- }
-};
-
-using ScopedBrowserCdmPtr = scoped_ptr<BrowserCdm, BrowserCdmDeleter>;
-
-} // namespace media
-
-#endif // MEDIA_BASE_BROWSER_CDM_H_
diff --git a/media/base/browser_cdm_factory.cc b/media/base/browser_cdm_factory.cc
index 73fd4c7..69a6a02 100644
--- a/media/base/browser_cdm_factory.cc
+++ b/media/base/browser_cdm_factory.cc
@@ -21,7 +21,7 @@ void SetBrowserCdmFactory(BrowserCdmFactory* factory) {
g_cdm_factory = factory;
}
-ScopedBrowserCdmPtr CreateBrowserCdm(
+scoped_refptr<MediaKeys> CreateBrowserCdm(
const std::string& key_system,
bool use_hw_secure_codecs,
const SessionMessageCB& session_message_cb,
@@ -31,10 +31,10 @@ ScopedBrowserCdmPtr CreateBrowserCdm(
const SessionExpirationUpdateCB& session_expiration_update_cb) {
if (!g_cdm_factory) {
#if defined(OS_ANDROID)
- SetBrowserCdmFactory(new BrowserCdmFactoryAndroid);
+ SetBrowserCdmFactory(new BrowserCdmFactoryAndroid());
#else
LOG(ERROR) << "Cannot create BrowserCdm: no BrowserCdmFactory available!";
- return ScopedBrowserCdmPtr();
+ return nullptr;
#endif
}
diff --git a/media/base/browser_cdm_factory.h b/media/base/browser_cdm_factory.h
index 99525a7..8a05a67 100644
--- a/media/base/browser_cdm_factory.h
+++ b/media/base/browser_cdm_factory.h
@@ -8,18 +8,19 @@
#include <string>
#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
-#include "media/base/browser_cdm.h"
+#include "base/memory/ref_counted.h"
#include "media/base/media_export.h"
+#include "media/base/media_keys.h"
namespace media {
+// TODO(xhwang): Merge this with media::CdmFactory.
class MEDIA_EXPORT BrowserCdmFactory {
public:
BrowserCdmFactory() {}
virtual ~BrowserCdmFactory() {}
- virtual ScopedBrowserCdmPtr CreateBrowserCdm(
+ virtual scoped_refptr<MediaKeys> CreateBrowserCdm(
const std::string& key_system,
bool use_hw_secure_codecs,
const SessionMessageCB& session_message_cb,
@@ -36,12 +37,12 @@ class MEDIA_EXPORT BrowserCdmFactory {
// BrowserCdmFactory per process.
void SetBrowserCdmFactory(BrowserCdmFactory* factory);
-// Creates a BrowserCdm for |key_system|. Returns NULL if the CDM cannot be
+// Creates a MediaKeys for |key_system|. Returns NULL if the CDM cannot be
// created.
// |use_hw_secure_codecs| indicates that the CDM should be configured to use
// hardware-secure codecs (for platforms that support it).
// TODO(xhwang): Add ifdef for IPC based CDM.
-ScopedBrowserCdmPtr MEDIA_EXPORT
+scoped_refptr<MediaKeys> MEDIA_EXPORT
CreateBrowserCdm(const std::string& key_system,
bool use_hw_secure_codecs,
const SessionMessageCB& session_message_cb,
diff --git a/media/base/cdm_factory.h b/media/base/cdm_factory.h
index 4a5cfb7..a120707 100644
--- a/media/base/cdm_factory.h
+++ b/media/base/cdm_factory.h
@@ -17,7 +17,7 @@ namespace media {
// Callback used when CDM is created. |error_message| only used if
// MediaKeys is null (i.e. CDM can't be created).
-using CdmCreatedCB = base::Callback<void(scoped_ptr<MediaKeys>,
+using CdmCreatedCB = base::Callback<void(const scoped_refptr<MediaKeys>&,
const std::string& error_message)>;
struct CdmConfig;
diff --git a/media/base/cdm_initialized_promise.cc b/media/base/cdm_initialized_promise.cc
index dcc9c79..d15d514e 100644
--- a/media/base/cdm_initialized_promise.cc
+++ b/media/base/cdm_initialized_promise.cc
@@ -6,17 +6,17 @@
namespace media {
-CdmInitializedPromise::CdmInitializedPromise(const CdmCreatedCB& cdm_created_cb,
- scoped_ptr<MediaKeys> cdm)
- : cdm_created_cb_(cdm_created_cb), cdm_(cdm.Pass()) {
-}
+CdmInitializedPromise::CdmInitializedPromise(
+ const CdmCreatedCB& cdm_created_cb,
+ const scoped_refptr<MediaKeys>& cdm)
+ : cdm_created_cb_(cdm_created_cb), cdm_(cdm) {}
CdmInitializedPromise::~CdmInitializedPromise() {
}
void CdmInitializedPromise::resolve() {
MarkPromiseSettled();
- cdm_created_cb_.Run(cdm_.Pass(), "");
+ cdm_created_cb_.Run(cdm_, "");
}
void CdmInitializedPromise::reject(MediaKeys::Exception exception_code,
diff --git a/media/base/cdm_initialized_promise.h b/media/base/cdm_initialized_promise.h
index bc4a569..f0ca012 100644
--- a/media/base/cdm_initialized_promise.h
+++ b/media/base/cdm_initialized_promise.h
@@ -5,7 +5,7 @@
#ifndef MEDIA_BASE_CDM_INITIALIZED_PROMISE_H_
#define MEDIA_BASE_CDM_INITIALIZED_PROMISE_H_
-#include "base/memory/scoped_ptr.h"
+#include "base/memory/ref_counted.h"
#include "media/base/cdm_factory.h"
#include "media/base/cdm_promise.h"
#include "media/base/media_export.h"
@@ -19,7 +19,7 @@ namespace media {
class MEDIA_EXPORT CdmInitializedPromise : public SimpleCdmPromise {
public:
CdmInitializedPromise(const CdmCreatedCB& cdm_created_cb,
- scoped_ptr<MediaKeys> cdm);
+ const scoped_refptr<MediaKeys>& cdm);
~CdmInitializedPromise() override;
// SimpleCdmPromise implementation.
@@ -30,7 +30,9 @@ class MEDIA_EXPORT CdmInitializedPromise : public SimpleCdmPromise {
private:
CdmCreatedCB cdm_created_cb_;
- scoped_ptr<MediaKeys> cdm_;
+
+ // Holds a ref-count of the CDM.
+ scoped_refptr<MediaKeys> cdm_;
};
} // namespace media
diff --git a/media/base/media_keys.cc b/media/base/media_keys.cc
index cf5256b..03e7acf 100644
--- a/media/base/media_keys.cc
+++ b/media/base/media_keys.cc
@@ -10,4 +10,13 @@ MediaKeys::MediaKeys() {}
MediaKeys::~MediaKeys() {}
+void MediaKeys::DeleteOnCorrectThread() const {
+ delete this;
+}
+
+// static
+void MediaKeysTraits::Destruct(const MediaKeys* media_keys) {
+ media_keys->DeleteOnCorrectThread();
+}
+
} // namespace media
diff --git a/media/base/media_keys.h b/media/base/media_keys.h
index dc4da6c..a84cdf7 100644
--- a/media/base/media_keys.h
+++ b/media/base/media_keys.h
@@ -10,6 +10,7 @@
#include "base/basictypes.h"
#include "base/callback.h"
+#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h"
#include "media/base/eme_constants.h"
@@ -24,6 +25,7 @@ namespace media {
class CdmContext;
struct CdmKeyInformation;
+struct MediaKeysTraits;
template <typename... T>
class CdmPromiseTemplate;
@@ -32,11 +34,35 @@ typedef CdmPromiseTemplate<std::string> NewSessionCdmPromise;
typedef CdmPromiseTemplate<> SimpleCdmPromise;
typedef ScopedVector<CdmKeyInformation> CdmKeysInfo;
-// Performs media key operations.
+// An interface that represents the Content Decryption Module (CDM) in the
+// Encrypted Media Extensions (EME) spec in Chromium.
+// See http://w3c.github.io/encrypted-media/#cdm
//
-// All key operations are called on the renderer thread. Therefore, these calls
-// should be fast and nonblocking; key events should be fired asynchronously.
-class MEDIA_EXPORT MediaKeys{
+// * Ownership
+//
+// This class is ref-counted. However, a ref-count should only be held by:
+// - The owner of the CDM. This is usually some class in the EME stack, e.g.
+// CdmSessionAdapter in the render process, or MojoCdmService in a non-render
+// process.
+// - The media player that uses the CDM, to prevent the CDM from being
+// destructed while still being used by the media player.
+//
+// When binding class methods into callbacks, prefer WeakPtr to using |this|
+// directly to avoid having a ref-count held by the callback.
+//
+// * Thread Safety
+//
+// Most CDM operations happen on one thread. However, it is not uncommon that
+// the media player lives on a different thread and may call into the CDM from
+// that thread. For example, if the CDM supports a Decryptor interface, the
+// Decryptor methods could be called on a different thread. The CDM
+// implementation should make sure it's thread safe for these situations.
+//
+// TODO(xhwang): Rename MediaKeys to ContentDecryptionModule. See
+// http://crbug.com/309237
+
+class MEDIA_EXPORT MediaKeys
+ : public base::RefCountedThreadSafe<MediaKeys, MediaKeysTraits> {
public:
// Reported to UMA, so never reuse a value!
// Must be kept in sync with blink::WebMediaPlayerClient::MediaKeyErrorCode
@@ -86,8 +112,6 @@ class MEDIA_EXPORT MediaKeys{
MESSAGE_TYPE_MAX = LICENSE_RELEASE
};
- virtual ~MediaKeys();
-
// Provides a server certificate to be used to encrypt messages to the
// license server.
virtual void SetServerCertificate(const std::vector<uint8_t>& certificate,
@@ -137,16 +161,30 @@ class MEDIA_EXPORT MediaKeys{
// not used after |this| is destructed.
virtual CdmContext* GetCdmContext() = 0;
+ // Deletes |this| on the correct thread. By default |this| is deleted
+ // immediately. Override this method if |this| needs to be deleted on a
+ // specific thread.
+ virtual void DeleteOnCorrectThread() const;
+
protected:
+ friend class base::RefCountedThreadSafe<MediaKeys, MediaKeysTraits>;
+
MediaKeys();
+ virtual ~MediaKeys();
private:
DISALLOW_COPY_AND_ASSIGN(MediaKeys);
};
-// Key event callbacks. See the spec for details:
-// https://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/encrypted-media.html#event-summary
+struct MEDIA_EXPORT MediaKeysTraits {
+ // Destroys |media_keys| on the correct thread.
+ static void Destruct(const MediaKeys* media_keys);
+};
+
+// CDM session event callbacks.
+// Called when the CDM needs to queue a message event to the session object.
+// See http://w3c.github.io/encrypted-media/#dom-evt-message
typedef base::Callback<void(const std::string& session_id,
MediaKeys::MessageType message_type,
const std::vector<uint8_t>& message,
@@ -156,19 +194,25 @@ typedef base::Callback<void(const std::string& session_id,
// Called when the session specified by |session_id| is closed. Note that the
// CDM may close a session at any point, such as in response to a CloseSession()
// call, when the session is no longer needed, or when system resources are
-// lost. See for details: http://w3c.github.io/encrypted-media/#session-close
+// lost. See http://w3c.github.io/encrypted-media/#session-close
typedef base::Callback<void(const std::string& session_id)> SessionClosedCB;
+// TODO(xhwang): Remove after prefixed EME support is removed. See
+// http://crbug.com/249976
typedef base::Callback<void(const std::string& session_id,
MediaKeys::Exception exception,
uint32_t system_code,
const std::string& error_message)>
LegacySessionErrorCB;
+// Called when there has been a change in the keys in the session or their
+// status. See http://w3c.github.io/encrypted-media/#dom-evt-keystatuseschange
typedef base::Callback<void(const std::string& session_id,
bool has_additional_usable_key,
CdmKeysInfo keys_info)> SessionKeysChangeCB;
+// Called when the CDM changes the expiration time of a session.
+// See http://w3c.github.io/encrypted-media/#update-expiration
typedef base::Callback<void(const std::string& session_id,
const base::Time& new_expiry_time)>
SessionExpirationUpdateCB;
diff --git a/media/base/player_tracker.h b/media/base/player_tracker.h
index 0ed1b3f..ff41c0a 100644
--- a/media/base/player_tracker.h
+++ b/media/base/player_tracker.h
@@ -19,7 +19,8 @@ class MEDIA_EXPORT PlayerTracker {
// Registers player callbacks with the CDM.
// - |new_key_cb| is fired when a new decryption key becomes available.
- // - |cdm_unset_cb| is fired when the CDM is detached from the player.
+ // - |cdm_unset_cb| is fired when the CDM is detached from the player. The
+ // player should stop using the CDM and release any ref-count to the CDM.
// Returns a registration ID which can be used to unregister a player.
virtual int RegisterPlayer(const base::Closure& new_key_cb,
const base::Closure& cdm_unset_cb) = 0;
diff --git a/media/blink/cdm_session_adapter.cc b/media/blink/cdm_session_adapter.cc
index 4dcfe96..e260340 100644
--- a/media/blink/cdm_session_adapter.cc
+++ b/media/blink/cdm_session_adapter.cc
@@ -128,11 +128,10 @@ const std::string& CdmSessionAdapter::GetKeySystemUMAPrefix() const {
return key_system_uma_prefix_;
}
-void CdmSessionAdapter::OnCdmCreated(
- const std::string& key_system,
- base::TimeTicks start_time,
- scoped_ptr<MediaKeys> cdm,
- const std::string& error_message) {
+void CdmSessionAdapter::OnCdmCreated(const std::string& key_system,
+ base::TimeTicks start_time,
+ const scoped_refptr<MediaKeys>& cdm,
+ const std::string& error_message) {
DVLOG(2) << __FUNCTION__;
DCHECK(!cdm_);
@@ -155,7 +154,7 @@ void CdmSessionAdapter::OnCdmCreated(
// Only report time for successful CDM creation.
ReportTimeToCreateCdmUMA(base::TimeTicks::Now() - start_time);
- cdm_ = cdm.Pass();
+ cdm_ = cdm;
cdm_created_result_->completeWithContentDecryptionModule(
new WebContentDecryptionModuleImpl(this));
diff --git a/media/blink/cdm_session_adapter.h b/media/blink/cdm_session_adapter.h
index ac4219e..a6fc2bc 100644
--- a/media/blink/cdm_session_adapter.h
+++ b/media/blink/cdm_session_adapter.h
@@ -111,7 +111,7 @@ class CdmSessionAdapter : public base::RefCounted<CdmSessionAdapter> {
// Callback for CreateCdm().
void OnCdmCreated(const std::string& key_system,
base::TimeTicks start_time,
- scoped_ptr<MediaKeys> cdm,
+ const scoped_refptr<MediaKeys>& cdm,
const std::string& error_message);
// Callbacks for firing session events.
@@ -136,7 +136,7 @@ class CdmSessionAdapter : public base::RefCounted<CdmSessionAdapter> {
void ReportTimeToCreateCdmUMA(base::TimeDelta cdm_creation_time) const;
- scoped_ptr<MediaKeys> cdm_;
+ scoped_refptr<MediaKeys> cdm_;
SessionMap sessions_;
diff --git a/media/cdm/aes_decryptor.h b/media/cdm/aes_decryptor.h
index e254026..2b5a49e 100644
--- a/media/cdm/aes_decryptor.h
+++ b/media/cdm/aes_decryptor.h
@@ -37,7 +37,6 @@ class MEDIA_EXPORT AesDecryptor : public MediaKeys,
const SessionMessageCB& session_message_cb,
const SessionClosedCB& session_closed_cb,
const SessionKeysChangeCB& session_keys_change_cb);
- ~AesDecryptor() override;
// MediaKeys implementation.
void SetServerCertificate(const std::vector<uint8_t>& certificate,
@@ -116,6 +115,8 @@ class MEDIA_EXPORT AesDecryptor : public MediaKeys,
scoped_ptr<SessionIdDecryptionKeyMap>>
KeyIdToSessionKeysMap;
+ ~AesDecryptor() override;
+
// Creates a DecryptionKey using |key_string| and associates it with |key_id|.
// Returns true if successful.
bool AddDecryptionKey(const std::string& session_id,
diff --git a/media/cdm/aes_decryptor_unittest.cc b/media/cdm/aes_decryptor_unittest.cc
index 9896575..2d8b1a6 100644
--- a/media/cdm/aes_decryptor_unittest.cc
+++ b/media/cdm/aes_decryptor_unittest.cc
@@ -214,13 +214,14 @@ enum PromiseResult { RESOLVED, REJECTED };
class AesDecryptorTest : public testing::Test {
public:
AesDecryptorTest()
- : decryptor_(GURL::EmptyGURL(),
- base::Bind(&AesDecryptorTest::OnSessionMessage,
- base::Unretained(this)),
- base::Bind(&AesDecryptorTest::OnSessionClosed,
- base::Unretained(this)),
- base::Bind(&AesDecryptorTest::OnSessionKeysChange,
- base::Unretained(this))),
+ : decryptor_(
+ new AesDecryptor(GURL::EmptyGURL(),
+ base::Bind(&AesDecryptorTest::OnSessionMessage,
+ base::Unretained(this)),
+ base::Bind(&AesDecryptorTest::OnSessionClosed,
+ base::Unretained(this)),
+ base::Bind(&AesDecryptorTest::OnSessionKeysChange,
+ base::Unretained(this)))),
decrypt_cb_(base::Bind(&AesDecryptorTest::BufferDecrypted,
base::Unretained(this))),
original_data_(kOriginalData, kOriginalData + kOriginalDataSize),
@@ -233,8 +234,7 @@ class AesDecryptorTest : public testing::Test {
iv_(kIv, kIv + arraysize(kIv)),
normal_subsample_entries_(
kSubsampleEntriesNormal,
- kSubsampleEntriesNormal + arraysize(kSubsampleEntriesNormal)) {
- }
+ kSubsampleEntriesNormal + arraysize(kSubsampleEntriesNormal)) {}
protected:
void OnResolveWithSession(PromiseResult expected_result,
@@ -285,9 +285,9 @@ class AesDecryptorTest : public testing::Test {
DCHECK(!key_id.empty());
EXPECT_CALL(*this, OnSessionMessage(IsNotEmpty(), _, IsJSONDictionary(),
GURL::EmptyGURL()));
- decryptor_.CreateSessionAndGenerateRequest(MediaKeys::TEMPORARY_SESSION,
- EmeInitDataType::WEBM, key_id,
- CreateSessionPromise(RESOLVED));
+ decryptor_->CreateSessionAndGenerateRequest(MediaKeys::TEMPORARY_SESSION,
+ EmeInitDataType::WEBM, key_id,
+ CreateSessionPromise(RESOLVED));
// This expects the promise to be called synchronously, which is the case
// for AesDecryptor.
return session_id_;
@@ -296,7 +296,7 @@ class AesDecryptorTest : public testing::Test {
// Closes the session specified by |session_id|.
void CloseSession(const std::string& session_id) {
EXPECT_CALL(*this, OnSessionClosed(session_id));
- decryptor_.CloseSession(session_id, CreatePromise(RESOLVED));
+ decryptor_->CloseSession(session_id, CreatePromise(RESOLVED));
}
// Removes the session specified by |session_id|. This should simply do a
@@ -305,7 +305,7 @@ class AesDecryptorTest : public testing::Test {
// http://crbug.com/249976.
void RemoveSession(const std::string& session_id) {
EXPECT_CALL(*this, OnSessionClosed(session_id));
- decryptor_.RemoveSession(session_id, CreatePromise(RESOLVED));
+ decryptor_->RemoveSession(session_id, CreatePromise(RESOLVED));
}
MOCK_METHOD2(OnSessionKeysChangeCalled,
@@ -334,9 +334,9 @@ class AesDecryptorTest : public testing::Test {
EXPECT_CALL(*this, OnSessionKeysChangeCalled(_, _)).Times(0);
}
- decryptor_.UpdateSession(session_id,
- std::vector<uint8>(key.begin(), key.end()),
- CreatePromise(expected_result));
+ decryptor_->UpdateSession(session_id,
+ std::vector<uint8>(key.begin(), key.end()),
+ CreatePromise(expected_result));
}
bool KeysInfoContains(std::vector<uint8> expected) {
@@ -380,7 +380,7 @@ class AesDecryptorTest : public testing::Test {
break;
}
- decryptor_.Decrypt(Decryptor::kVideo, encrypted, decrypt_cb_);
+ decryptor_->Decrypt(Decryptor::kVideo, encrypted, decrypt_cb_);
std::vector<uint8> decrypted_text;
if (decrypted.get() && decrypted->data_size()) {
@@ -413,7 +413,7 @@ class AesDecryptorTest : public testing::Test {
const GURL& legacy_destination_url));
MOCK_METHOD1(OnSessionClosed, void(const std::string& session_id));
- AesDecryptor decryptor_;
+ scoped_refptr<AesDecryptor> decryptor_;
AesDecryptor::DecryptCB decrypt_cb_;
std::string session_id_;
CdmKeysInfo keys_info_;
@@ -431,7 +431,7 @@ class AesDecryptorTest : public testing::Test {
TEST_F(AesDecryptorTest, CreateSessionWithNullInitData) {
EXPECT_CALL(*this,
OnSessionMessage(IsNotEmpty(), _, IsEmpty(), GURL::EmptyGURL()));
- decryptor_.CreateSessionAndGenerateRequest(
+ decryptor_->CreateSessionAndGenerateRequest(
MediaKeys::TEMPORARY_SESSION, EmeInitDataType::WEBM, std::vector<uint8>(),
CreateSessionPromise(RESOLVED));
}
@@ -439,19 +439,19 @@ TEST_F(AesDecryptorTest, CreateSessionWithNullInitData) {
TEST_F(AesDecryptorTest, MultipleCreateSession) {
EXPECT_CALL(*this,
OnSessionMessage(IsNotEmpty(), _, IsEmpty(), GURL::EmptyGURL()));
- decryptor_.CreateSessionAndGenerateRequest(
+ decryptor_->CreateSessionAndGenerateRequest(
MediaKeys::TEMPORARY_SESSION, EmeInitDataType::WEBM, std::vector<uint8>(),
CreateSessionPromise(RESOLVED));
EXPECT_CALL(*this,
OnSessionMessage(IsNotEmpty(), _, IsEmpty(), GURL::EmptyGURL()));
- decryptor_.CreateSessionAndGenerateRequest(
+ decryptor_->CreateSessionAndGenerateRequest(
MediaKeys::TEMPORARY_SESSION, EmeInitDataType::WEBM, std::vector<uint8>(),
CreateSessionPromise(RESOLVED));
EXPECT_CALL(*this,
OnSessionMessage(IsNotEmpty(), _, IsEmpty(), GURL::EmptyGURL()));
- decryptor_.CreateSessionAndGenerateRequest(
+ decryptor_->CreateSessionAndGenerateRequest(
MediaKeys::TEMPORARY_SESSION, EmeInitDataType::WEBM, std::vector<uint8>(),
CreateSessionPromise(RESOLVED));
}
@@ -474,12 +474,12 @@ TEST_F(AesDecryptorTest, CreateSessionWithCencInitData) {
#if defined(USE_PROPRIETARY_CODECS)
EXPECT_CALL(*this, OnSessionMessage(IsNotEmpty(), _, IsJSONDictionary(),
GURL::EmptyGURL()));
- decryptor_.CreateSessionAndGenerateRequest(
+ decryptor_->CreateSessionAndGenerateRequest(
MediaKeys::TEMPORARY_SESSION, EmeInitDataType::CENC,
std::vector<uint8>(init_data, init_data + arraysize(init_data)),
CreateSessionPromise(RESOLVED));
#else
- decryptor_.CreateSessionAndGenerateRequest(
+ decryptor_->CreateSessionAndGenerateRequest(
MediaKeys::TEMPORARY_SESSION, EmeInitDataType::CENC,
std::vector<uint8>(init_data, init_data + arraysize(init_data)),
CreateSessionPromise(REJECTED));
@@ -492,7 +492,7 @@ TEST_F(AesDecryptorTest, CreateSessionWithKeyIdsInitData) {
EXPECT_CALL(*this, OnSessionMessage(IsNotEmpty(), _, IsJSONDictionary(),
GURL::EmptyGURL()));
- decryptor_.CreateSessionAndGenerateRequest(
+ decryptor_->CreateSessionAndGenerateRequest(
MediaKeys::TEMPORARY_SESSION, EmeInitDataType::KEYIDS,
std::vector<uint8>(init_data, init_data + arraysize(init_data) - 1),
CreateSessionPromise(RESOLVED));
@@ -525,7 +525,7 @@ TEST_F(AesDecryptorTest, NoKey) {
scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer(
encrypted_data_, key_id_, iv_, no_subsample_entries_);
EXPECT_CALL(*this, BufferDecrypted(AesDecryptor::kNoKey, IsNull()));
- decryptor_.Decrypt(Decryptor::kVideo, encrypted_buffer, decrypt_cb_);
+ decryptor_->Decrypt(Decryptor::kVideo, encrypted_buffer, decrypt_cb_);
}
TEST_F(AesDecryptorTest, KeyReplacement) {
diff --git a/media/cdm/default_cdm_factory.cc b/media/cdm/default_cdm_factory.cc
index c025fe9..675cb05 100644
--- a/media/cdm/default_cdm_factory.cc
+++ b/media/cdm/default_cdm_factory.cc
@@ -43,11 +43,11 @@ void DefaultCdmFactory::Create(
return;
}
- scoped_ptr<MediaKeys> cdm(
+ scoped_refptr<MediaKeys> cdm(
new AesDecryptor(security_origin, session_message_cb, session_closed_cb,
session_keys_change_cb));
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::Bind(cdm_created_cb, base::Passed(&cdm), ""));
+ FROM_HERE, base::Bind(cdm_created_cb, cdm, ""));
}
} // namespace media
diff --git a/media/cdm/player_tracker_impl.cc b/media/cdm/player_tracker_impl.cc
index e4abd61..98f2050 100644
--- a/media/cdm/player_tracker_impl.cc
+++ b/media/cdm/player_tracker_impl.cc
@@ -11,25 +11,21 @@
namespace media {
PlayerTrackerImpl::PlayerCallbacks::PlayerCallbacks(
- base::Closure new_key_cb,
- base::Closure cdm_unset_cb)
- : new_key_cb(new_key_cb), cdm_unset_cb(cdm_unset_cb) {
-}
+ const base::Closure& new_key_cb,
+ const base::Closure& cdm_unset_cb)
+ : new_key_cb(new_key_cb), cdm_unset_cb(cdm_unset_cb) {}
PlayerTrackerImpl::PlayerCallbacks::~PlayerCallbacks() {
}
PlayerTrackerImpl::PlayerTrackerImpl() : next_registration_id_(1) {
- // Enable PlayerTrackerImpl to be created on another thread than it will be
- // later exclusively used.
- thread_checker_.DetachFromThread();
}
PlayerTrackerImpl::~PlayerTrackerImpl() {}
int PlayerTrackerImpl::RegisterPlayer(const base::Closure& new_key_cb,
const base::Closure& cdm_unset_cb) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ base::AutoLock lock(lock_);
int registration_id = next_registration_id_++;
DCHECK(!ContainsKey(player_callbacks_map_, registration_id));
player_callbacks_map_.insert(std::make_pair(
@@ -38,24 +34,36 @@ int PlayerTrackerImpl::RegisterPlayer(const base::Closure& new_key_cb,
}
void PlayerTrackerImpl::UnregisterPlayer(int registration_id) {
- DCHECK(thread_checker_.CalledOnValidThread());
+ base::AutoLock lock(lock_);
DCHECK(ContainsKey(player_callbacks_map_, registration_id))
<< registration_id;
player_callbacks_map_.erase(registration_id);
}
void PlayerTrackerImpl::NotifyNewKey() {
- DCHECK(thread_checker_.CalledOnValidThread());
- std::map<int, PlayerCallbacks>::iterator iter = player_callbacks_map_.begin();
- for (; iter != player_callbacks_map_.end(); ++iter)
- iter->second.new_key_cb.Run();
+ std::vector<base::Closure> new_key_callbacks;
+
+ {
+ base::AutoLock lock(lock_);
+ for (const auto& entry : player_callbacks_map_)
+ new_key_callbacks.push_back(entry.second.new_key_cb);
+ }
+
+ for (const auto& cb : new_key_callbacks)
+ cb.Run();
}
void PlayerTrackerImpl::NotifyCdmUnset() {
- DCHECK(thread_checker_.CalledOnValidThread());
- std::map<int, PlayerCallbacks>::iterator iter = player_callbacks_map_.begin();
- for (; iter != player_callbacks_map_.end(); ++iter)
- iter->second.cdm_unset_cb.Run();
+ std::vector<base::Closure> cdm_unset_callbacks;
+
+ {
+ base::AutoLock lock(lock_);
+ for (const auto& entry : player_callbacks_map_)
+ cdm_unset_callbacks.push_back(entry.second.cdm_unset_cb);
+ }
+
+ for (const auto& cb : cdm_unset_callbacks)
+ cb.Run();
}
} // namespace media
diff --git a/media/cdm/player_tracker_impl.h b/media/cdm/player_tracker_impl.h
index 6d4cee3..7da1a25 100644
--- a/media/cdm/player_tracker_impl.h
+++ b/media/cdm/player_tracker_impl.h
@@ -9,15 +9,14 @@
#include "base/basictypes.h"
#include "base/callback.h"
-#include "base/threading/thread_checker.h"
+#include "base/synchronization/lock.h"
#include "media/base/media_export.h"
#include "media/base/player_tracker.h"
namespace media {
// A common implementation that can be shared by different PlayerTracker
-// implementations. This class is not thread safe and should only be called
-// on one thread.
+// implementations. This class is thread safe and can be called on any thread.
class MEDIA_EXPORT PlayerTrackerImpl : public PlayerTracker {
public:
PlayerTrackerImpl();
@@ -34,18 +33,20 @@ class MEDIA_EXPORT PlayerTrackerImpl : public PlayerTracker {
private:
struct PlayerCallbacks {
- PlayerCallbacks(base::Closure new_key_cb, base::Closure cdm_unset_cb);
+ PlayerCallbacks(const base::Closure& new_key_cb,
+ const base::Closure& cdm_unset_cb);
~PlayerCallbacks();
base::Closure new_key_cb;
base::Closure cdm_unset_cb;
};
+ // Lock used to serialize access to other data members.
+ base::Lock lock_;
+
int next_registration_id_;
std::map<int, PlayerCallbacks> player_callbacks_map_;
- base::ThreadChecker thread_checker_;
-
DISALLOW_COPY_AND_ASSIGN(PlayerTrackerImpl);
};
diff --git a/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc b/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc
index 4533f39..f6c7781 100644
--- a/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc
+++ b/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc
@@ -267,12 +267,12 @@ namespace media {
ClearKeyCdm::ClearKeyCdm(ClearKeyCdmHost* host,
const std::string& key_system,
const GURL& origin)
- : decryptor_(
+ : decryptor_(new AesDecryptor(
origin,
base::Bind(&ClearKeyCdm::OnSessionMessage, base::Unretained(this)),
base::Bind(&ClearKeyCdm::OnSessionClosed, base::Unretained(this)),
base::Bind(&ClearKeyCdm::OnSessionKeysChange,
- base::Unretained(this))),
+ base::Unretained(this)))),
host_(host),
key_system_(key_system),
has_received_keys_change_event_for_emulated_loadsession_(false),
@@ -311,7 +311,7 @@ void ClearKeyCdm::CreateSessionAndGenerateRequest(
base::Bind(&ClearKeyCdm::OnPromiseFailed,
base::Unretained(this),
promise_id)));
- decryptor_.CreateSessionAndGenerateRequest(
+ decryptor_->CreateSessionAndGenerateRequest(
ConvertSessionType(session_type), ConvertInitDataType(init_data_type),
std::vector<uint8_t>(init_data, init_data + init_data_size),
promise.Pass());
@@ -347,7 +347,7 @@ void ClearKeyCdm::LoadSession(uint32 promise_id,
base::Bind(&ClearKeyCdm::OnPromiseFailed,
base::Unretained(this),
promise_id)));
- decryptor_.CreateSessionAndGenerateRequest(
+ decryptor_->CreateSessionAndGenerateRequest(
MediaKeys::TEMPORARY_SESSION, EmeInitDataType::WEBM,
std::vector<uint8_t>(), promise.Pass());
}
@@ -369,7 +369,7 @@ void ClearKeyCdm::UpdateSession(uint32 promise_id,
promise_id),
base::Bind(&ClearKeyCdm::OnPromiseFailed, base::Unretained(this),
promise_id)));
- decryptor_.UpdateSession(
+ decryptor_->UpdateSession(
web_session_str, std::vector<uint8_t>(response, response + response_size),
promise.Pass());
@@ -394,7 +394,7 @@ void ClearKeyCdm::CloseSession(uint32 promise_id,
&ClearKeyCdm::OnPromiseResolved, base::Unretained(this), promise_id),
base::Bind(
&ClearKeyCdm::OnPromiseFailed, base::Unretained(this), promise_id)));
- decryptor_.CloseSession(web_session_str, promise.Pass());
+ decryptor_->CloseSession(web_session_str, promise.Pass());
}
void ClearKeyCdm::RemoveSession(uint32 promise_id,
@@ -423,7 +423,7 @@ void ClearKeyCdm::RemoveSession(uint32 promise_id,
promise_id),
base::Bind(&ClearKeyCdm::OnPromiseFailed, base::Unretained(this),
promise_id)));
- decryptor_.RemoveSession(web_session_str, promise.Pass());
+ decryptor_->RemoveSession(web_session_str, promise.Pass());
}
void ClearKeyCdm::SetServerCertificate(uint32 promise_id,
@@ -671,9 +671,8 @@ cdm::Status ClearKeyCdm::DecryptToMediaDecoderBuffer(
media::Decryptor::Status status = media::Decryptor::kError;
// The AesDecryptor does not care what the stream type is. Pass kVideo
// for both audio and video decryption.
- decryptor_.Decrypt(
- media::Decryptor::kVideo,
- buffer,
+ decryptor_->Decrypt(
+ media::Decryptor::kVideo, buffer,
base::Bind(&CopyDecryptResults, &status, decrypted_buffer));
if (status == media::Decryptor::kError)
@@ -707,9 +706,9 @@ void ClearKeyCdm::LoadLoadableSession() {
base::Bind(&ClearKeyCdm::OnLoadSessionUpdated, base::Unretained(this)),
base::Bind(&ClearKeyCdm::OnPromiseFailed, base::Unretained(this),
promise_id_for_emulated_loadsession_)));
- decryptor_.UpdateSession(session_id_for_emulated_loadsession_,
- std::vector<uint8_t>(jwk_set.begin(), jwk_set.end()),
- promise.Pass());
+ decryptor_->UpdateSession(
+ session_id_for_emulated_loadsession_,
+ std::vector<uint8_t>(jwk_set.begin(), jwk_set.end()), promise.Pass());
}
void ClearKeyCdm::OnSessionMessage(const std::string& session_id,
diff --git a/media/cdm/ppapi/external_clear_key/clear_key_cdm.h b/media/cdm/ppapi/external_clear_key/clear_key_cdm.h
index 6418679..70d1584 100644
--- a/media/cdm/ppapi/external_clear_key/clear_key_cdm.h
+++ b/media/cdm/ppapi/external_clear_key/clear_key_cdm.h
@@ -145,7 +145,7 @@ class ClearKeyCdm : public ClearKeyCdmInterface {
// Keep track of the last session created.
void SetSessionId(const std::string& session_id);
- AesDecryptor decryptor_;
+ scoped_refptr<AesDecryptor> decryptor_;
ClearKeyCdmHost* host_;
diff --git a/media/cdm/proxy_decryptor.cc b/media/cdm/proxy_decryptor.cc
index 321a4a2c..b42666a 100644
--- a/media/cdm/proxy_decryptor.cc
+++ b/media/cdm/proxy_decryptor.cc
@@ -60,7 +60,7 @@ ProxyDecryptor::ProxyDecryptor(MediaPermission* media_permission,
ProxyDecryptor::~ProxyDecryptor() {
// Destroy the decryptor explicitly before destroying the plugin.
- media_keys_.reset();
+ media_keys_ = nullptr;
}
void ProxyDecryptor::CreateCdm(CdmFactory* cdm_factory,
@@ -96,7 +96,7 @@ void ProxyDecryptor::CreateCdm(CdmFactory* cdm_factory,
void ProxyDecryptor::OnCdmCreated(const std::string& key_system,
const GURL& security_origin,
const CdmContextReadyCB& cdm_context_ready_cb,
- scoped_ptr<MediaKeys> cdm,
+ const scoped_refptr<MediaKeys>& cdm,
const std::string& /* error_message */) {
is_creating_cdm_ = false;
@@ -106,7 +106,7 @@ void ProxyDecryptor::OnCdmCreated(const std::string& key_system,
key_system_ = key_system;
security_origin_ = security_origin;
is_clear_key_ = IsClearKey(key_system) || IsExternalClearKey(key_system);
- media_keys_ = cdm.Pass();
+ media_keys_ = cdm;
cdm_context_ready_cb.Run(media_keys_->GetCdmContext());
}
diff --git a/media/cdm/proxy_decryptor.h b/media/cdm/proxy_decryptor.h
index c7f60b9..bcf34c2 100644
--- a/media/cdm/proxy_decryptor.h
+++ b/media/cdm/proxy_decryptor.h
@@ -10,6 +10,7 @@
#include "base/basictypes.h"
#include "base/containers/hash_tables.h"
+#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h"
#include "base/memory/weak_ptr.h"
@@ -77,7 +78,7 @@ class MEDIA_EXPORT ProxyDecryptor {
void OnCdmCreated(const std::string& key_system,
const GURL& security_origin,
const CdmContextReadyCB& cdm_context_ready_cb,
- scoped_ptr<MediaKeys> cdm,
+ const scoped_refptr<MediaKeys>& cdm,
const std::string& error_message);
void GenerateKeyRequestInternal(EmeInitDataType init_data_type,
@@ -129,7 +130,7 @@ class MEDIA_EXPORT ProxyDecryptor {
bool is_creating_cdm_;
// The real MediaKeys that manages key operations for the ProxyDecryptor.
- scoped_ptr<MediaKeys> media_keys_;
+ scoped_refptr<MediaKeys> media_keys_;
#if defined(OS_CHROMEOS) || defined(OS_ANDROID)
MediaPermission* media_permission_;
diff --git a/media/media.gyp b/media/media.gyp
index 58d592b..9acf41e 100644
--- a/media/media.gyp
+++ b/media/media.gyp
@@ -715,8 +715,6 @@
}],
['enable_browser_cdms==1', {
'sources': [
- 'base/browser_cdm.cc',
- 'base/browser_cdm.h',
'base/browser_cdm_factory.cc',
'base/browser_cdm_factory.h',
],
diff --git a/media/mojo/services/mojo_cdm.cc b/media/mojo/services/mojo_cdm.cc
index 218dda4..00eb28a 100644
--- a/media/mojo/services/mojo_cdm.cc
+++ b/media/mojo/services/mojo_cdm.cc
@@ -35,18 +35,17 @@ void MojoCdm::Create(
const media::SessionKeysChangeCB& session_keys_change_cb,
const media::SessionExpirationUpdateCB& session_expiration_update_cb,
const media::CdmCreatedCB& cdm_created_cb) {
- scoped_ptr<MojoCdm> mojo_cdm(
+ scoped_refptr<MojoCdm> mojo_cdm(
new MojoCdm(remote_cdm.Pass(), session_message_cb, session_closed_cb,
legacy_session_error_cb, session_keys_change_cb,
session_expiration_update_cb));
- // |mojo_cdm|'s ownership will be passed to the promise. Get a raw pointer
- // here in order to call Initialize().
- MojoCdm* mojo_cdm_ptr = mojo_cdm.get();
+ // |mojo_cdm| ownership is passed to the promise.
scoped_ptr<CdmInitializedPromise> promise(
- new CdmInitializedPromise(cdm_created_cb, mojo_cdm.Pass()));
- mojo_cdm_ptr->InitializeCdm(key_system, security_origin, cdm_config,
- promise.Pass());
+ new CdmInitializedPromise(cdm_created_cb, mojo_cdm));
+
+ mojo_cdm->InitializeCdm(key_system, security_origin, cdm_config,
+ promise.Pass());
}
MojoCdm::MojoCdm(interfaces::ContentDecryptionModulePtr remote_cdm,
diff --git a/media/mojo/services/mojo_cdm.h b/media/mojo/services/mojo_cdm.h
index 0cb2ee9..57369ebe 100644
--- a/media/mojo/services/mojo_cdm.h
+++ b/media/mojo/services/mojo_cdm.h
@@ -41,8 +41,6 @@ class MojoCdm : public MediaKeys,
const media::SessionExpirationUpdateCB& session_expiration_update_cb,
const media::CdmCreatedCB& cdm_created_cb);
- ~MojoCdm() final;
-
// MediaKeys implementation.
void SetServerCertificate(const std::vector<uint8_t>& certificate,
scoped_ptr<SimpleCdmPromise> promise) final;
@@ -75,6 +73,8 @@ class MojoCdm : public MediaKeys,
const SessionKeysChangeCB& session_keys_change_cb,
const SessionExpirationUpdateCB& session_expiration_update_cb);
+ ~MojoCdm() final;
+
void InitializeCdm(const std::string& key_system,
const GURL& security_origin,
const media::CdmConfig& cdm_config,
diff --git a/media/mojo/services/mojo_cdm_service.cc b/media/mojo/services/mojo_cdm_service.cc
index c30a4f7..4a16387 100644
--- a/media/mojo/services/mojo_cdm_service.cc
+++ b/media/mojo/services/mojo_cdm_service.cc
@@ -140,7 +140,7 @@ CdmContext* MojoCdmService::GetCdmContext() {
}
void MojoCdmService::OnCdmCreated(scoped_ptr<CdmIdMojoCdmPromise> promise,
- scoped_ptr<MediaKeys> cdm,
+ const scoped_refptr<MediaKeys>& cdm,
const std::string& error_message) {
// TODO(xhwang): This should not happen when KeySystemInfo is properly
// populated. See http://crbug.com/469366
@@ -149,7 +149,7 @@ void MojoCdmService::OnCdmCreated(scoped_ptr<CdmIdMojoCdmPromise> promise,
return;
}
- cdm_ = cdm.Pass();
+ cdm_ = cdm;
cdm_id_ = next_cdm_id_++;
context_->RegisterCdm(cdm_id_, this);
promise->resolve(cdm_id_);
diff --git a/media/mojo/services/mojo_cdm_service.h b/media/mojo/services/mojo_cdm_service.h
index 0f974da..c669a74 100644
--- a/media/mojo/services/mojo_cdm_service.h
+++ b/media/mojo/services/mojo_cdm_service.h
@@ -7,6 +7,7 @@
#include "base/callback.h"
#include "base/macros.h"
+#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "media/base/media_keys.h"
@@ -76,7 +77,7 @@ class MojoCdmService : public interfaces::ContentDecryptionModule {
private:
// Callback for CdmFactory::Create().
void OnCdmCreated(scoped_ptr<MojoCdmPromise<int>> promise,
- scoped_ptr<MediaKeys> cdm,
+ const scoped_refptr<MediaKeys>& cdm,
const std::string& error_message);
// Callbacks for firing session events.
@@ -105,7 +106,7 @@ class MojoCdmService : public interfaces::ContentDecryptionModule {
mojo::ServiceProvider* service_provider_;
CdmFactory* cdm_factory_;
- scoped_ptr<MediaKeys> cdm_;
+ scoped_refptr<MediaKeys> cdm_;
// Set to a valid CDM ID if the |cdm_| is successfully created.
int cdm_id_;
diff --git a/media/test/pipeline_integration_test.cc b/media/test/pipeline_integration_test.cc
index 9f979ce..b62b5cb 100644
--- a/media/test/pipeline_integration_test.cc
+++ b/media/test/pipeline_integration_test.cc
@@ -4,6 +4,7 @@
#include "base/bind.h"
#include "base/command_line.h"
+#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/stl_util.h"
#include "base/strings/string_split.h"
@@ -202,14 +203,15 @@ class FakeEncryptedMedia {
};
FakeEncryptedMedia(AppBase* app)
- : decryptor_(GURL::EmptyGURL(),
- base::Bind(&FakeEncryptedMedia::OnSessionMessage,
- base::Unretained(this)),
- base::Bind(&FakeEncryptedMedia::OnSessionClosed,
- base::Unretained(this)),
- base::Bind(&FakeEncryptedMedia::OnSessionKeysChange,
- base::Unretained(this))),
- cdm_context_(&decryptor_),
+ : decryptor_(new AesDecryptor(
+ GURL::EmptyGURL(),
+ base::Bind(&FakeEncryptedMedia::OnSessionMessage,
+ base::Unretained(this)),
+ base::Bind(&FakeEncryptedMedia::OnSessionClosed,
+ base::Unretained(this)),
+ base::Bind(&FakeEncryptedMedia::OnSessionKeysChange,
+ base::Unretained(this)))),
+ cdm_context_(decryptor_.get()),
app_(app) {}
CdmContext* GetCdmContext() { return &cdm_context_; }
@@ -220,7 +222,7 @@ class FakeEncryptedMedia {
const std::vector<uint8_t>& message,
const GURL& legacy_destination_url) {
app_->OnSessionMessage(session_id, message_type, message,
- legacy_destination_url, &decryptor_);
+ legacy_destination_url, decryptor_.get());
}
void OnSessionClosed(const std::string& session_id) {
@@ -244,7 +246,7 @@ class FakeEncryptedMedia {
void OnEncryptedMediaInitData(EmeInitDataType init_data_type,
const std::vector<uint8_t>& init_data) {
- app_->OnEncryptedMediaInitData(init_data_type, init_data, &decryptor_);
+ app_->OnEncryptedMediaInitData(init_data_type, init_data, decryptor_.get());
}
private:
@@ -259,7 +261,7 @@ class FakeEncryptedMedia {
Decryptor* decryptor_;
};
- AesDecryptor decryptor_;
+ scoped_refptr<AesDecryptor> decryptor_;
TestCdmContext cdm_context_;
scoped_ptr<AppBase> app_;
};