[M120] Suspend/Resume sequence 84/311984/10
authorxiaofang <fang.xiao@samsung.com>
Fri, 31 May 2024 09:38:46 +0000 (17:38 +0800)
committerSunwoo Nam <sunny.nam@samsung.com>
Mon, 8 Jul 2024 06:14:09 +0000 (06:14 +0000)
Four player state defined:
enum class PlayerState {
  BARRED = underlying(State::NONE),
  AWAITING = underlying(State::ACTIVE),
  PREEMPTED = underlying(State::VISIBLE),
  RUNNING = underlying(State::ACTIVE | State::VISIBLE),
};

When player created, it will be marked VISIBLE by default. Once player
can play, will be marked ACTIVE.Only ACTIVE&VISIBLE, player will be in RUNNING state.
There are three suspend scenarios in current logic, suspend_by_element,
suspend_by_capability and suspend_by_resource_conflict.suspend_by_element
 will mark as ~VISIBLE.the others will both mark as ~AVTIVE,but
suspend_by_capability is done in MediaCapabilityManager,
suspend_by_resource_conflict is done in TizenRendererImpl.
Both of suspend_by_capability and suspend_by_resource_conflict only send
suspend to render process, but not send to browser process from render.

Change-Id: I2a0487ed19186539e45a6d4f52ad8524e7494946
Signed-off-by: xiaofang <fang.xiao@samsung.com>
24 files changed:
media/base/pipeline.h
media/base/pipeline_impl.cc
media/base/pipeline_impl.h
media/base/renderer.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.h
third_party/blink/renderer/core/html/media/html_media_element.cc
third_party/blink/renderer/platform/media/web_media_player_impl.cc
third_party/blink/renderer/platform/media/web_media_player_impl.h
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/filters/longest_conflict_strategy.cc
tizen_src/chromium_impl/media/filters/media_capability_manager.h
tizen_src/chromium_impl/media/filters/media_capability_manager_impl.h
tizen_src/chromium_impl/media/filters/media_player_esplusplayer.cc
tizen_src/chromium_impl/media/filters/media_player_registry.cc

index e6838a544ff343b7a32c482391a16d87b847a007..64f21e0ee468d167edf7fb5f515d97e40c3ee822 100644 (file)
@@ -356,6 +356,10 @@ class MEDIA_EXPORT Pipeline {
   virtual bool SetWallClock(const std::string& wallclock_url) = 0;
   virtual double GetStartDate() = 0;
   virtual void DestroyPlayerSync(base::OnceClosure cb) = 0;
+  virtual void Activate() = 0;
+  virtual void Deactivate() = 0;
+  virtual void Show() = 0;
+  virtual void Hide() = 0;
 #endif
 };
 
index 293a06836e1e3832208f6c87d669bfd399703c89..6b9e9a2f13c51ffe50a84ba7cbfbc865f4e1e26a 100644 (file)
@@ -143,6 +143,10 @@ class PipelineImpl::RendererWrapper final : public DemuxerHost,
   double GetStartDate();
   void DestroyPlayerSync(base::OnceClosure cb);
   void OnUpdatePlayerID(int player_id);
+  void Activate();
+  void Deactivate();
+  void Show();
+  void Hide();
 #endif
 
   // |enabled_track_ids| contains track ids of enabled audio tracks.
@@ -565,6 +569,11 @@ void PipelineImpl::RendererWrapper::Suspend() {
   SetState(kSuspending);
 
 #if defined(TIZEN_MULTIMEDIA)
+  if (!shared_state_.renderer) {
+    LOG(WARNING) << __func__ << " renderer is not created yet, not do suspend. ";
+    return;
+  }
+
   if (request_suspend_task_handle_.IsValid()) {
     LOG(INFO) << " Cancel posted request suspend task if pended.";
     request_suspend_task_handle_.CancelTask();
@@ -607,12 +616,6 @@ void PipelineImpl::RendererWrapper::Resume(
   }
   DCHECK(!pending_callbacks_.get());
 
-  if (!default_renderer) {
-    OnPipelineError({PIPELINE_ERROR_INITIALIZATION_FAILED,
-                     "Media Renderer creation failed during resume!"});
-    return;
-  }
-
   SetState(kResuming);
 
   {
@@ -1122,6 +1125,38 @@ void PipelineImpl::RendererWrapper::PlayerDestroyed() {
   // signal
   std::move(player_destroy_cb_).Run();
 }
+
+void PipelineImpl::RendererWrapper::Activate() {
+  DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
+
+  LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
+  if (shared_state_.renderer)
+    shared_state_.renderer->Activate();
+}
+
+void PipelineImpl::RendererWrapper::Deactivate() {
+  DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
+
+  LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
+  if (shared_state_.renderer)
+    shared_state_.renderer->Deactivate();
+}
+
+void PipelineImpl::RendererWrapper::Show() {
+  DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
+
+  LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
+  if (shared_state_.renderer)
+    shared_state_.renderer->Show();
+}
+
+void PipelineImpl::RendererWrapper::Hide() {
+  DCHECK(media_task_runner_->RunsTasksInCurrentSequence());
+
+  LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
+  if (shared_state_.renderer)
+    shared_state_.renderer->Hide();
+}
 #endif
 
 void PipelineImpl::RendererWrapper::CreateRendererInternal(
@@ -1571,6 +1606,42 @@ bool PipelineImpl::SetWallClock(const std::string& wallclock_url) {
   DCHECK(thread_checker_.CalledOnValidThread());
   return renderer_wrapper_->SetWallClock(wallclock_url);
 }
+
+void PipelineImpl::Activate() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
+  media_task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&RendererWrapper::Activate,
+                     base::Unretained(renderer_wrapper_.get())));
+}
+
+void PipelineImpl::Deactivate() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
+  media_task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&RendererWrapper::Deactivate,
+                     base::Unretained(renderer_wrapper_.get())));
+}
+
+void PipelineImpl::Show() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
+  media_task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&RendererWrapper::Show,
+                     base::Unretained(renderer_wrapper_.get())));
+}
+
+void PipelineImpl::Hide() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
+  media_task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&RendererWrapper::Hide,
+                     base::Unretained(renderer_wrapper_.get())));
+}
 #endif
 
 #if defined(TIZEN_MULTIMEDIA)
@@ -2145,7 +2216,6 @@ void PipelineImpl::Suspend(PipelineStatusCallback suspend_cb) {
   DCHECK(IsRunning());
   DCHECK(!suspend_cb_);
   suspend_cb_ = std::move(suspend_cb);
-
   media_task_runner_->PostTask(
       FROM_HERE, base::BindOnce(&RendererWrapper::Suspend,
                                 base::Unretained(renderer_wrapper_.get())));
index ea35341c278c85250c27206fafda6d985cc6c7a9..296c5e3a0c5312dc79333779de1003643e6b078f 100644 (file)
@@ -144,6 +144,13 @@ class MEDIA_EXPORT PipelineImpl : public Pipeline {
 
   void OnExternalVideoFrameRequest() override;
 
+#if BUILDFLAG(IS_TIZEN_TV)
+  void Activate() override;
+  void Deactivate() override;
+  void Show() override;
+  void Hide() override;
+#endif
+
  private:
   friend class MediaLog;
   class RendererWrapper;
index ecea53f882dde39bca7985c564fbc2cc577ceef6..86555ab69f5972b81d7b0d8adccdb93001926fa9 100644 (file)
@@ -159,6 +159,10 @@ class MEDIA_EXPORT Renderer {
                             SetWallClockCB cb) {}
   virtual void GetStartDate(StartDateCB cb) {}
   virtual void DestroyPlayerSync(base::OnceClosure cb) {}
+  virtual void Activate() {}
+  virtual void Deactivate() {}
+  virtual void Show() {}
+  virtual void Hide() {}
 #endif
 
   // Starts rendering from |time|.
index ddef322746ad4febf7e82346b47ea24a5f1cc913..7f459751788b0193743dc35e8bec6c5e01964a08 100644 (file)
@@ -171,7 +171,13 @@ void PipelineController::OnPipelineStatus(State expected_state,
   }
 
   State old_state = state_;
-  state_ = expected_state;
+
+#if BUILDFLAG(IS_TIZEN_TV)
+  if ((old_state == State::RESUMING) && (expected_state == State::SUSPENDED))
+    state_ = State::RESUMING;
+  else
+#endif
+    state_ = expected_state;
 
   // Resolve ambiguity of the current state if we may have suspended in startup.
   if (state_ == State::PLAYING_OR_SUSPENDED) {
@@ -220,8 +226,18 @@ void PipelineController::Dispatch() {
   // are wasted, and seeks after can be merged into the resume operation.
   if (pending_suspend_ && state_ == State::PLAYING) {
     pending_suspend_ = false;
+
+// During suspend sequence, pipeline_impl suspended status post task will be
+// done after resume excuted. suspend_cb_ always return OK except pipeline
+// error, so here can set suspended directly once suspend called.
+#if BUILDFLAG(IS_TIZEN_TV)
+    state_ = State::SUSPENDED;
+#else
     state_ = State::SUSPENDING;
-    LOG(INFO) << "Dispatch Suspend: " << this;
+#endif
+
+    LOG(INFO) << __func__ << "  this : " << (void*)this << " state_: "
+             << static_cast<typename std::underlying_type<State>::type>(state_);
     pipeline_->Suspend(base::BindOnce(&PipelineController::OnPipelineStatus,
                                       weak_factory_.GetWeakPtr(),
                                       State::SUSPENDED));
@@ -260,7 +276,8 @@ void PipelineController::Dispatch() {
     state_ = State::RESUMING;
     before_resume_cb_.Run();
 
-    LOG(INFO) << "Dispatch Resume: " << this;
+    LOG(INFO) << "Dispatch Resume: " << this << " state_: "
+              << static_cast<typename std::underlying_type<State>::type>(state_);
     pipeline_->Resume(
         seek_time_, base::BindOnce(&PipelineController::OnPipelineStatus,
                                    weak_factory_.GetWeakPtr(), State::PLAYING));
@@ -632,5 +649,41 @@ void PipelineController::DestroyPlayerSync(base::OnceClosure cb) {
     std::move(cb).Run();
   }
 }
+
+void PipelineController::Activate() {
+  if (pipeline_) {
+    pipeline_->Activate();
+  }
+  else {
+    LOG(ERROR) << "pipeline_ is null";
+  }
+}
+
+void PipelineController::Deactivate() {
+  if (pipeline_) {
+    pipeline_->Deactivate();
+  }
+  else {
+    LOG(ERROR) << "pipeline_ is null";
+  }
+}
+
+void PipelineController::Show() {
+  if (pipeline_) {
+    pipeline_->Show();
+  }
+  else {
+    LOG(ERROR) << "pipeline_ is null";
+  }
+}
+
+void PipelineController::Hide() {
+  if (pipeline_) {
+    pipeline_->Hide();
+  }
+  else {
+    LOG(ERROR) << "pipeline_ is null";
+  }
+}
 #endif
 }  // namespace media
index 63795ff95897262af376ac99e320b476460eb22c..37e9cef6e2ef6000bc9116055442b7a5ab9e22e1 100644 (file)
@@ -189,6 +189,10 @@ class MEDIA_EXPORT PipelineController {
   bool SetWallClock(const std::string& wallclock_url);
   double GetStartDate() const;
   void DestroyPlayerSync(base::OnceClosure cb);
+  void Activate();
+  void Deactivate();
+  void Show();
+  void Hide();
 #endif
  private:
   // Attempts to make progress from the current state to the target state.
index 28f7d32c4f07841b3e9b1d5359cd12ce462c3ef0..e529a01540321410e0029e58b91f47c85a8a1f2f 100644 (file)
@@ -562,6 +562,38 @@ void MojoRenderer::OnUpdatePlayerID(int player_id) {
            << " player_id " << player_id;
   client_->OnUpdatePlayerID(player_id);
 }
+
+void MojoRenderer::Activate() {
+  DVLOG(2) << "(" << static_cast<void*>(this) << ") " << __func__;
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
+
+  if (remote_renderer_.is_bound())
+    remote_renderer_->Activate();
+}
+
+void MojoRenderer::Deactivate() {
+  DVLOG(2) << "(" << static_cast<void*>(this) << ") " << __func__;
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
+
+  if (remote_renderer_.is_bound())
+    remote_renderer_->Deactivate();
+}
+
+void MojoRenderer::Show() {
+  DVLOG(2) << "(" << static_cast<void*>(this) << ") " << __func__;
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
+
+  if (remote_renderer_.is_bound())
+    remote_renderer_->Show();
+}
+
+void MojoRenderer::Hide() {
+  DVLOG(2) << "(" << static_cast<void*>(this) << ") " << __func__;
+  DCHECK(task_runner_->RunsTasksInCurrentSequence());
+
+  if (remote_renderer_.is_bound())
+    remote_renderer_->Hide();
+}
 #endif
 
 void MojoRenderer::OnWaiting(WaitingReason reason) {
index e6952df436894e63b8591216f7edf8a090da65e7..b8ab4f124466f3c1b4ea0298f7e40783f6e4089a 100644 (file)
@@ -111,6 +111,10 @@ class MojoRenderer : public Renderer, public mojom::RendererClient {
   void GetStartDate(StartDateCB cb) override;
   void DestroyPlayerSync(base::OnceClosure cb) override;
   void OnUpdatePlayerID(int player_id) override;
+  void Activate() override;
+  void Deactivate() override;
+  void Show() override;
+  void Hide() override;
 #endif
 
  private:
index 8a975050114771fc2c36f77a2ee7cd3ee0c1af69..942027fc0cd3dbfb5c3447f1de15595263fd9abd 100644 (file)
@@ -206,6 +206,38 @@ void MojoRendererWrapper::DestroyPlayerSync(base::OnceClosure cb) {
     std::move(cb).Run();
   }
 }
+
+void MojoRendererWrapper::Activate() {
+  if (mojo_renderer_) {
+    mojo_renderer_->Activate();
+  } else {
+    LOG(ERROR) << "mojo_renderer_ is null";
+  }
+}
+
+void MojoRendererWrapper::Deactivate() {
+  if (mojo_renderer_) {
+    mojo_renderer_->Deactivate();
+  } else {
+    LOG(ERROR) << "mojo_renderer_ is null";
+  }
+}
+
+void MojoRendererWrapper::Show() {
+  if (mojo_renderer_) {
+    mojo_renderer_->Show();
+  } else {
+    LOG(ERROR) << "mojo_renderer_ is null";
+  }
+}
+
+void MojoRendererWrapper::Hide() {
+  if (mojo_renderer_) {
+    mojo_renderer_->Hide();
+  } else {
+    LOG(ERROR) << "mojo_renderer_ is null";
+  }
+}
 #endif
 
 }  // namespace media
index b74f99bec0c10beb04e96ad554ce02dad88bc3f9..6e767c3e0f108759dd861d9837163eda00e9cff0 100644 (file)
@@ -87,6 +87,11 @@ class MojoRendererWrapper : public Renderer {
                     SetWallClockCB cb) override;
   void GetStartDate(StartDateCB cb) override;
   void DestroyPlayerSync(base::OnceClosure cb) override;
+
+  void Activate() override;
+  void Deactivate() override;
+  void Show() override;
+  void Hide() override;
 #endif
 
   base::TimeDelta GetMediaTime() override;
index 187dc0cb856e14afef59e7f7ea26be4019394c56..a60dc4e8f323f6bbdf7727319529ef72d0fe6422 100644 (file)
@@ -148,6 +148,18 @@ interface Renderer {
 
   [EnableIf=is_tizen_tv]
   DestroyPlayerSync() => ();
+
+  [EnableIf=is_tizen_tv]
+  Activate();
+
+  [EnableIf=is_tizen_tv]
+  Deactivate();
+
+  [EnableIf=is_tizen_tv]
+  Show();
+
+  [EnableIf=is_tizen_tv]
+  Hide();
 };
 
 // A Mojo equivalent of media::RendererClient. See media/mojo/README.md
index 8cf15226f5a9f369ba3f1dd9f308224135ab117c..bea6ad8312e4e20d51dff4a31762f0204565bff1 100644 (file)
@@ -407,6 +407,46 @@ void MojoRendererService::OnUpdatePlayerID(int player_id) {
   DVLOG(2) << __func__ << "(" << player_id << ")";
   client_->OnUpdatePlayerID(player_id);
 }
+
+void MojoRendererService::Activate() {
+  DVLOG(2) << __func__;
+
+  if (renderer_) {
+    renderer_->Activate();
+  } else {
+    LOG(ERROR) << "renderer_ is null";
+  }
+}
+
+void MojoRendererService::Deactivate() {
+  DVLOG(2) << __func__;
+
+  if (renderer_){
+    renderer_->Deactivate();
+  } else {
+    LOG(ERROR) << "renderer_ is null";
+  }
+}
+
+void MojoRendererService::Show() {
+  DVLOG(2) << __func__;
+
+  if (renderer_) {
+    renderer_->Show();
+  } else {
+    LOG(ERROR) << "renderer_ is null";
+  }
+}
+
+void MojoRendererService::Hide() {
+  DVLOG(2) << __func__;
+
+  if (renderer_){
+    renderer_->Hide();
+  } else {
+    LOG(ERROR) << "renderer_ is null";
+  }
+}
 #endif
 
 void MojoRendererService::OnBufferingStateChange(
index af29878991cfcd0e30e3ca0426f12c97ff51c6cb..c602fe8fad7e69f3a2ba5e5d893f5ad4961737f7 100644 (file)
@@ -118,6 +118,11 @@ class MEDIA_MOJO_EXPORT MojoRendererService final : public mojom::Renderer,
   void GetStartDate(GetStartDateCallback cb) final;
   void DestroyPlayerSync(base::OnceClosure destroy_cb) final;
   void OnUpdatePlayerID(int player_id) final;
+
+  void Activate() final;
+  void Deactivate() final;
+  void Show() final;
+  void Hide() final;
 #endif
 
  private:
index b6dc6c0c3209c4ad1d5ed0b6651aac393b85927f..6e3210d7b4eaacc98dcd29dd4eaa16bfc79f9c51 100644 (file)
@@ -449,6 +449,12 @@ class WebMediaPlayer {
   virtual double GetStartDate() const {
     return std::numeric_limits<double>::quiet_NaN();
   }
+
+  virtual void Activate() {};
+  virtual void Deactivate() {};
+  virtual void Show() {};
+  virtual void Hide() {};
+  virtual bool IsSuspendByInternal() {return false;};
 #endif
 };
 
index 2f4a9de2fb1968c87fe3536ac37c8f37406ebcc7..2906f86b81e0f29daef87f8020d001764540d43a 100644 (file)
@@ -913,6 +913,9 @@ void HTMLMediaElement::ScheduleEvent(Event* event) {
     DVLOG(3) << "ScheduleEvent(" << (void*)this << ")"
              << " - scheduling '" << event->type() << "'";
 #endif
+  if (event_type_names::kTimeupdate != event->type())
+    LOG(INFO) << "ScheduleEvent(" << (void*)this << ")"
+              << " - scheduling '" << event->type() << "'";
   async_event_queue_->EnqueueEvent(FROM_HERE, *event);
 }
 
@@ -2858,6 +2861,11 @@ absl::optional<DOMExceptionCode> HTMLMediaElement::Play() {
       autoplay_policy_->RequestPlay();
 #if BUILDFLAG(IS_TIZEN_TV)
   is_deactivate_ = false;
+  if (GetWebMediaPlayer() && GetWebMediaPlayer()->IsSuspendByInternal()) {
+    LOG(INFO) << "play(" << *this << ") Resume play due to requestsuspend!";
+    GetWebMediaPlayer()->Activate();
+    GetWebMediaPlayer()->Resume();
+  }
 #endif
 
   if (exception_code == DOMExceptionCode::kNotAllowedError) {
@@ -4290,6 +4298,7 @@ void HTMLMediaElement::ContextLifecycleStateChanged(
       LOG(INFO) << "Already suspend by WRT, return directly.";
       return;
     }
+    suspend_media_by_wrt_ = true;
 #endif
     // Suspend if a browser tab is switched.
     if (GetWebMediaPlayer())
@@ -4308,6 +4317,7 @@ void HTMLMediaElement::ContextLifecycleStateChanged(
       LOG(INFO) << "Already resume by WRT, return directly.";
       return;
     }
+    resume_media_by_wrt_ = false;
 #endif
 
     // Do not resume if suspended by player except the resource conflict case.
@@ -4768,6 +4778,11 @@ void HTMLMediaElement::SetPreferTextLang(const String& lang) {
 void HTMLMediaElement::WRTMediaSuspend(bool suspend) {
   LOG(INFO) << "WRTMediaSuspend:" << suspend << ",this:" << (void*)this;
   if (suspend) {
+    resume_media_by_wrt_ = false;
+    if (suspend_media_by_wrt_) {
+      LOG(INFO) << "Already suspend, return directly.";
+      return;
+    }
     suspend_media_by_wrt_ = true;
 
 #if defined(SAMSUNG_ELEMENTARY_MEDIA_STREAM_SOURCE)
@@ -4788,6 +4803,11 @@ void HTMLMediaElement::WRTMediaSuspend(bool suspend) {
       pause();
     }
   } else {
+    suspend_media_by_wrt_ = false;
+    if (resume_media_by_wrt_) {
+      LOG(INFO) << "Already resume, return directly.";
+      return;
+    }
     resume_media_by_wrt_ = true;
 
 #if defined(SAMSUNG_ELEMENTARY_MEDIA_STREAM_SOURCE)
index e92b7e0391fa8890aef301fdf960d847f3b0cca5..71dceea68c6b4e719ac335eacf25366e841c3bfa 100644 (file)
@@ -41,6 +41,7 @@
 #include "media/base/demuxer.h"
 #include "media/base/encryption_scheme.h"
 #include "media/base/limits.h"
+#include "media/base/logging_override_if_enabled.h"
 #include "media/base/media_content_type.h"
 #include "media/base/media_log.h"
 #include "media/base/media_player_logging_id.h"
@@ -627,6 +628,9 @@ WebMediaPlayerImpl::~WebMediaPlayerImpl() {
         &base::WaitableEvent::Signal, base::Unretained(&waiter)));
     waiter.Wait();
   }
+
+  is_paused_by_internal_ = false;
+  is_suspend_by_upper_ = false;
 #endif
 
   // The underlying Pipeline must be stopped before it is destroyed.
@@ -1009,7 +1013,7 @@ void WebMediaPlayerImpl::DoLoad(LoadType load_type,
 }
 
 void WebMediaPlayerImpl::Play() {
-  DVLOG(1) << __func__;
+  DVLOG(1) << __func__ << ", this : " << (void*)this;
   DCHECK(main_task_runner_->BelongsToCurrentThread());
 
   // User initiated play unlocks background video playback.
@@ -1021,8 +1025,8 @@ void WebMediaPlayerImpl::Play() {
   paused_ = false;
   pipeline_controller_->SetPlaybackRate(playback_rate_);
   background_pause_timer_.Stop();
-#if defined(TIZEN_MULTIMEDIA)
-  was_suspended_by_player_ = false;
+#if BUILDFLAG(IS_TIZEN_TV)
+  is_paused_by_internal_ = false;
 #endif
 
   if (observer_)
@@ -2319,6 +2323,28 @@ bool WebMediaPlayerImpl::IsSyncDestroyPlayerNeeded() {
     return true;
   return false;
 }
+
+void WebMediaPlayerImpl::Activate() {
+  is_paused_by_internal_ = false;
+  if (pipeline_controller_)
+    pipeline_controller_->Activate();
+}
+
+void WebMediaPlayerImpl::Deactivate() {
+  if (pipeline_controller_)
+    pipeline_controller_->Deactivate();
+}
+
+void WebMediaPlayerImpl::Show() {
+  is_suspend_by_upper_ = false;
+  if (pipeline_controller_)
+    pipeline_controller_->Show();
+}
+
+void WebMediaPlayerImpl::Hide() {
+  if (pipeline_controller_)
+    pipeline_controller_->Hide();
+}
 #endif
 
 bool WebMediaPlayerImpl::CanPlayThrough() {
@@ -2434,8 +2460,18 @@ void WebMediaPlayerImpl::OnBufferingStateChangeInternal(
 
     // It shouldn't be possible to underflow if we've not advanced past
     // HAVE_CURRENT_DATA.
-    DCHECK_GT(highest_ready_state_, WebMediaPlayer::kReadyStateHaveCurrentData);
-    SetReadyState(WebMediaPlayer::kReadyStateHaveCurrentData);
+#if BUILDFLAG(IS_TIZEN_TV)
+    if (is_paused_by_internal_) {
+      LOG(INFO) << "Suspended by internal, just report kReadyStateHaveMetadata.";
+      DCHECK_GT(highest_ready_state_, WebMediaPlayer::kReadyStateHaveMetadata);
+      SetReadyState(WebMediaPlayer::kReadyStateHaveMetadata);
+    } else {
+#endif
+      DCHECK_GT(highest_ready_state_, WebMediaPlayer::kReadyStateHaveCurrentData);
+      SetReadyState(WebMediaPlayer::kReadyStateHaveCurrentData);
+#if BUILDFLAG(IS_TIZEN_TV)
+    }
+#endif
   }
 
   // If this is an NNR, then notify the smoothness helper about it.  Note that
@@ -2857,14 +2893,23 @@ void WebMediaPlayerImpl::OnVideoPipelineInfoChange(
 }
 
 #if defined(TIZEN_MULTIMEDIA)
+// Only Tab switch or APP suspend called
 void WebMediaPlayerImpl::Suspend() {
   LOG(INFO) << __func__ << " this " << this;
   SetSuspendState(true);
+#if BUILDFLAG(IS_TIZEN_TV)
+  is_suspend_by_upper_ = true;
+  Hide();
+#endif
 }
 
 void WebMediaPlayerImpl::Resume() {
   LOG(INFO) << __func__ << " this " << this;
   SetSuspendState(false);
+#if BUILDFLAG(IS_TIZEN_TV)
+  is_suspend_by_upper_ = false;
+  Show();
+#endif
 }
 
 void WebMediaPlayerImpl::OnSeekableTimeChange(base::TimeDelta min_time,
@@ -2887,10 +2932,7 @@ void WebMediaPlayerImpl::OnLivePlaybackComplete() {
 }
 
 void WebMediaPlayerImpl::OnRequestSuspend(bool resource_conflicted) {
-  if (pipeline_controller_->IsSuspended()) {
-    LOG(INFO) << __func__ << " Already suspended.";
-    return;
-  }
+  LOG(INFO) << __func__ << " resource_conflicted : " << resource_conflicted;
 
 #if BUILDFLAG(IS_TIZEN_TV)
   if (suspend_by_multi_reload_) {
@@ -2901,11 +2943,21 @@ void WebMediaPlayerImpl::OnRequestSuspend(bool resource_conflicted) {
   }
 #endif
 
+  if (pipeline_controller_->IsSuspended()) {
+    LOG(INFO) << __func__ << " Already suspended."
+              << ", this : " << (void*)this;
+    return;
+  }
+
+#if BUILDFLAG(IS_TIZEN_TV)
+  is_paused_by_internal_ = true;
+#endif
+
   // Check if suspended by the resource conflict or not.
   // If resource is conflicted by other process, it can be resumed.
-  was_suspended_by_player_ = !resource_conflicted;
+  // fixup! in resource_conflict scenario
+  // was_suspended_by_player_ = !resource_conflicted;
 
-  client_->PausePlayback(WebMediaPlayerClient::PauseReason::kUnknown);
   client_->SuspendPlayer();
   SetSuspendState(true);
 }
@@ -3523,12 +3575,16 @@ void WebMediaPlayerImpl::SetMemoryReportingState(
 
 void WebMediaPlayerImpl::SetSuspendState(bool is_suspended) {
   DCHECK(main_task_runner_->BelongsToCurrentThread());
-  LOG(INFO) << __func__ << "(" << is_suspended << ")";
+  LOG(INFO) << __func__ << "(" << is_suspended << ") ; this : " << (void*)this;
 
   // Do not change the state after an error has occurred.
   // TODO(sandersd): Update PipelineController to remove the need for this.
-  if (IsNetworkStateError(network_state_))
+  if (IsNetworkStateError(network_state_)) {
+    LOG(ERROR) << __func__
+               << " network_state_: " << static_cast<int>(network_state_)
+               << " ; this : " << (void*)this;
     return;
+  }
 
   if (is_suspended) {
     // If we were not resumed for long enough to satisfy the preroll attempt,
@@ -3599,8 +3655,9 @@ WebMediaPlayerImpl::UpdatePlayState_ComputePlayState(
 
   // Combined suspend state.
   result.is_suspended = must_suspend || idle_suspended ||
-#if defined(TIZEN_MULTIMEDIA)
-                        was_suspended_by_player_ ||
+#if BUILDFLAG(IS_TIZEN_TV)
+                          is_paused_by_internal_ ||
+                          is_suspend_by_upper_ ||
 #endif
                         background_suspended || can_stay_suspended;
 
@@ -3610,7 +3667,13 @@ WebMediaPlayerImpl::UpdatePlayState_ComputePlayState(
             << ", can_stay_suspended=" << can_stay_suspended
             << ", is_stale=" << is_stale
             << ", have_future_data=" << have_future_data
-            << ", paused_=" << paused_ << ", seeking_=" << seeking_;
+            << ", paused_=" << paused_ << ", seeking_=" << seeking_
+#if BUILDFLAG(IS_TIZEN_TV)
+            << ", is_paused_by_internal_ =" << is_paused_by_internal_
+            << ", is_suspend_by_upper_ = " << is_suspend_by_upper_
+#endif
+            << ", result.is_suspended=" << result.is_suspended
+            << ", this : " << (void*)this;
 
   // We do not treat `playback_rate_` == 0 as paused. For the media session,
   // being paused implies displaying a play button, which is incorrect in this
index 1009be0e5d0b24daa65d750968912abfa1b7f977..3d8836bd05cd7093412e7971b7718be69f0e8ba5 100644 (file)
@@ -189,8 +189,6 @@ class PLATFORM_EXPORT WebMediaPlayerImpl
 #if defined(TIZEN_MULTIMEDIA)
   void Suspend() override;
   void Resume() override;
-
-  bool SuspendedByPlayer() override { return was_suspended_by_player_; }
 #endif
 
   void OnFrozen() override;
@@ -249,6 +247,11 @@ class PLATFORM_EXPORT WebMediaPlayerImpl
       media::register_timeline_cb_info_s info) override;
   void OnMrsUrlChange(const std::string& url) override;
   void OnContentIdChange(const std::string& id) override;
+
+  void Activate() override;
+  void Deactivate() override;
+  void Show() override;
+  void Hide() override;
 #endif
 
   // Shared between the WebMediaPlayer and DemuxerManager::Client interfaces.
@@ -358,6 +361,7 @@ class PLATFORM_EXPORT WebMediaPlayerImpl
 
 #if BUILDFLAG(IS_TIZEN_TV)
   double GetStartDate() const override;
+  bool IsSuspendByInternal() override { return is_paused_by_internal_; }
 #endif
 
   // Distinct states that |delegate_| can be in. (Public for testing.)
@@ -1184,6 +1188,11 @@ class PLATFORM_EXPORT WebMediaPlayerImpl
   base::TimeDelta max_seekable_time_;
 #endif
 
+#if BUILDFLAG(IS_TIZEN_TV)
+  bool is_paused_by_internal_ = false;
+  bool is_suspend_by_upper_ = false;
+#endif
+
   // Request pipeline to suspend. It should not block other signals after
   // suspended.
   bool pending_oneshot_suspend_ = false;
index 453cf522235fdb3eebef61da0e40f675de6c59ec..bed1b0662922732109e73339338734f94593725b 100644 (file)
@@ -231,15 +231,23 @@ void TizenRendererImpl::Initialize(media::MediaResource* media_resource,
   media_player_->SetTaskRunner(task_runner_.get());
 
   if (!media::MediaPlayerRegistry::GetInstance()->ActivateMediaPlayer(
-          player_id_, !resource_conflicted_)) {
+          player_id_, !is_suspended_by_resource_conflicted_)) {
     LOG_ID(INFO, player_id_)
         << "(" << static_cast<void*>(this) << ") " << __func__
         << " Can not initialize the player id: " << player_id_;
     return;
   }
 
-  is_suspended_ = false;
-  resource_conflicted_ = false;
+  is_suspended_by_resource_conflicted_ = false;
+  is_suspended_by_upper_ = false;
+  is_suspended_by_internal_ = false;
+  LOG_ID(INFO, player_id_) << "(" << static_cast<void*>(this) << ") "
+                           << __func__ << " is_suspended_by_upper_: "
+                           << is_suspended_by_upper_
+                           << " is_suspended_by_internal_: "
+                           << is_suspended_by_internal_
+                           << " is_suspended_by_resource_conflicted_ : "
+                           << is_suspended_by_resource_conflicted_;
 
   // Initialize and Prepare early when resource type is URL.
   if (media_resource_->GetType() == media::MediaResource::Type::KUrl) {
@@ -416,10 +424,11 @@ content::WebContents* TizenRendererImpl::GetWebContents() const {
       RenderFrameHost::FromID(render_process_id_, routing_id_));
 }
 
+// upper suspend
 void TizenRendererImpl::Suspend() {
   LOG_ID(INFO, player_id_) << "(" << static_cast<void*>(this) << ") "
                            << __func__;
-  if (is_suspended_)
+  if (is_suspended_by_upper_)
     return;
 
   if (!media_player_) {
@@ -427,10 +436,8 @@ void TizenRendererImpl::Suspend() {
     return;
   }
 
-  media::MediaPlayerRegistry::GetInstance()->DeactivateMediaPlayer(
-      player_id_, !resource_conflicted_);
   media_player_->Release();
-  is_suspended_ = true;
+  is_suspended_by_upper_ = true;
 }
 
 void TizenRendererImpl::EnableLowLatencyMode() {
@@ -649,6 +656,15 @@ void TizenRendererImpl::StartPlayingFrom(base::TimeDelta time) {
   TRACE_EVENT1("media", "TizenRendererImpl::StartPlayingFrom", "time_us",
                time.InMicroseconds());
 
+#if BUILDFLAG(IS_TIZEN_TV)
+  if (!is_player_can_start_) {
+    LOG_ID(WARNING, player_id_)
+          << "(" << static_cast<void*>(this) << ") " << __func__
+          << " , player state not match. Can not initialize the player id: " << player_id_;
+    return;
+  }
+#endif
+
   SetPlayerInitialize();
   SetPlayerPrepare();
 
@@ -899,7 +915,7 @@ void TizenRendererImpl::GetStartDate(StartDateCB cb) {
 void TizenRendererImpl::DestroyPlayerSync(base::OnceClosure destroy_cb) {
   if (media_player_) {
     media::MediaPlayerRegistry::GetInstance()->DeactivateMediaPlayer(
-        player_id_, !resource_conflicted_);
+        player_id_, !is_suspended_by_resource_conflicted_);
     media_player_->DestroyPlayerSync(std::move(destroy_cb));
   } else {
     LOG_ID(INFO, player_id_) << "media_player_ is nullptr";
@@ -999,6 +1015,37 @@ void TizenRendererImpl::SetCallBackFrameSize(const gfx::Size& size) {
   }
   media_player_->SetCallBackFrameSize(size);
 }
+
+void TizenRendererImpl::Activate() {
+  is_suspended_by_internal_ = false;
+  is_player_can_start_ = media::MediaPlayerRegistry::GetInstance()->ActivateMediaPlayer(
+        player_id_, false);
+  LOG_ID(INFO, player_id_) << __func__ << " ; is_player_can_start_ : " << is_player_can_start_;
+}
+
+void TizenRendererImpl::Deactivate() {
+  LOG_ID(INFO, player_id_) << __func__;
+  media::MediaPlayerRegistry::GetInstance()->DeactivateMediaPlayer(
+        player_id_, false);
+}
+
+void TizenRendererImpl::Show() {
+  if(!is_suspended_by_upper_) {
+    LOG_ID(INFO, player_id_) << __func__ << " ; no suspend, not need to resume.";
+    return;
+  }
+
+  is_suspended_by_upper_ = false;
+  is_player_can_start_ = media::MediaPlayerRegistry::GetInstance()->ActivateMediaPlayer(
+        player_id_, true);
+  LOG_ID(INFO, player_id_) << __func__ << " ; is_player_can_start_ : " << is_player_can_start_;
+}
+
+void TizenRendererImpl::Hide() {
+  LOG_ID(INFO, player_id_) << __func__;
+  media::MediaPlayerRegistry::GetInstance()->DeactivateMediaPlayer(
+        player_id_, true);
+}
 #endif  // BUILDFLAG(IS_TIZEN_TV)
 
 void TizenRendererImpl::OnSeekableTimeChange(base::TimeDelta min_time,
@@ -1062,20 +1109,27 @@ void TizenRendererImpl::OnRequestSeek(base::TimeDelta time) {
   client_->OnRequestSeek(time);
 }
 
+// Two scenarios: (both need set inactive)
+// 1) capability exceed, will call OnRequestSuspend(false)
+// 2) resource confict, will call OnRequestSuspend(false)
 void TizenRendererImpl::OnRequestSuspend(bool resource_conflicted) {
   LOG_ID(INFO, player_id_) << "(" << static_cast<void*>(this) << ") "
                            << __func__
                            << " ; resource_conflicted: " << resource_conflicted;
 
-  if (is_suspended_) {
-    LOG_ID(INFO, player_id_) << " Media is already suspended.";
+  if (is_suspended_by_internal_) {
+    LOG_ID(INFO, player_id_) << " Media is already suspended by internal.";
     return;
   }
 
-  resource_conflicted_ = resource_conflicted;
-  media::MediaPlayerRegistry::GetInstance()->DeactivateMediaPlayer(
-      player_id_, !resource_conflicted_);
-  is_suspended_ = true;
+  // Keep same logic with 23TV
+  // capability exceed, player state will set player state &= ~State::ACTIVE in
+  // other place resource conflict will set inactive here.
+  if (is_suspended_by_resource_conflicted_) {
+    media::MediaPlayerRegistry::GetInstance()->DeactivateMediaPlayer(
+        player_id_, !is_suspended_by_resource_conflicted_);
+  }
+  is_suspended_by_internal_ = true;
   client_->OnRequestSuspend(resource_conflicted);
 }
 
index 07d8ae0a858c6c047d49696877ab9da0ecc3df02..bd0521d6a0f6ed83531d03aef6e3a75560be2303 100644 (file)
@@ -152,6 +152,11 @@ class CONTENT_EXPORT TizenRendererImpl
   void GetVideoId(GetVideoIdCB cb) override;
   void SetCallBackFrameSize(const gfx::Size& size) override;
   void EnableTbmBufferCallback(bool enable) override;
+
+  void Activate() override;
+  void Deactivate() override;
+  void Show() override;
+  void Hide() override;
 #endif
 
 #if defined(TIZEN_TBM_SUPPORT)
@@ -282,8 +287,9 @@ class CONTENT_EXPORT TizenRendererImpl
 
   // Indicates if a serious error has been encountered by the |media_player_|.
   bool has_error_ = false;
-  bool resource_conflicted_ = true;
-  bool is_suspended_ = false;
+  bool is_suspended_by_resource_conflicted_ = true;
+  bool is_suspended_by_internal_ = false;
+  bool is_suspended_by_upper_ = false;
 
 #if defined(TIZEN_VIDEO_HOLE)
   bool use_subsurface_controller_ = false;
@@ -302,6 +308,7 @@ class CONTENT_EXPORT TizenRendererImpl
   // content, so that we can set it to the media_player_ before calling
   // initialize / prepare.
   std::string mime_type_;
+  bool is_player_can_start_ = true;
 #endif
 
   WebContents* web_contents_ = nullptr;
index f83bba869dbbf7337871376ad465443f633c2a69..ad15bb5b1681239b8d693040cff80cdccef9f888 100644 (file)
@@ -242,9 +242,10 @@ void LongestConflictStrategy::OnActivated(MediaPlayerTizen* player) {
 
 void LongestConflictStrategy::OnDeactivated(MediaPlayerTizen* player) {
   auto it = find(player);
-  if (it != info_.end())
+  if (it != info_.end()) {
     info_.erase(it);
-  LOG(INFO) << "Deactivating " << player << Info();
+    LOG(INFO) << "Deactivating " << player << Info();
+  }
 }
 
 LongestConflictStrategy::Resolution LongestConflictStrategy::Resolve(
index b148d15b374b893bccbe2b2eb7b9066fb8ddce70..86496d1e88fda6dba802106ec45e0d7d2fab83d9 100644 (file)
@@ -149,6 +149,7 @@ class MediaCapabilityManager : public MediaCapabilityManagerBase,
   // is called. As a matter of fact, they
   // are done in MoveTowardsRunning via
   // MovedFromBarred
+  template <State which_transition>
   std::vector<MediaPlayerTizen*> MarkRunning(MediaPlayerTizen* player);
 
   // Once the MarkRunning finds enough empty slots,
index 514aa8a4812153c1879ee28071b0c80939820c29..4453fbd116da63c6ec77fcf015d8846d2d511d0a 100644 (file)
@@ -164,7 +164,7 @@ bool MediaCapabilityManager<ConflictStrategy>::MoveTowardsRunning(
   while (!players.empty()) {
     auto front = players.front();
     players.pop();
-    auto conflicts = MarkRunning(front);
+    auto conflicts = MarkRunning<which_transition>(front);
     for (auto ptr : conflicts) {
       if (ptr == player)
         succeeded = false;
@@ -185,8 +185,10 @@ bool MediaCapabilityManager<ConflictStrategy>::MovedFromBarred(
 
   // here: RUNNING and the other one
   // of the single-bit |PlayerState|s
-  if ((it->second.state & ~which_transition) != State::NONE)
+  if ((it->second.state & ~which_transition) != State::NONE) {
+    LOG(WARNING) << __func__ << " player: " << it->first << " ,state: " << it->second.state;
     return false;
+  }
 
   // either BARRED -> which_transition, or
   // which_transition -> which_transition
@@ -208,6 +210,7 @@ inline int PlayerRoleToPriority(const PlayerRoleFlags& role) {
 }
 
 template <typename ConflictStrategy>
+template <State which_transition>
 std::vector<MediaPlayerTizen*>
 MediaCapabilityManager<ConflictStrategy>::MarkRunning(
     MediaPlayerTizen* player) {
@@ -270,12 +273,18 @@ MediaCapabilityManager<ConflictStrategy>::MarkRunning(
   LOG(INFO) << "Resolved for " << descriptor << " with:";
   evicted.reserve(removed.size());
   for (auto& item : removed) {
-    LOG(INFO) << "  " << item->first << " " << item->second.descriptor;
+    // only mark active player need deactive conflict player.
+    // Fix issue: Tab1 RUNNING player-> change to Tab2 --> Tab2 visible player
+    // --> Tab1 deactive player --> Tab1 player state not match
+    if (which_transition == State::ACTIVE) {
+      LOG(INFO) << "Mark inactive:  " << item->first << " " << item->second.descriptor;
 
-    evicted.push_back(item->first);
-    item->second.state &= ~State::ACTIVE;
-    detail::RemovePlayer{}(slots_, item->first);
-    ConflictStrategy::OnDeactivated(item->first);
+      evicted.push_back(item->first);
+      item->second.state &= ~State::ACTIVE;
+
+      detail::RemovePlayer{}(slots_, item->first);
+      ConflictStrategy::OnDeactivated(item->first);
+    }
   }
 
   RunPlayer(descriptor, player);
index f92334d255e8921e8628cf41c579318a65fee028..b5d21165b51bf37c92d57c226a5697ab0a7a1bb4 100644 (file)
@@ -382,6 +382,8 @@ void MediaPlayerESPlusPlayer::Release() {
   buffer_observer_->ResetBufferStatus();
   buffer_observer_->ResetBufferStatusCallbacks();
 
+  ReportBufferingStateIfNeeded(BUFFERING_HAVE_NOTHING,
+                               BUFFERING_CHANGE_REASON_UNKNOWN);
   reported_buffering_state_ = BUFFERING_HAVE_NOTHING;
 
   volume_ = 1.0;
@@ -1200,7 +1202,6 @@ void MediaPlayerESPlusPlayer::OnPrepareComplete(bool result) {
 
   if (!result) {
     LOG_ID(ERROR, player_id_) << "OnPrepareComplete prepare_async failed.";
-    GetMediaPlayerClient()->OnError(PIPELINE_ERROR_INITIALIZATION_FAILED);
     return;
   }
 
index 315b18e680be5bf80d5e7f207d7ddea9c82f406d..9bd9e8cef803240a559fc8b690ae7b388d7fc023 100644 (file)
@@ -112,19 +112,23 @@ void MediaPlayerRegistry::UnregisterMediaPlayer(int player_id) {
 
 bool MediaPlayerRegistry::ActivateMediaPlayer(int player_id,
                                               bool is_suspended) {
-  LOG(INFO) << __func__ << " player id: " << player_id;
-  if (is_suspended)
+  if (is_suspended) {
+    LOG(INFO) << __func__ << " MarkVisible player id: " << player_id;
     return media_capability_manager_.MarkVisible(GetMediaPlayer(player_id));
+  }
 
+  LOG(INFO) << __func__ << " MarkActive player id: " << player_id;
   return media_capability_manager_.MarkActive(GetMediaPlayer(player_id));
 }
 
 bool MediaPlayerRegistry::DeactivateMediaPlayer(int player_id,
                                                 bool is_suspended) {
-  LOG(INFO) << __func__ << " player id: " << player_id;
-  if (is_suspended)
+  if (is_suspended) {
+    LOG(INFO) << __func__ << " MarkHidden player id: " << player_id;
     return media_capability_manager_.MarkHidden(GetMediaPlayer(player_id));
+  }
 
+  LOG(INFO) << __func__ << " MarkInactive player id: " << player_id;
   return media_capability_manager_.MarkInactive(GetMediaPlayer(player_id));
 }