Index: media/base/android/media_drm_proxy.cc |
diff --git a/media/base/android/media_drm_proxy.cc b/media/base/android/media_drm_proxy.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..385666d761f9cfd7f7120f12d61e2e9c12a15f06 |
--- /dev/null |
+++ b/media/base/android/media_drm_proxy.cc |
@@ -0,0 +1,258 @@ |
+// Copyright (c) 2015 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/android/media_drm_proxy.h" |
+ |
+#include "base/bind.h" |
+#include "base/thread_task_runner_handle.h" |
+#include "media/base/android/media_codec_player.h" // for GetMediaTaskRunner() |
+#include "media/base/android/media_drm_bridge.h" |
+#include "media/base/cdm_key_information.h" |
+#include "third_party/widevine/cdm/widevine_cdm_common.h" |
+ |
+#define POST_ON_MEDIA_THREAD_AND_RETURN(method, ...) \ |
+ do { \ |
+ if (!GetMediaTaskRunner()->BelongsToCurrentThread()) { \ |
+ GetMediaTaskRunner()->PostTask( \ |
+ FROM_HERE, base::Bind(&MediaDrmProxy::method, media_weak_this_, \ |
+ ##__VA_ARGS__)); \ |
+ return; \ |
+ } \ |
+ } while (0) |
+ |
+namespace media { |
+ |
+// static |
+scoped_ptr<MediaDrmProxy, BrowserCdmDeleter> MediaDrmProxy::Create( |
+ const std::string& key_system, |
+ MediaDrmBridge::SecurityLevel widevine_security_level, |
+ 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<MediaDrmProxy, BrowserCdmDeleter> media_drm_proxy; |
+ |
+ // Perform as many checks as we can on the UI thread before we do |
+ // the creation asynchronously on Media thread. |
+ if (!MediaDrmBridge::CanCreate(key_system, widevine_security_level)) |
+ return media_drm_proxy.Pass(); |
+ |
+ media_drm_proxy.reset( |
+ new MediaDrmProxy(key_system, widevine_security_level, session_message_cb, |
+ session_closed_cb, legacy_session_error_cb, |
+ session_keys_change_cb, session_expiration_update_cb)); |
+ |
+ // The actual work is done on the Media thread and there the creation |
+ // might fail, but we are still passing a valid pointer. |
+ return media_drm_proxy.Pass(); |
+} |
+ |
+MediaDrmProxy::MediaDrmProxy( |
+ const std::string& key_system, |
+ MediaDrmBridge::SecurityLevel widevine_security_level, |
+ 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) |
+ : ui_task_runner_(base::ThreadTaskRunnerHandle::Get()), |
+ key_system_(key_system), |
+ widevine_security_level_(widevine_security_level), |
+ session_message_cb_(session_message_cb), |
+ 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), |
+ media_weak_factory_(this) { |
+ media_weak_this_ = media_weak_factory_.GetWeakPtr(); |
+ |
+ internal_session_message_cb_ = |
+ base::Bind(&MediaDrmProxy::OnSessionMessage, media_weak_this_); |
+ internal_session_closed_cb_ = |
+ base::Bind(&MediaDrmProxy::OnSessionClosed, media_weak_this_); |
+ internal_legacy_session_error_cb_ = |
+ base::Bind(&MediaDrmProxy::OnLegacySessionError, media_weak_this_); |
+ internal_session_keys_change_cb_ = |
+ base::Bind(&MediaDrmProxy::OnSessionKeysChange, media_weak_this_); |
+ internal_session_expiration_update_cb_ = |
+ base::Bind(&MediaDrmProxy::OnSessionExpirationUpdate, media_weak_this_); |
+ |
+ // Perform MediaDrmBridge creation on the Media thread. |
+ GetMediaTaskRunner()->PostTask( |
+ FROM_HERE, base::Bind(&MediaDrmProxy::Initialize, media_weak_this_)); |
+} |
+ |
+MediaDrmProxy::~MediaDrmProxy() { |
+ DVLOG(1) << "MediaDrmProxy::" << __FUNCTION__; |
+ DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); |
+} |
+ |
+void MediaDrmProxy::DeleteOnCorrectThread() { |
+ DVLOG(1) << "MediaDrmProxy::" << __FUNCTION__; |
+ |
+ // Post deletion onto Media thread |
+ GetMediaTaskRunner()->DeleteSoon(FROM_HERE, this); |
+} |
+ |
+void MediaDrmProxy::Initialize() { |
+ DVLOG(1) << "MediaDrmProxy::" << __FUNCTION__; |
+ |
+ // Pass the original callbacks, those that should be called on UI thread. |
+ media_drm_bridge_ = |
+ scoped_ptr<MediaDrmBridge, BrowserCdmDeleter>(MediaDrmBridge::Create( |
+ key_system_, |
+ widevine_security_level_, |
+ internal_session_message_cb_, |
+ internal_session_closed_cb_, |
+ internal_legacy_session_error_cb_, |
+ internal_session_keys_change_cb_, |
+ internal_session_expiration_update_cb_)); |
+ |
+ if (!media_drm_bridge_) |
+ DVLOG(1) << __FUNCTION__ << ": MediaDrmBridge::Create() failed"; |
+} |
+ |
+void MediaDrmProxy::SetServerCertificate( |
+ const std::vector<uint8_t>& certificate, |
+ scoped_ptr<media::SimpleCdmPromise> promise) { |
+ POST_ON_MEDIA_THREAD_AND_RETURN(SetServerCertificate, certificate, |
+ base::Passed(&promise)); |
+ |
+ DVLOG(1) << "MediaDrmProxy::" << __FUNCTION__; |
+ |
+ media_drm_bridge_->SetServerCertificate(certificate, promise.Pass()); |
+} |
+ |
+void MediaDrmProxy::CreateSessionAndGenerateRequest( |
+ SessionType session_type, |
+ media::EmeInitDataType init_data_type, |
+ const std::vector<uint8_t>& init_data, |
+ scoped_ptr<media::NewSessionCdmPromise> promise) { |
+ POST_ON_MEDIA_THREAD_AND_RETURN(CreateSessionAndGenerateRequest, session_type, |
+ init_data_type, init_data, |
+ base::Passed(&promise)); |
+ |
+ DVLOG(1) << "MediaDrmProxy::" << __FUNCTION__; |
+ |
+ media_drm_bridge_->CreateSessionAndGenerateRequest( |
+ session_type, init_data_type, init_data, promise.Pass()); |
+} |
+ |
+void MediaDrmProxy::LoadSession( |
+ SessionType session_type, |
+ const std::string& session_id, |
+ scoped_ptr<media::NewSessionCdmPromise> promise) { |
+ POST_ON_MEDIA_THREAD_AND_RETURN(LoadSession, session_type, session_id, |
+ base::Passed(&promise)); |
+ |
+ DVLOG(1) << "MediaDrmProxy::" << __FUNCTION__; |
+ |
+ media_drm_bridge_->LoadSession(session_type, session_id, promise.Pass()); |
+} |
+ |
+void MediaDrmProxy::UpdateSession(const std::string& session_id, |
+ const std::vector<uint8_t>& response, |
+ scoped_ptr<media::SimpleCdmPromise> promise) { |
+ POST_ON_MEDIA_THREAD_AND_RETURN(UpdateSession, session_id, response, |
+ base::Passed(&promise)); |
+ |
+ DVLOG(1) << "MediaDrmProxy::" << __FUNCTION__; |
+ |
+ media_drm_bridge_->UpdateSession(session_id, response, promise.Pass()); |
+} |
+ |
+void MediaDrmProxy::CloseSession(const std::string& session_id, |
+ scoped_ptr<media::SimpleCdmPromise> promise) { |
+ POST_ON_MEDIA_THREAD_AND_RETURN(CloseSession, session_id, |
+ base::Passed(&promise)); |
+ |
+ DVLOG(1) << "MediaDrmProxy::" << __FUNCTION__; |
+ |
+ media_drm_bridge_->CloseSession(session_id, promise.Pass()); |
+} |
+ |
+void MediaDrmProxy::RemoveSession(const std::string& session_id, |
+ scoped_ptr<media::SimpleCdmPromise> promise) { |
+ POST_ON_MEDIA_THREAD_AND_RETURN(RemoveSession, session_id, |
+ base::Passed(&promise)); |
+ |
+ DVLOG(1) << "MediaDrmProxy::" << __FUNCTION__; |
+ |
+ media_drm_bridge_->RemoveSession(session_id, promise.Pass()); |
+} |
+ |
+CdmContext* MediaDrmProxy::GetCdmContext() { |
+ NOTREACHED(); |
+ return nullptr; |
+} |
+ |
+int MediaDrmProxy::RegisterPlayer(const base::Closure& new_key_cb, |
+ const base::Closure& cdm_unset_cb) { |
+ NOTREACHED() << __FUNCTION__ << " should be called on MediaDrmBridge"; |
+ return -1; |
+} |
+ |
+void MediaDrmProxy::UnregisterPlayer(int registration_id) { |
+ NOTREACHED() << __FUNCTION__ << " should be called on MediaDrmBridge"; |
+} |
+ |
+MediaDrmBridge* MediaDrmProxy::GetDrmBridge() { |
+ DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); |
+ |
+ return media_drm_bridge_.get(); |
+} |
+ |
+// Internal callbacks |
+ |
+void MediaDrmProxy::OnSessionMessage(const std::string& session_id, |
+ MediaKeys::MessageType message_type, |
+ const std::vector<uint8>& message, |
+ const GURL& legacy_destination_url) { |
+ DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); |
+ |
+ ui_task_runner_->PostTask( |
+ FROM_HERE, base::Bind(session_message_cb_, session_id, message_type, |
+ message, legacy_destination_url)); |
+} |
+ |
+void MediaDrmProxy::OnSessionClosed(const std::string& session_id) { |
+ DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); |
+ |
+ ui_task_runner_->PostTask(FROM_HERE, |
+ base::Bind(session_closed_cb_, session_id)); |
+} |
+ |
+void MediaDrmProxy::OnLegacySessionError(const std::string& session_id, |
+ MediaKeys::Exception exception_code, |
+ uint32 system_code, |
+ const std::string& error_message) { |
+ DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); |
+ |
+ ui_task_runner_->PostTask( |
+ FROM_HERE, base::Bind(legacy_session_error_cb_, session_id, |
+ exception_code, system_code, error_message)); |
+} |
+ |
+void MediaDrmProxy::OnSessionKeysChange(const std::string& session_id, |
+ bool has_additional_usable_key, |
+ CdmKeysInfo keys_info) { |
+ DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); |
+ |
+ ui_task_runner_->PostTask( |
+ FROM_HERE, |
+ base::Bind(session_keys_change_cb_, session_id, has_additional_usable_key, |
+ base::Passed(&keys_info))); |
+} |
+ |
+void MediaDrmProxy::OnSessionExpirationUpdate( |
+ const std::string& session_id, |
+ const base::Time& new_expiry_time) { |
+ DCHECK(GetMediaTaskRunner()->BelongsToCurrentThread()); |
+ |
+ ui_task_runner_->PostTask(FROM_HERE, base::Bind(session_expiration_update_cb_, |
+ session_id, new_expiry_time)); |
+} |
+ |
+} // namespace media |