[M120 Migration][MM] Migrate patches for suspend and resume. 73/305473/3
authorSun-woo Nam <sunny.nam@samsung.com>
Fri, 2 Feb 2024 04:19:46 +0000 (20:19 -0800)
committerSunwoo Nam <sunny.nam@samsung.com>
Fri, 16 Feb 2024 02:16:55 +0000 (02:16 +0000)
This patch supports suspend and resume behaviors when media goes to
background or the mulit-videos scenario.

- Handle suspend for Capi Player.
Handle suspend request from MediaCapabilityManager and resource conflict.
https://review.tizen.org/gerrit/#/c/292279/

- Arrange the suspend logic.
Release the esplusplayer when resource is conflicted.
https://review.tizen.org/gerrit/#/c/298638/

- Fix potential crash issue
Add null check to avoid crash.
https://review.tizen.org/gerrit/#/c/300715/

- Fix the media suspend/resume issue between apps.
Cancel the request suspend task if it has not been completed
when the player is resumed.
Flush the player buffer before seek.
https://review.tizen.org/gerrit/#/c/298571/

- Distinguish suspend situations based on the resource conflict.
The suspend situation by the player is mainly as follows.
1) If there are multiple videos in one content, request suspend by
MediaCapabilityManager.
2) Resource conflict occurs when another video plays in another process.
In case 1), these suspended videos doon't need to be resumed
when the app is suspended and resumed.
In case 2), the video should be resumed when the app is suspended and resumed.
https://review.tizen.org/gerrit/#/c/299121/

Change-Id: I53a602665458945bd359b89276f3602479fea5e7
Signed-off-by: Sun-woo Nam <sunny.nam@samsung.com>
21 files changed:
base/task/sequenced_task_runner.h
media/base/pipeline.h
media/base/pipeline_impl.cc
media/base/pipeline_impl.h
media/base/renderer_client.h
media/mojo/clients/mojo_renderer.cc
media/mojo/clients/mojo_renderer.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/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/chromium_impl/content/browser/media/tizen_renderer_impl.cc
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_esplusplayer.cc
tizen_src/chromium_impl/media/filters/media_player_esplusplayer.h
tizen_src/chromium_impl/media/filters/media_player_tizen.h

index c19f24a..6668ada 100644 (file)
@@ -29,6 +29,9 @@ namespace media {
 class AlsaPcmOutputStream;
 class AlsaPcmInputStream;
 class FakeAudioWorker;
+#if defined(TIZEN_MULTIMEDIA)
+class PipelineImpl;
+#endif
 }  // namespace media
 
 namespace base {
@@ -64,6 +67,9 @@ class PostDelayedTaskPassKey {
   friend class media::AlsaPcmOutputStream;
   friend class media::AlsaPcmInputStream;
   friend class media::FakeAudioWorker;
+#if defined(TIZEN_MULTIMEDIA)
+  friend class media::PipelineImpl;
+#endif
 };
 
 class PostDelayedTaskPassKeyForTesting : public PostDelayedTaskPassKey {};
index c267f58..8204732 100644 (file)
@@ -90,7 +90,7 @@ class MEDIA_EXPORT Pipeline {
     virtual void OnVideoFrameRateChange(absl::optional<int> fps) = 0;
 
 #if defined(TIZEN_MULTIMEDIA)
-    virtual void OnRequestSuspend() = 0;
+    virtual void OnRequestSuspend(bool resource_conflicted) = 0;
 #endif
   };
 
index a25c770..de940d4 100644 (file)
@@ -186,7 +186,7 @@ class PipelineImpl::RendererWrapper final : public DemuxerHost,
   void OnVideoOpacityChange(bool opaque) final;
   void OnVideoFrameRateChange(absl::optional<int> fps) final;
 #if defined(TIZEN_MULTIMEDIA)
-  void OnRequestSuspend() final;
+  void OnRequestSuspend(bool resource_conflict) final;
   void OnRequestSeek(base::TimeDelta time) final;
 #endif
 
@@ -258,6 +258,7 @@ class PipelineImpl::RendererWrapper final : public DemuxerHost,
 
 #if defined(TIZEN_MULTIMEDIA)
   bool renderer_suspended_ = false;
+  base::DelayedTaskHandle request_suspend_task_handle_;
 #endif
 
 #if defined(TIZEN_VIDEO_HOLE)
@@ -454,6 +455,11 @@ void PipelineImpl::RendererWrapper::Suspend() {
   SetState(kSuspending);
 
 #if defined(TIZEN_MULTIMEDIA)
+  if (request_suspend_task_handle_.IsValid()) {
+    LOG(INFO) << " Cancel posted request suspend task if pended.";
+    request_suspend_task_handle_.CancelTask();
+  }
+
   shared_state_.renderer->Suspend();
 #endif
 
@@ -503,6 +509,11 @@ void PipelineImpl::RendererWrapper::Resume(
   }
 
 #if defined(TIZEN_MULTIMEDIA)
+  if (request_suspend_task_handle_.IsValid()) {
+    LOG(INFO) << " Cancel posted request suspend task if pended.";
+    request_suspend_task_handle_.CancelTask();
+  }
+
   renderer_suspended_ = false;
 
   bool default_renderer_created = default_renderer.get() ? true : false;
@@ -1014,11 +1025,16 @@ void PipelineImpl::RendererWrapper::ToggleFullscreenMode(
     shared_state_.renderer->ToggleFullscreenMode(is_fullscreen, std::move(cb));
 }
 
-void PipelineImpl::RendererWrapper::OnRequestSuspend() {
+void PipelineImpl::RendererWrapper::OnRequestSuspend(bool resource_conflict) {
+  if (state_ == kSuspending || state_ == kSuspended)
+    return;
+
   LOG(INFO) << __func__;
-  main_task_runner_->PostTask(
-      FROM_HERE,
-      base::BindOnce(&PipelineImpl::OnRequestSuspend, weak_pipeline_));
+  request_suspend_task_handle_ = main_task_runner_->PostCancelableDelayedTask(
+      base::subtle::PostDelayedTaskPassKey(), FROM_HERE,
+      base::BindOnce(&PipelineImpl::OnRequestSuspend, weak_pipeline_,
+                     resource_conflict),
+      base::TimeDelta());
 }
 
 void PipelineImpl::RendererWrapper::OnRequestSeek(base::TimeDelta time) {
@@ -1035,6 +1051,9 @@ void PipelineImpl::RendererWrapper::OnRequestSeek(base::TimeDelta time) {
 
   SerialRunner::Queue bound_fns;
   demuxer_->AbortPendingReads();
+
+  bound_fns.Push(base::BindOnce(
+      &Renderer::Flush, base::Unretained(shared_state_.renderer.get())));
   bound_fns.Push(
       base::BindOnce(&Demuxer::Seek, base::Unretained(demuxer_), time));
   pending_callbacks_ = SerialRunner::Run(
@@ -1888,9 +1907,9 @@ void PipelineImpl::OnVideoPipelineInfoChange(const VideoPipelineInfo& info) {
 }
 
 #if defined(TIZEN_MULTIMEDIA)
-void PipelineImpl::OnRequestSuspend() {
+void PipelineImpl::OnRequestSuspend(bool resource_conflicted) {
   DVLOG(3) << __func__;
-  client_->OnRequestSuspend();
+  client_->OnRequestSuspend(resource_conflicted);
 }
 #endif
 
index 374f671..e8af8a2 100644 (file)
@@ -188,7 +188,7 @@ class MEDIA_EXPORT PipelineImpl : public Pipeline {
   void OnRemotePlayStateChange(MediaStatus::State state);
   void OnVideoFrameRateChange(absl::optional<int> fps);
 #if defined(TIZEN_MULTIMEDIA)
-  void OnRequestSuspend();
+  void OnRequestSuspend(bool resource_conflicted);
 #endif
 
   // Task completion callbacks from RendererWrapper.
index c61a675..7c3321b 100644 (file)
@@ -67,7 +67,7 @@ class MEDIA_EXPORT RendererClient {
   virtual void OnVideoFrameRateChange(absl::optional<int> fps) = 0;
 
 #if defined(TIZEN_MULTIMEDIA)
-  virtual void OnRequestSuspend() {}
+  virtual void OnRequestSuspend(bool resource_conflicted) {}
 
   virtual void OnRequestSeek(base::TimeDelta time) {}
 #endif
index 8452731..6285bf4 100644 (file)
@@ -427,9 +427,9 @@ void MojoRenderer::OnFlushed() {
 }
 
 #if defined(TIZEN_MULTIMEDIA)
-void MojoRenderer::OnRequestSuspend() {
+void MojoRenderer::OnRequestSuspend(bool resource_conflicted) {
   DVLOG(2) << __func__;
-  client_->OnRequestSuspend();
+  client_->OnRequestSuspend(resource_conflicted);
 }
 
 void MojoRenderer::OnRequestSeek(base::TimeDelta time) {
index 8acf23f..ce8680b 100644 (file)
@@ -92,7 +92,7 @@ class MojoRenderer : public Renderer, public mojom::RendererClient {
   void OnWaiting(WaitingReason reason) override;
   void OnStatisticsUpdate(const PipelineStatistics& stats) override;
 #if defined(TIZEN_MULTIMEDIA)
-  void OnRequestSuspend() override;
+  void OnRequestSuspend(bool resource_conflicted) override;
   void OnRequestSeek(base::TimeDelta time) override;
 #endif
 
index 645fcc3..f6ad684 100644 (file)
@@ -114,7 +114,7 @@ interface RendererClient {
   OnWaiting(WaitingReason reason);
 
   [EnableIf=tizen_multimedia]
-  OnRequestSuspend();
+  OnRequestSuspend(bool resource_conflicted);
 
   [EnableIf=tizen_multimedia]
   OnRequestSeek(mojo_base.mojom.TimeDelta time);
index 30b4420..e3b262f 100644 (file)
@@ -244,9 +244,9 @@ void MojoRendererService::OnVideoOpacityChange(bool opaque) {
 }
 
 #if defined(TIZEN_MULTIMEDIA)
-void MojoRendererService::OnRequestSuspend() {
+void MojoRendererService::OnRequestSuspend(bool resource_conflicted) {
   DVLOG(2) << __func__;
-  client_->OnRequestSuspend();
+  client_->OnRequestSuspend(resource_conflicted);
 }
 
 void MojoRendererService::OnRequestSeek(base::TimeDelta time) {
index 7474b50..e6c297a 100644 (file)
@@ -105,7 +105,7 @@ class MEDIA_MOJO_EXPORT MojoRendererService final : public mojom::Renderer,
   void OnVideoOpacityChange(bool opaque) final;
   void OnVideoFrameRateChange(absl::optional<int> fps) final;
 #if defined(TIZEN_MULTIMEDIA)
-  void OnRequestSuspend() final;
+  void OnRequestSuspend(bool resource_conflicted) final;
   void OnRequestSeek(base::TimeDelta time) final;
 #endif
 
index 573bbe1..6b600f6 100644 (file)
@@ -184,6 +184,7 @@ class WebMediaPlayer {
 #if defined(TIZEN_MULTIMEDIA)
   virtual void Suspend() {}
   virtual void Resume() {}
+  virtual bool SuspendedByPlayer() { return false; }
 #endif
 
   // Called when the backing media element and the page it is attached to is
index c93d8e7..3974d21 100644 (file)
@@ -498,9 +498,6 @@ HTMLMediaElement::HTMLMediaElement(const QualifiedName& tag_name,
 #if BUILDFLAG(IS_TIZEN_TV)
       is_deactivate_(false),
 #endif
-#if defined(TIZEN_MULTIMEDIA)
-      suspended_by_player_(false),
-#endif
       audio_tracks_(MakeGarbageCollected<AudioTrackList>(*this)),
       video_tracks_(MakeGarbageCollected<VideoTrackList>(*this)),
       audio_source_node_(nullptr),
@@ -2787,10 +2784,6 @@ ScriptPromise HTMLMediaElement::playForBindings(ScriptState* script_state) {
 absl::optional<DOMExceptionCode> HTMLMediaElement::Play() {
   DVLOG(2) << "play(" << *this << ")";
 
-#if defined(TIZEN_MULTIMEDIA)
-  suspended_by_player_ = false;
-#endif
-
   absl::optional<DOMExceptionCode> exception_code =
       autoplay_policy_->RequestPlay();
 #if BUILDFLAG(IS_TIZEN_TV)
@@ -3986,7 +3979,8 @@ void HTMLMediaElement::ContextLifecycleStateChanged(
       pause();
     }
   } else if (state == mojom::FrameLifecycleState::kRunning) {
-    if (suspended_by_player_)
+    // Do not resume if suspended by player except the resource conflict case.
+    if (GetWebMediaPlayer() && GetWebMediaPlayer()->SuspendedByPlayer())
       return;
 
     if (GetWebMediaPlayer())
@@ -4823,7 +4817,6 @@ void HTMLMediaElement::SuspendPlayer() {
   ScheduleEvent(event_type_names::kSuspend);
   SetShouldDelayLoadEvent(false);
   SetNetworkState(kNetworkIdle);
-  suspended_by_player_ = true;
 }
 #endif
 
index ec1d65e..1613b3a 100644 (file)
@@ -883,10 +883,6 @@ class CORE_EXPORT HTMLMediaElement
   bool suppress_events_ : 1;
 #endif
 
-#if defined(TIZEN_MULTIMEDIA)
-  bool suspended_by_player_ : 1;
-#endif
-
   // Whether the player disables the Remote Playback feature.
   bool is_remote_playback_disabled_ = false;
   // Whether the player is rendering remotely.
index 55c0dd0..0fea41f 100644 (file)
@@ -2547,8 +2547,16 @@ void WebMediaPlayerImpl::Resume() {
   SetSuspendState(false);
 }
 
-void WebMediaPlayerImpl::OnRequestSuspend() {
-  was_suspended_by_player_ = true;
+void WebMediaPlayerImpl::OnRequestSuspend(bool resource_conflicted) {
+  if (pipeline_controller_->IsSuspended()) {
+    LOG(INFO) << __func__ << " Already suspended.";
+    return;
+  }
+
+  // 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;
+
   client_->PausePlayback(WebMediaPlayerClient::PauseReason::kUnknown);
   client_->SuspendPlayer();
   SetSuspendState(true);
index f3fb38d..1e380c2 100644 (file)
@@ -189,6 +189,8 @@ 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;
@@ -417,7 +419,7 @@ class PLATFORM_EXPORT WebMediaPlayerImpl
   void OnVideoPipelineInfoChange(const media::VideoPipelineInfo& info) override;
 #if defined(TIZEN_MULTIMEDIA)
   // Called if a player in the browser process is suspended.
-  void OnRequestSuspend() override;
+  void OnRequestSuspend(bool resource_conflicted) override;
 
   void FullscreenModeToggled();
 #endif
index bf5eee2..180dcbe 100644 (file)
@@ -279,6 +279,12 @@ void TizenRendererImpl::Suspend() {
   LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
   if (is_suspended_)
     return;
+
+  if (!media_player_) {
+    LOG(INFO) << "media_player_ is not created yet";
+    return;
+  }
+
   media::MediaPlayerRegistry::GetInstance()->DeactivateMediaPlayer(
       player_id_, !resource_conflicted_);
   media_player_->Release();
@@ -468,11 +474,17 @@ void TizenRendererImpl::OnRequestSeek(base::TimeDelta time) {
 
 void TizenRendererImpl::OnRequestSuspend(bool resource_conflicted) {
   LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
+
+  if (is_suspended_) {
+    LOG(INFO) << " Media is already suspended.";
+    return;
+  }
+
   resource_conflicted_ = resource_conflicted;
   media::MediaPlayerRegistry::GetInstance()->DeactivateMediaPlayer(
       player_id_, !resource_conflicted_);
   is_suspended_ = true;
-  client_->OnRequestSuspend();
+  client_->OnRequestSuspend(resource_conflicted);
 }
 
 #if defined(TIZEN_TBM_SUPPORT)
index 1f5fef8..2d1b86f 100644 (file)
@@ -96,7 +96,11 @@ static void ErrorCb(int error_code, void* data) {
 
 // Called by player_set_interrupted_cb()
 static void InterruptCb(player_interrupted_code_e code, void* data) {
-  NOTIMPLEMENTED();
+  DCHECK(data);
+  media::MediaPlayerBridgeCapi* player =
+      static_cast<media::MediaPlayerBridgeCapi*>(data);
+
+  player->OnResourceConflict();
 }
 
 }  // namespace
@@ -542,6 +546,12 @@ void MediaPlayerBridgeCapi::SetMediaGeometry(const gfx::Rect& viewport_rect,
 }
 #endif
 
+void MediaPlayerBridgeCapi::RequestSuspend(bool resource_conflicted) {
+  LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
+  GetMediaPlayerClient()->OnRequestSuspend(resource_conflicted);
+  Suspend();
+}
+
 void MediaPlayerBridgeCapi::UpdateMediaType() {
   LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
   int sample_rate = 0;
@@ -823,6 +833,17 @@ void MediaPlayerBridgeCapi::OnHandlePlayerError(
   OnMediaError(GetMediaError(player_error_code));
 }
 
+void MediaPlayerBridgeCapi::OnResourceConflict() {
+  if (!task_runner_->BelongsToCurrentThread()) {
+    task_runner_->PostTask(
+        FROM_HERE, base::BindOnce(&MediaPlayerBridgeCapi::OnResourceConflict,
+                                  weak_factory_.GetWeakPtr()));
+    return;
+  }
+  LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
+  RequestSuspend(true);
+}
+
 void MediaPlayerBridgeCapi::OnResumeComplete(bool success) {
   NOTIMPLEMENTED();
 }
index b3270c5..285780a 100644 (file)
@@ -78,6 +78,7 @@ class MEDIA_EXPORT MediaPlayerBridgeCapi : public MediaPlayerTizen {
   void SetMediaGeometry(const gfx::Rect& viewport_rect,
                         const gfx::RectF& rect) override;
 #endif
+  void RequestSuspend(bool resource_conflicted) override;
 
   void ExecuteDelayedPlayerState();
 
@@ -86,6 +87,7 @@ class MEDIA_EXPORT MediaPlayerBridgeCapi : public MediaPlayerTizen {
   void OnPlayerPrepared();
   void OnHandleBufferingStatus(int percent);
   void OnHandlePlayerError(int player_error_code, const base::Location& loc);
+  void OnResourceConflict();
   void OnResumeComplete(bool success);
   void OnMediaPacketUpdated(media_packet_h packet);
 
index 60a8639..2739d4a 100644 (file)
@@ -1175,7 +1175,7 @@ void MediaPlayerESPlusPlayer::OnResourceConflict() {
   }
 
   LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
-  GetMediaPlayerClient()->OnRequestSuspend(true);
+  RequestSuspend(true);
 }
 
 void MediaPlayerESPlusPlayer::OnError(const esplusplayer_error_type error) {
@@ -1342,9 +1342,9 @@ void MediaPlayerESPlusPlayer::PrepareVideoHole() {
 }
 #endif
 
-void MediaPlayerESPlusPlayer::RequestSuspend() {
+void MediaPlayerESPlusPlayer::RequestSuspend(bool resource_conflicted) {
   LOG(INFO) << "(" << static_cast<void*>(this) << ") " << __func__;
-  GetMediaPlayerClient()->OnRequestSuspend(true);
+  GetMediaPlayerClient()->OnRequestSuspend(resource_conflicted);
   Release();
 }
 
index e0541de..40bf0d0 100644 (file)
@@ -91,7 +91,7 @@ class MEDIA_EXPORT MediaPlayerESPlusPlayer : public MediaPlayerTizen {
 
   void OnBufferingStatusChanged(DemuxerStream::Type type, BufferStatus status);
 
-  void RequestSuspend() override;
+  void RequestSuspend(bool resource_conflicted) override;
 
   MediaTypeFlags GetMediaType() const override { return media_type_; }
   void SetMediaType(DemuxerStream::Type type) override;
index 4cb7308..2e4d974 100644 (file)
@@ -82,7 +82,7 @@ class MEDIA_EXPORT MediaPlayerTizen {
                                 const gfx::RectF& rect) = 0;
   virtual void PrepareVideoHole() {}
 #endif
-  virtual void RequestSuspend() {}
+  virtual void RequestSuspend(bool resource_conflicted = false) = 0;
 
   virtual MediaTypeFlags GetMediaType() const = 0;
   virtual void SetMediaType(DemuxerStream::Type type) = 0;