[M130 Migration]DRM EME support part 1 38/325038/8
authorMark Toller <mark.toller@samsung.com>
Thu, 15 Aug 2024 07:44:27 +0000 (08:44 +0100)
committerBot Blink <blinkbot@samsung.com>
Mon, 2 Jun 2025 12:13:38 +0000 (12:13 +0000)
* Add DRM EME for HbbTV, including the fix for the LFD issue from the
original patch.

https://archive.tizen.org/gerrit/c/platform/framework/web/chromium-efl/+/316193

Signed-off-by: Mark Toller <mark.toller@samsung.com>
Signed-off-by: Maciej Pietka <m.pietka@samsung.com>
Change-Id: I0b44830be59e35ccb164923e91bb01577334aba3

47 files changed:
components/cast_streaming/renderer/control/playback_command_forwarding_renderer.cc
media/base/cdm_context.cc
media/base/cdm_context.h
media/base/key_systems_impl.cc
media/base/pipeline.h
media/base/pipeline_impl.cc
media/base/pipeline_impl.h
media/base/renderer.h
media/base/renderer_client.h
media/filters/pipeline_controller.cc
media/filters/pipeline_controller.h
media/mojo/clients/mojo_renderer.cc
media/mojo/clients/mojo_renderer.h
media/mojo/clients/mojo_renderer_wrapper.cc
media/mojo/clients/mojo_renderer_wrapper.h
media/mojo/mojom/renderer.mojom
media/mojo/services/mojo_renderer_service.cc
media/mojo/services/mojo_renderer_service.h
third_party/blink/public/platform/web_media_player_client.h
third_party/blink/renderer/core/html/media/html_media_element.cc
third_party/blink/renderer/core/html/media/html_media_element.h
third_party/blink/renderer/platform/media/web_media_player_impl.cc
third_party/blink/renderer/platform/media/web_media_player_impl.h
tizen_src/build/config/BUILD.gn
tizen_src/chromium_impl/content/browser/browser_efl.gni
tizen_src/chromium_impl/content/browser/media/tizen_renderer_impl.cc
tizen_src/chromium_impl/content/browser/media/tizen_renderer_impl.h
tizen_src/chromium_impl/media/base/efl/media_player_util_efl.cc
tizen_src/chromium_impl/media/filters/ieme_drm_bridge.cc
tizen_src/chromium_impl/media/filters/ieme_drm_bridge.h
tizen_src/chromium_impl/media/filters/media_player_bridge_capi.cc
tizen_src/chromium_impl/media/filters/media_player_bridge_capi.h
tizen_src/chromium_impl/media/filters/media_player_bridge_capi_tv.cc
tizen_src/chromium_impl/media/filters/media_player_bridge_capi_tv.h
tizen_src/chromium_impl/media/filters/media_player_esplusplayer.h
tizen_src/chromium_impl/media/filters/media_player_tizen.h
tizen_src/chromium_impl/media/filters/media_player_tizen_client.h
tizen_src/ewk/efl_integration/common/render_messages_ewk.h
tizen_src/ewk/efl_integration/eweb_view.cc
tizen_src/ewk/efl_integration/eweb_view.h
tizen_src/ewk/efl_integration/eweb_view_callbacks.h
tizen_src/ewk/efl_integration/public/ewk_view.cc
tizen_src/ewk/efl_integration/renderer/content_renderer_client_efl.h
tizen_src/ewk/efl_integration/renderer/render_frame_observer_efl.cc
tizen_src/ewk/efl_integration/renderer/render_frame_observer_efl.h
tizen_src/ewk/efl_integration/web_contents_delegate_efl.cc
tizen_src/ewk/efl_integration/web_contents_delegate_efl.h

index 1a1c9d2ec20f18788c63415c0790293f772887ef..aac6573619f58389442c58d996a2315db2277dd6 100644 (file)
@@ -9,6 +9,10 @@
 #include "base/task/bind_post_task.h"
 #include "base/task/sequenced_task_runner.h"
 
+#if BUILDFLAG(IS_TIZEN_TV)
+#include <drmdecrypt/emeCDM/IEME.h>
+#endif
+
 namespace cast_streaming {
 namespace {
 
@@ -104,6 +108,8 @@ class RendererCommandForwarder : public media::mojom::Renderer {
   void SetWallClock(const std::string& wallclock_url,
                     SetWallClockCallback /*callback*/) override {}
   void OnDemuxerFpsGot(int num, int den) override {}
+  void SetDecryptorHandle(uint64_t decryptor) override {}
+  void SetHasEncryptedListenerOrCdm(bool value) override{}
 #endif
 
  private:
index 4bac2e232c10ba17547417b8b06dbc8d1c4072ab..5daa22afaab789940f1a3d7cd676f7f07a5e7202 100644 (file)
@@ -65,4 +65,22 @@ TizenCdmBridge* CdmContext::GetTizenCdmBridge() {
 }
 #endif
 
+#if BUILDFLAG(IS_TIZEN_TV)
+void CdmContext::SetPlayerType(MediaPlayerType player_type) {
+  player_type_ = player_type;
+}
+
+CdmContext::MediaPlayerType CdmContext::GetPlayerType() const {
+  return player_type_;
+}
+
+void CdmContext::SetExternalError(ExternalError error_type) {
+  external_error_ = error_type;
+}
+
+CdmContext::ExternalError CdmContext::GetExternalError() const {
+  return external_error_;
+}
+#endif
+
 }  // namespace media
index 434ceb31bb7f2e1cdebfc7af2b92ca28cc2f8487..8d254b2da788aefbf4239c321ba944a44ac6dac9 100644 (file)
@@ -62,6 +62,27 @@ class MEDIA_EXPORT CdmContext {
     kHardwareContextReset,
   };
 
+  // Types of Media Player
+  enum MediaPlayerType {
+    MEDIA_PLAYER_TYPE_NONE,
+    MEDIA_PLAYER_TYPE_URL,
+    MEDIA_PLAYER_TYPE_MEDIA_SOURCE,
+    MEDIA_PLAYER_TYPE_MEDIA_STREAM,
+#if defined(SAMSUNG_ELEMENTARY_MEDIA_STREAM_SOURCE)
+    MEDIA_PLAYER_TYPE_ELEMENTARY_MEDIA_STREAM_SOURCE,
+#endif  // SAMSUNG_ELEMENTARY_MEDIA_STREAM_SOURCE
+#if defined(TIZEN_VIDEO_HOLE)
+    MEDIA_PLAYER_TYPE_URL_WITH_VIDEO_HOLE,
+    MEDIA_PLAYER_TYPE_WEBRTC_LOCAL_MEDIA_STREAM_WITH_VIDEO_HOLE,
+    MEDIA_PLAYER_TYPE_WEBRTC_MEDIA_STREAM_WITH_VIDEO_HOLE,
+    MEDIA_PLAYER_TYPE_MEDIA_SOURCE_WITH_VIDEO_HOLE,
+#if defined(SAMSUNG_ELEMENTARY_MEDIA_STREAM_SOURCE)
+    MEDIA_PLAYER_TYPE_ELEMENTARY_MEDIA_STREAM_SOURCE_WITH_VIDEO_HOLE,
+#endif  // SAMSUNG_ELEMENTARY_MEDIA_STREAM_SOURCE
+#endif  // TIZEN_VIDEO_HOLE
+    MEDIA_PLAYER_TYPE_UNDECIDED,
+  };
+
   // Callback to notify the occurrence of an Event.
   using EventCB = base::RepeatingCallback<void(Event)>;
 
@@ -133,8 +154,23 @@ class MEDIA_EXPORT CdmContext {
   virtual TizenCdmBridge* GetTizenCdmBridge();
 #endif
 
+#if BUILDFLAG(IS_TIZEN_TV)
+  // Getter and setter for player_type_ used to select remote or local CDM mode
+  void SetPlayerType(MediaPlayerType player_type);
+  MediaPlayerType GetPlayerType() const;
+  enum class ExternalError { NONE, PLAYER_SRC_SET_BEFORE_MEDIA_KEYS };
+  void SetExternalError(ExternalError error_type);
+  ExternalError GetExternalError() const;
+#endif
+
  protected:
   CdmContext();
+
+ private:
+#if BUILDFLAG(IS_TIZEN_TV)
+  MediaPlayerType player_type_{MEDIA_PLAYER_TYPE_NONE};
+  ExternalError external_error_{ExternalError::NONE};
+#endif
 };
 
 // A reference holder to make sure the CdmContext is always valid as long as
index 4fcb11dc4180478dc047c88e5decb44e55301eb3..45034325cbb4723cc7805d95a682bfc538f6ffa5 100644 (file)
@@ -30,6 +30,8 @@ namespace media {
 
 namespace {
 
+const char kTVkeySystem[] = "com.tvkey.drm";
+
 struct MimeTypeToCodecs {
   const char* mime_type;
   SupportedCodecs codecs;
@@ -215,6 +217,10 @@ static bool IsPotentiallySupportedKeySystem(const std::string& key_system) {
   if (key_system == kWidevineKeySystem)
     return true;
 
+  if (key_system == kTVkeySystem) {
+    return true;
+  }
+
   if (key_system == kClearKeyKeySystem) {
     return true;
   }
@@ -378,8 +384,10 @@ void KeySystemsImpl::OnSupportedKeySystemsUpdated(KeySystemInfos key_systems) {
 
   is_updating_ = false;
 
+#if !BUILDFLAG(IS_TIZEN_TV)
   // Clear Key is always supported.
   key_systems.emplace_back(std::make_unique<ClearKeyKeySystemInfo>());
+#endif
 
   ProcessSupportedKeySystems(std::move(key_systems));
 
index 0f8b54cb83fddfccdb6b110f6d2727574b007b0c..abc5cea75097a191c79bb0f7d05442e8cbfc5d99 100644 (file)
 #include "ui/gfx/geometry/rect_f.h"
 #endif
 
+#if BUILDFLAG(IS_TIZEN_TV)
+#include <drmdecrypt/emeCDM/IEME.h>
+#endif
+
 namespace media {
 
 struct register_timeline_cb_info_s {
@@ -105,6 +109,7 @@ class MEDIA_EXPORT Pipeline {
                                       int sync) {}
     virtual void OnMrsUrlChange(const std::string& url) {}
     virtual void OnContentIdChange(const std::string& id) {}
+    virtual void OnInitData(const std::vector<unsigned char>& init_data) = 0;
 #endif
 
     // Executed whenever the presentation duration changes.
@@ -371,6 +376,8 @@ class MEDIA_EXPORT Pipeline {
   virtual void DestroyPlayerSync(base::OnceClosure cb) = 0;
   virtual void SetVideoVisibility(bool visible) = 0;
   virtual void OnDemuxerFpsGot(int num, int den) = 0;
+  virtual void SetDecryptorHandle(eme::eme_decryptor_t decryptor) = 0;
+  virtual void SetHasEncryptedListenerOrCdm(bool value) = 0;
 #endif
 };
 
index e2da207b0111b8f761267dccf24461c60253713c..1311b97099acc06d223637b48766815dd72ef16a 100644 (file)
@@ -34,6 +34,7 @@
 #include "media/base/serial_runner.h"
 #include "media/base/timestamp_constants.h"
 #include "media/base/video_decoder_config.h"
+#include "absl/types/optional.h"
 
 #if BUILDFLAG(IS_WIN)
 #include "media/base/win/mf_feature_checks.h"
@@ -44,6 +45,7 @@
 #include "media/base/logging_override_if_enabled.h"
 #include "media/filters/decrypting_media_resource.h"
 #include "tizen_src/chromium_impl/tizen/tizen_tv_platform.h"
+#include "tizen_src/ewk/efl_integration/common/application_type.h"
 #endif
 
 static const double kDefaultPlaybackRate = 0.0;
@@ -152,6 +154,8 @@ class PipelineImpl::RendererWrapper final : public DemuxerHost,
   void DestroyPlayerSync(base::OnceClosure cb);
   void SetVideoVisibility(bool visible);
   void OnDemuxerFpsGot(int num, int den);
+  void SetDecryptorHandle(eme::eme_decryptor_t decryptor);
+  void SetHasEncryptedListenerOrCdm(bool value);
 #endif
 
   // |enabled_track_ids| contains track ids of enabled audio tracks.
@@ -257,6 +261,7 @@ class PipelineImpl::RendererWrapper final : public DemuxerHost,
   void GetContentIdCB(const std::string& content_id);
   void SyncTimelineCB(bool success);
   void SetWallClockCB(bool success);
+  void OnInitData(const std::vector<unsigned char>& init_data);
 #endif
   void OnBufferingStateChange(BufferingState state,
                               BufferingStateChangeReason reason) final;
@@ -372,6 +377,7 @@ class PipelineImpl::RendererWrapper final : public DemuxerHost,
       base::WaitableEvent::ResetPolicy::AUTOMATIC};
   std::string mime_type_;
   bool transparent_ = false;
+  bool has_encrypted_listener_or_cdm_ = false;
   bool register_time_line_ = false;
   bool unregister_time_line_ = false;
   double speed_data_ = 0.0;
@@ -797,6 +803,24 @@ void PipelineImpl::RendererWrapper::SetCdm(CdmContext* cdm_context,
 
   // If there's already a renderer, set the CDM on the renderer directly.
   if (shared_state_.renderer) {
+#if BUILDFLAG(IS_TIZEN_TV)
+    if (content::IsHbbTV()) {
+      absl::optional<base::UnguessableToken> cdm_id = cdm_context->GetCdmId();
+      if (!cdm_id) {
+        // If there is no cdm_id, then the SetCdm on the renderer (mojo) is
+        // not valid, but for HbbTV Standalone EME we need to store the
+        // context and signal the CDM is attached.
+        LOG(INFO) << "HbbTV : store the context and run OnCdmAttached....";
+        shared_state_.renderer->SetHasEncryptedListenerOrCdm(true);
+        cdm_context_ = cdm_context;
+        std::move(cdm_attached_cb).Run(true);
+        return;
+      }
+
+      LOG(INFO) << "HbbTV with CDM ID, go via shared_state_.renderer->SetCdm()";
+    }
+#endif
+
     shared_state_.renderer->SetCdm(
         cdm_context, base::BindOnce(&RendererWrapper::OnCdmAttached,
                                     weak_factory_.GetWeakPtr(),
@@ -1202,6 +1226,23 @@ void PipelineImpl::RendererWrapper::OnDemuxerFpsGot(int num, int den) {
     shared_state_.renderer->OnDemuxerFpsGot(num, den);
   }
 }
+
+void PipelineImpl::RendererWrapper::SetDecryptorHandle(
+    eme::eme_decryptor_t decryptor) {
+  if (shared_state_.renderer) {
+    shared_state_.renderer->SetDecryptorHandle(decryptor);
+  }
+}
+
+void PipelineImpl::RendererWrapper::SetHasEncryptedListenerOrCdm(bool value) {
+  if (shared_state_.renderer) {
+    shared_state_.renderer->SetHasEncryptedListenerOrCdm(value);
+  } else {
+    // Store the value, as we need to set it before calling Initialize() on the
+    // renderer.
+    has_encrypted_listener_or_cdm_ = value;
+  }
+}
 #endif
 
 void PipelineImpl::RendererWrapper::CreateRendererInternal(
@@ -1575,6 +1616,14 @@ void PipelineImpl::RendererWrapper::OnContentIdChange(const std::string& id) {
       FROM_HERE,
       base::BindOnce(&PipelineImpl::OnContentIdChange, weak_pipeline_, id));
 }
+
+void PipelineImpl::RendererWrapper::OnInitData(
+    const std::vector<unsigned char>& init_data) {
+  DVLOG(2) << __func__;
+  main_task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&PipelineImpl::OnInitData, weak_pipeline_, init_data));
+}
 #endif
 
 void PipelineImpl::RendererWrapper::OnBufferingStateChange(
@@ -2058,6 +2107,10 @@ void PipelineImpl::RendererWrapper::InitializeRenderer(
   // case, and the player needs the mime type to configure itself correctly.
   shared_state_.renderer->SetContentMimeType(mime_type_);
   shared_state_.renderer->SetTransparent(transparent_);
+  LOG(INFO) << "Call SetHasEncryptedListenerOrCdm("
+            << has_encrypted_listener_or_cdm_ << ")";
+  shared_state_.renderer->SetHasEncryptedListenerOrCdm(
+      has_encrypted_listener_or_cdm_);
 #endif
 
   // Initialize Renderer and report timeout UMA.
@@ -2248,8 +2301,9 @@ void PipelineImpl::Start(StartType start_type,
   // kSuspendAfterMetadata, latency is not important and the video may never
   // play. In this case, not creating a default renderer to reduce memory usage.
   std::unique_ptr<Renderer> default_renderer;
-  if (start_type != StartType::kSuspendAfterMetadata)
-    default_renderer = create_renderer_cb_.Run(std::nullopt);
+  if (start_type != StartType::kSuspendAfterMetadata) {
+    default_renderer = create_renderer_cb_.Run(absl::nullopt);
+  }
 
   media_task_runner_->PostTask(
       FROM_HERE,
@@ -2534,6 +2588,16 @@ void PipelineImpl::SetVideoVisibility(bool visible) {
       base::BindOnce(&RendererWrapper::SetVideoVisibility,
                      base::Unretained(renderer_wrapper_.get()), visible));
 }
+
+void PipelineImpl::SetDecryptorHandle(eme::eme_decryptor_t decryptor) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  renderer_wrapper_->SetDecryptorHandle(decryptor);
+}
+
+void PipelineImpl::SetHasEncryptedListenerOrCdm(bool value) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  renderer_wrapper_->SetHasEncryptedListenerOrCdm(value);
+}
 #endif
 
 #if defined(TIZEN_MULTIMEDIA)
@@ -2757,6 +2821,12 @@ double PipelineImpl::GetStartDate() {
   DCHECK(thread_checker_.CalledOnValidThread());
   return renderer_wrapper_->GetStartDate();
 }
+
+void PipelineImpl::OnInitData(const std::vector<unsigned char>& init_data) {
+  DVLOG(2) << __func__;
+  DCHECK(client_);
+  client_->OnInitData(init_data);
+}
 #endif
 
 void PipelineImpl::OnDurationChange(base::TimeDelta duration) {
index 048a1b35a126d7f2072236a34567c07687e66bc9..79ab9db53abc32eb2c1805f98070483b4850728f 100644 (file)
@@ -218,6 +218,9 @@ class MEDIA_EXPORT PipelineImpl : public Pipeline {
   void DestroyPlayerSync(base::OnceClosure cb) override;
   void SetVideoVisibility(bool visible) override;
   void OnDemuxerFpsGot(int num, int den) override;
+  void SetDecryptorHandle(eme::eme_decryptor_t decryptor) override;
+  void OnInitData(const std::vector<unsigned char>& init_data);
+  void SetHasEncryptedListenerOrCdm(bool value) override;
 #endif
   void OnBufferingStateChange(BufferingState state,
                               BufferingStateChangeReason reason);
index 347741f76c4126998f8edf421a454677d29b2bcb..15939be65d28d79179b9769db5d36ae9693dcc2f 100644 (file)
 #include "ui/gfx/geometry/rect_f.h"
 #endif
 
+#if BUILDFLAG(IS_TIZEN_TV)
+#include <drmdecrypt/emeCDM/IEME.h>
+#endif
+
 namespace media {
 
 class CdmContext;
@@ -151,6 +155,8 @@ class MEDIA_EXPORT Renderer {
   virtual void DestroyPlayerSync(base::OnceClosure cb) {}
   virtual void SetVideoVisibility(bool visible) {}
   virtual void OnDemuxerFpsGot(int num, int den) {}
+  virtual void SetDecryptorHandle(eme::eme_decryptor_t decryptor) {}
+  virtual void SetHasEncryptedListenerOrCdm(bool value) {}
 #endif
 
   // Starts rendering from |time|.
index 32343ca60c92d58620987cb7e3389cdbc9160b6e..115a8b5a62ffb714d367fbc924acd5f60fab4fc0 100644 (file)
@@ -51,6 +51,7 @@ class MEDIA_EXPORT RendererClient {
                                     int sync) {}
   virtual void OnMrsUrlChange(const std::string& url) {}
   virtual void OnContentIdChange(const std::string& id) {}
+  virtual void OnInitData(const std::vector<unsigned char>& init_data) {}
 #endif
 
   // Executed when buffering state is changed. |reason| indicates the cause of
index 2d83bfb366e526130ab1557b256aedff8b76867d..6465a0fad4e4ce61a310ca4b54497f2dffeeec58 100644 (file)
@@ -725,5 +725,17 @@ void PipelineController::OnDemuxerFpsGot(int num, int den){
     pipeline_->OnDemuxerFpsGot(num, den);
   }
 }
+
+void PipelineController::SetDecryptorHandle(eme::eme_decryptor_t decryptor) {
+  if (pipeline_) {
+    pipeline_->SetDecryptorHandle(decryptor);
+  }
+}
+
+void PipelineController::SetHasEncryptedListenerOrCdm(bool value) {
+  if (pipeline_) {
+    pipeline_->SetHasEncryptedListenerOrCdm(value);
+  }
+}
 #endif
 }  // namespace media
index 84d6315977cd186ea4b4160682d3073d8b869a06..d8fab86df089e6f733b5b719cb1bea0565d10576 100644 (file)
@@ -200,6 +200,8 @@ class MEDIA_EXPORT PipelineController {
   void SetVideoVisibility(bool visible);
   bool ShouldUseUpstreamArchitecture() const;
   void OnDemuxerFpsGot(int num, int den);
+  void SetDecryptorHandle(eme::eme_decryptor_t decryptor);
+  void SetHasEncryptedListenerOrCdm(bool value);
 #endif
  private:
   // Attempts to make progress from the current state to the target state.
index 41db5a1e6c0b374121d2532428fc17673726cb31..9adb08f2cec632223d924a08c4e2aec9b0bfc83b 100644 (file)
@@ -580,6 +580,27 @@ void MojoRenderer::OnDemuxerFpsGot(int num, int den) {
 
   remote_renderer_->OnDemuxerFpsGot(num, den);
 }
+
+void MojoRenderer::SetDecryptorHandle(eme::eme_decryptor_t decryptor) {
+  DVLOG(2) << __func__;
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
+  DCHECK(remote_renderer_.is_bound());
+
+  remote_renderer_->SetDecryptorHandle(decryptor);
+}
+
+void MojoRenderer::OnInitData(const std::vector<unsigned char>& init_data) {
+  DVLOG(2) << __func__;
+  client_->OnInitData(init_data);
+}
+
+void MojoRenderer::SetHasEncryptedListenerOrCdm(bool value) {
+  DVLOG(2) << __func__;
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
+  DCHECK(remote_renderer_.is_bound());
+
+  remote_renderer_->SetHasEncryptedListenerOrCdm(value);
+}
 #endif
 
 void MojoRenderer::OnWaiting(WaitingReason reason) {
index 37703350090b9ac3e91be6b4e95331b0ea25e138..2cbb49f03b7649b3152861600f57bc5f3e3dce38 100644 (file)
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/remote.h"
 
+#if BUILDFLAG(IS_TIZEN_TV)
+#include <drmdecrypt/emeCDM/IEME.h>
+#endif
+
 namespace media {
 
 class MediaResource;
@@ -110,6 +114,9 @@ class MojoRenderer : public Renderer, public mojom::RendererClient {
   void DestroyPlayerSync(base::OnceClosure cb) override;
   void SetVideoVisibility(bool visible) override;
   void OnDemuxerFpsGot(int num, int den) override;
+  void SetDecryptorHandle(eme::eme_decryptor_t decryptor) override;
+  void OnInitData(const std::vector<unsigned char>& init_data) override;
+  void SetHasEncryptedListenerOrCdm(bool value) override;
 #endif
 
  private:
index 12aeb86c25e75bc5a5af1b09771cbfe5dba71b63..527200638e999609bab55e680fbb965545c45ceb 100644 (file)
@@ -248,6 +248,18 @@ void MojoRendererWrapper::OnDemuxerFpsGot(int num, int den) {
   if (mojo_renderer_)
     mojo_renderer_->OnDemuxerFpsGot(num, den);
 }
+
+void MojoRendererWrapper::SetDecryptorHandle(eme::eme_decryptor_t decryptor) {
+  if (mojo_renderer_) {
+    mojo_renderer_->SetDecryptorHandle(decryptor);
+  }
+}
+
+void MojoRendererWrapper::SetHasEncryptedListenerOrCdm(bool value) {
+  if (mojo_renderer_) {
+    mojo_renderer_->SetHasEncryptedListenerOrCdm(value);
+  }
+}
 #endif
 
 }  // namespace media
index 8bdb34561099e92864b669c1d6ad28a14a13cfd8..5b26180bbbaca4f5ba56cfa58a1ebcdb16fe376b 100644 (file)
 #include "media/base/renderer.h"
 #include "media/mojo/clients/mojo_renderer.h"
 
+#if BUILDFLAG(IS_TIZEN_TV)
+#include <drmdecrypt/emeCDM/IEME.h>
+#endif
+
 namespace media {
 
 // Simple wrapper around a MojoRenderer.
@@ -91,6 +95,8 @@ class MojoRendererWrapper : public Renderer {
   void DestroyPlayerSync(base::OnceClosure cb) override;
   void SetVideoVisibility(bool visible) override;
   void OnDemuxerFpsGot(int num, int den) override;
+  void SetDecryptorHandle(eme::eme_decryptor_t decryptor) override;
+  void SetHasEncryptedListenerOrCdm(bool value) override;
 #endif
 
   base::TimeDelta GetMediaTime() override;
index f024e1719ee3c9f0c743fd8e773da4f91e22fa93..274b33f77c781dd7d7d49fa64bc78c20c76851d6 100644 (file)
@@ -151,6 +151,12 @@ interface Renderer {
 
   [EnableIf=is_tizen_tv]
   OnDemuxerFpsGot(int32 num, int32 den);
+
+  [EnableIf=is_tizen_tv]
+  SetDecryptorHandle(uint64 decryptor);
+
+  [EnableIf=is_tizen_tv]
+  SetHasEncryptedListenerOrCdm(bool value);
 };
 
 // A Mojo equivalent of media::RendererClient. See media/mojo/README.md
@@ -219,4 +225,7 @@ interface RendererClient {
 
   [EnableIf=is_tizen_tv]
   OnPlayerStarted(bool play_started);
+
+  [EnableIf=is_tizen_tv]
+  OnInitData(array<uint8> init_data);
 };
index e524bdaea7623577014098c6cc9f84786dd15e53..12ba592ee1ac126e3aee7f8d6147436acd256676 100644 (file)
@@ -451,6 +451,28 @@ void MojoRendererService::OnDemuxerFpsGot(int num, int den) {
   if (renderer_)
     renderer_->OnDemuxerFpsGot(num, den);
 }
+
+void MojoRendererService::SetDecryptorHandle(uint64_t decryptor) {
+  DVLOG(2) << __func__;
+
+  if (renderer_) {
+    renderer_->SetDecryptorHandle(decryptor);
+  }
+}
+
+void MojoRendererService::OnInitData(
+    const std::vector<unsigned char>& init_data) {
+  DVLOG(3) << __func__;
+  client_->OnInitData(init_data);
+}
+
+void MojoRendererService::SetHasEncryptedListenerOrCdm(bool value) {
+  DVLOG(2) << __func__;
+
+  if (renderer_) {
+    renderer_->SetHasEncryptedListenerOrCdm(value);
+  }
+}
 #endif
 
 void MojoRendererService::OnBufferingStateChange(
index 38840deaabcc62949ccbfabc84c49db195bbfb41..562519061c834f70b49002271504033a73b6bd02 100644 (file)
@@ -118,6 +118,9 @@ class MEDIA_MOJO_EXPORT MojoRendererService final : public mojom::Renderer,
   void DestroyPlayerSync(base::OnceClosure destroy_cb) final;
   void SetVideoVisibility(bool visible) final;
   void OnDemuxerFpsGot(int num, int den) final;
+  void SetDecryptorHandle(uint64_t decryptor) final;
+  void OnInitData(const std::vector<unsigned char>& init_data) final;
+  void SetHasEncryptedListenerOrCdm(bool value) final;
 #endif
 
  private:
index 1d5c2e025c9a6c8c66cf6109da7e0f6834337c26..eadbd613273fecaa7e9dc5958c012154e07499d4 100644 (file)
@@ -287,6 +287,7 @@ class BLINK_PLATFORM_EXPORT WebMediaPlayerClient {
       media::register_timeline_cb_info_s info) = 0;
   virtual void OnMrsUrlChange(const std::string& url) = 0;
   virtual void OnContentIdChange(const std::string& id) = 0;
+  virtual bool HasEncryptedListener() const = 0;
 #endif
   // Returns the DOMNodeId of the DOM element hosting this media player.
   virtual int GetElementId() = 0;
index 02abe527de83abaab79b86acb00b88d3d65b1e54..5a86a7b9e55779d00939206bdf4469beeeac9d47 100644 (file)
@@ -2335,6 +2335,7 @@ void HTMLMediaElement::SetReadyState(ReadyState state) {
   // potentiallyPlaying() uses it
   bool was_potentially_playing = PotentiallyPlaying();
 
+  ReadyState old_max_state = ready_state_maximum_;
   ReadyState old_state = ready_state_;
   ReadyState new_state = state;
 
@@ -2446,7 +2447,12 @@ void HTMLMediaElement::SetReadyState(ReadyState state) {
 
     if (IsHTMLVideoElement())
       ScheduleNamedEvent(event_type_names::kResize);
-    ScheduleNamedEvent(event_type_names::kLoadedmetadata);
+
+    #if BUILDFLAG(IS_TIZEN_TV)
+    if ((!IsHbbTV()) ||
+      (ready_state_ > kHaveMetadata && old_max_state <= kHaveMetadata))
+    #endif
+      ScheduleNamedEvent(event_type_names::kLoadedmetadata);
 
     bool jumped = false;
     if (default_playback_start_position_ > 0) {
@@ -5178,6 +5184,12 @@ void HTMLMediaElement::SuspendMediaByHost(bool suspend) {
 #endif  // TIZEN_MULTIMEDIA
 }
 
+#if BUILDFLAG(IS_TIZEN_TV)
+bool HTMLMediaElement::HasEncryptedListener() const {
+  return HasEventListeners(event_type_names::kEncrypted);
+}
+#endif
+
 bool HTMLMediaElement::HasPendingActivity() const {
   const auto result = HasPendingActivityInternal();
   // TODO(dalecurtis): Replace c-style casts in followup patch.
index 0ce4729bb00befc5c621a05d1996f840a297c4c4..c83cb58000541355a4314f369fa9b4beb4541fcd 100644 (file)
@@ -440,6 +440,7 @@ class CORE_EXPORT HTMLMediaElement
       media::register_timeline_cb_info_s info) override;
   void OnMrsUrlChange(const std::string& url) override;
   void OnContentIdChange(const std::string& id) override;
+  bool HasEncryptedListener() const override;
 #endif
   void SuspendMediaByHost(bool suspend) override;
 
index eb0f5131914d466feccb5cfecb3808cb85c9e7fc..4c7e29f5bf3b88644324bf7a9f4a3e0081729858 100644 (file)
@@ -591,6 +591,12 @@ WebMediaPlayerImpl::WebMediaPlayerImpl(
   // it's not interested in recording these events.
   playback_events_recorder_.reset_on_disconnect();
 
+#if BUILDFLAG(IS_TIZEN_TV)
+  if (content::IsHbbTV()) {
+    SetDecryptorCb();
+  }
+#endif
+
 #if defined(TIZEN_VIDEO_HOLE)
   if (is_video_hole_) {
     vfc_task_runner_->PostTask(
@@ -971,6 +977,55 @@ void WebMediaPlayerImpl::DoLoad(LoadType load_type,
   demuxer_manager_->SetLoadedUrl(GURL(url));
   load_type_ = load_type;
 
+#if defined(TIZEN_VIDEO_HOLE)
+  switch (load_type_) {
+    case kLoadTypeMediaSource:
+      LOG(ERROR)
+          << "player_type_ = MEDIA_PLAYER_TYPE_MEDIA_SOURCE_WITH_VIDEO_HOLE";
+      player_type_ =
+          media::CdmContext::MEDIA_PLAYER_TYPE_MEDIA_SOURCE_WITH_VIDEO_HOLE;
+      break;
+    case kLoadTypeURL:
+      LOG(ERROR) << "player_type_ = MEDIA_PLAYER_TYPE_URL_WITH_VIDEO_HOLE";
+      player_type_ = media::CdmContext::MEDIA_PLAYER_TYPE_URL_WITH_VIDEO_HOLE;
+      break;
+#if defined(SAMSUNG_ELEMENTARY_MEDIA_STREAM_SOURCE)
+    case kLoadTypeSamsungElementaryMediaStreamSource:
+      LOG(ERROR)
+          << "player_type_ = "
+             "MEDIA_PLAYER_TYPE_ELEMENTARY_MEDIA_STREAM_SOURCE_WITH_VIDEO_HOLE";
+      player_type_ = media::CdmContext::
+          MEDIA_PLAYER_TYPE_ELEMENTARY_MEDIA_STREAM_SOURCE_WITH_VIDEO_HOLE;
+      break;
+#endif
+    default:
+      LOG(ERROR) << "Unsupported load type...";
+      break;
+  }
+#else
+  switch (load_type_) {
+    case kLoadTypeMediaSource:
+      LOG(ERROR) << "player_type_ = MEDIA_PLAYER_TYPE_MEDIA_SOURCE";
+      player_type_ = media::CdmContext::MEDIA_PLAYER_TYPE_MEDIA_SOURCE;
+      break;
+    case kLoadTypeURL:
+      LOG(ERROR) << "player_type_ = MEDIA_PLAYER_TYPE_URL";
+      player_type_ = media::CdmContext::MEDIA_PLAYER_TYPE_URL;
+      break;
+#if defined(SAMSUNG_ELEMENTARY_MEDIA_STREAM_SOURCE)
+    case kLoadTypeSamsungElementaryMediaStreamSource:
+      LOG(ERROR)
+          << "player_type_ = MEDIA_PLAYER_TYPE_ELEMENTARY_MEDIA_STREAM_SOURCE";
+      player_type_ =
+          media::CdmContext::MEDIA_PLAYER_TYPE_ELEMENTARY_MEDIA_STREAM_SOURCE;
+      break;
+#endif
+    default:
+      LOG(ERROR) << "Unsupported load type...";
+      break;
+  }
+#endif
+
 #if BUILDFLAG(IS_TIZEN_TV)
   // |MediaUrlDemuxer| will be created if |IsHbbTV| function returns true. In
   // this case, |demuxer_override_| is not null. (i.e, |demuxer_override_| is
@@ -1014,6 +1069,17 @@ void WebMediaPlayerImpl::DoLoad(LoadType load_type,
           : media::mojom::MediaURLScheme::kUnknown,
       media::mojom::MediaStreamType::kNone);
 
+#if BUILDFLAG(IS_TIZEN_TV)
+  if (content::IsHbbTV()) {
+    SetCDMPlayerType();
+    if (client_->HasEncryptedListener()) {
+      had_encrypted_listener_ = true;
+    }
+    pipeline_controller_->SetHasEncryptedListenerOrCdm(
+        HasEncryptedListenerOrCdm());
+  }
+#endif
+
   // If a demuxer override was specified or a Media Source pipeline will be
   // used, the pipeline can start immediately.
   if (demuxer_manager_->HasDemuxerOverride() ||
@@ -1759,7 +1825,14 @@ void WebMediaPlayerImpl::SetContentDecryptionModule(
 
   SetCdmInternal(cdm);
 
+  pending_cdm_context_ref_ =
+      blink::ToWebContentDecryptionModuleImpl(cdm)->GetCdmContextRef();
+
 #if BUILDFLAG(IS_TIZEN_TV)
+  if (content::IsHbbTV()) {
+    SetDecryptorCb();
+  }
+
   // Finish set media key directly
   // Fix issue : AD insert case in EME stream, no cdm_id in this case and will
   // return failed here. And then JS error occurred.
@@ -1905,6 +1978,13 @@ void WebMediaPlayerImpl::SetCdmInternal(WebContentDecryptionModule* cdm) {
   // Keep the reference to the CDM, as it shouldn't be destroyed until
   // after the pipeline is done with the `cdm_context`.
   pending_cdm_context_ref_ = std::move(cdm_context_ref);
+
+#if BUILDFLAG(IS_TIZEN_TV)
+  if (content::IsHbbTV()) {
+    SetCDMPlayerType();
+  }
+#endif
+
   pipeline_controller_->SetCdm(
       cdm_context,
       base::BindOnce(&WebMediaPlayerImpl::OnCdmAttached, weak_this_));
@@ -1922,6 +2002,11 @@ void WebMediaPlayerImpl::OnCdmAttached(bool success) {
   if (success) {
     // This will release the previously attached CDM (if any).
     cdm_context_ref_ = std::move(pending_cdm_context_ref_);
+#if BUILDFLAG(IS_TIZEN_TV)
+    if (content::IsHbbTV()) {
+      SetCDMPlayerType();
+    }
+#endif
     if (set_cdm_result_) {
       set_cdm_result_->Complete();
       set_cdm_result_.reset();
@@ -2645,6 +2730,46 @@ int32_t WebMediaPlayerImpl::GetVideoId() const {
   return pipeline_controller_->GetVideoId();
 }
 
+bool WebMediaPlayerImpl::IsNotValidCDMPlayer() const {
+  if (!cdm_context_ref_ && !pending_cdm_context_ref_) {
+    return false;
+  }
+
+  auto cdm_context_type =
+      cdm_context_ref_
+          ? cdm_context_ref_->GetCdmContext()->GetPlayerType()
+          : pending_cdm_context_ref_->GetCdmContext()->GetPlayerType();
+
+  // If player type is set to none, change is valid
+  if (cdm_context_type == media::CdmContext::MEDIA_PLAYER_TYPE_NONE) {
+    return false;
+  }
+
+  // If default type is set in cmd and player is URL type,
+  // then change is not valid.
+  if (cdm_context_type == media::CdmContext::MEDIA_PLAYER_TYPE_UNDECIDED) {
+    bool is_url_player =
+#ifdef TIZEN_VIDEO_HOLE
+        (player_type_ ==
+              media::CdmContext::MEDIA_PLAYER_TYPE_URL_WITH_VIDEO_HOLE) ||
+#endif // TIZEN_VIDEO_HOLE
+        (player_type_ == media::CdmContext::MEDIA_PLAYER_TYPE_URL);
+    if (is_url_player) {
+      return true;
+    }
+
+    return false;
+  }
+
+  // If other type than choosen, default or none was already
+  // set, then change is not valid.
+  if (cdm_context_type != player_type_) {
+    return true;
+  }
+
+  return false;
+}
+
 void WebMediaPlayerImpl::SetParentalRatingResult(bool is_pass) {
   pipeline_controller_->SetParentalRatingResult(is_pass);
 }
@@ -2843,6 +2968,11 @@ double WebMediaPlayerImpl::GetStartDate() const {
   return pipeline_controller_->GetStartDate();
 }
 
+void WebMediaPlayerImpl::OnInitData(
+    const std::vector<unsigned char>& init_data) {
+  OnEncryptedMediaInitData(media::EmeInitDataType::CENC, init_data);
+}
+
 void WebMediaPlayerImpl::SetVideoVisibility(bool visible) {
   return pipeline_controller_->SetVideoVisibility(visible);
 }
@@ -4962,5 +5092,76 @@ PlatformPlayerType WebMediaPlayerImpl::GetCurrentPlatformPlayerType() {
     }
   }
 }
+
+bool WebMediaPlayerImpl::HasEncryptedListenerOrCdm() const {
+  return client_->HasEncryptedListener() || cdm_context_ref_ ||
+         pending_cdm_context_ref_;
+}
+
+void WebMediaPlayerImpl::SetCDMPlayerType() const {
+  if (IsNotValidCDMPlayer()) {
+    LOG(ERROR) << "player type mismatch";
+    pipeline_controller_->SetDecryptorHandle(0);
+    return;
+  }
+
+  if (cdm_context_ref_) {
+    cdm_context_ref_->GetCdmContext()->SetPlayerType(player_type_);
+  } else if (pending_cdm_context_ref_) {
+    pending_cdm_context_ref_->GetCdmContext()->SetPlayerType(player_type_);
+  }
+}
+
+void WebMediaPlayerImpl::SetDecryptorHandle() const {
+  if (cdm_context_ref_ && cdm_context_ref_->GetCdmContext()->GetDecryptor()) {
+    auto decryptor_handle =
+        cdm_context_ref_->GetCdmContext()->GetDecryptor()->GetDecryptorHandle();
+    LOG(INFO) << "Get decryptor handle ["
+              << reinterpret_cast<void*>(decryptor_handle)
+              << "] from cdm context";
+    pipeline_controller_->SetDecryptorHandle(decryptor_handle);
+  } else if (pending_cdm_context_ref_ &&
+             pending_cdm_context_ref_->GetCdmContext()->GetDecryptor()) {
+    auto decryptor_handle = pending_cdm_context_ref_->GetCdmContext()
+                                ->GetDecryptor()
+                                ->GetDecryptorHandle();
+    LOG(INFO) << "Get decryptor handle ["
+              << reinterpret_cast<void*>(decryptor_handle)
+              << "] from cdm context";
+    pipeline_controller_->SetDecryptorHandle(decryptor_handle);
+  }
+}
+
+void WebMediaPlayerImpl::OnCdmContextEvent(media::CdmContext::Event event) {
+  LOG(INFO) << "New key notified";
+
+  if (event != media::CdmContext::Event::kHasAdditionalUsableKey) {
+    return;
+  }
+
+  main_task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&WebMediaPlayerImpl::SetDecryptorHandle, weak_this_));
+}
+
+void WebMediaPlayerImpl::SetDecryptorCb() {
+  if (cdm_event_cb_registration_) {
+    LOG(INFO) << "Already registered - destruction should unregister";
+  }
+  if (cdm_context_ref_) {
+    LOG(INFO) << "Register on cdm_context_ref_";
+    cdm_event_cb_registration_ =
+        cdm_context_ref_->GetCdmContext()->RegisterEventCB(
+            base::BindRepeating(&WebMediaPlayerImpl::OnCdmContextEvent,
+                                weak_factory_.GetWeakPtr()));
+  } else if (pending_cdm_context_ref_) {
+    LOG(INFO) << "Register on pending_cdm_context_ref_";
+    cdm_event_cb_registration_ =
+        pending_cdm_context_ref_->GetCdmContext()->RegisterEventCB(
+            base::BindRepeating(&WebMediaPlayerImpl::OnCdmContextEvent,
+                                weak_factory_.GetWeakPtr()));
+  }
+}
 #endif
+
 }  // namespace blink
index 0e4be86141f8712f2947516642de577b9bd41412..8b9ac0a56f4efcda1dcb114edbb7a1767cfd1190 100644 (file)
@@ -25,7 +25,9 @@
 #include "base/timer/elapsed_timer.h"
 #include "base/timer/timer.h"
 #include "build/build_config.h"
+#include "media/base/callback_registry.h"
 #include "media/base/cdm_config.h"
+#include "media/base/cdm_context.h"
 #include "media/base/data_source.h"
 #include "media/base/demuxer.h"
 #include "media/base/eme_constants.h"
@@ -281,6 +283,7 @@ class PLATFORM_EXPORT WebMediaPlayerImpl
   void OnRegisterTimelineCbInfo(media::register_timeline_cb_info_s info);
   void OnMrsUrlChange(const std::string& url);
   void OnContentIdChange(const std::string& id);
+  void OnInitData(const std::vector<unsigned char>& init_data) override;
 #endif
 
   // Shared between the WebMediaPlayer and DemuxerManager::Client interfaces.
@@ -498,6 +501,13 @@ class PLATFORM_EXPORT WebMediaPlayerImpl
   void SetActiveAudioTrack(int index) override;
   void SetActiveVideoTrack(int index) override;
   void SetPreferTextLanguage(const std::string& lang) override;
+  bool HasEncryptedListenerOrCdm() const;
+  void SetCDMPlayerType() const;
+  void SetDecryptorHandle() const;
+  // Callback for the CDM to notify |this|.
+  void OnCdmContextEvent(media::CdmContext::Event event);
+  bool IsNotValidCDMPlayer() const;
+  void SetHasEncryptedListenerOrCdm(bool value);
 #endif
   void OnWaiting(media::WaitingReason reason) override;
   void OnAudioConfigChange(const media::AudioDecoderConfig& config) override;
@@ -627,6 +637,8 @@ class PLATFORM_EXPORT WebMediaPlayerImpl
 
 #if BUILDFLAG(IS_TIZEN_TV)
   bool IsSyncDestroyPlayerNeeded();
+  void SetCdm(media::CdmContext* cdm_reference);
+  void SetDecryptorCb();
 #endif
 
   // Sets CdmContext from |cdm| on the pipeline and calls OnCdmAttached()
@@ -1238,6 +1250,8 @@ class PLATFORM_EXPORT WebMediaPlayerImpl
 
   bool was_suspended_for_frame_closed_ = false;
 
+  media::CdmContext::MediaPlayerType player_type_;
+
 #if defined(TIZEN_MULTIMEDIA)
   bool was_suspended_by_player_ = false;
   bool suspend_by_multi_reload_ = false;
@@ -1246,6 +1260,7 @@ class PLATFORM_EXPORT WebMediaPlayerImpl
   bool is_live_stream_ = false;
   base::TimeDelta min_seekable_time_;
   base::TimeDelta max_seekable_time_;
+  bool had_encrypted_listener_{};
 #endif
 
 #if BUILDFLAG(IS_TIZEN_TV)
@@ -1289,6 +1304,9 @@ class PLATFORM_EXPORT WebMediaPlayerImpl
   uint32_t session_id_ = 0;
 #endif
 
+  // To keep the CdmContext event callback registered.
+  std::unique_ptr<media::CallbackRegistration> cdm_event_cb_registration_;
+
   base::WeakPtr<WebMediaPlayerImpl> weak_this_;
   base::WeakPtrFactory<WebMediaPlayerImpl> weak_factory_{this};
 };
index ce20950821a41e3e780425f26a06cf953fe82ae2..2dd9327e95fb10f4d667804f71b4f533ace39c72 100644 (file)
@@ -72,6 +72,9 @@ config("tizen_feature_flags") {
         "TIZEN_MULTIMEDIA_WEBM_SUPPORT",
       ]
       if (tizen_version >= 60) {
+        defines += [
+          "TIZEN_MULTIMEDIA_DRMMANAGER_SUPPORT",
+        ]
         if (tizen_tv_riscv64) {
           defines += [ "TIZEN_TV_RISCV64" ]
         }
index 659d4b1ed54db0fd480e136d4bd847e6c98513b4..72104e6bc41d551fc8877645491acda54cdf753f 100644 (file)
@@ -50,6 +50,10 @@ if (!use_wayland) {
     "//tizen_src/build:ecore-x",
     "//tizen_src/build:libecore-x",
   ]
+
+  if (tizen_product_tv) {
+    external_content_browser_efl_configs += [ "//tizen_src/build:drmdecrypt" ]
+  }
 }
 
 if (tizen_web_speech_recognition) {
index 36960cd0a1b97ccdcd8bb382a98eaafd466d7053..f14b0e7246e8e7b2697336548a663af9c603f450 100644 (file)
@@ -298,6 +298,9 @@ void TizenRendererImpl::Initialize(media::MediaResource* media_resource,
   // Initialize and Prepare early when resource type is URL.
   if (media_resource_->GetType() == media::MediaResource::Type::KUrl) {
     SetPlayerInitialize();
+#if BUILDFLAG(IS_TIZEN_TV)
+    media_player_->SetHasEncryptedListenerOrCdm(has_encrypted_listener_or_cdm_);
+#endif
     SetPlayerPrepare();
   }
 #if BUILDFLAG(IS_TIZEN_TV)
@@ -890,6 +893,21 @@ void TizenRendererImpl::SetVideoVisibility(bool visible) {
   }
 }
 
+#if BUILDFLAG(IS_TIZEN_TV)
+void TizenRendererImpl::SetDecryptorHandle(eme::eme_decryptor_t decryptor) {
+  if (media_player_) {
+    media_player_->SetDecryptorHandle(decryptor);
+  }
+}
+
+void TizenRendererImpl::SetHasEncryptedListenerOrCdm(bool value) {
+  has_encrypted_listener_or_cdm_ = value;
+  if (media_player_) {
+    media_player_->SetHasEncryptedListenerOrCdm(value);
+  }
+}
+#endif
+
 bool TizenRendererImpl::PlaybackNotificationEnabled() {
   content::WebContents* web_contents = GetWebContents();
   if (!web_contents) {
@@ -1026,7 +1044,14 @@ void TizenRendererImpl::GetFpsInfo(int& num, int& den){
   num = fps_num_;
   den = fps_den_;
 }
-#endif
+
+void TizenRendererImpl::OnInitData(
+    const std::vector<unsigned char>& init_data) {
+  if (client_) {
+    client_->OnInitData(init_data);
+  }
+}
+#endif  // BUILDFLAG(IS_TIZEN_TV)
 
 void TizenRendererImpl::OnSeekableTimeChange(base::TimeDelta min_time,
                                              base::TimeDelta max_time,
index fdf413b510bf8ff71a156bad50bd588f5ee0ab11..705c5118126fc44e8ad2eeadceccae30169d1064 100644 (file)
 #include "tizen_src/chromium_impl/ui/gfx/tbm_buffer_handle_inter_process.h"
 #endif
 
+#if BUILDFLAG(IS_TIZEN_TV)
+#include <drmdecrypt/emeCDM/IEME.h>
+#endif
+
 namespace base {
 class SingleThreadTaskRunner;
 }
@@ -150,6 +154,7 @@ class CONTENT_EXPORT TizenRendererImpl
   void Show() override;
   void Hide() override;
   void GetFpsInfo(int& num, int& den) override;
+  void OnInitData(const std::vector<unsigned char>& init_data) override;
 #endif
 
 #if defined(TIZEN_TBM_SUPPORT)
@@ -200,6 +205,8 @@ class CONTENT_EXPORT TizenRendererImpl
   void DestroyPlayerSync(base::OnceClosure destroy_cb) override;
   void SetVideoVisibility(bool visible) override;
   void OnDemuxerFpsGot(int num, int den) override;
+  void SetDecryptorHandle(eme::eme_decryptor_t decryptor) override;
+  void SetHasEncryptedListenerOrCdm(bool value) override;
 #endif
 
  private:
@@ -295,6 +302,10 @@ class CONTENT_EXPORT TizenRendererImpl
   // initialize / prepare.
   std::string mime_type_ = "";
   bool is_player_can_start_ = true;
+  // Stores the has_encrypted_listener_or_cdm_ .  Required for URL streams which
+  // are DASH content, so that we can set it to the media_player_ before calling
+  // initialize / prepare.
+  bool has_encrypted_listener_or_cdm_ = false;
   bool transparent_ = false;
   // one video + one transparent case, should disable mixer mode
   // otherwise multi video will enter mixer mode and cause error
index f9521b5b01c53c922f799564eb59b61a7b16c1af..95ad6c47fe6a2c078126bba221bccff78938f041 100644 (file)
@@ -383,6 +383,7 @@ int PlayerGetPlayPosition(player_h player, base::TimeDelta& position) {
 #if BUILDFLAG(IS_TIZEN_TV)
   int64_t player_position = 0;
   const int ret_val = player_get_play_position_ex(player, &player_position);
+  LOG(INFO) << "Current play position " << player_position;
 #else
   int player_position = 0;
   const int ret_val = player_get_play_position(player, &player_position);
@@ -397,6 +398,7 @@ int PlayerSetPlayPosition(player_h player,
                           player_seek_completed_cb callback,
                           void* user_data) {
 #if BUILDFLAG(IS_TIZEN_TV)
+  LOG(INFO) << "Set play position " << position.InMilliseconds();
   return player_set_play_position_ex(player, position.InMilliseconds(),
                                      accurate, callback, user_data);
 #else
index 136bde13113eab1cc16e9fca7c101cca3a98cd45..764ecda4c00e000912ddd80a8b445c181341229e 100644 (file)
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/trace_event/trace_event.h"
 #include "content/public/common/content_switches.h"
 #include "media/base/decoder_buffer.h"
 #include "tizen_src/platform_api_wrapper/platform_api_wrapper.h"
+#include "tizen_src/ewk/efl_integration/common/application_type.h"
 #include "url/gurl.h"
 
 namespace media {
@@ -253,20 +255,8 @@ IEMEDrmBridge::IEMEDrmBridge(
       privacy_mode_(privacy_mode),
       server_certificate_registered_(false),
       weak_factory_(this) {
-  LOG(INFO) << "Constructing DRM for " << key_system_
-            << ", privacy mode: " << privacy_mode
-            << ", this:" << (void*)this;
-  single_process_mode_ = base::CommandLine::ForCurrentProcess()->HasSwitch(
-      switches::kSingleProcess);
-  LOG(INFO) << "single process mode:" << std::boolalpha << single_process_mode_;
-  // TODO(mdebski): what is privacy_mode?
-#if defined(PLATFORM_API_WRAPPER)
-  cdm_.reset(
-      platform_api_wrapper::createIEME(this, key_system_.c_str(), privacy_mode_));
-#else
-  cdm_.reset(eme::IEME::create(this, key_system_, privacy_mode_));
-#endif
-  CHECK(cdm_.get());
+  LOG(INFO) << "Constructing DRM bridge " << this << " for key system "
+            << key_system;
 }
 
 IEMEDrmBridge::~IEMEDrmBridge() {
@@ -285,32 +275,106 @@ ScopedIEMEDrmBridgePtr IEMEDrmBridge::Create(
     const SessionKeysChangeCB& session_keys_change_cb,
     const SessionExpirationUpdateCB& session_expiration_update_cb,
     bool privacy_mode) {
-  LOG(INFO) << "Creating DRM  bridge for key system: " << key_system;
+  LOG(INFO) << "Creating DRM bridge for key system: " << key_system;
   ScopedIEMEDrmBridgePtr ieme_drm_bridge;
 
   ieme_drm_bridge.reset(new IEMEDrmBridge(
       key_system, session_message_cb, session_closed_cb,
       session_keys_change_cb, session_expiration_update_cb, privacy_mode));
 
-  if (ieme_drm_bridge->cdm_ == nullptr)
-    ieme_drm_bridge.reset();
-
   return ieme_drm_bridge;
 }
 
 // static
 ScopedIEMEDrmBridgePtr IEMEDrmBridge::CreateWithoutSessionSupport(
     const std::string& key_system) {
+  LOG(INFO) << "CreateWithoutSessionSupport";
   return IEMEDrmBridge::Create(key_system, SessionMessageCB(),
                                SessionClosedCB(), SessionKeysChangeCB(),
                                SessionExpirationUpdateCB(), false);
 }
 
+bool IEMEDrmBridge::VerifyStandaloneEmePreconditions(CdmPromise& promise,
+                                                     const char* method_name) {
+  auto RejectPromise = [&promise, method_name](const char* message) {
+    std::string error_str("Unable to call ");
+    error_str += method_name;
+    error_str += message;
+    LOG(WARNING) << error_str;
+    promise.reject(CdmPromise::Exception::INVALID_STATE_ERROR, 0, error_str);
+  };
+
+  if (GetExternalError() ==
+      CdmContext::ExternalError::PLAYER_SRC_SET_BEFORE_MEDIA_KEYS) {
+    RejectPromise(" as MediaKeys was set after assigning media element source");
+    return false;
+  } else if (GetPlayerType() == MEDIA_PLAYER_TYPE_NONE) {
+    // We can't reject here for HbbTV + EME standalone case, because the
+    // MSE + EME case can request the keys before the player type can be set.
+    SetPlayerType(MEDIA_PLAYER_TYPE_UNDECIDED);
+    return true;
+  }
+
+  return true;
+}
+
+void IEMEDrmBridge::CreateIEME() {
+  // Up to now IEME instance was created in IEMEDrmBridge's constructor.
+  // This is now delayed to additionally support EME + DASH scenario in HbbTV.
+  // Previously IEMEDrmBridge was used only for EME + MSE case. It requires
+  // IEME instanced in the default model (local) as the decryption calls are
+  // invoked in Chromium.
+  // EME + DASH requires IEME in the remote model as the decryption is performed
+  // in CAPI Player process.
+  // However HbbTV still can use EME + MSE. Delaying IEME creation gives more
+  // wiggle room to detect which EME use case HbbTV application attempts.
+  // This is currently based on the source type the related media element was
+  // set with. If MediaSource was set we need default model. If URL was set we
+  // need remote model.
+  // Without the delay we would need to know the source type when MediaKeys
+  // is created (impossible as to know the source type MediaKeys needs to
+  // be already assigned to media element). With the delay we require it much
+  // later - during MediaKeySession's generateRequest() call.
+
+  if (cdm_) {
+    return;
+  }
+
+  single_process_mode_ = base::CommandLine::ForCurrentProcess()->HasSwitch(
+      switches::kSingleProcess);
+
+  // remote model for standalone EME in HbbTV
+  bool is_url_player =
+#ifdef TIZEN_VIDEO_HOLE
+        (GetPlayerType() == MEDIA_PLAYER_TYPE_URL_WITH_VIDEO_HOLE) ||
+#endif
+        (GetPlayerType() == MEDIA_PLAYER_TYPE_URL);
+
+  auto ieme_model = (content::IsHbbTV() && is_url_player)
+                        ? eme::CDM_MODEL::E_CDM_MODEL_REMOTE
+                        : eme::CDM_MODEL::E_CDM_MODEL_DEFAULT;
+
+  LOG(INFO) << "Creating IEME, key system: " << key_system_
+            << ", player type: " << GetPlayerType()
+            << ", IEME model: " << ieme_model
+            << ", single process mode:" << std::boolalpha
+            << single_process_mode_;
+
+  cdm_.reset(eme::IEME::create(this, key_system_, false, ieme_model));
+  CHECK(cdm_.get());
+}
+
 void IEMEDrmBridge::SetServerCertificate(
     const std::vector<uint8_t>& certificate,
     std::unique_ptr<media::SimpleCdmPromise> promise) {
   LOG(INFO) << "Setting server certificate";
   CHECK(!certificate.empty());
+  if (content::IsHbbTV() && !VerifyStandaloneEmePreconditions(
+                                *promise.get(), "setServerCeritficate")) {
+    return;
+  }
+
+  CreateIEME();
 
   const auto result_status =
       cdm_->setServerCertificate(CreateStringFromBinaryData(certificate));
@@ -390,6 +454,12 @@ void IEMEDrmBridge::CreateSessionAndGenerateRequest(
                    init_data_type)
             << ", server_certificate_registered_ "
             << server_certificate_registered_;
+  if (content::IsHbbTV() &&
+      !VerifyStandaloneEmePreconditions(*promise.get(), "generateRequest")) {
+    return;
+  }
+
+  CreateIEME();
 
   // In privacy mode server certificate request has to be generated before
   // creating session and generating request. All requests have to be queued
@@ -466,6 +536,12 @@ void IEMEDrmBridge::LoadSession(
 
   CHECK(session_type != CdmSessionType::kTemporary);
 
+  if (content::IsHbbTV() &&
+      !VerifyStandaloneEmePreconditions(*promise.get(), "load")) {
+    return;
+  }
+  CreateIEME();
+
   const auto load_result_status = cdm_->session_load(ieme_session_id);
   if (eme::kSuccess != load_result_status) {
     LOG(ERROR) << "Loading session failed with status: " << load_result_status;
@@ -992,6 +1068,7 @@ ContentDecryptionModule* CreateIEMEDrmBridge(
     const SessionKeysChangeCB& session_keys_change_cb,
     const SessionExpirationUpdateCB& session_expiration_update_cb,
     bool privacy_mode) {
+  LOG(INFO) << "CreateIEMEDrmBridge";
   return IEMEDrmBridge::Create(key_system, session_message_cb,
                                session_closed_cb, session_keys_change_cb,
                                session_expiration_update_cb, privacy_mode)
index 43b592a8a44e88e6b45d7719c3d0b415b436519b..5c699965fd134bd97491c18a29fd3361cbfde194 100644 (file)
@@ -168,6 +168,9 @@ class MEDIA_EXPORT IEMEDrmBridge : public ContentDecryptionModule,
                 const SessionKeysChangeCB& session_keys_change_cb,
                 const SessionExpirationUpdateCB& session_expiration_update_cb,
                 bool privacy_mode);
+  bool VerifyStandaloneEmePreconditions(CdmPromise& promise,
+                                        const char* method_name);
+  void CreateIEME();
 
   void ResolvePromise(uint32_t promise_id);
   void ChangeKeyStatuses(const std::string& ieme_session_id);
index 15517eae6a9f450cb55beb35ea0f2d01d357ef21..cb80e0ccce75d95ab3d04e0c829f335baa152bc1 100644 (file)
 #if defined(TIZEN_VIDEO_HOLE)
 #include <Ecore_Wl2.h>
 #include "tizen_src/chromium_impl/media/base/tizen/video_plane_controller_capi.h"
+#endif
 #if BUILDFLAG(IS_TIZEN_TV)
+#include <player_product.h>
 #include <player_product_platform_interface.h>
-#endif
+#include <player_product_module_interface.h>
 #endif
 
 #if defined(ENABLE_WRT_JS)
@@ -30,6 +32,9 @@ namespace {
 // Update duration every 100ms.
 const int kDurationUpdateInterval = 100;
 
+#if BUILDFLAG(IS_TIZEN_TV)
+char kCAPath[] = "/opt/data/cert/user/";
+#endif
 // TODO(max): Remove these proxy free functions.
 
 // Called by player_prepare_async()
@@ -165,6 +170,14 @@ bool MediaPlayerBridgeCapi::CreatePlayer(int player_id) {
     OnHandlePlayerError(ret, FROM_HERE);
     return false;
   }
+#if BUILDFLAG(IS_TIZEN_TV)
+  ret = player_set_certificate_path(player_, kCAPath);
+  if (ret != PLAYER_ERROR_NONE) {
+    LOG_ID(ERROR, GetPlayerId())
+        << "player_set_certificate_path failed " << ret;
+  }
+#endif // BUILDFLAG(IS_TIZEN_TV)
+
   return true;
 }
 
@@ -195,6 +208,7 @@ void MediaPlayerBridgeCapi::Prepare() {
 #else
   player_set_uri(player_, url_.spec().c_str());
 #endif
+
 #if !defined(EWK_BRINGUP)
   player_set_sound_type(player_, SOUND_TYPE_MEDIA);
 #endif
@@ -259,6 +273,12 @@ void MediaPlayerBridgeCapi::Prepare() {
 }
 
 bool MediaPlayerBridgeCapi::SetPlayerPrepareAsync() {
+  if (is_preparing_) {
+    LOG_ID(INFO, player_id_) << "Already performing player_prepare_async";
+    return true;
+  }
+  LOG_ID(INFO, player_id_) << "Call player_prepare_async";
+
   int ret = player_prepare_async(player_, PlayerPreparedCb, this);
   if (ret != PLAYER_ERROR_NONE) {
     is_preparing_ = false;
@@ -541,6 +561,7 @@ void MediaPlayerBridgeCapi::SeekInternal(base::TimeDelta time) {
   int err = PlayerSetPlayPosition(player_, time, true, SeekCompletedCb, this);
   if (err != PLAYER_ERROR_NONE) {
     LOG_ID(ERROR, player_id_) << "|player_set_play_position| failed";
+    UpdateSeekState(false);
     OnTimeUpdate(player_id_, GetCurrentTime());
     OnTimeChanged(player_id_);
     if (seek_cb_)
@@ -808,6 +829,7 @@ void MediaPlayerBridgeCapi::SeekCompleteUpdate() {
 }
 
 void MediaPlayerBridgeCapi::UpdateSeekState(bool state) {
+  LOG_ID(INFO, player_id_) << "UpdateSeekState " << state;
   is_seeking_ = state;
 }
 
@@ -892,7 +914,12 @@ void MediaPlayerBridgeCapi::ExecuteDelayedPlayerState() {
   switch (delayed_player_state_) {
     case PLAYER_STATE_DELAYED_PLAY:
       delayed_player_state_ = PLAYER_STATE_DELAYED_NULL;
-      Play();
+      {
+        bool ret = Play();
+        LOG_ID(INFO, player_id_)
+            << "Play returned " << ret << " delayed_player_state_ "
+            << delayed_player_state_;
+      }
       break;
     case PLAYER_STATE_DELAYED_PAUSE:
       delayed_player_state_ = PLAYER_STATE_DELAYED_NULL;
@@ -907,6 +934,12 @@ void MediaPlayerBridgeCapi::ExecuteDelayedPlayerState() {
         }
         return;
       }
+
+      if (waiting_for_drm_init_complete_) {
+        LOG_ID(INFO, player_id_) << "Waiting for DRM init, don't seek";
+        return;
+      }
+
       LOG_ID(INFO, player_id_)
           << "(" << static_cast<void*>(this) << ") " << __func__
           << " applying pending seek - " << pending_seek_duration_.InSecondsF();
@@ -924,6 +957,10 @@ void MediaPlayerBridgeCapi::ExecuteDelayedPlayerState() {
         return;
       }
 
+      if (waiting_for_drm_init_complete_) {
+        LOG_ID(INFO, player_id_) << "Waiting for DRM init, don't seek";
+        return;
+      }
       LOG_ID(INFO, player_id_)
           << "(" << static_cast<void*>(this) << ") " << __func__
           << " applying pending seek, then play - "
index 4aaaa832bcdf9dbb8bd06269d6a4250097735a92..8a97d606c5ca2ce5a665ecd96534a544ab29546d 100644 (file)
@@ -186,7 +186,7 @@ class MEDIA_EXPORT MediaPlayerBridgeCapi : public MediaPlayerTizen {
   GURL url_;
   bool is_live_stream_{false};
   int player_id_ = 0;
-  int delayed_player_state_;
+  MediaPlayerBridgeCapi::PlayerState delayed_player_state_;
   player_h player_ = nullptr;
 
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
@@ -204,6 +204,7 @@ class MEDIA_EXPORT MediaPlayerBridgeCapi : public MediaPlayerTizen {
   bool is_preparing_{false};
   bool is_play_pending_{false};
   bool suspended_{false};
+  bool waiting_for_drm_init_complete_ = false;
 
   bool pending_set_volume_{false};
   double volume_{0.0};
index 2281a99087356211889367a3d9c47ea35009cb37..d4ee8945062f2275dddde0356d790d4174a6864b 100644 (file)
@@ -20,7 +20,8 @@
 
 namespace {
 const int kSeekableTimeUpdateInterval = 500;
-}
+const int64_t kDrmTimeoutSeconds = 10;
+}  // namespace
 
 static void OnSubtitleDataCallback(unsigned long long time_stamp,
                                    unsigned index,
@@ -176,6 +177,7 @@ MediaPlayerBridgeCapiTV::MediaPlayerBridgeCapiTV(const GURL& url,
 MediaPlayerBridgeCapiTV::~MediaPlayerBridgeCapiTV() {
   LOG_ID(INFO, player_id_) << "(" << static_cast<void*>(this) << ") "
                            << __func__;
+  drm_condition_.Signal();
   weak_factory_.InvalidateWeakPtrs();
 
   if (GetProductType() == "LFD") {
@@ -228,11 +230,41 @@ bool MediaPlayerBridgeCapiTV::SetAppInfo() {
   return true;
 }
 
+bool MediaPlayerBridgeCapiTV::SetURIToPlayer(const std::string& fs_path) {
+#if BUILDFLAG(IS_TIZEN_TV)
+  if (blink::IsHbbTV()) {
+    if (IsStandaloneEme()) {
+      int ret = PreparePlayerForStandaloneEme();
+      if (PLAYER_ERROR_NONE != ret) {
+        OnHandlePlayerError(ret, FROM_HERE);
+        return false;
+      }
+
+      if (!is_preloaded_) {
+        player_set_uri(player_,
+                       (hbbtv_url_ + "|DRM_TYPE=DRM_TYPE_CENC").c_str());
+      }
+    } else if (!is_preloaded_) {
+      player_set_uri(player_, hbbtv_url_.c_str());
+    }
+
+#ifdef TIZEN_MULTIMEDIA_DRMMANAGER_SUPPORT
+    if (!IsStandaloneEme() && IsEncryptedContent()) {
+      if (PreparePlayerDrmManager() == MM_PLAYER_ERROR) {
+        return false;
+      }
+    }
+#endif
+  }
+#endif
+
+  return true;
+}
+
 void MediaPlayerBridgeCapiTV::Prepare() {
   int ret = PLAYER_ERROR_NONE;
   bool media_resource_acquired = false;
   std::string translated_url;
-  std::string drm_info;
 
   if (IsPlayerSuspended() && !is_resuming_) {
     LOG(INFO) << "Player is suspended, and !is_resuming_ - call Resume()";
@@ -344,7 +376,7 @@ void MediaPlayerBridgeCapiTV::Prepare() {
   if (GetMediaPlayerClient())
     GetMediaPlayerClient()->NotifyPlaybackState(
         kPlaybackLoad, player_id_, url_.spec(), mime_type_,
-        &media_resource_acquired, &translated_url, &drm_info);
+        &media_resource_acquired, &translated_url, &drm_info_);
 
   if (!SetAppInfo()) {
     LOG(ERROR) << "SetAppInfo failed";
@@ -353,7 +385,7 @@ void MediaPlayerBridgeCapiTV::Prepare() {
 
   LOG_ID(INFO, GetPlayerId())
       << "media_resource_acquired: " << media_resource_acquired
-      << ",translated_url:" << translated_url << ",drm_info: " << drm_info;
+      << ",translated_url:" << translated_url << ",drm_info: " << drm_info_;
 
   if (mime_type_.find("application/vnd.oipf.contentaccessstreaming+xml") !=
       std::string::npos) {
@@ -367,7 +399,7 @@ void MediaPlayerBridgeCapiTV::Prepare() {
       GetMediaPlayerClient()->PlaybackNotificationEnabled() &&
       blink::IsHbbTV()) {
 #if !defined(TIZEN_MULTIMEDIA_DRMMANAGER_SUPPORT)
-    if (!SetDrmInfo(drm_info)) {
+    if (!SetDrmInfo(drm_info_)) {
       LOG_ID(ERROR, GetPlayerId()) << "SetDrmInfo failed";
       return;
     }
@@ -379,6 +411,7 @@ void MediaPlayerBridgeCapiTV::Prepare() {
   if (blink::IsHbbTV()) {
     hbbtv_url_ = url_.spec();
     content_id_ = url_.spec();
+    LOG_ID(INFO, player_id_) << "content_id_ set " << content_id_;
     clean_url_ = url_.spec();
     RemoveUrlSuffixForCleanUrl();
     GetUserPreferAudioLanguage();
@@ -451,13 +484,14 @@ void MediaPlayerBridgeCapiTV::Prepare() {
   }
   if (blink::IsHbbTV() && CheckHighBitRate() && stream_type_ == DASH_STREAM)
     AppendUrlHighBitRate(url_.spec());
-  player_prepared_ = false;
 
-  // TODO(k.brzuszczak): To remove when EME ported
-  if (!is_preloaded_) {
-    player_set_uri(player_, hbbtv_url_.c_str());
+  if (!SetURIToPlayer(url_.spec())) {
+    LOG_ID(ERROR, GetPlayerId()) << "set uri failed";
+    return;
   }
 
+  player_prepared_ = false;
+  player_released_ = false;
   parental_rating_pass_ = true;
   MediaPlayerBridgeCapi::Prepare();
   if (!is_preloading_ && GetMediaPlayerClient()) {
@@ -468,6 +502,14 @@ void MediaPlayerBridgeCapiTV::Prepare() {
 void MediaPlayerBridgeCapiTV::Release() {
   is_preloaded_ = false;
   player_prepared_ = false;
+  if (player_released_) {
+    LOG_ID(INFO, GetPlayerId()) << "player is already released";
+    return;
+  }
+  player_released_ = true;
+  is_preloaded_ = false;
+  drm_condition_.Signal();
+
   StopSeekableTimeUpdateTimer();
   if (IsMultiVideo() && is_player_mixer_opened_) {
     int ret = player_video_mixer_close(player_, DEPRECATED_PARAM);
@@ -510,9 +552,16 @@ void MediaPlayerBridgeCapiTV::Release() {
     }
     SetDecoderReleased(content::kAudioDecoder);
   }
-  if (GetMediaPlayerClient())
-    GetMediaPlayerClient()->NotifyPlaybackState(kPlaybackStop, player_id_);
-  NotifySubtitleState(blink::WebMediaPlayer::kSubtitleStop);
+
+  // If the encrypted_listener_or_cdm_has_changed_ is true, then we're
+  // restarting due to this, so don't send the NotifyPlaybackState.
+  if (encrypted_listener_or_cdm_has_changed_ == false) {
+    if (GetMediaPlayerClient()) {
+      GetMediaPlayerClient()->NotifyPlaybackState(kPlaybackStop, player_id_);
+    }
+    NotifySubtitleState(blink::WebMediaPlayer::kSubtitleStop);
+  }
+
   pending_active_text_track_id_ = active_text_track_id_;
   pending_active_audio_track_id_ = active_audio_track_id_;
   pending_active_video_track_id_ = active_video_track_id_;
@@ -624,6 +673,8 @@ bool MediaPlayerBridgeCapiTV::Play() {
   if (!MediaPlayerBridgeCapi::Play())
     return false;
 
+  drm_condition_.Signal();
+
   if (blink::IsHbbTV()) {
     if (!ActivateAudioStreamIfNeeded()) {
       return false;
@@ -756,7 +807,10 @@ void MediaPlayerBridgeCapiTV::PlaybackCompleteUpdate() {
 void MediaPlayerBridgeCapiTV::Seek(base::TimeDelta time,
                                    base::OnceClosure seek_cb) {
   LOG_ID(INFO, player_id_) << "(" << static_cast<void*>(this) << ") "
-                           << __func__ << " time: " << time.InSecondsF();
+                           << __func__ << " time: " << time.InSecondsF()
+                           << ", playback_time_: " << playback_time_
+                           << ", waiting_for_drm_init_complete_: "
+                           << waiting_for_drm_init_complete_;
   // Ignore seek in release state. Will catch-up later.
   if (GetPlayerState() == PLAYER_STATE_NONE) {
     LOG_ID(INFO, player_id_) << __func__ << " Ignore seek in release state.";
@@ -777,9 +831,20 @@ void MediaPlayerBridgeCapiTV::Seek(base::TimeDelta time,
     }
   }
   seek_cb_ = std::move(seek_cb);
-  if (IsPlayerSuspended() && playback_time_ != time) {
+  bool is_suspend_seek = IsPlayerSuspended() && playback_time_ != time;
+  if (is_seeking_ || is_suspend_seek || waiting_for_drm_init_complete_ ||
+      is_preparing_ || is_preloading_) {
+    LOG_ID(INFO, player_id_)
+        << "(" << static_cast<void*>(this) << ") "
+        << " stashing pending seek - " << time.InSecondsF() << "s";
+
     playback_time_ = time;
-    delayed_player_state_ = PLAYER_STATE_DELAYED_SEEK;
+    if (delayed_player_state_ == PLAYER_STATE_DELAYED_PLAY ||
+        delayed_player_state_ == PLAYER_STATE_DELAYED_SEEK_THEN_PLAY) {
+      delayed_player_state_ = PLAYER_STATE_DELAYED_SEEK_THEN_PLAY;
+    } else {
+      delayed_player_state_ = PLAYER_STATE_DELAYED_SEEK;
+    }
     pending_seek_duration_ = playback_time_;
     OnTimeUpdate(player_id_, playback_time_);
     OnTimeChanged(player_id_);
@@ -787,7 +852,10 @@ void MediaPlayerBridgeCapiTV::Seek(base::TimeDelta time,
     return;
   }
 
+  LOG_ID(INFO, player_id_) << "SeekInternal";
   MediaPlayerBridgeCapi::SeekInternal(time);
+
+  LOG_ID(INFO, player_id_) << "NotifySubtitleState seek start";
   NotifySubtitleState(blink::WebMediaPlayer::kSubtitleSeekStart,
                       time.InSecondsF());
 
@@ -1016,6 +1084,17 @@ void MediaPlayerBridgeCapiTV::OnResumeComplete(bool success) {
 
 void MediaPlayerBridgeCapiTV::PlayerPrepared() {
   player_prepared_ = true;
+
+  // If the encrypted_listener_or_cdm_has_changed_ flag is true, then the
+  // CDM has changed or been set since we started to preload, so we'll
+  // restart the preload/prepare to use the new CDM.
+  if (encrypted_listener_or_cdm_has_changed_) {
+    Release();
+    encrypted_listener_or_cdm_has_changed_ = false;
+    Prepare();
+    return;
+  }
+  is_resuming_ = false;
   MediaPlayerBridgeCapi::PlayerPrepared();
 
   int canSeek = 0;
@@ -1216,6 +1295,7 @@ void MediaPlayerBridgeCapiTV::HandleBufferingStatus(int percent) {
                            << " is_live_stream_ " << is_live_stream_
                            << " player_prepared_ " << player_prepared_;
   if (is_paused_) {
+    LOG_ID(INFO, player_id_) << "Paused, return";
     return;
   }
 
@@ -1259,6 +1339,8 @@ void MediaPlayerBridgeCapiTV::HandleBufferingStatus(int percent) {
     }
     if (GetPlayerState() != PLAYER_STATE_PLAYING)
       return;
+
+    LOG_ID(INFO, player_id_) << "Pause due to buffering " << percent;
     if (player_pause(player_) != PLAYER_ERROR_NONE) {
       LOG(ERROR) << "|player_pause| failed";
       return;
@@ -1912,6 +1994,16 @@ void MediaPlayerBridgeCapiTV::PlayerPreloaded() {
   LOG_ID(INFO, GetPlayerId()) << "PlayerPreloaded,this: " << this
                               << ",player_prepared_:" << player_prepared_;
 
+  // If the encrypted_listener_or_cdm_has_changed_ flag is true, then the
+  // CDM has changed or been set since we started to preload, so we'll
+  // restart the preload/prepare to use the new CDM.
+  if (encrypted_listener_or_cdm_has_changed_) {
+    Release();
+    encrypted_listener_or_cdm_has_changed_ = false;
+    Prepare();
+    return;
+  }
+
   is_preloaded_ = true;
   is_preloading_ = false;
   is_live_stream_ = CheckLiveStreaming();
@@ -2084,6 +2176,7 @@ bool MediaPlayerBridgeCapiTV::SetMediaDRMInfo(const std::string& type_data,
   int ret = PLAYER_ERROR_INVALID_OPERATION;
   const void* type_data_ptr = type_data.c_str();
   const void* value_data_ptr = value_data.c_str();
+  uses_hbbtv_drm_ = true;
   player_drm_type_e drm_type = PLAYER_DRM_TYPE_PLAYREADY;
   ret = player_set_drm_info(player_, type_data_ptr, type_data.length(),
                             value_data_ptr, value_data.length(), drm_type);
@@ -2103,6 +2196,13 @@ void MediaPlayerBridgeCapiTV::OnDrmError(int err_code, char* err_str) {
         base::BindOnce(&MediaPlayerBridgeCapiTV::OnDrmError,
                        weak_factory_.GetWeakPtr(), err_code, err_str));
   }
+#if defined(TIZEN_MULTIMEDIA_DRMMANAGER_SUPPORT)
+  content::WebContentsDelegate* web_contents_delegate =
+      GetMediaPlayerClient()->GetWebContentsDelegate();
+  if (web_contents_delegate) {
+    web_contents_delegate->NotifyDRMError(err_code, {});
+  }
+#endif
   MediaPlayerBridgeCapi::OnHandlePlayerError(err_code, FROM_HERE);
 }
 
@@ -3402,6 +3502,7 @@ std::string MediaPlayerBridgeCapiTV::GetMrsUrl() {
 }
 
 std::string MediaPlayerBridgeCapiTV::GetContentId() {
+  LOG_ID(INFO, player_id_) << content_id_;
   return content_id_;
 }
 
@@ -3714,4 +3815,319 @@ int MediaPlayerBridgeCapiTV::GetPreferAudioIndex(
   return -1;
 }
 
+#if BUILDFLAG(IS_TIZEN_TV)
+void MediaPlayerBridgeCapiTV::SetHasEncryptedListenerOrCdm(bool value) {
+  LOG_ID(INFO, GetPlayerId()) << "Has encrypted listener or CDM: " << value;
+
+  // If the CDM has changed, and we're still preloading or preparing, then
+  // set the encrypted_listener_or_cdm_has_changed_ flag - when the current
+  // preloading/preparing completed, we'll re-set and restart the
+  // preload/prepare with the correct CDM settings.
+  if ((has_encrypted_listener_or_cdm_ != value) &&
+      (is_preparing_ || is_preloading_)) {
+    encrypted_listener_or_cdm_has_changed_ = true;
+  }
+
+  has_encrypted_listener_or_cdm_ = value;
+}
+
+void MediaPlayerBridgeCapiTV::SetDecryptorHandle(
+    eme::eme_decryptor_t decryptor) {
+  LOG_ID(INFO, GetPlayerId())
+      << "Received decryptor " << reinterpret_cast<void*>(decryptor);
+
+  base::AutoLock auto_lock(drm_lock_);
+  decryptor_ = decryptor;
+
+  if (decryptor == 0) {
+    OnHandlePlayerError(PLAYER_ERROR_DRM_EXPIRED, FROM_HERE);
+  }
+
+  drm_condition_.Signal();
+}
+
+bool MediaPlayerBridgeCapiTV::IsEncryptedContent() const {
+  bool is_encrypted = false;
+  std::vector<std::string> drm_info_pairs = base::SplitStringUsingSubstr(
+      drm_info_, ", ", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+  for (auto it = drm_info_pairs.begin(); it != drm_info_pairs.end(); ++it) {
+    std::vector<std::string> drm_info_pair = base::SplitStringUsingSubstr(
+        *it, ": ", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+
+    if (drm_info_pair.size() != 2) {
+      continue;
+    }
+
+    std::string trim_key = drm_info_pair.at(0);
+    std::string trim_value = drm_info_pair.at(1);
+    if (trim_key == "\"detected_drm\"" && trim_value != "\"0\"") {
+      is_encrypted = true;
+      break;
+    }
+  }
+  return is_encrypted;
+}
+
+bool MediaPlayerBridgeCapiTV::IsStandaloneEme() {
+  // assumes HbbTV DRM is inactive
+  bool is_hbbtv_drm_inactive = true;
+
+  content::WebContentsDelegate* contents_delegate =
+      GetMediaPlayerClient()->GetWebContentsDelegate();
+  if (contents_delegate != nullptr) {
+    auto& active_drm = contents_delegate->GetActiveDRM();
+
+    LOG_ID(INFO, GetPlayerId()) << "active DRM: '" << active_drm << "'";
+
+    // for HbbTV 2.0.2 assumes inactive DRM unless drmAgent.setActiveDRM() was
+    // called with something else than "urn:hbbtv:oipfdrm:inactive"
+
+    is_hbbtv_drm_inactive =
+        active_drm.empty() || (active_drm == "urn:hbbtv:oipfdrm:inactive");
+  }
+
+  bool ret = blink::IsHbbTV() && (stream_type_ == DASH_STREAM) &&
+             is_hbbtv_drm_inactive && !uses_hbbtv_drm_ &&
+             has_encrypted_listener_or_cdm_;
+
+  LOG_ID(INFO, GetPlayerId())
+      << "is HbbTV: " << blink::IsHbbTV()
+      << ", HbbTV DRM inactive: " << is_hbbtv_drm_inactive
+      << ", uses HbbTV DRM: " << uses_hbbtv_drm_
+      << ", stream type: " << stream_type_
+      << ", has encrypted listener or CDM: " << has_encrypted_listener_or_cdm_
+      << ", standalone EME: " << ret;
+
+  return ret;
+}
+
+int MediaPlayerBridgeCapiTV::PreparePlayerForDrmEme(
+    set_drm_init_data_cb init_data_cb,
+    security_init_complete_cb init_complete_cb) {
+  waiting_for_drm_init_complete_ = false;
+  auto player_res = player_set_drm_handle(player_, PLAYER_DRM_TYPE_EME, 0);
+  if (PLAYER_ERROR_NONE != player_res) {
+    LOG_ID(ERROR, GetPlayerId())
+        << "Failed to set drm handle with error [" << player_res << "]";
+    return player_res;
+  }
+
+  player_res = player_set_drm_init_data_cb(player_, init_data_cb, this);
+  if (PLAYER_ERROR_NONE != player_res) {
+    LOG_ID(ERROR, GetPlayerId())
+        << "Failed to set drm init data cb with error [" << player_res << "]";
+    return player_res;
+  }
+
+  player_res = player_set_drm_init_complete_cb(player_, init_complete_cb, this);
+  if (PLAYER_ERROR_NONE != player_res) {
+    LOG_ID(ERROR, GetPlayerId())
+        << "Failed to set drm init complete cb with error [" << player_res
+        << "]";
+    return player_res;
+  }
+
+  return player_res;
+}
+
+void MediaPlayerBridgeCapiTV::WaitingDRMInitComplete() {
+  base::AutoLock auto_lock(drm_lock_);
+  if (decryptor_ != 0) {
+    LOG_ID(INFO, player_id_) << "Already got decryptor!";
+    waiting_for_drm_init_complete_ = false;
+    return;
+  }
+
+  LOG_ID(INFO, player_id_) << "Got Init Data, waiting for init complete";
+  waiting_for_drm_init_complete_ = true;
+}
+
+int MediaPlayerBridgeCapiTV::PreparePlayerForStandaloneEme() {
+  LOG_ID(INFO, GetPlayerId()) << "Preparing player for standalone DRM EME";
+
+  const auto init_data_cb = [](drm_init_data_type init_type, void* data,
+                               int data_length, void* user_data) -> int {
+    LOG(INFO) << "Received init data, size: " << data_length
+              << ", type: " << init_type;
+    if (init_type != CENC) {
+      LOG(WARNING) << "Not CENC init data type";
+      return NOT_CENC_DATA;
+    }
+    if (!user_data) {
+      LOG(ERROR) << "No user data";
+      return NO_USER_DATA;
+    }
+
+    auto data_bytes = static_cast<unsigned char*>(data);
+    std::vector<unsigned char> init_data(data_bytes, data_bytes + data_length);
+
+    auto thiz = static_cast<MediaPlayerBridgeCapiTV*>(user_data);
+    if (thiz->GetMediaPlayerClient()) {
+      thiz->WaitingDRMInitComplete();
+      thiz->GetMediaPlayerClient()->OnInitData(init_data);
+    }
+
+    return ERROR_NONE;
+  };
+
+  const auto init_complete_cb = [](int* drmhandle, unsigned int length,
+                                   unsigned char* psshdata,
+                                   void* user_data) -> bool {
+    if (!user_data) {
+      LOG(ERROR) << "No user data";
+      return false;
+    }
+
+    auto thiz = static_cast<MediaPlayerBridgeCapiTV*>(user_data);
+    return thiz->CompleteDrmInit(*drmhandle);
+  };
+
+  return PreparePlayerForDrmEme(init_data_cb, init_complete_cb);
+}
+
+#if defined(TIZEN_MULTIMEDIA_DRMMANAGER_SUPPORT)
+InitDataError MediaPlayerBridgeCapiTV::PreparePlayerDrmManager() {
+  LOG_ID(INFO, GetPlayerId()) << "Preparing player for DRM EME";
+
+  const auto init_data_cb = [](drm_init_data_type init_type, void* data,
+                               int data_length, void* user_data) -> int {
+    if (!user_data) {
+      return NULL_PTR_ERROR;
+    }
+
+    const auto data_bytes = static_cast<unsigned char*>(data);
+    std::vector<unsigned char> init_data(data_bytes, data_bytes + data_length);
+
+    auto thiz = static_cast<MediaPlayerBridgeCapiTV*>(user_data);
+    thiz->WaitingDRMInitComplete();
+    thiz->task_runner_->PostTask(
+        FROM_HERE,
+        base::BindOnce(&MediaPlayerBridgeCapiTV::NotifyDrmInitData,
+                       thiz->weak_factory_.GetWeakPtr(), init_type, init_data));
+    return ERROR_NONE;
+  };
+
+  const auto init_complete_cb = [](int* drmhandle, unsigned int length,
+                                   unsigned char* psshdata,
+                                   void* user_data) -> bool {
+    if (!user_data) {
+      return NULL_PTR_ERROR;
+    }
+    auto thiz = static_cast<MediaPlayerBridgeCapiTV*>(user_data);
+    LOG_ID(INFO, thiz->GetPlayerId())
+        << "Post to task to run NotifyDrmInitComplete";
+    thiz->task_runner_->PostTask(
+        FROM_HERE,
+        base::BindOnce(&MediaPlayerBridgeCapiTV::NotifyDrmInitComplete,
+                       thiz->weak_factory_.GetWeakPtr(), length, psshdata));
+    LOG_ID(INFO, thiz->GetPlayerId()) << "Wait for result....";
+    thiz->CompleteDrmInit(*drmhandle);
+    return *drmhandle != 0;
+  };
+
+  int ret = PreparePlayerForDrmEme(init_data_cb, init_complete_cb);
+  if (ret != PLAYER_ERROR_NONE) {
+    return MM_PLAYER_ERROR;
+  }
+  return ERROR_NONE;
+}
+
+void MediaPlayerBridgeCapiTV::NotifyDrmInitData(
+    int init_type,
+    const std::vector<unsigned char>& data) {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+
+  content::WebContentsDelegate* web_contents_delegate =
+      GetMediaPlayerClient()->GetWebContentsDelegate();
+  if (!web_contents_delegate) {
+    return;
+  }
+
+  web_contents_delegate->NotifyDRMInitData(init_type, data);
+}
+
+void MediaPlayerBridgeCapiTV::NotifyDrmInitComplete(unsigned int length,
+                                                    unsigned char* psshdata) {
+  DCHECK(task_runner_->BelongsToCurrentThread());
+  base::AutoLock auto_lock(drm_lock_);
+
+  content::WebContentsDelegate* web_contents_delegate =
+      GetMediaPlayerClient()->GetWebContentsDelegate();
+  if (!web_contents_delegate) {
+    return;
+  }
+
+  if (decryptor_ == 0) {
+    decryptor_ = web_contents_delegate->NotifyDRMInitComplete(length, psshdata);
+    LOG(INFO) << "decryptor_ = " << decryptor_;
+  }
+  drm_condition_.Signal();
+}
+#endif  // TIZEN_MULTIMEDIA_DRMMANAGER_SUPPORT
+
+bool MediaPlayerBridgeCapiTV::CompleteDrmInit(int& drmhandle) {
+  base::AutoLock auto_lock(drm_lock_);
+
+  if (player_released_) {
+    LOG_ID(INFO, GetPlayerId())
+        << "Not waiting for decryptor as player is releasing";
+    drmhandle = 0;
+    return false;
+  }
+
+  if (decryptor_ == 0) {
+    // OnPlayerDrmInitComplete callback will be invoked by CAPI Player when
+    // drmeme GStreamer element will attempt decrypting first frame.
+    // drmeme then waits 20 seconds during which it expects to receive
+    // decryptor handle. If this time-outs player error is reported.
+    // If the decryptor_ is not yet known below we need to wait for it.
+    // It will arrive when Media Keys Session is updated with license data
+    // for the first time.
+    // If the application misbehaves the wait here would be indefinite blocking
+    // other callbacks registered in CAPI Player.
+    // The timed wait here is a safety net for cases when the
+    // OnPlayerDrmInitComplete callback was invoked but we the decryptor handle
+    // doesn't arrive on time.
+    // 10 seconds was picked here, because it should be enough for a roundtrip
+    // to the license server, and HbbTV requires unavailable keys to timeout in
+    // < 20 seconds.
+    LOG_ID(INFO, GetPlayerId()) << "Waiting for decryptor...";
+
+    if (IsStandaloneEme()) {
+      if (GetMediaPlayerClient()) {
+        GetMediaPlayerClient()->OnWaiting(
+            media::WaitingReason::kNoDecryptionKey);
+      }
+    }
+
+    base::TimeTicks start = base::TimeTicks::Now();
+    while (decryptor_ == 0) {
+      base::TimeTicks curr = base::TimeTicks::Now();
+      if ((curr - start).InSeconds() >= kDrmTimeoutSeconds) {
+        break;
+      }
+      LOG_ID(WARNING, GetPlayerId())
+          << "Wait for " << (kDrmTimeoutSeconds - (curr - start).InSeconds());
+      drm_condition_.TimedWait(base::TimeDelta::FromSeconds(
+          kDrmTimeoutSeconds - (curr - start).InSeconds()));
+    }
+    if (decryptor_ == 0) {
+      LOG_ID(ERROR, GetPlayerId())
+          << "No decryptor received before drmeme timeout!";
+      OnMediaError(MEDIA_ERROR_DECODE);
+    } else {
+      base::TimeTicks curr = base::TimeTicks::Now();
+      LOG_ID(INFO, GetPlayerId()) << "Waited " << (curr - start).InSecondsF();
+    }
+  } else {
+    LOG_ID(INFO, GetPlayerId()) << "Decryptor already set";
+  }
+  LOG_ID(INFO, GetPlayerId())
+      << "Decryptor: " << reinterpret_cast<void*>(decryptor_);
+
+  drmhandle = decryptor_;
+  waiting_for_drm_init_complete_ = false;
+  return (decryptor_ != 0);
+}
+#endif
 }  // namespace media
index ef8e0a4012d5d2d7b2f5e08ec607a40b9bc2e710..a42bc295531caf248b759f4919ef573d847b3f6c 100644 (file)
@@ -5,8 +5,10 @@
 #ifndef MEDIA_FILTERS_MEDIA_PLAYER_BRIDGE_CAPI_TV_H_
 #define MEDIA_FILTERS_MEDIA_PLAYER_BRIDGE_CAPI_TV_H_
 
+#include <emeCDM/IEME.h>
 #include <player_product.h>
 
+#include "base/synchronization/condition_variable.h"
 #include "media/filters/hardware_resource_helper.h"
 #include "media/filters/media_player_bridge_capi.h"
 #include "tizen_src/chromium_impl/build/tizen_version.h"
@@ -55,6 +57,14 @@ enum ScalerType {
   SCALER_SUB3,
 };
 
+enum InitDataError {
+  ERROR_NONE = 0,
+  NOT_CENC_DATA,
+  NO_USER_DATA,
+  NULL_PTR_ERROR,
+  MM_PLAYER_ERROR,
+};
+
 #if defined(TIZEN_VD_NGA)
 struct AudioPreselectionInfos {
   std::string id;
@@ -200,12 +210,15 @@ class MEDIA_EXPORT MediaPlayerBridgeCapiTV : public MediaPlayerBridgeCapi {
   double GetStartDate() override;
 
   // LFD TV mixer mode
-  bool IsMuted(void);
+  bool IsMuted();
   void SetMultiVideoState();
   void ActivateCurrentStream(player_stream_type_e stream_type);
   bool IsMultiVideo() const override;
   void SetMultiVideo(bool is_multi_video) override;
   bool Is4thVideo() override { return is_4th_video_; }
+  void SetHasEncryptedListenerOrCdm(bool value) override;
+  void SetDecryptorHandle(eme::eme_decryptor_t decryptor) override;
+  bool SetURIToPlayer(const std::string&);
 
  protected:
   void PlayerPrepared() override;
@@ -225,6 +238,7 @@ class MEDIA_EXPORT MediaPlayerBridgeCapiTV : public MediaPlayerBridgeCapi {
   bool is_player_seek_available_{true};
   bool is_notification_playback_ready_delayed_{false};
   bool leave_not_visible_{false};
+  std::string drm_info_{""};
 
   void NotifySubtitlePlay(int id,
                           const std::string& url,
@@ -301,6 +315,18 @@ class MEDIA_EXPORT MediaPlayerBridgeCapiTV : public MediaPlayerBridgeCapi {
   void SetVideoVisibilityPrivate(bool);
 #endif
 
+  bool IsStandaloneEme();
+  bool IsEncryptedContent() const;
+  int PreparePlayerForDrmEme(set_drm_init_data_cb init_data_cb,
+                             security_init_complete_cb init_complete_cb);
+  int PreparePlayerForStandaloneEme();
+#if defined(TIZEN_MULTIMEDIA_DRMMANAGER_SUPPORT)
+  InitDataError PreparePlayerDrmManager();
+  void NotifyDrmInitData(int init_type, const std::vector<unsigned char>& data);
+  void NotifyDrmInitComplete(unsigned int length, unsigned char* psshdata);
+#endif
+  bool CompleteDrmInit(int& drmhandle);
+
   StreamType stream_type_{OTHER_STREAM};
   std::string hbbtv_url_{""};  // url_ + HIGHBITRATE(if mpd)
   std::string mime_type_ = "";
@@ -358,8 +384,18 @@ class MEDIA_EXPORT MediaPlayerBridgeCapiTV : public MediaPlayerBridgeCapi {
   base::TimeDelta min_seekable_time_{base::TimeDelta()};
   base::TimeDelta max_seekable_time_{base::TimeDelta()};
   base::RepeatingTimer seekable_time_update_timer_;
+  void WaitingDRMInitComplete();
   // NOTE: Weak pointers must be invalidated before all other member variables.
   base::WeakPtrFactory<MediaPlayerBridgeCapiTV> weak_factory_;
+
+  bool has_encrypted_listener_or_cdm_{false};
+  // Flag indicating that has_encrypted_listener_or_cdm_ has been changed.
+  bool encrypted_listener_or_cdm_has_changed_{false};
+  bool uses_hbbtv_drm_{false};
+  eme::eme_decryptor_t decryptor_{0};
+  base::Lock drm_lock_;
+  base::ConditionVariable drm_condition_{&drm_lock_};
+  std::atomic<bool> player_released_;
 };
 }  // namespace media
 
index 159e47761d09e0cef4a3528d1777637014e64964..5f0230933be663b975c1bf908b817619f4604a1e 100644 (file)
 #include "ui/gfx/geometry/rect_f.h"
 #endif
 
+#if BUILDFLAG(IS_TIZEN_TV)
+#include <drmdecrypt/emeCDM/IEME.h>
+#endif
+
 namespace media {
 
 class DemuxerStream;
index 6887133aa720e6b2351b9e0898bd411acf4a21c0..22953b67cb5d4c3c5d4d66a1e1ed81b80971fb1a 100644 (file)
@@ -24,6 +24,8 @@
 #else
 #include <ivideo-dp-control.hpp>
 #endif  // TIZEN_VERSION_AT_LEAST(9, 0, 0) && !BUILDFLAG(IS_RISCV64_TV)
+
+#include <drmdecrypt/emeCDM/IEME.h>
 #endif  // BUILDFLAG(IS_TIZEN_TV)
 
 namespace media {
@@ -167,6 +169,10 @@ class MEDIA_EXPORT MediaPlayerTizen {
   virtual bool IsMultiVideo() const { return false; }
   virtual void SetMultiVideo(bool is_multi_video) {}
   virtual void SetVideoVisibility(bool visible) {}
+#if BUILDFLAG(IS_TIZEN_TV)
+  virtual void SetDecryptorHandle(eme::eme_decryptor_t decryptor) {}
+  virtual void SetHasEncryptedListenerOrCdm(bool value) {}
+#endif
 };
 
 #if BUILDFLAG(IS_TIZEN_TV)
index 2d976d27d06ebdc387e9aa4d7b4e12cd9c35220b..89791b013d64db2078020d97bf94bb7c35155d7b 100644 (file)
@@ -89,6 +89,7 @@ class MEDIA_EXPORT MediaPlayerTizenClient {
   virtual content::WebContentsDelegate* GetWebContentsDelegate() const = 0;
   virtual void OnPlayerStarted(bool play_started) = 0;
   virtual void GetFpsInfo(int& num, int& den) = 0;
+  virtual void OnInitData(const std::vector<unsigned char>& init_data) = 0;
 #endif
 };
 
index a8abec8479f87770e13d0e44eb913164fdd1c402..f17ed3d650b8dc1dea098daee012cbe363d67c35 100644 (file)
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 // Multiply-included file, no traditional include guard.
+#include <vector>
 
 #include "base/values.h"
 #include "common/hit_test_params.h"
@@ -269,6 +270,10 @@ IPC_MESSAGE_CONTROL1(HbbtvMsg_RegisterURLSchemesAsCORSEnabled,
                      std::string /* scheme */)
 
 IPC_MESSAGE_CONTROL1(EwkViewMsg_SetTimeOffset, double /* time offset */)
+
+IPC_MESSAGE_ROUTED1(EwkFrameMsg_SetKeySystemWhitelist,
+                    std::vector<std::string> /* key system list */)
+
 // Sent when the renderer was prevented from displaying insecure content in
 // a secure page by a security policy.  The page may appear incomplete.
 IPC_MESSAGE_ROUTED0(EwkHostMsg_DidBlockInsecureContent)
index 0d812022ecef3343acbfed548813373dd811d594..45c77fcd608c30b1d9c9c7aaaa8a8d34b3e098cd 100644 (file)
@@ -2115,6 +2115,10 @@ void EWebView::RenderViewReady() {
 
   RenderViewHost* render_view_host = web_contents_->GetRenderViewHost();
 
+#if BUILDFLAG(IS_TIZEN_TV)
+  SendKeySystemWhitelist();
+#endif
+
   SendDelayedMessages(render_view_host);
 
   if (render_view_host) {
@@ -3889,6 +3893,75 @@ void EWebView::NotifySubtitleData(int track_id,
   ewkMediaSubtitleDataDelete(subtitle_data);
 }
 
+bool EWebView::SetKeySystemWhitelist(const char* list[], unsigned list_size) {
+  key_system_whitelist_.clear();
+  for (unsigned n = 0; n < list_size; ++n) {
+    key_system_whitelist_.emplace_back(list[n]);
+    LOG(INFO) << "whitelisted key system: " << key_system_whitelist_.back();
+  }
+
+  return SendKeySystemWhitelist();
+}
+
+void EWebView::SetActiveDRM(const char* drm_system_id) {
+  active_drm_ = drm_system_id ? drm_system_id : "";
+  LOG(INFO) << "active DRM: \"" << active_drm_ << "\"";
+}
+
+const std::string& EWebView::GetActiveDRM() const {
+  return active_drm_;
+}
+
+bool EWebView::SendKeySystemWhitelist() const {
+  RenderFrameHost* render_frame_host = web_contents_->GetPrimaryMainFrame();
+
+  if (render_frame_host) {
+    LOG(INFO) << "sending key system whitelist"
+              << ", size: " << key_system_whitelist_.size();
+    const bool send_result =
+        render_frame_host->Send(new EwkFrameMsg_SetKeySystemWhitelist(
+            render_frame_host->GetRoutingID(), key_system_whitelist_));
+    if (!send_result) {
+      LOG(WARNING) << "failed sending key system whitelist";
+    }
+    return send_result;
+  } else {
+    // will try sending when render frame host is available (RenderViewCreated)
+    return true;
+  }
+}
+
+#if defined(TIZEN_MULTIMEDIA_DRMMANAGER_SUPPORT)
+void EWebView::NotifyDRMInitData(int init_type,
+                                 const std::vector<unsigned char>& data) {
+  Ewk_DRM_Init_Data_Info info;
+  info.init_type = init_type;
+  info.data = static_cast<void*>(const_cast<unsigned char*>(data.data()));
+  info.data_length = data.size();
+
+  SmartCallback<EWebViewCallbacks::DRMInitData>().call(
+      static_cast<void*>(&info));
+}
+
+int EWebView::NotifyDRMInitComplete(unsigned int pssh_data_length,
+                                    unsigned char* pssh_data) {
+  Ewk_DRM_Init_Complete_Info info;
+  info.pssh_data_length = pssh_data_length;
+  info.pssh_data = pssh_data;
+  info.decryptor = 0;
+
+  SmartCallback<EWebViewCallbacks::DRMInitComplete>().call(
+      static_cast<void*>(&info));
+
+  return info.decryptor;
+}
+
+void EWebView::NotifyDRMError(int error_code, const std::string& error_string) {
+  Ewk_DRM_Error_Info info{error_code, error_string.c_str()};
+  SmartCallback<EWebViewCallbacks::DRMError>().call(static_cast<void*>(&info));
+}
+#endif
+
 void EWebView::UpdateCurrentTime(double current_time) {
   current_time_ = current_time;
 }
index 02eda2468e945f7bdd01318e952d917a12eec7ec..26868df140c82a4112d2f84828aa5bd01e885367 100644 (file)
@@ -865,6 +865,15 @@ class EWebView {
                      unsigned int len,
                      int media_position);
   void SetPreferSubtitleLang(const char* lang_list);
+  bool SetKeySystemWhitelist(const char* list[], unsigned list_size);
+  void SetActiveDRM(const char* drm_system_id);
+  const std::string& GetActiveDRM() const;
+#if defined(TIZEN_MULTIMEDIA_DRMMANAGER_SUPPORT)
+  void NotifyDRMInitData(int init_type, const std::vector<unsigned char>& data);
+  int NotifyDRMInitComplete(unsigned int pssh_data_length,
+                            unsigned char* pssh_data);
+  void NotifyDRMError(int error_code, const std::string& error_string);
+#endif
   void NotifySubtitleState(int state, double time_stamp);
   void NotifySubtitlePlay(int active_track_id,
                           const char* url,
@@ -932,6 +941,7 @@ class EWebView {
       WebViewAsyncRequestHitTestDataCallback* cb);
 
 #if BUILDFLAG(IS_TIZEN_TV)
+  bool SendKeySystemWhitelist() const;
   void InitInspectorServer();
 
   void RunPendingSetFocus(Eina_Bool focus);
@@ -1121,6 +1131,8 @@ class EWebView {
   double current_time_ = 0.0;
   bool use_sw_audio_decoder_ = false;
   Ewk_Hardware_Decoders broadcast_decoder_ = EWK_HARDWARE_DECODERS_NONE;
+  std::vector<std::string> key_system_whitelist_;
+  std::string active_drm_;
 #endif
 
   std::unique_ptr<_Ewk_Back_Forward_List> back_forward_list_;
index d05ca7b471d9aa0ab234916d008f6851ffd5e453..7b968f4b1d88bcd533b01d6e35259749cab5b940 100644 (file)
@@ -148,6 +148,11 @@ enum CallbackType {
   FirstTimestamp,
   PESData,
   EVENTData,
+#if defined(TIZEN_MULTIMEDIA_DRMMANAGER_SUPPORT)
+  DRMInitData,
+  DRMInitComplete,
+  DRMError,
+#endif
 #endif
   OverscrolledLeft,
   OverscrolledRight,
@@ -370,6 +375,11 @@ DECLARE_EWK_VIEW_CALLBACK(SubtitleNotifyData, "on,subtitle,data", void*);
 DECLARE_EWK_VIEW_CALLBACK(FirstTimestamp, "on,dvb,subtitle,timestamp", void*);
 DECLARE_EWK_VIEW_CALLBACK(PESData, "on,dvb,subtitle,data", void*);
 DECLARE_EWK_VIEW_CALLBACK(EVENTData, "update,event,data", void*);
+#if defined(TIZEN_MULTIMEDIA_DRMMANAGER_SUPPORT)
+DECLARE_EWK_VIEW_CALLBACK(DRMInitData, "drm,init,data", void*);
+DECLARE_EWK_VIEW_CALLBACK(DRMInitComplete, "drm,init,complete", void*);
+DECLARE_EWK_VIEW_CALLBACK(DRMError, "drm,error", void*);
+#endif
 #endif
 DECLARE_EWK_VIEW_CALLBACK(OverscrolledLeft, "overscrolled,left", void);
 DECLARE_EWK_VIEW_CALLBACK(OverscrolledRight, "overscrolled,right", void);
index 2d6fbd8fcbc5e7222232cfc41117d94ed14eac26..790d3a05865a9cd3ed76f779dc877c0134e2525e 100644 (file)
@@ -1758,10 +1758,17 @@ Eina_Bool ewk_view_marlin_enable_set(Evas_Object* ewkView, Eina_Bool is_enable)
   return EINA_FALSE;
 }
 
-Eina_Bool ewk_view_key_system_whitelist_set(Evas_Object* ewkView, const char** list, unsigned list_size)
-{
-  LOG_EWK_API_MOCKUP();
+Eina_Bool ewk_view_key_system_whitelist_set(Evas_Object* ewkView,
+                                            const char** list,
+                                            unsigned list_size) {
+#if BUILDFLAG(IS_TIZEN_TV)
+  EWK_VIEW_IMPL_GET_OR_RETURN(ewkView, impl, EINA_FALSE);
+  const bool result = impl->SetKeySystemWhitelist(list, list_size);
+  return (result ? EINA_TRUE : EINA_FALSE);
+#else
+  LOG_EWK_API_MOCKUP("Only for Tizen TV.");
   return EINA_FALSE;
+#endif
 }
 
 Eina_Bool ewk_view_is_video_playing(Evas_Object* o, Ewk_Is_Video_Playing_Callback callback, void* user_data)
@@ -1785,8 +1792,14 @@ Eina_Bool ewk_view_stop_video(Evas_Object* o, Ewk_Stop_Video_Callback callback,
 
 Eina_Bool ewk_view_active_drm_set(Evas_Object* view, const char* drm_system_id)
 {
-  LOG_EWK_API_MOCKUP();
+#if BUILDFLAG(IS_TIZEN_TV)
+  EWK_VIEW_IMPL_GET_OR_RETURN(view, impl, EINA_FALSE);
+  impl->SetActiveDRM(drm_system_id);
+  return EINA_TRUE;
+#else
+  LOG_EWK_API_MOCKUP("Only for Tizen TV.");
   return EINA_FALSE;
+#endif
 }
 
 void ewk_view_broadcast_decoder_set(
index 2764d519b2c4fd3b1c25a68f24fee4184d8b798b..7a96a067ba817c1f9d8f1d43872b22bcfe19d5ec 100644 (file)
@@ -5,6 +5,9 @@
 #ifndef CONTENT_RENDERER_CLIENT_EFL_H
 #define CONTENT_RENDERER_CLIENT_EFL_H
 
+#include <string>
+#include <vector>
+
 #include "content/public/renderer/content_renderer_client.h"
 #include "content/public/renderer/render_frame_observer.h"
 #include "renderer/render_thread_observer_efl.h"
@@ -121,6 +124,12 @@ class ContentRendererClientEfl : public content::ContentRendererClient {
       int element_id) override;
 #endif  // defined(TIZEN_TV_UPSTREAM_MULTIMEDIA)
 
+#if BUILDFLAG(IS_TIZEN_TV)
+  void SetKeySystemWhitelist(const std::vector<std::string>& key_systems) {
+    key_system_whitelist_ = key_systems;
+  }
+#endif
+
  private:
   static void ApplyCustomMobileSettings(blink::WebView*);
 
index 9197dd0cf6dc4f25caecef1a230c07a7ac788a8e..9f3d1e1d0bc0ba2e542a190cdffbbb697d873b34 100644 (file)
@@ -86,6 +86,10 @@ bool RenderFrameObserverEfl::OnMessageReceived(const IPC::Message& message) {
     IPC_MESSAGE_HANDLER(EwkFrameMsg_LoadNotFoundErrorPage, OnLoadNotFoundErrorPage)
     IPC_MESSAGE_HANDLER(EwkFrameMsg_MoveToNextOrPreviousSelectElement, OnMoveToNextOrPreviousSelectElement)
     IPC_MESSAGE_HANDLER(EwkFrameMsg_RequestSelectCollectionInformation, OnRequestSelectCollectionInformation);
+#if BUILDFLAG(IS_TIZEN_TV)
+    IPC_MESSAGE_HANDLER(EwkFrameMsg_SetKeySystemWhitelist,
+                        OnSetKeySystemWhitelist)
+#endif
     IPC_MESSAGE_HANDLER(EwkFrameMsg_GetPlainText, OnGetPlainText);
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
@@ -156,6 +160,18 @@ void RenderFrameObserverEfl::OnRequestSelectCollectionInformation() {
 #endif
 }
 
+#if BUILDFLAG(IS_TIZEN_TV)
+void RenderFrameObserverEfl::OnSetKeySystemWhitelist(
+    const std::vector<std::string>& list) {
+  auto client = static_cast<ContentRendererClientEfl*>(
+      GetContentClientExport()->renderer());
+  LOG(INFO) << "received key system whitelist, size: " << list.size();
+  if (client) {
+    client->SetKeySystemWhitelist(list);
+  }
+}
+#endif
+
 void RenderFrameObserverEfl::DidChangeScrollOffset() {
   if (render_frame()->GetMainRenderFrame() != render_frame()) {
     return;
index 2059509c2aa300a5ad733dcf3bd5e044d3bed181..6cc36337e66dc7e2ebeefc769c65af4d84b096e5 100644 (file)
@@ -5,6 +5,7 @@
 #ifndef RENDER_FRAME_OBSERVER_EFL_H_
 #define RENDER_FRAME_OBSERVER_EFL_H_
 
+#include <string>
 #include <vector>
 
 #include "content/public/renderer/render_frame_observer.h"
@@ -70,6 +71,9 @@ class RenderFrameObserverEfl : public RenderFrameObserver {
 
   void OnMoveToNextOrPreviousSelectElement(bool direction);
   void OnRequestSelectCollectionInformation();
+#if BUILDFLAG(IS_TIZEN_TV)
+  void OnSetKeySystemWhitelist(const std::vector<std::string>& list);
+#endif
   void OnGetPlainText(int callback_id);
 
   gfx::Size max_scroll_offset_;
index 9bc87e07c316d70aaeb02a30451633bf08ccbfa6..34e987e2bd1d7c05ac06209dece3fc541c20481b 100644 (file)
@@ -838,6 +838,28 @@ void WebContentsDelegateEfl::ShowInspectorPortInfo() {
         JAVASCRIPT_DIALOG_TYPE_ALERT, false, std::move(dialog_closed_callback));
   }
 }
+
+const std::string& WebContentsDelegateEfl::GetActiveDRM() {
+  return web_view_->GetActiveDRM();
+}
+
+#if defined(TIZEN_MULTIMEDIA_DRMMANAGER_SUPPORT)
+void WebContentsDelegateEfl::NotifyDRMInitData(
+    int init_type,
+    const std::vector<unsigned char>& data) {
+  web_view_->NotifyDRMInitData(init_type, data);
+}
+
+int WebContentsDelegateEfl::NotifyDRMInitComplete(unsigned int pssh_data_length,
+                                                  unsigned char* pssh_data) {
+  return web_view_->NotifyDRMInitComplete(pssh_data_length, pssh_data);
+}
+
+void WebContentsDelegateEfl::NotifyDRMError(int error_code,
+                                            const std::string& error_string) {
+  return web_view_->NotifyDRMError(error_code, error_string);
+}
+#endif
 #endif
 
 #if BUILDFLAG(IS_TIZEN_TV)
index f05395d0f136f3babf4b5fbb2d1d98eb0120409f..8029cbbe8a9e6278450c667e429c7c74928dd15f 100644 (file)
@@ -207,6 +207,14 @@ class WebContentsDelegateEfl : public WebContentsDelegate {
                                 int framerate) override;
   void NotifyMediaDeviceConnectionChanged(int device_type) override;
   int GetBroadcastDecoder() override;
+  const std::string& GetActiveDRM() override;
+#if defined(TIZEN_MULTIMEDIA_DRMMANAGER_SUPPORT)
+  void NotifyDRMInitData(int init_type,
+                         const std::vector<unsigned char>& data) override;
+  int NotifyDRMInitComplete(unsigned int pssh_data_length,
+                            unsigned char* pssh_data) override;
+  void NotifyDRMError(int error_code, const std::string& error_string) override;
+#endif
 #endif
 
 #if defined(TIZEN_AUTOFILL)