[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 c19f24af99bf6ab0318b6fbfe653f67edec71865..6668ada703f2cd51149f00fc2c4b5f5a64d46446 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 c267f58216778ca8739903605988bdd7f9cda59a..820473242d7b43829853f5118768beb0fb644cac 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 a25c770b796501e06e54dd386d17e9b6d36cbc52..de940d477aa11aa6e61287f8de9192366c85bf6a 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 374f67116c1aef191f84134baa0dbea313102693..e8af8a2036dc344554df55811b8f63e499142832 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 c61a6756e755b7ed9e4d20951b38692ecb844602..7c3321bed4cf8f0fcfa7177932061af227efe5bd 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 845273147c32551f3e4af32f5cc93a247911c82a..6285bf44e5ca46949afbf3eb274415817263e4dd 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 8acf23f0430c722500c8a04183076b15c0bd9ef8..ce8680b9c209f2fce67fbb73d9656fac69d814b3 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 645fcc3c888d47056cf706eb940c4e44bae1d2fc..f6ad6849dd29ba7d95e6e10df78e3d7562a16d1f 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 30b4420ea4d0c71169492db1499231179fbfa546..e3b262ff699b3b8ad5cfa1aaa4f01b9f4a6cf0ae 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 7474b500c3ca7ba3b731bd4fb82abadd8227a003..e6c297ae86aa0ab05f1c0e05a5fc32f2dedbd935 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 573bbe19179f148ebda421b4370ea063a3d04953..6b600f68f5824085c11dcc674b0d53158389e3dc 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 c93d8e7866cf44f4109409ca03d466b149ba62af..3974d21f4ace3417b49e17c0bbb829d086debb5f 100644 (file)
@@ -497,9 +497,6 @@ HTMLMediaElement::HTMLMediaElement(const QualifiedName& tag_name,
       was_always_muted_(true),
 #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)),
@@ -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 ec1d65e61a14ffc0d837ce6d011a670079490160..1613b3a7a8284168180d492a956d64bbd9fb3ebc 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 55c0dd0fc2e4b02417d3db21894b4a654d9a4bc4..0fea41f720c766c5e6790048d90fe330381a8b78 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 f3fb38dea8981ca79a13e177f840705892862f70..1e380c28d7acff69fef6a9db6a50526dea025e66 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 bf5eee2b7fe090652e1575b964928b79253ca888..180dcbe19e7c7e7761fbe6a8ab4b99a32f275d48 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 1f5fef87276efac8a9275b79931c2ea0c3a2d38d..2d1b86f24b3840269ce2082fe0216b187375ed3a 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 b3270c55725bacf066b2f2a7e9600c3d1051f7ab..285780a9f64e44bcb39ec37630aaa47cb245491f 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 60a8639913866331b0847bb3113f9ef9ee558431..2739d4a3335598cbc45cc7b73a6c600d9ca6491c 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 e0541deae94d44fe9a0f69bf3207c73dcb18a285..40bf0d0417367c18bd6d43f0c517abe9f052d604 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 4cb73087eeba243cdda3df353e936de0e8752d9d..2e4d9749ff8cfc976a1cb394ea683a0446b0fb7a 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;