[EMSS] Make sure `MsDecodingStream` is deleted on the worker thread 83/315083/5
authorPiotr Bałut <p.balut@samsung.com>
Tue, 18 Jun 2024 09:32:47 +0000 (11:32 +0200)
committerBot Blink <blinkbot@samsung.com>
Fri, 26 Jul 2024 09:27:02 +0000 (09:27 +0000)
[PROBLEM]
It's possible that MsDecodingStream class used for low latency decoding
in WASM Player is deleted on the control thread (i.e. main JS thread)
while it's still used on the worker thread. This may lead to a crash.

[SOLUTION]
Destruction of MsDecodingStream worker part is posted on the worker
thread. Additionally, usage of shared_ptr was dropped for demuxer layer
objects on worker thread, as those objects are assigned to worker
sequence exclusively and moving to unique_ptr + base::WeakPtr eliminates
ownership ambiguity.

Bug: https://jira-eu.sec.samsung.net/browse/VDWASM-1501
Change-Id: I0c05c369079bf35d601f050cf31ccfe73da4c7fb
Signed-off-by: Piotr Bałut <p.balut@samsung.com>
28 files changed:
tizen_src/chromium_impl/content/renderer/media/tizen/elementary_media_stream_source/any_thread/demuxer_dispatcher.cc
tizen_src/chromium_impl/content/renderer/media/tizen/elementary_media_stream_source/any_thread/demuxer_dispatcher.h
tizen_src/chromium_impl/content/renderer/media/tizen/elementary_media_stream_source/worker_thread/BUILD.gn
tizen_src/chromium_impl/content/renderer/media/tizen/elementary_media_stream_source/worker_thread/data_stream_demuxer_impl.cc
tizen_src/chromium_impl/content/renderer/media/tizen/elementary_media_stream_source/worker_thread/data_stream_demuxer_impl.h
tizen_src/chromium_impl/content/renderer/media/tizen/elementary_media_stream_source/worker_thread/demuxer.h
tizen_src/chromium_impl/content/renderer/media/tizen/elementary_media_stream_source/worker_thread/demuxer_client.h
tizen_src/chromium_impl/content/renderer/media/tizen/elementary_media_stream_source/worker_thread/demuxer_dispatcher_client.cc [new file with mode: 0644]
tizen_src/chromium_impl/content/renderer/media/tizen/elementary_media_stream_source/worker_thread/demuxer_dispatcher_client.h
tizen_src/chromium_impl/content/renderer/media/tizen/elementary_media_stream_source/worker_thread/media_stream_demuxer_impl.cc
tizen_src/chromium_impl/content/renderer/media/tizen/elementary_media_stream_source/worker_thread/media_stream_demuxer_impl.h
tizen_src/chromium_impl/content/renderer/media/tizen/elementary_media_stream_source/worker_thread/ms_decoding_stream.cc
tizen_src/chromium_impl/content/renderer/media/tizen/elementary_media_stream_source/worker_thread/ms_decoding_stream.h
tizen_src/chromium_impl/content/renderer/media/tizen/elementary_media_stream_source/worker_thread/source_client.h
tizen_src/chromium_impl/content/renderer/media/tizen/elementary_media_stream_source/worker_thread/source_impl.cc
tizen_src/chromium_impl/content/renderer/media/tizen/elementary_media_stream_source/worker_thread/source_impl.h
tizen_src/chromium_impl/content/renderer/media/tizen/elementary_media_stream_source/worker_thread/track_impl.cc
tizen_src/chromium_impl/content/renderer/media/tizen/elementary_media_stream_source/worker_thread/track_impl.h
tizen_src/chromium_impl/content/renderer/media/tizen/elementary_media_stream_source/worker_thread/video_track_impl.cc
tizen_src/chromium_impl/content/renderer/media/tizen/elementary_media_stream_source/worker_thread/video_track_impl.h
tizen_src/chromium_impl/content/test/elementary_media_stream_source/any_thread/demuxer_dispatcher_for_testing.h
tizen_src/chromium_impl/content/test/elementary_media_stream_source/common/demuxer_impl_unittest_base.h
tizen_src/chromium_impl/content/test/elementary_media_stream_source/worker_thread/mock_append_host.h
tizen_src/chromium_impl/content/test/elementary_media_stream_source/worker_thread/mock_demuxer_client.h
tizen_src/chromium_impl/content/test/elementary_media_stream_source/worker_thread/mock_demuxer_dispatcher_client.h
tizen_src/chromium_impl/content/test/elementary_media_stream_source/worker_thread/worker_thread_track_impl_unittest.cc
tizen_src/chromium_impl/services/elementary_media_stream_source/any_thread/host_dispatcher.h
tizen_src/chromium_impl/services/elementary_media_stream_source/public/cpp/dispatcher.h

index 065cdfd3434286d638383bcfbebf690e90eae16f..e381d97dbb15ab95fc0d97a7c42376d4060bed24 100644 (file)
@@ -34,6 +34,7 @@
 #include "mojo/public/cpp/bindings/remote.h"
 #include "platform/scheduler/public/thread.h"
 #include "services/elementary_media_stream_source/public/cpp/logger.h"
+#include "third_party/abseil-cpp/absl/types/variant.h"
 #include "third_party/blink/public/common/thread_safe_browser_interface_broker_proxy.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/renderer/platform/scheduler/public/main_thread.h"
@@ -49,6 +50,19 @@ namespace any_thread {
 
 namespace {
 
+template <typename T>
+class DeleteOnTaskRunner {
+ public:
+  explicit DeleteOnTaskRunner(
+      const scoped_refptr<base::SingleThreadTaskRunner>& task_runner)
+      : task_runner_(task_runner) {}
+
+  void operator()(T* obj) { task_runner_->DeleteSoon(FROM_HERE, obj); }
+
+ private:
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+};
+
 std::tuple<worker_thread::PendingDataStreamSrcInterfaces,
            DemuxerDispatcher::PendingDataStreamSinkInterfaces>
 CreateDataStream() {
@@ -79,6 +93,27 @@ void GetGpuFactoriesOnBlinkMainThread(
 
 }  // anonymous namespace
 
+class DemuxerDispatcher::WorkerDemuxerImplHolder {
+ public:
+  template <typename T>
+  explicit WorkerDemuxerImplHolder(
+      std::unique_ptr<T>&& impl,
+      const scoped_refptr<base::SingleThreadTaskRunner>& task_runner)
+      : impl_(std::unique_ptr<T, DeleteOnTaskRunner<T>>{
+            impl.release(), DeleteOnTaskRunner<T>{task_runner}}) {}
+
+ private:
+  absl::variant<
+      std::unique_ptr<worker_thread::DataStreamDemuxerImpl,
+                      DeleteOnTaskRunner<worker_thread::DataStreamDemuxerImpl>>,
+      std::unique_ptr<
+          worker_thread::MediaStreamDemuxerImpl,
+          DeleteOnTaskRunner<worker_thread::MediaStreamDemuxerImpl>>,
+      std::unique_ptr<worker_thread::MsDecodingStream,
+                      DeleteOnTaskRunner<worker_thread::MsDecodingStream>>>
+      impl_;
+};  // class WorkerDemuxerImplHolder
+
 // static
 std::shared_ptr<DemuxerDispatcher> DemuxerDispatcher::Create(
     PipelineMode pipeline_mode,
@@ -130,41 +165,36 @@ std::shared_ptr<DemuxerDispatcher> DemuxerDispatcher::Create(
   }
 
   if (pipeline_mode.demuxer_mode == DemuxerMode::kDataStream) {
-    SetWorkerClients<worker_thread::DataStreamDemuxerImpl>(
-        pipeline_mode, demuxer_dispatcher,
-        std::move(maybe_pending_data_stream_src),
-        std::make_shared<worker_thread::DataStreamDemuxerImpl>(params));
+    demuxer_dispatcher->SetWorkerClients<worker_thread::DataStreamDemuxerImpl>(
+        pipeline_mode, std::move(maybe_pending_data_stream_src),
+        std::make_unique<worker_thread::DataStreamDemuxerImpl>(params));
   } else if (pipeline_mode.latency_mode == LatencyMode::kNormal) {
-    SetWorkerClients<worker_thread::MediaStreamDemuxerImpl>(
-        pipeline_mode, demuxer_dispatcher,
-        std::move(maybe_pending_data_stream_src),
-        std::make_shared<worker_thread::MediaStreamDemuxerImpl>(params));
+    demuxer_dispatcher->SetWorkerClients<worker_thread::MediaStreamDemuxerImpl>(
+        pipeline_mode, std::move(maybe_pending_data_stream_src),
+        std::make_unique<worker_thread::MediaStreamDemuxerImpl>(params));
   } else {
     auto worker_demuxer_impl =
-        std::make_shared<worker_thread::MsDecodingStream>(params);
-    auto weak_ms_decoding_stream =
-        std::weak_ptr<worker_thread::MsDecodingStream>{worker_demuxer_impl};
-    SetWorkerClients<worker_thread::MsDecodingStream>(
-        pipeline_mode, demuxer_dispatcher,
-        std::move(maybe_pending_data_stream_src),
+        std::make_unique<worker_thread::MsDecodingStream>(params);
+    demuxer_dispatcher->SetWorkerClients<worker_thread::MsDecodingStream>(
+        pipeline_mode, std::move(maybe_pending_data_stream_src),
         std::move(worker_demuxer_impl));
 
     blink::Thread::MainThread()->GetDeprecatedTaskRunner()->PostTask(
         FROM_HERE,
         base::BindOnce(
             &GetGpuFactoriesOnBlinkMainThread,
-            base::BindPostTask(
-                demuxer_dispatcher->GetWorkerThreadTaskRunner(),
-                base::BindOnce(
-                    [](std::weak_ptr<worker_thread::MsDecodingStream>
-                           weak_ms_decoding_stream,
-                       media::GpuVideoAcceleratorFactories* gpu_factories) {
-                      if (auto ms_decoding_stream =
-                              weak_ms_decoding_stream.lock()) {
-                        ms_decoding_stream->SetGpuFactories(gpu_factories);
-                      }
-                    },
-                    std::move(weak_ms_decoding_stream)))));
+            base::BindOnce(
+                [](std::weak_ptr<DemuxerDispatcher> maybe_dispatcher,
+                   media::GpuVideoAcceleratorFactories* gpu_factories) {
+                  auto dispatcher = maybe_dispatcher.lock();
+
+                  if (!dispatcher)
+                    return;
+
+                  dispatcher->DispatchTask(&WorkerThreadClient::SetGpuFactories,
+                                           gpu_factories);
+                },
+                std::weak_ptr<DemuxerDispatcher>(demuxer_dispatcher))));
   }
 
   return demuxer_dispatcher;
@@ -173,10 +203,8 @@ std::shared_ptr<DemuxerDispatcher> DemuxerDispatcher::Create(
 DemuxerDispatcher::~DemuxerDispatcher() {
   EMSS_DEBUG() << "Destructing object";
 
-  if (!HasClient<WorkerLifecycleObserver>())
-    return;
-
-  DispatchTask(&WorkerLifecycleObserver::OnDispatcherDisconnected);
+  if (HasClient<WorkerLifecycleObserver>())
+    DispatchTask(&WorkerLifecycleObserver::OnDispatcherDisconnected);
 }
 
 DemuxerDispatcher::DemuxerDispatcher(
@@ -187,7 +215,8 @@ DemuxerDispatcher::DemuxerDispatcher(
         worker_thread_task_runner)
     : Dispatcher(control_thread_task_runner),
       pending_data_stream_sink_(std::move(pending_data_stream_sink)),
-      worker_thread_task_runner_(worker_thread_task_runner) {
+      worker_thread_task_runner_(worker_thread_task_runner),
+      worker_demuxer_impl_holder_(nullptr) {
   EMSS_DEBUG() << "Constructing object";
 }
 
@@ -235,6 +264,27 @@ void DemuxerDispatcher::RegisterSource(
                std::move(on_emss_initialized));
 }
 
+std::unique_ptr<DemuxerDispatcher::WorkerDemuxerImplHolder>
+DemuxerDispatcher::WrapDemuxerWorkerImpl(
+    std::unique_ptr<worker_thread::DataStreamDemuxerImpl>&& impl) {
+  return std::make_unique<WorkerDemuxerImplHolder>(std::move(impl),
+                                                   worker_thread_task_runner_);
+}
+
+std::unique_ptr<DemuxerDispatcher::WorkerDemuxerImplHolder>
+DemuxerDispatcher::WrapDemuxerWorkerImpl(
+    std::unique_ptr<worker_thread::MediaStreamDemuxerImpl>&& impl) {
+  return std::make_unique<WorkerDemuxerImplHolder>(std::move(impl),
+                                                   worker_thread_task_runner_);
+}
+
+std::unique_ptr<DemuxerDispatcher::WorkerDemuxerImplHolder>
+DemuxerDispatcher::WrapDemuxerWorkerImpl(
+    std::unique_ptr<worker_thread::MsDecodingStream>&& impl) {
+  return std::make_unique<WorkerDemuxerImplHolder>(std::move(impl),
+                                                   worker_thread_task_runner_);
+}
+
 }  // namespace any_thread
 
 }  // namespace elementary_media_stream_source
index 2af5ecbbb12063d4fc967f9f3f01e170ffb241cc..c48cfc8c43c903e359e668afc2d626119887364d 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <atomic>
 #include <memory>
+#include <optional>
 #include <type_traits>
 #include <utility>
 
@@ -37,7 +38,10 @@ class PlatformDemuxerAdapter;
 }  // namespace media_thread
 
 namespace worker_thread {
+class DataStreamDemuxerImpl;
 class DemuxerDispatcherClient;
+class MediaStreamDemuxerImpl;
+class MsDecodingStream;
 class PlatformDemuxerAdapterClient;
 class SourceImpl;
 }  // namespace worker_thread
@@ -53,16 +57,6 @@ class TypedMediaStreamProxy;
 }  // namespace elementary_media_stream_source
 }  // namespace content
 
-namespace elementary_media_stream_source {
-template <>
-struct ClientTraits<::content::elementary_media_stream_source::media_thread::
-                        PlatformDemuxerAdapter> {
- public:
-  using PointerType = ::content::elementary_media_stream_source::media_thread::
-      PlatformDemuxerAdapter*;
-};
-}  // namespace elementary_media_stream_source
-
 namespace content {
 namespace elementary_media_stream_source {
 namespace any_thread {
@@ -137,6 +131,10 @@ class DemuxerDispatcher
   }
 
  private:
+  // Hides implementation of worker thread demuxer impl. Required, because it
+  // needs class implementation, not only forward declaration.
+  class WorkerDemuxerImplHolder;
+
   template <typename DemuxerImplT>
   static void SetAnyClients(
       const std::shared_ptr<DemuxerDispatcher>& demuxer_dispatcher,
@@ -155,24 +153,31 @@ class DemuxerDispatcher
         std::move(control_demuxer_impl));
   }
 
+  std::unique_ptr<WorkerDemuxerImplHolder> WrapDemuxerWorkerImpl(
+      std::unique_ptr<worker_thread::DataStreamDemuxerImpl>&& impl);
+  std::unique_ptr<WorkerDemuxerImplHolder> WrapDemuxerWorkerImpl(
+      std::unique_ptr<worker_thread::MediaStreamDemuxerImpl>&& impl);
+  std::unique_ptr<WorkerDemuxerImplHolder> WrapDemuxerWorkerImpl(
+      std::unique_ptr<worker_thread::MsDecodingStream>&& impl);
+
   template <typename DemuxerImplT>
-  static void SetWorkerClients(
-      PipelineMode pipeline_mode,
-      const std::shared_ptr<DemuxerDispatcher>& demuxer_dispatcher,
-      worker_thread::PendingDataStreamSrcInterfaces
-          maybe_pending_data_stream_src,
-      std::shared_ptr<DemuxerImplT>&& worker_demuxer_impl) {
-    demuxer_dispatcher->SetClient<WorkerThreadClient>(worker_demuxer_impl);
-    demuxer_dispatcher->SetClient<WorkerThreadDemuxerAdapterClient>(
-        worker_demuxer_impl);
+  void SetWorkerClients(PipelineMode pipeline_mode,
+                        worker_thread::PendingDataStreamSrcInterfaces
+                            maybe_pending_data_stream_src,
+                        std::unique_ptr<DemuxerImplT> worker_demuxer_impl) {
+    SetClient<WorkerThreadClient>(worker_demuxer_impl->GetWeakPtr());
+    SetClient<WorkerThreadDemuxerAdapterClient>(
+        worker_demuxer_impl->GetWeakPtr());
 
     if constexpr (std::is_base_of_v<WorkerLifecycleObserver, DemuxerImplT>) {
-      demuxer_dispatcher->SetClient<WorkerLifecycleObserver>(
-          std::move(worker_demuxer_impl));
-      demuxer_dispatcher->DispatchTask(
-          &WorkerLifecycleObserver::OnDispatcherConnected,
-          std::move(maybe_pending_data_stream_src));
+      SetClient<WorkerLifecycleObserver>(
+          std::move(worker_demuxer_impl->GetWeakPtr()));
+      DispatchTask(&WorkerLifecycleObserver::OnDispatcherConnected,
+                   std::move(maybe_pending_data_stream_src));
     }
+
+    worker_demuxer_impl_holder_ =
+        WrapDemuxerWorkerImpl(std::move(worker_demuxer_impl));
   };
 
   std::tuple<std::shared_ptr<AnyAudioMediaStream>,
@@ -181,14 +186,16 @@ class DemuxerDispatcher
              std::shared_ptr<AnyVideoMediaStream>,
              std::shared_ptr<ControlThreadClient>,
              std::shared_ptr<ControlThreadDemuxerAdapterClient>,
-             std::shared_ptr<WorkerLifecycleObserver>,
-             std::shared_ptr<WorkerThreadClient>,
-             std::shared_ptr<WorkerThreadDemuxerAdapterClient>,
+             base::WeakPtr<WorkerLifecycleObserver>,
+             base::WeakPtr<WorkerThreadClient>,
+             base::WeakPtr<WorkerThreadDemuxerAdapterClient>,
              media_thread::PlatformDemuxerAdapter*>
       clients_;
   std::optional<PendingDataStreamSinkInterfaces> pending_data_stream_sink_;
   scoped_refptr<base::SingleThreadTaskRunner> worker_thread_task_runner_;
   scoped_refptr<base::SingleThreadTaskRunner> media_thread_task_runner_;
+
+  std::unique_ptr<WorkerDemuxerImplHolder> worker_demuxer_impl_holder_;
 };
 
 }  // namespace any_thread
index 3c78f33786d1cdedcaa845f16ec3af896e49e5fe..062225cfc37aaa4be7cce8ede33fd30bb6d667e4 100644 (file)
@@ -17,6 +17,7 @@ elementary_media_stream_source_renderer("worker_thread") {
     "demuxer.cc",
     "demuxer.h",
     "demuxer_client.h",
+    "demuxer_dispatcher_client.cc",
     "demuxer_dispatcher_client.h",
     "demuxer_dispatcher_lifecycle_observer.h",
     "demuxer_stream_impl.h",
index a93b101967062db3f79f2922c5fc1dc69acd65ad..b5573d17fcf198c0249dcca7b67fcfb6688607a3 100644 (file)
@@ -10,6 +10,7 @@
 
 #include "base/functional/callback_forward.h"
 #include "base/functional/callback_helpers.h"
+#include "base/memory/weak_ptr.h"
 #include "content/renderer/media/tizen/elementary_media_stream_source/any_thread/common_tools.h"
 #include "content/renderer/media/tizen/elementary_media_stream_source/any_thread/common_types.h"
 #include "content/renderer/media/tizen/elementary_media_stream_source/any_thread/demuxer_dispatcher.h"
@@ -61,6 +62,12 @@ DataStreamDemuxerImpl::~DataStreamDemuxerImpl() {
   EMSS_DEBUG() << "Destructing object";
 }
 
+base::WeakPtr<DataStreamDemuxerImpl> DataStreamDemuxerImpl::GetWeakPtr() {
+  EMSS_VERBOSE();
+
+  return weak_ptr_factory_.GetMutableWeakPtr();
+}
+
 //////////////////// DemuxerDispatcherLifecycleObserver ////////////////////
 
 void DataStreamDemuxerImpl::OnDispatcherConnected(
@@ -145,21 +152,18 @@ void DataStreamDemuxerImpl::OnVideoTextureReady(
       gfx::Size{tbm_buffer_handle.width, tbm_buffer_handle.height},
       base::TimeDelta(), tbm_buffer_handle);
 
-  auto weak_this = std::weak_ptr<DataStreamDemuxerImpl>(shared_from_this());
   auto release_cb_runner =
       base::ScopedClosureRunner{media::BindToCurrentLoop(base::BindOnce(
-          [](const std::weak_ptr<DataStreamDemuxerImpl>& weak_demuxer_impl,
+          [](const base::WeakPtr<DataStreamDemuxerImpl>& maybe_demuxer_impl,
              uint64_t packet_id) {
-            auto demuxer_impl = weak_demuxer_impl.lock();
-
-            if (!demuxer_impl) {
+            if (!maybe_demuxer_impl) {
               EMSS_DEBUG_NO_INSTANCE();
               return;
             }
 
-            demuxer_impl->ReleaseVideoTexture(packet_id);
+            maybe_demuxer_impl->ReleaseVideoTexture(packet_id);
           },
-          std::move(weak_this), packet_id))};
+          weak_ptr_factory_.GetWeakPtr(), packet_id))};
 
   if (!video_frame) {
     LOG(ERROR) << "Creating video frame failed";
@@ -229,10 +233,10 @@ void DataStreamDemuxerImpl::OnClosedCaptions(
 
 //////////////////// Demuxer ///////////////////
 
-std::shared_ptr<AppendHost> DataStreamDemuxerImpl::GetAppendHost(TrackType) {
+base::WeakPtr<AppendHost> DataStreamDemuxerImpl::GetAppendHost(TrackType) {
   EMSS_DEBUG();
 
-  return shared_from_this();
+  return weak_ptr_factory_.GetWeakPtr();
 }
 
 void DataStreamDemuxerImpl::OnBufferedTimeRangesChanged(
@@ -347,7 +351,7 @@ void DataStreamDemuxerImpl::RegisterSource(
     base::OnceClosure on_source_registered) {
   EMSS_DEBUG();
 
-  client->RegisterDemuxer(shared_from_this());
+  client->RegisterDemuxer(weak_ptr_factory_.GetWeakPtr());
   client_ = std::move(client);
 
   std::move(on_source_registered).Run();
index 8ed53fa00780fb27e84110ac32966c75a95543a2..c6de29241b476d991ad5b66e5f8b8f73de3f0917 100644 (file)
@@ -10,6 +10,7 @@
 #include <vector>
 
 #include "base/memory/scoped_refptr.h"
+#include "base/memory/weak_ptr.h"
 #include "base/threading/thread.h"
 #include "content/renderer/media/tizen/elementary_media_stream_source/any_thread/common_types.h"
 #include "content/renderer/media/tizen/elementary_media_stream_source/any_thread/demuxer_dispatcher.h"
@@ -39,14 +40,12 @@ namespace worker_thread {
 class AppendClient;
 
 // Demuxer implementation for MediaResource::Type::ELEMENTARY_STREAM.
-class DataStreamDemuxerImpl
-    : public AppendHost,
-      public DataStreamClient,
-      public Demuxer,
-      public DemuxerDispatcherClient,
-      public PlatformDemuxerAdapterClient,
-      public DemuxerDispatcherLifecycleObserver,
-      public std::enable_shared_from_this<DataStreamDemuxerImpl> {
+class DataStreamDemuxerImpl : public AppendHost,
+                              public DataStreamClient,
+                              public Demuxer,
+                              public DemuxerDispatcherClient,
+                              public PlatformDemuxerAdapterClient,
+                              public DemuxerDispatcherLifecycleObserver {
  public:
   using BackendError = ::elementary_media_stream_source::mojom::BackendError;
 
@@ -54,6 +53,9 @@ class DataStreamDemuxerImpl
 
   ~DataStreamDemuxerImpl() override;
 
+  // Note: weak ptr is valid on worker_thread
+  base::WeakPtr<DataStreamDemuxerImpl> GetWeakPtr();
+
   // DemuxerDispatcherLifecycleObserver
   void OnDispatcherConnected(
       PendingDataStreamSrcInterfaces pending_data_stream) override;
@@ -80,7 +82,7 @@ class DataStreamDemuxerImpl
   void OnClosedCaptions(const std::vector<uint8_t>& closed_captions) override;
 
   // Demuxer
-  std::shared_ptr<AppendHost> GetAppendHost(TrackType) override;
+  base::WeakPtr<AppendHost> GetAppendHost(TrackType) override;
   void OnBufferedTimeRangesChanged(media::Ranges<base::TimeDelta>&&) override;
   void OnInitialConfigReady(const MaybeAudioConfig&,
                             const MaybeVideoConfig&) override;
@@ -112,6 +114,8 @@ class DataStreamDemuxerImpl
   PipelineMode pipeline_mode_;
   std::shared_ptr<any_thread::LockableDemuxerState> state_;
   std::weak_ptr<VideoTextureClient> video_texture_client_;
+
+  base::WeakPtrFactory<DataStreamDemuxerImpl> weak_ptr_factory_{this};
 };
 
 }  // namespace worker_thread
index 1387fb6f1debe13fec582f10c9e60bf6c7c09a61..8ccfb5979aa0366e1180d5122de5c0fdba47d9e3 100644 (file)
@@ -28,7 +28,7 @@ class VideoTextureClient;
 class Demuxer {
  public:
   virtual ~Demuxer() = default;
-  virtual std::shared_ptr<AppendHost> GetAppendHost(TrackType) = 0;
+  virtual base::WeakPtr<AppendHost> GetAppendHost(TrackType) = 0;
   virtual void OnBufferedTimeRangesChanged(
       media::Ranges<base::TimeDelta>&&) = 0;
   virtual void OnInitialConfigReady(const MaybeAudioConfig&,
index 322fd21ea2eb80b87d65d877f4e5a31bb853cf0d..ddfc4ce3fb862f49814b5f43fd10592dfdb0face 100644 (file)
@@ -20,7 +20,7 @@ class Demuxer;
 class DemuxerClient {
  public:
   virtual ~DemuxerClient() = default;
-  virtual void RegisterDemuxer(std::shared_ptr<Demuxer>) = 0;
+  virtual void RegisterDemuxer(base::WeakPtr<Demuxer>) = 0;
 
  protected:
   DemuxerClient() = default;
diff --git a/tizen_src/chromium_impl/content/renderer/media/tizen/elementary_media_stream_source/worker_thread/demuxer_dispatcher_client.cc b/tizen_src/chromium_impl/content/renderer/media/tizen/elementary_media_stream_source/worker_thread/demuxer_dispatcher_client.cc
new file mode 100644 (file)
index 0000000..28d7830
--- /dev/null
@@ -0,0 +1,24 @@
+// Copyright (c) 2024 Samsung Electronics. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/renderer/media/tizen/elementary_media_stream_source/worker_thread/demuxer_dispatcher_client.h"
+
+#include "services/elementary_media_stream_source/public/cpp/logger.h"
+
+namespace content {
+namespace elementary_media_stream_source {
+namespace worker_thread {
+
+DemuxerDispatcherClient::DemuxerDispatcherClient() = default;
+
+DemuxerDispatcherClient::~DemuxerDispatcherClient() = default;
+
+void DemuxerDispatcherClient::SetGpuFactories(
+    media::GpuVideoAcceleratorFactories*) {
+  EMSS_LOG_ASSERT(false) << "Not implemented! Should never be called.";
+}
+
+}  // namespace worker_thread
+}  // namespace elementary_media_stream_source
+}  // namespace content
index ec803f4ed94e3bc3c54ab2457713a6595cdfcdad..5d642952c799e5f76dee06116aa735ccd3e6bbd0 100644 (file)
 #include "media/base/demuxer_stream.h"
 #include "media/base/video_frame.h"
 
+namespace media {
+class GpuVideoAcceleratorFactories;
+}  // namespace media
+
 namespace content {
 
 namespace elementary_media_stream_source {
@@ -26,7 +30,7 @@ namespace worker_thread {
 // `DemuxerDispatcher` keeps `DemuxerImpl` alive through this interface.
 class DemuxerDispatcherClient : public EnableDispatcher {
  public:
-  virtual ~DemuxerDispatcherClient() = default;
+  virtual ~DemuxerDispatcherClient();
 
   virtual void OnPipelineClosed() = 0;
   virtual void OnPipelineResuming() = 0;
@@ -34,9 +38,11 @@ class DemuxerDispatcherClient : public EnableDispatcher {
   virtual void OnReadRequested(TrackType) = 0;
   virtual void OnSeekDone(base::TimeDelta new_time, uint32_t session_id) = 0;
   virtual void OnSessionIdChange(uint32_t session_id) = 0;
+  virtual void SetGpuFactories(
+      media::GpuVideoAcceleratorFactories* gpu_factories);
 
  protected:
-  DemuxerDispatcherClient() = default;
+  DemuxerDispatcherClient();
 };
 
 }  // namespace worker_thread
index a2cd569d7b9a1b9809fd3bd459e6304f6eb08fdb..768d8c294292cbed158adc3d3bcb378d180fc197 100644 (file)
@@ -35,12 +35,18 @@ MediaStreamDemuxerImpl::~MediaStreamDemuxerImpl() {
   EMSS_DEBUG() << "Destructing object";
 }
 
+base::WeakPtr<MediaStreamDemuxerImpl> MediaStreamDemuxerImpl::GetWeakPtr() {
+  EMSS_VERBOSE();
+
+  return weak_ptr_factory_.GetMutableWeakPtr();
+}
+
 //////////////////// Demuxer ////////////////////
 
-std::shared_ptr<AppendHost> MediaStreamDemuxerImpl::GetAppendHost(TrackType) {
+base::WeakPtr<AppendHost> MediaStreamDemuxerImpl::GetAppendHost(TrackType) {
   EMSS_DEBUG();
 
-  return shared_from_this();
+  return weak_ptr_factory_.GetMutableWeakPtr();
 }
 
 void MediaStreamDemuxerImpl::OnBufferedTimeRangesChanged(
@@ -151,7 +157,7 @@ void MediaStreamDemuxerImpl::RegisterSource(
     base::OnceClosure on_source_registered) {
   EMSS_DEBUG();
 
-  client->RegisterDemuxer(shared_from_this());
+  client->RegisterDemuxer(weak_ptr_factory_.GetMutableWeakPtr());
   client_ = std::move(client);
 
   std::move(on_source_registered).Run();
index 948fb233adfadd3fa528b12f27af6387921c3bf4..9d3a73f86440b0de4524c81fc3914f39b5e4c0c4 100644 (file)
@@ -24,12 +24,10 @@ namespace worker_thread {
 class AppendClient;
 
 // Demuxer implementation for MediaResource::Type::STREAM.
-class MediaStreamDemuxerImpl
-    : public Demuxer,
-      public DemuxerDispatcherClient,
-      public AppendHost,
-      public PlatformDemuxerAdapterClient,
-      public std::enable_shared_from_this<MediaStreamDemuxerImpl> {
+class MediaStreamDemuxerImpl : public Demuxer,
+                               public DemuxerDispatcherClient,
+                               public AppendHost,
+                               public PlatformDemuxerAdapterClient {
  public:
   using BackendError = ::elementary_media_stream_source::mojom::BackendError;
 
@@ -37,8 +35,11 @@ class MediaStreamDemuxerImpl
 
   ~MediaStreamDemuxerImpl() override;
 
+  // Note: weak ptr is valid on worker_thread
+  base::WeakPtr<MediaStreamDemuxerImpl> GetWeakPtr();
+
   // Demuxer
-  std::shared_ptr<AppendHost> GetAppendHost(TrackType) override;
+  base::WeakPtr<AppendHost> GetAppendHost(TrackType) override;
   void OnBufferedTimeRangesChanged(media::Ranges<base::TimeDelta>&&) override;
   void OnInitialConfigReady(const MaybeAudioConfig&,
                             const MaybeVideoConfig&) override;
@@ -75,6 +76,8 @@ class MediaStreamDemuxerImpl
   PipelineMode pipeline_mode_;
   // std::shared_ptr<any_thread::LockableDemuxerState> state_;
   // std::weak_ptr<VideoTextureClient> video_texture_client_;
+
+  base::WeakPtrFactory<MediaStreamDemuxerImpl> weak_ptr_factory_{this};
 };
 
 }  // namespace worker_thread
index a28e92cb79cd7db0855e81ef7ea88f883cef0f6b..b17e1885620b1400a2289dbcd4e70a33ce1db7be 100644 (file)
@@ -682,6 +682,12 @@ void MsDecodingStream::EmitError(BackendError backend_error,
   }
 }
 
+base::WeakPtr<MsDecodingStream> MsDecodingStream::GetWeakPtr() {
+  EMSS_VERBOSE();
+
+  return weak_ptr_factory_.GetMutableWeakPtr();
+}
+
 void MsDecodingStream::SetGpuFactories(
     media::GpuVideoAcceleratorFactories* gpu_factories) {
   EMSS_DEBUG() << gpu_factories;
@@ -740,10 +746,10 @@ void MsDecodingStream::SetMediaStreamDecoderFactory(
         decoder_factory_, dispatcher_.lock()->GetControlThreadTaskRunner()));
 }
 
-std::shared_ptr<AppendHost> MsDecodingStream::GetAppendHost(TrackType) {
+base::WeakPtr<AppendHost> MsDecodingStream::GetAppendHost(TrackType) {
   EMSS_VERBOSE();
 
-  return shared_from_this();
+  return weak_ptr_factory_.GetMutableWeakPtr();
 }
 
 void MsDecodingStream::OnBufferedTimeRangesChanged(
@@ -849,7 +855,7 @@ void MsDecodingStream::RegisterSource(std::shared_ptr<DemuxerClient> client,
                                       base::OnceClosure on_source_registered) {
   EMSS_DEBUG();
 
-  client->RegisterDemuxer(shared_from_this());
+  client->RegisterDemuxer(weak_ptr_factory_.GetMutableWeakPtr());
 
   std::move(on_source_registered).Run();
 }
index 6892eb64b01f17ab3f8b27ade0991166185964c6..b5ff017ddd67f3f6b6466834f4da9542aa94a5d1 100644 (file)
@@ -38,8 +38,7 @@ namespace worker_thread {
 class MsDecodingStream : public Demuxer,
                          public DemuxerDispatcherClient,
                          public AppendHost,
-                         public PlatformDemuxerAdapterClient,
-                         public std::enable_shared_from_this<MsDecodingStream> {
+                         public PlatformDemuxerAdapterClient {
  public:
   using BackendError = ::elementary_media_stream_source::mojom::BackendError;
   using CreateAudioDecodersCb =
@@ -51,12 +50,14 @@ class MsDecodingStream : public Demuxer,
   ~MsDecodingStream() override;
 
   void EmitError(BackendError backend_error, const std::string& message);
-  void SetGpuFactories(media::GpuVideoAcceleratorFactories* gpu_factories);
+
+  // Note: weak ptr is valid on worker_thread
+  base::WeakPtr<MsDecodingStream> GetWeakPtr();
 
   // Demuxer:
   void SetMediaStreamDecoderFactory(
       base::WeakPtr<media::DecoderFactory>) override;
-  std::shared_ptr<AppendHost> GetAppendHost(TrackType) override;
+  base::WeakPtr<AppendHost> GetAppendHost(TrackType) override;
   void OnBufferedTimeRangesChanged(media::Ranges<base::TimeDelta>&&) override;
   void OnInitialConfigReady(const MaybeAudioConfig&,
                             const MaybeVideoConfig&) override;
@@ -70,6 +71,8 @@ class MsDecodingStream : public Demuxer,
   void OnReadRequested(TrackType) override;
   void OnSeekDone(base::TimeDelta new_time, uint32_t session_id) override;
   void OnSessionIdChange(uint32_t session_id) override;
+  void SetGpuFactories(
+      media::GpuVideoAcceleratorFactories* gpu_factories) override;
 
   // AppendHost:
   void NotifyFramerateSet(
@@ -97,6 +100,8 @@ class MsDecodingStream : public Demuxer,
   std::weak_ptr<any_thread::DemuxerDispatcher> dispatcher_;
   media::GpuVideoAcceleratorFactories* gpu_factories_{nullptr};
   std::unique_ptr<media::MediaLog> media_log_;
+
+  base::WeakPtrFactory<MsDecodingStream> weak_ptr_factory_{this};
 };
 
 }  // namespace worker_thread
index 8abd6a036e1239e5b6338fa12fec5b8ea3217c94..fde26ae3d24853603772aba23ab7dc79bdcd2a58 100644 (file)
@@ -31,7 +31,7 @@ class SourceClient {
   virtual const media::Ranges<base::TimeDelta>& GetBufferedRanges() const = 0;
   virtual std::shared_ptr<VideoTextureClient> GetVideoTextureClient() = 0;
   virtual TrackType Type() const = 0;
-  virtual void SetAppendHost(std::shared_ptr<AppendHost>) = 0;
+  virtual void SetAppendHost(base::WeakPtr<AppendHost>) = 0;
   virtual void RegisterSource(std::shared_ptr<Source>) = 0;
 
  protected:
index 14f07b6d73fc177a6a542bf7e4ccccb0acadc14d..7859afaef88debf5d4a8b32bdb02f9819c694e4a 100644 (file)
@@ -31,7 +31,7 @@ SourceImpl::~SourceImpl() {
 
 //////////////////// Source ////////////////////
 
-void SourceImpl::RegisterDemuxer(std::shared_ptr<Demuxer> demuxer) {
+void SourceImpl::RegisterDemuxer(base::WeakPtr<Demuxer> demuxer) {
   EMSS_DEBUG();
 
   demuxer_ = demuxer;
@@ -67,8 +67,10 @@ void SourceImpl::BufferedRangesChanged() const {
     shared_state->buffered_ranges = new_ranges;
   }
 
-  if (auto demuxer = demuxer_.lock())
-    demuxer->OnBufferedTimeRangesChanged(std::move(new_ranges));
+  if (!demuxer_)
+    return;
+
+  demuxer_->OnBufferedTimeRangesChanged(std::move(new_ranges));
 }
 
 //////////////////// SourceDispatcherClient ////////////////////
@@ -81,9 +83,10 @@ void SourceImpl::OnInitialConfigReady(MaybeAudioConfig audio_config,
       << "Should not be called in " << pipeline_mode_.demuxer_mode << " and "
       << pipeline_mode_.latency_mode;
 
-  if (auto demuxer = demuxer_.lock()) {
-    demuxer->OnInitialConfigReady(audio_config, video_config);
-  }
+  if (!demuxer_)
+    return;
+
+  demuxer_->OnInitialConfigReady(audio_config, video_config);
 }
 
 void SourceImpl::RegisterClient(std::shared_ptr<SourceClient> client) {
@@ -92,42 +95,47 @@ void SourceImpl::RegisterClient(std::shared_ptr<SourceClient> client) {
   clients_[+client->Type()] = client;
   client->RegisterSource(std::static_pointer_cast<Source>(shared_from_this()));
 
-  if (auto demuxer = demuxer_.lock()) {
-    demuxer->SetAppendClient(client->Type(), client->GetAppendClient());
-    client->SetAppendHost(demuxer->GetAppendHost(client->Type()));
+  if (!demuxer_)
+    return;
 
-    if (pipeline_mode_.player_mode != PlayerMode::kDecodeToTexture ||
-        client->Type() != TrackType::kVideo)
-      return;
+  demuxer_->SetAppendClient(client->Type(), client->GetAppendClient());
+  client->SetAppendHost(demuxer_->GetAppendHost(client->Type()));
 
-    demuxer->SetVideoTextureClient(client->GetVideoTextureClient());
-  }
+  if (pipeline_mode_.player_mode != PlayerMode::kDecodeToTexture ||
+      client->Type() != TrackType::kVideo)
+    return;
+
+  demuxer_->SetVideoTextureClient(client->GetVideoTextureClient());
 }
 
 void SourceImpl::SetMediaStreamAudioTrackSink(
     std::shared_ptr<blink::WebElementaryMediaTrackMsAudioSink> audio_sink) {
   EMSS_DEBUG();
-  if (auto demuxer = demuxer_.lock()) {
-    demuxer->GetAppendHost(TrackType::kAudio)
-        ->SetAudioSink(std::move(audio_sink));
-  }
+  if (!demuxer_)
+    return;
+  auto append_host = demuxer_->GetAppendHost(TrackType::kAudio);
+  if (!append_host)
+    return;
+  append_host->SetAudioSink(std::move(audio_sink));
 }
 
 void SourceImpl::SetMediaStreamVideoTrackSink(
     std::shared_ptr<blink::WebElementaryMediaTrackMsVideoSink> video_sink) {
   EMSS_DEBUG();
-  if (auto demuxer = demuxer_.lock()) {
-    demuxer->GetAppendHost(TrackType::kVideo)
-        ->SetVideoSink(std::move(video_sink));
-  }
+  if (!demuxer_)
+    return;
+  auto append_host = demuxer_->GetAppendHost(TrackType::kVideo);
+  if (!append_host)
+    return;
+  append_host->SetVideoSink(std::move(video_sink));
 }
 
 void SourceImpl::SetMediaStreamDecoderFactory(
     base::WeakPtr<media::DecoderFactory> decoder_factory) {
   EMSS_DEBUG();
-  if (auto demuxer = demuxer_.lock()) {
-    demuxer->SetMediaStreamDecoderFactory(std::move(decoder_factory));
-  }
+  if (!demuxer_)
+    return;
+  demuxer_->SetMediaStreamDecoderFactory(std::move(decoder_factory));
 }
 
 }  // namespace worker_thread
index 2454f3ffd1ff29029467454e4dd8eb0ba5ac8131..212e605c943c27f5fe887e88077af1789b979901 100644 (file)
@@ -35,7 +35,7 @@ class SourceImpl : public DemuxerClient,
   ~SourceImpl() override;
 
   // DemuxerClient
-  void RegisterDemuxer(std::shared_ptr<Demuxer>) override;
+  void RegisterDemuxer(base::WeakPtr<Demuxer>) override;
 
   // Source + SourceDispatcherClient
   void BufferedRangesChanged() const override;
@@ -54,7 +54,7 @@ class SourceImpl : public DemuxerClient,
   const PipelineMode pipeline_mode_;
 
   std::array<std::weak_ptr<SourceClient>, (+TrackType::kMaxValue + 1)> clients_;
-  std::weak_ptr<Demuxer> demuxer_;
+  base::WeakPtr<Demuxer> demuxer_;
   std::shared_ptr<any_thread::LockableSourceState> state_;
 };
 
index 0f06fb07bd58a5cd5b7f94efe07d38606c5f2724..41a6ed2ad7f6d4948a230d4b7bad80c7bcd4943e 100644 (file)
@@ -147,7 +147,7 @@ void TrackImpl::RegisterSource(std::shared_ptr<Source> source) {
   source_ = source;
 }
 
-void TrackImpl::SetAppendHost(std::shared_ptr<AppendHost> append_host) {
+void TrackImpl::SetAppendHost(base::WeakPtr<AppendHost> append_host) {
   EMSS_DEBUG_TYPED();
 
   append_host_ = append_host;
@@ -170,8 +170,8 @@ void TrackImpl::AbortPendingReads() {
       track_mode_.demuxer_mode == DemuxerMode::kMediaStream) {
     // Media Stream expects response to each read. Do not silently drop a read
     // but fire an empty one if reseting read state was requested.
-    if (auto append_host = append_host_.lock()) {
-      append_host->OnReadMediaPackets(Type(), std::vector<Packet>{});
+    if (append_host_) {
+      append_host_->OnReadMediaPackets(Type(), std::vector<Packet>{});
     }
   }
 
@@ -272,8 +272,7 @@ void TrackImpl::RunReadCb() {
   EMSS_LOG_ASSERT(is_read_requested_) << "Read called when not requested";
   EMSS_LOG_ASSERT(!packets_queue_.empty()) << "Read called on empty queue";
 
-  auto append_host = append_host_.lock();
-  if (!append_host) {
+  if (!append_host_) {
     EMSS_VERBOSE_TYPED();
     return;
   }
@@ -292,20 +291,20 @@ void TrackImpl::RunReadCb() {
     const auto& first_packet = packets_queue_.front();
     if (first_packet.packet) {
       EMSS_VERBOSE_TYPED();
-      ReadMediaPackets(shared_state, append_host.get());
+      ReadMediaPackets(shared_state, append_host_.get());
     } else if (first_packet.status == ReadStatus::kConfigChanged) {
       if (Type() == TrackType::kAudio) {
         EMSS_VERBOSE_TYPED() << "Reading audio config";
         EMSS_LOG_ASSERT(std::holds_alternative<media::AudioDecoderConfig>(
             shared_state->config));
-        append_host->OnReadConfig(ToAudioConfig(
+        append_host_->OnReadConfig(ToAudioConfig(
             std::get<media::AudioDecoderConfig>(shared_state->config),
             track_mode_.decoding_mode));
       } else {
         EMSS_VERBOSE_TYPED() << "Reading video config";
         EMSS_LOG_ASSERT(std::holds_alternative<media::VideoDecoderConfig>(
             shared_state->config));
-        append_host->OnReadConfig(ToVideoConfig(
+        append_host_->OnReadConfig(ToVideoConfig(
             std::get<media::VideoDecoderConfig>(shared_state->config),
             track_mode_.decoding_mode));
       }
index 94ee79a75924bb0454d901df4334364de91266b2..4011d463855cdc187be80d03e950a338eecf9a1d 100644 (file)
@@ -48,7 +48,7 @@ class TrackImpl : public AppendClient,
   std::shared_ptr<VideoTextureClient> GetVideoTextureClient() override;
   TrackType Type() const override = 0;
   void RegisterSource(std::shared_ptr<Source>) override;
-  void SetAppendHost(std::shared_ptr<AppendHost>) override;
+  void SetAppendHost(base::WeakPtr<AppendHost>) override;
 
   // TrackDispatcherClient
   void AbortPendingReads() override;
@@ -80,7 +80,7 @@ class TrackImpl : public AppendClient,
   const PacketHolder& GetNextPacket() const;
   virtual void RunReadCb();
 
-  std::weak_ptr<AppendHost> append_host_;
+  base::WeakPtr<AppendHost> append_host_;
   std::weak_ptr<any_thread::TrackDispatcher> dispatcher_;
   std::shared_ptr<any_thread::LockableTrackState> state_;
   TrackMode track_mode_;
index 178e2a28856600dd2ab9d0e78e2bfe18a4e7e2a0..436b51116922655a65f4755750794dbccfafc24c 100644 (file)
@@ -35,7 +35,7 @@ std::shared_ptr<VideoTextureClient> VideoTrackImpl::GetVideoTextureClient() {
   return std::static_pointer_cast<VideoTrackImpl>(shared_from_this());
 }
 
-void VideoTrackImpl::SetAppendHost(std::shared_ptr<AppendHost> append_host) {
+void VideoTrackImpl::SetAppendHost(base::WeakPtr<AppendHost> append_host) {
   EMSS_DEBUG();
 
   {
@@ -87,8 +87,8 @@ void VideoTrackImpl::ChangeConfiguration(
 void VideoTrackImpl::NotifyFramerateChange() const {
   EMSS_VERBOSE();
 
-  if (auto append_host = append_host_.lock())
-    append_host->NotifyFramerateSet(current_framerate_);
+  if (append_host_)
+    append_host_->NotifyFramerateSet(current_framerate_);
 }
 
 void VideoTrackImpl::RunReadCb() {
index 3da692a016f766cdfaadc03181d21cb8c3c13205..9728503a810401390f0f216b314dc4f2c07c720a 100644 (file)
@@ -28,7 +28,7 @@ class VideoTrackImpl : public TrackImpl, public VideoTextureClient {
 
   // SourceClient
   std::shared_ptr<VideoTextureClient> GetVideoTextureClient() override;
-  void SetAppendHost(std::shared_ptr<AppendHost>) override;
+  void SetAppendHost(base::WeakPtr<AppendHost>) override;
   TrackType Type() const override;
 
   // VideoTextureClient
index d59aa5b9b5a52d718fb20ba388e34e648222cb08..60a21ab71e0804fa91f40ecaee175fee4318fa61 100644 (file)
@@ -27,12 +27,12 @@ class DemuxerDispatcherForTesting : public DemuxerDispatcher {
                           worker_thread_task_runner) {}
 
   void SetClientsForTesting(
-      std::shared_ptr<AnyThreadClient> any_thread_client_,
-      std::shared_ptr<ControlThreadClient> control_thread_client_,
-      std::shared_ptr<WorkerThreadClient> worker_thread_client_) {
-    SetClient<AnyThreadClient>(std::move(any_thread_client_));
-    SetClient<ControlThreadClient>(std::move(control_thread_client_));
-    SetClient<WorkerThreadClient>(std::move(worker_thread_client_));
+      std::shared_ptr<AnyThreadClient> any_thread_client,
+      std::shared_ptr<ControlThreadClient> control_thread_client,
+      base::WeakPtr<WorkerThreadClient> worker_thread_client) {
+    SetClient<AnyThreadClient>(std::move(any_thread_client));
+    SetClient<ControlThreadClient>(std::move(control_thread_client));
+    SetClient<WorkerThreadClient>(std::move(worker_thread_client));
   }
 };
 
index 4e912774cedf656ce891a82c83786da8aaf18aed..dd4758aa5dd5c71e1fb93bb555d415cae3807379 100644 (file)
@@ -40,14 +40,14 @@ class DemuxerImplTestBase : public EmssTestBase {
             std::make_shared<testing::NiceMock<
                 control_thread::MockDemuxerDispatcherClient>>()),
         mock_worker_thread_client_(
-            std::make_shared<testing::NiceMock<
+            std::make_unique<testing::NiceMock<
                 worker_thread::MockDemuxerDispatcherClient>>()),
         fake_media_thread_(CreateAndStartBaseThread("TestingMediaThread")),
         mock_proxy_(std::make_unique<testing::NiceMock<
                         media_thread::MockPlatformDemuxerAdapter>>()) {
-    demuxer_dispatcher_->SetClientsForTesting(mock_any_thread_client_,
-                                              mock_control_thread_client_,
-                                              mock_worker_thread_client_);
+    demuxer_dispatcher_->SetClientsForTesting(
+        mock_any_thread_client_, mock_control_thread_client_,
+        mock_worker_thread_client_->GetWeakPtr());
 
     fake_media_thread_->task_runner()->PostTask(
         FROM_HERE,
@@ -99,7 +99,7 @@ class DemuxerImplTestBase : public EmssTestBase {
       mock_any_thread_client_;
   std::shared_ptr<control_thread::MockDemuxerDispatcherClient>
       mock_control_thread_client_;
-  std::shared_ptr<worker_thread::MockDemuxerDispatcherClient>
+  std::unique_ptr<worker_thread::MockDemuxerDispatcherClient>
       mock_worker_thread_client_;
 
   std::shared_ptr<base::Thread> fake_media_thread_;
index 6554155ec65e49164f09c62962c31d6f0062cf5f..1f6e26c17c3b18107c4c0c698b1fba45c2d26b08 100644 (file)
@@ -21,6 +21,10 @@ namespace worker_thread {
 
 class MockAppendHost : public AppendHost {
  public:
+  base::WeakPtr<AppendHost> GetWeakPtr() {
+    return weak_ptr_factory_.GetMutableWeakPtr();
+  }
+
   MOCK_METHOD(void,
               NotifyFramerateSet,
               (const media::StreamFramerate::Framerate&),
@@ -31,6 +35,9 @@ class MockAppendHost : public AppendHost {
               OnReadMediaPackets,
               (TrackType, std::vector<Packet>),
               (override));
+
+ private:
+  base::WeakPtrFactory<AppendHost> weak_ptr_factory_{this};
 };
 
 }  // namespace worker_thread
index 2374238ec7b8dbb7d860b7646ee11fe5c03326c6..ef6fc8e3b7719e661c01cbf621450b22c110d45e 100644 (file)
@@ -17,7 +17,7 @@ namespace worker_thread {
 
 class MockDemuxerClient : public DemuxerClient {
  public:
-  MOCK_METHOD1(RegisterDemuxer, void(std::shared_ptr<Demuxer>));
+  MOCK_METHOD1(RegisterDemuxer, void(base::WeakPtr<Demuxer>));
 };
 
 }  // namespace worker_thread
index e2880ca0cf2f8f56477148ef6e89980b879c3458..a96fe1277d372767ebc15866058aeebd0b249be8 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <memory>
 
+#include "base/memory/weak_ptr.h"
 #include "content/renderer/media/tizen/elementary_media_stream_source/worker_thread/demuxer_dispatcher_client.h"
 
 #include "testing/gmock/include/gmock/gmock.h"
@@ -17,6 +18,10 @@ namespace worker_thread {
 
 class MockDemuxerDispatcherClient : public DemuxerDispatcherClient {
  public:
+  base::WeakPtr<DemuxerDispatcherClient> GetWeakPtr() {
+    return weak_ptr_factory_.GetMutableWeakPtr();
+  }
+
   MOCK_METHOD(void, OnPipelineClosed, (), (override));
   MOCK_METHOD(void, OnPipelineResuming, (), (override));
   MOCK_METHOD(void, OnPipelineSuspended, (), (override));
@@ -26,6 +31,9 @@ class MockDemuxerDispatcherClient : public DemuxerDispatcherClient {
               (base::TimeDelta new_time, uint32_t session_id),
               (override));
   MOCK_METHOD(void, OnSessionIdChange, (uint32_t session_id), (override));
+
+ private:
+  base::WeakPtrFactory<DemuxerDispatcherClient> weak_ptr_factory_{this};
 };
 
 }  // namespace worker_thread
index 29638825c36bb45e7cd6139cc953901312d7466b..b4c95debdbc99fb5d1752165d7281efec1b17603 100644 (file)
@@ -170,8 +170,8 @@ void WorkerThreadTrackImplNormalLatencyPlayerTest::AddSuccessfulPacketAndCheck(
   ResultCb cb_append = GetOnceCallback(cb_append_fn);
 
   // append host needs to be set, or RunReadCb exits quickly
-  auto append_host_mock = std::make_shared<NiceMock<MockAppendHost>>();
-  track_->SetAppendHost(append_host_mock);
+  auto append_host_mock = std::make_unique<NiceMock<MockAppendHost>>();
+  track_->SetAppendHost(append_host_mock->GetWeakPtr());
   auto source_mock = std::make_shared<MockSource>();
   track_->RegisterSource(source_mock);
 
@@ -307,8 +307,8 @@ TEST_F(WorkerThreadTrackImplNormalLatencyPlayerTest,
   SetSessionId(session_id);
 
   // append host needs to be set, or RunReadCb exits quickly
-  auto append_host_mock = std::make_shared<NiceMock<MockAppendHost>>();
-  track_->SetAppendHost(append_host_mock);
+  auto append_host_mock = std::make_unique<NiceMock<MockAppendHost>>();
+  track_->SetAppendHost(append_host_mock->GetWeakPtr());
   auto source_mock = std::make_shared<MockSource>();
   track_->RegisterSource(source_mock);
 
@@ -348,8 +348,8 @@ TEST_F(WorkerThreadTrackImplNormalLatencyPlayerTest,
   SetSessionId(session_id_state);
 
   // append host needs to be set, or RunReadCb exits quickly
-  auto append_host_mock = std::make_shared<NiceMock<MockAppendHost>>();
-  track_->SetAppendHost(append_host_mock);
+  auto append_host_mock = std::make_unique<NiceMock<MockAppendHost>>();
+  track_->SetAppendHost(append_host_mock->GetWeakPtr());
   auto source_mock = std::make_shared<MockSource>();
   track_->RegisterSource(source_mock);
 
@@ -400,8 +400,8 @@ TEST_F(WorkerThreadTrackImplNormalLatencyPlayerTest,
   AddPacketToState();
 
   // append host needs to be set, or RunReadCb exits quickly
-  auto append_host_mock = std::make_shared<NiceMock<MockAppendHost>>();
-  track_->SetAppendHost(append_host_mock);
+  auto append_host_mock = std::make_unique<NiceMock<MockAppendHost>>();
+  track_->SetAppendHost(append_host_mock->GetWeakPtr());
   auto source_mock = std::make_shared<MockSource>();
   track_->RegisterSource(source_mock);
   ResultCb cb_append = GetOnceCallback(cb_append_fn);
@@ -535,8 +535,8 @@ TEST_F(WorkerThreadTrackImplNormalLatencyPlayerTest,
   ResultCb cb_append = GetOnceCallback(cb_append_fn);
 
   // append host needs to be set, or RunReadCb exits quickly
-  auto append_host_mock = std::make_shared<NiceMock<MockAppendHost>>();
-  track_->SetAppendHost(append_host_mock);
+  auto append_host_mock = std::make_unique<NiceMock<MockAppendHost>>();
+  track_->SetAppendHost(append_host_mock->GetWeakPtr());
   auto source_mock = std::make_shared<MockSource>();
   track_->RegisterSource(source_mock);
 
@@ -600,8 +600,8 @@ TEST_F(WorkerThreadTrackImplNormalLatencyPlayerTest,
   ResultCb cb_append = GetOnceCallback(cb_append_fn);
 
   // append host needs to be set, or RunReadCb exits quickly
-  auto append_host_mock = std::make_shared<NiceMock<MockAppendHost>>();
-  track_->SetAppendHost(append_host_mock);
+  auto append_host_mock = std::make_unique<NiceMock<MockAppendHost>>();
+  track_->SetAppendHost(append_host_mock->GetWeakPtr());
   auto source_mock = std::make_shared<MockSource>();
   track_->RegisterSource(source_mock);
 
@@ -635,8 +635,8 @@ TEST_F(WorkerThreadTrackImplNormalLatencyPlayerTest,
   uint32_t session_id_new = kDefaultSessionId + 1;
 
   // append host needs to be set, or RunReadCb exits quickly
-  auto append_host_mock = std::make_shared<NiceMock<MockAppendHost>>();
-  track_->SetAppendHost(append_host_mock);
+  auto append_host_mock = std::make_unique<NiceMock<MockAppendHost>>();
+  track_->SetAppendHost(append_host_mock->GetWeakPtr());
   auto source_mock = std::make_shared<MockSource>();
   track_->RegisterSource(source_mock);
 
@@ -672,8 +672,8 @@ TEST_F(WorkerThreadTrackImplNormalLatencyPlayerTest,
   uint32_t session_id = kDefaultSessionId;
 
   // append host needs to be set, or RunReadCb exits quickly
-  auto append_host_mock = std::make_shared<NiceMock<MockAppendHost>>();
-  track_->SetAppendHost(append_host_mock);
+  auto append_host_mock = std::make_unique<NiceMock<MockAppendHost>>();
+  track_->SetAppendHost(append_host_mock->GetWeakPtr());
   auto source_mock = std::make_shared<MockSource>();
   track_->RegisterSource(source_mock);
 
@@ -702,8 +702,8 @@ TEST_F(WorkerThreadTrackImplNormalLatencyPlayerTest,
   uint32_t session_id = kDefaultSessionId;
 
   // append host needs to be set, or RunReadCb exits quickly
-  auto append_host_mock = std::make_shared<NiceMock<MockAppendHost>>();
-  track_->SetAppendHost(append_host_mock);
+  auto append_host_mock = std::make_unique<NiceMock<MockAppendHost>>();
+  track_->SetAppendHost(append_host_mock->GetWeakPtr());
   auto source_mock = std::make_shared<MockSource>();
   track_->RegisterSource(source_mock);
 
@@ -724,8 +724,8 @@ TEST_F(WorkerThreadTrackImplNormalLatencyPlayerTest,
   uint32_t session_id = kDefaultSessionId;
 
   // append host needs to be set, or RunReadCb exits quickly
-  auto append_host_mock = std::make_shared<NiceMock<MockAppendHost>>();
-  track_->SetAppendHost(append_host_mock);
+  auto append_host_mock = std::make_unique<NiceMock<MockAppendHost>>();
+  track_->SetAppendHost(append_host_mock->GetWeakPtr());
   auto source_mock = std::make_shared<MockSource>();
   track_->RegisterSource(source_mock);
 
index 6af2531e34fb72edeb70e2e25ffc6d3e70c6bcc4..33ceaec9b123398c95a6ed58ed1513251f8d0561 100644 (file)
@@ -29,12 +29,6 @@ class PlatformPlayerListenerInterface;
 
 }  // namespace player_thread
 
-template <>
-struct ClientTraits<control_thread::HostClientInterface> {
- public:
-  using PointerType = control_thread::HostClientInterface*;
-};
-
 namespace any_thread {
 
 class HostDispatcher
index c587df9daf00c3c4bb22374de93678464073d750..9d3b37fea93d1aad7d84f5bab5a3a6375159b07f 100644 (file)
@@ -48,16 +48,6 @@ class EnableDispatcher;
 
 namespace elementary_media_stream_source {
 
-// By default all clients execute on shared_ptr and make dispatcher owner of the
-// clients. Their pointer type can be changed by providing partial ClientTraits
-// specialization in dispatcher implementation (typically change pointer type to
-// raw ptr and make it a client dispatcher doesn't own).
-template <typename ClientType>
-struct ClientTraits {
- public:
-  using PointerType = std::shared_ptr<ClientType>;
-};
-
 namespace control_thread {
 class EnableDispatcher;
 }  // namespace control_thread
@@ -101,6 +91,26 @@ struct compatible_arg_dispatch : std::true_type {
 template <class T>
 using compatible_arg_dispatch_t = typename compatible_arg_dispatch<T>::type;
 
+template <class T, class Tuple>
+struct is_type_in_tuple : public std::false_type {};
+
+template <class T, class... TupleTypes>
+struct is_type_in_tuple<T, std::tuple<TupleTypes...>>
+    : public std::disjunction<std::is_same<T, TupleTypes>..., std::false_type> {
+};
+
+template <class T>
+struct is_shared_ptr : public std::false_type {};
+
+template <class HeldT>
+struct is_shared_ptr<std::shared_ptr<HeldT>> : public std::true_type {};
+
+template <class T>
+struct is_base_weak_ptr : public std::false_type {};
+
+template <class HeldT>
+struct is_base_weak_ptr<base::WeakPtr<HeldT>> : public std::true_type {};
+
 // Base class for all dispatchers.
 // Implements DispatchTask and RunTask public methods to be used in derived
 // dispatchers classes.
@@ -111,13 +121,14 @@ class Dispatcher : public std::enable_shared_from_this<Dispatcher<Impl>> {
 
   template <typename ClientType>
   bool HasClient() const {
-    return !!GetClient<ClientType>();
+    return !!GetClient<ClientType>(static_cast<const Impl*>(this)->clients_);
   }
 
   template <typename ClientType, typename ReturnType, typename... Args>
   DispatchResult DispatchTask(ReturnType (ClientType::*method)(Args...),
-                              compatible_arg_dispatch_t<Args>... args) const {
-    auto client = GetClient<ClientType>();
+                              compatible_arg_dispatch_t<Args>... args) {
+    auto client =
+        GetClient<ClientType>(static_cast<const Impl*>(this)->clients_);
     if (!client)
       return DispatchResult::kFailed;
 
@@ -125,21 +136,27 @@ class Dispatcher : public std::enable_shared_from_this<Dispatcher<Impl>> {
     LOG_ASSERT(client_task_runner)
         << "A task runner for ClientType* is not set.";
 
-    if constexpr (!std::is_pointer<decltype(client)>::value) {
-      // If it's not pointer, it's shared_ptr
+    if constexpr (is_shared_ptr<decltype(client)>::value) {
       if (!client_task_runner->PostTask(
               FROM_HERE,
               base::BindOnce(
-                  ExecuteOnSharedPtr<ClientType, ReturnType, Args...>, method,
+                  &ExecuteOnSharedPtr<ClientType, ReturnType, Args...>, method,
                   client, std::forward<decltype(args)>(args)...)))
         return DispatchResult::kFailed;
+    } else if constexpr (is_base_weak_ptr<decltype(client)>::value) {
+      if (!client_task_runner->PostTask(
+              FROM_HERE,
+              base::BindOnce(&ExecuteOnWeakPtr<ClientType, ReturnType, Args...>,
+                             method, client,
+                             std::forward<decltype(args)>(args)...)))
+        return DispatchResult::kFailed;
     } else {
       if (!client_task_runner->PostTask(
               FROM_HERE,
-              base::BindOnce(&ExecuteOnRawPtr<ClientType, ReturnType, Args...>,
-                             std::weak_ptr<const Dispatcher<Impl>>{
-                                 this->shared_from_this()},
-                             method, std::forward<decltype(args)>(args)...)))
+              base::BindOnce(
+                  &ExecuteOnRawPtr<ClientType, ReturnType, Args...>,
+                  std::weak_ptr<Dispatcher<Impl>>{this->shared_from_this()},
+                  method, std::forward<decltype(args)>(args)...)))
         return DispatchResult::kFailed;
     }
     return DispatchResult::kOk;
@@ -148,7 +165,8 @@ class Dispatcher : public std::enable_shared_from_this<Dispatcher<Impl>> {
   template <typename ClientType, typename ReturnType, typename... Args>
   DispatchResult DispatchTask(ReturnType (ClientType::*method)(Args...) const,
                               compatible_arg_dispatch_t<Args>... args) const {
-    auto client = GetClient<ClientType>();
+    auto client =
+        GetClient<ClientType>(static_cast<const Impl*>(this)->clients_);
     if (!client)
       return DispatchResult::kFailed;
 
@@ -156,15 +174,22 @@ class Dispatcher : public std::enable_shared_from_this<Dispatcher<Impl>> {
     LOG_ASSERT(client_task_runner)
         << "A task runner for ClientType* is not set.";
 
-    if constexpr (!std::is_pointer<decltype(client)>::value) {
-      // If it's not pointer, it's shared_ptr
+    if constexpr (is_shared_ptr<decltype(client)>::value) {
       if (!client_task_runner->PostTask(
               FROM_HERE,
               base::BindOnce(
                   ExecuteConstOnSharedPtr<ClientType, ReturnType, Args...>,
                   method, client, std::forward<decltype(args)>(args)...)))
         return DispatchResult::kFailed;
+    } else if constexpr (is_base_weak_ptr<decltype(client)>::value) {
+      if (!client_task_runner->PostTask(
+              FROM_HERE,
+              base::BindOnce(
+                  ExecuteConstOnWeakPtr<ClientType, ReturnType, Args...>,
+                  method, client, std::forward<decltype(args)>(args)...)))
+        return DispatchResult::kFailed;
     } else {
+      // It's a raw pointer.
       if (!client_task_runner->PostTask(
               FROM_HERE,
               base::BindOnce(
@@ -206,11 +231,17 @@ class Dispatcher : public std::enable_shared_from_this<Dispatcher<Impl>> {
     LOG_ASSERT(client_task_runner->BelongsToCurrentThread())
         << "Running method from other thread without dispatching!";
 
-    auto client = GetClient<ClientType>();
+    auto client =
+        GetClient<ClientType>(static_cast<const Impl*>(this)->clients_);
     LOG_ASSERT(client) << "Client is empty. Should never happen...";
 
-    return ExecuteOnSharedPtr<ClientType, ReturnType, Args...>(
-        method, client, std::forward<decltype(args)>(args)...);
+    if constexpr (is_shared_ptr<decltype(client)>::value) {
+      return ExecuteOnSharedPtr<ClientType, ReturnType, Args...>(
+          method, client, std::forward<decltype(args)>(args)...);
+    } else {
+      return ExecuteOnWeakPtr<ClientType, ReturnType, Args...>(
+          method, client, std::forward<decltype(args)>(args)...);
+    }
   }
 
   template <typename ClientType, typename ReturnType, typename... Args>
@@ -222,11 +253,17 @@ class Dispatcher : public std::enable_shared_from_this<Dispatcher<Impl>> {
     LOG_ASSERT(client_task_runner->BelongsToCurrentThread())
         << "Running method from other thread without dispatching!";
 
-    auto client = GetClient<ClientType>();
+    auto client =
+        GetClient<ClientType>(static_cast<const Impl*>(this)->clients_);
     LOG_ASSERT(client) << "Client is empty. Should never happen...";
 
-    return ExecuteConstOnSharedPtr<ClientType, ReturnType, Args...>(
-        method, client, std::forward<decltype(args)>(args)...);
+    if constexpr (is_shared_ptr<decltype(client)>::value) {
+      return ExecuteConstOnSharedPtr<ClientType, ReturnType, Args...>(
+          method, client, std::forward<decltype(args)>(args)...);
+    } else {
+      return ExecuteConstOnWeakPtr<ClientType, ReturnType, Args...>(
+          method, client, std::forward<decltype(args)>(args)...);
+    }
   }
 
   scoped_refptr<base::SingleThreadTaskRunner> GetControlThreadTaskRunner()
@@ -248,6 +285,15 @@ class Dispatcher : public std::enable_shared_from_this<Dispatcher<Impl>> {
     client = std::move(ptr);
   }
 
+  template <typename ClientType>
+  void SetClient(const base::WeakPtr<ClientType>& weak_ptr) {
+    auto& client =
+        std::get<base::WeakPtr<ClientType>>(static_cast<Impl*>(this)->clients_);
+    LOG_ASSERT(!client) << "Overriding existing client!";
+
+    client = std::move(weak_ptr);
+  }
+
   // Client may not be owned by dispatcher and held by raw pointer. Following
   // restrictions apply:
   // * Client must outlive dispatcher, or dispatcher must be unset before client
@@ -287,9 +333,38 @@ class Dispatcher : public std::enable_shared_from_this<Dispatcher<Impl>> {
     return (client.get()->*method)(std::forward<Args>(args)...);
   }
 
+  template <typename ClientType, typename ReturnType, typename... Args>
+  static ReturnType ExecuteOnWeakPtr(ReturnType (ClientType::*method)(Args...),
+                                     base::WeakPtr<ClientType> client,
+                                     Args... args) {
+    if (!client) {
+      if constexpr (std::is_void<ReturnType>::value) {
+        return;
+      } else {
+        return {};
+      }
+    }
+    return (client.get()->*method)(std::forward<Args>(args)...);
+  }
+
+  template <typename ClientType, typename ReturnType, typename... Args>
+  static ReturnType ExecuteConstOnWeakPtr(
+      ReturnType (ClientType::*method)(Args...) const,
+      base::WeakPtr<ClientType> client,
+      Args... args) {
+    if (!client) {
+      if constexpr (std::is_void<ReturnType>::value) {
+        return;
+      } else {
+        return {};
+      }
+    }
+    return (client.get()->*method)(std::forward<Args>(args)...);
+  }
+
   template <typename ClientType, typename ReturnType, typename... Args>
   static ReturnType ExecuteOnRawPtr(
-      std::weak_ptr<const Dispatcher<Impl>> weak_dispatcher,
+      std::weak_ptr<Dispatcher<Impl>> weak_dispatcher,
       ReturnType (ClientType::*method)(Args...),
       Args... args) {
     auto dispatcher = weak_dispatcher.lock();
@@ -301,7 +376,8 @@ class Dispatcher : public std::enable_shared_from_this<Dispatcher<Impl>> {
       }
     }
 
-    auto* client = dispatcher->template GetClient<ClientType>();
+    auto* client =
+        GetClient<ClientType>(static_cast<Impl*>(dispatcher.get())->clients_);
     if (!client) {
       if constexpr (std::is_void<ReturnType>::value) {
         return;
@@ -315,27 +391,63 @@ class Dispatcher : public std::enable_shared_from_this<Dispatcher<Impl>> {
 
   template <typename ClientType, typename ReturnType, typename... Args>
   static ReturnType ExecuteConstOnRawPtr(
-      std::weak_ptr<Dispatcher> weak_dispatcher,
+      std::weak_ptr<const Dispatcher> weak_dispatcher,
       ReturnType (ClientType::*method)(Args...) const,
       Args... args) {
     auto dispatcher = weak_dispatcher.lock();
     if (!dispatcher)
       return ReturnType{};
 
-    auto* client = dispatcher->template GetClient<ClientType>();
+    auto* client = GetClient<ClientType>(
+        static_cast<const Impl*>(dispatcher.get())->clients_);
     if (!client)
       return ReturnType{};
 
     return (client->*method)(std::forward<Args>(args)...);
   }
 
-  template <typename ClientType>
-  typename ::elementary_media_stream_source::ClientTraits<
-      ClientType>::PointerType
-  GetClient() const {
-    using PointerT = typename ::elementary_media_stream_source::ClientTraits<
-        ClientType>::PointerType;
-    return std::get<PointerT>(static_cast<const Impl*>(this)->clients_);
+  template <typename ClientType, typename ClientsTupleT>
+  typename std::enable_if_t<
+      is_type_in_tuple<std::shared_ptr<ClientType>, ClientsTupleT>::value,
+      std::shared_ptr<ClientType>&> static GetClient(ClientsTupleT& clients) {
+    return std::get<std::shared_ptr<ClientType>>(clients);
+  }
+
+  template <typename ClientType, typename ClientsTupleT>
+  typename std::enable_if_t<
+      is_type_in_tuple<std::shared_ptr<ClientType>, ClientsTupleT>::value,
+      const std::shared_ptr<ClientType>&> static GetClient(const ClientsTupleT&
+                                                               clients) {
+    return std::get<std::shared_ptr<ClientType>>(clients);
+  }
+
+  template <typename ClientType, typename ClientsTupleT>
+  typename std::enable_if_t<
+      is_type_in_tuple<base::WeakPtr<ClientType>, ClientsTupleT>::value,
+      base::WeakPtr<ClientType>&> static GetClient(ClientsTupleT& clients) {
+    return std::get<base::WeakPtr<ClientType>>(clients);
+  }
+
+  template <typename ClientType, typename ClientsTupleT>
+  typename std::enable_if_t<
+      is_type_in_tuple<base::WeakPtr<ClientType>, ClientsTupleT>::value,
+      const base::WeakPtr<ClientType>&> static GetClient(const ClientsTupleT&
+                                                             clients) {
+    return std::get<base::WeakPtr<ClientType>>(clients);
+  }
+
+  template <typename ClientType, typename ClientsTupleT>
+  typename std::enable_if_t<is_type_in_tuple<ClientType*, ClientsTupleT>::value,
+                            ClientType*> static GetClient(ClientsTupleT&
+                                                              clients) {
+    return std::get<ClientType*>(clients);
+  }
+
+  template <typename ClientType, typename ClientsTupleT>
+  typename std::enable_if_t<
+      is_type_in_tuple<ClientType*, ClientsTupleT>::value,
+      const ClientType*> static GetClient(const ClientsTupleT& clients) {
+    return std::get<ClientType*>(clients);
   }
 
   template <typename ClientType>