summaryrefslogtreecommitdiffstats
path: root/chromium/content/browser/video_capture_service.cc
blob: c408d3b11a8580ef5b49afef0040004ca397cebb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
// Copyright 2019 The Chromium Authors. 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/public/browser/video_capture_service.h"

#include "base/no_destructor.h"
#include "base/task/thread_pool.h"
#include "base/threading/sequence_local_storage_slot.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "content/browser/service_sandbox_type.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/service_process_host.h"
#include "content/public/common/child_process_host.h"
#include "content/public/common/content_features.h"
#include "content/public/common/content_switches.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
#include "services/video_capture/public/uma/video_capture_service_event.h"
#include "services/video_capture/video_capture_service_impl.h"

#if defined(OS_WIN)
#define CREATE_IN_PROCESS_TASK_RUNNER base::ThreadPool::CreateCOMSTATaskRunner
#else
#define CREATE_IN_PROCESS_TASK_RUNNER \
  base::ThreadPool::CreateSingleThreadTaskRunner
#endif

namespace content {

namespace {

video_capture::mojom::VideoCaptureService* g_service_override = nullptr;

void BindInProcessInstance(
    mojo::PendingReceiver<video_capture::mojom::VideoCaptureService> receiver) {
  static base::NoDestructor<video_capture::VideoCaptureServiceImpl> service(
      std::move(receiver), GetUIThreadTaskRunner({}));
}

mojo::Remote<video_capture::mojom::VideoCaptureService>& GetUIThreadRemote() {
  // NOTE: This use of sequence-local storage is only to ensure that the Remote
  // only lives as long as the UI-thread sequence, since the UI-thread sequence
  // may be torn down and reinitialized e.g. between unit tests.
  static base::NoDestructor<base::SequenceLocalStorageSlot<
      mojo::Remote<video_capture::mojom::VideoCaptureService>>>
      remote_slot;
  return remote_slot->GetOrCreateValue();
}

// This is a custom traits type we use in conjunction with mojo::ReceiverSetBase
// so that all dispatched messages can be forwarded to the currently bound UI
// thread Remote.
struct ForwardingImplRefTraits {
  using PointerType = void*;
  static bool IsNull(PointerType) { return false; }
  static video_capture::mojom::VideoCaptureService* GetRawPointer(PointerType) {
    return &GetVideoCaptureService();
  }
};

// If |GetVideoCaptureService()| is called from off the UI thread, return a
// sequence-local Remote. Its corresponding receiver will be bound in this set,
// forwarding to the current UI-thread Remote.
void BindProxyRemoteOnUIThread(
    mojo::PendingReceiver<video_capture::mojom::VideoCaptureService> receiver) {
  static base::NoDestructor<mojo::ReceiverSetBase<
      mojo::Receiver<video_capture::mojom::VideoCaptureService,
                     ForwardingImplRefTraits>,
      void>>
      receivers;
  receivers->Add(nullptr, std::move(receiver));
}

}  // namespace

video_capture::mojom::VideoCaptureService& GetVideoCaptureService() {
  if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
    static base::NoDestructor<base::SequenceLocalStorageSlot<
        mojo::Remote<video_capture::mojom::VideoCaptureService>>>
        storage;
    auto& remote = storage->GetOrCreateValue();
    if (!remote.is_bound()) {
      GetUIThreadTaskRunner({})->PostTask(
          FROM_HERE, base::BindOnce(&BindProxyRemoteOnUIThread,
                                    remote.BindNewPipeAndPassReceiver()));
    }
    return *remote.get();
  }

  if (g_service_override)
    return *g_service_override;

  auto& remote = GetUIThreadRemote();
  if (!remote.is_bound()) {
    auto receiver = remote.BindNewPipeAndPassReceiver();
    if (features::IsVideoCaptureServiceEnabledForBrowserProcess()) {
      auto dedicated_task_runner = CREATE_IN_PROCESS_TASK_RUNNER(
          {base::MayBlock(), base::WithBaseSyncPrimitives(),
           base::TaskPriority::BEST_EFFORT},
          base::SingleThreadTaskRunnerThreadMode::DEDICATED);
      dedicated_task_runner->PostTask(
          FROM_HERE,
          base::BindOnce(&BindInProcessInstance, std::move(receiver)));
    } else {
      ServiceProcessHost::Launch(
          std::move(receiver),
          ServiceProcessHost::Options()
              .WithDisplayName("Video Capture")
#if defined(OS_MAC)
              // On Mac, the service requires a CFRunLoop which is provided by a
              // UI message loop. See https://crbug.com/834581.
              .WithExtraCommandLineSwitches({switches::kMessageLoopTypeUi})
              // On Mac, the service also needs to have a different set of
              // entitlements, the reason being that some virtual cameras
              // are not signed or are signed by a different Team ID. Hence,
              // library validation has to be disabled (see
              // http://crbug.com/990381#c21).
              .WithChildFlags(ChildProcessHost::CHILD_PLUGIN)
#endif
              .Pass());

#if !defined(OS_ANDROID)
      // On Android, we do not use automatic service shutdown, because when
      // shutting down the service, we lose caching of the supported formats,
      // and re-querying these can take several seconds on certain Android
      // devices.
      remote.set_idle_handler(
          base::TimeDelta::FromSeconds(5),
          base::BindRepeating(
              [](mojo::Remote<video_capture::mojom::VideoCaptureService>*
                     remote) {
                video_capture::uma::LogVideoCaptureServiceEvent(
                    video_capture::uma ::
                        SERVICE_SHUTTING_DOWN_BECAUSE_NO_CLIENT);
                remote->reset();
              },
              &remote));
#endif  // !defined(OS_ANDROID)

      // Make sure the Remote is also reset in case of e.g. service crash so we
      // can restart it as needed.
      remote.reset_on_disconnect();
    }
  }

  return *remote.get();
}

void OverrideVideoCaptureServiceForTesting(
    video_capture::mojom::VideoCaptureService* service) {
  g_service_override = service;
}

}  // namespace content