chromium/content/browser/media/capture/video_capture_device_proxy_lacros.h

// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CONTENT_BROWSER_MEDIA_CAPTURE_VIDEO_CAPTURE_DEVICE_PROXY_LACROS_H_
#define CONTENT_BROWSER_MEDIA_CAPTURE_VIDEO_CAPTURE_DEVICE_PROXY_LACROS_H_

#include <memory>
#include <optional>
#include <string>

#include "base/functional/callback_forward.h"
#include "base/memory/weak_ptr.h"
#include "chromeos/crosapi/mojom/screen_manager.mojom.h"
#include "chromeos/crosapi/mojom/video_capture.mojom.h"
#include "content/browser/media/capture/receiver_media_to_crosapi_adapter.h"
#include "content/common/content_export.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/desktop_media_id.h"
#include "content/public/browser/device_service.h"
#include "media/capture/mojom/video_capture_types.mojom.h"
#include "media/capture/video/video_capture_device.h"
#include "media/capture/video/video_frame_receiver.h"
#include "media/capture/video_capture_types.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/device/public/mojom/wake_lock.mojom.h"
#include "services/video_capture/lacros/video_frame_handler_proxy_lacros.h"
#include "services/viz/public/cpp/compositing/video_capture_target_mojom_traits.h"

namespace content {

// Given that lacros-chrome runs on ChromeOS, there are type optimizations that
// we can take advantage of above and beyond a typical webrtc::DesktopCapturer.
//
// This requires implementing the VideoCaptureDevice interface instead of the
// webrtc::DesktopCapturer interface. However, lacros-chrome, as a user-side
// process, doesn't actually have permissions to capture the desktop or windows
// itself. Thus, this class is responsible for acting as the lacros-chrome side
// capturer for the purposes of the video capture stack by proxying the calls
// across the crosapi boundary to the *actual* capturer running in the system-
// side ash-chrome process.
//
// Note that objects of this class are thread-affine (e.g. once created it must
// be used on the same thread).
class CONTENT_EXPORT VideoCaptureDeviceProxyLacros
    : public media::VideoCaptureDevice {
 public:
  explicit VideoCaptureDeviceProxyLacros(const DesktopMediaID& device_id);

  VideoCaptureDeviceProxyLacros(const VideoCaptureDeviceProxyLacros&) = delete;
  VideoCaptureDeviceProxyLacros& operator=(
      const VideoCaptureDeviceProxyLacros&) = delete;

  ~VideoCaptureDeviceProxyLacros() override;

  // Deviation from the VideoCaptureDevice interface: Since the memory pooling
  // provided by a VideoCaptureDevice::Client is not needed, we will provide
  // frames to a VideoFrameReceiver directly.
  void AllocateAndStartWithReceiver(
      const media::VideoCaptureParams& params,
      std::unique_ptr<media::VideoFrameReceiver> receiver);

  // Remaining VideoCaptureDevice implementation.
  void AllocateAndStart(const media::VideoCaptureParams& params,
                        std::unique_ptr<Client> client) final;
  void RequestRefreshFrame() final;
  void MaybeSuspend() final;
  void Resume() final;
  void ApplySubCaptureTarget(
      media::mojom::SubCaptureTargetType type,
      const base::Token& target,
      uint32_t sub_capture_target_version,
      base::OnceCallback<void(media::mojom::ApplySubCaptureTargetResult)>
          callback) override;
  void StopAndDeAllocate() final;
  void GetPhotoState(GetPhotoStateCallback callback) final;
  void SetPhotoOptions(media::mojom::PhotoSettingsPtr settings,
                       SetPhotoOptionsCallback callback) final;
  void TakePhoto(TakePhotoCallback callback) final;
  void OnUtilizationReport(media::VideoCaptureFeedback feedback) final;

 private:
  // Helper that logs the given error |message| to the |receiver_adapater_| and
  // then stops capture and this VideoCaptureDevice.
  void OnFatalError(std::string message);

  // Helper that requests wake lock to prevent the display from sleeping while
  // capturing is going on.
  void RequestWakeLock();

  const DesktopMediaID capture_id_;

  // Receives video frames from ash, for translation and propagation into the
  // video capture stack. This is set by AllocateAndStartWithReceiver(), and
  // cleared by StopAndDeAllocate().
  std::unique_ptr<crosapi::mojom::VideoFrameHandler> receiver_adapter_;

  // Set when OnFatalError() is called. This prevents any future
  // AllocateAndStartWithReceiver() calls from succeeding.
  std::optional<std::string> fatal_error_message_;

  // Note that because we do not run on the main thread and because we want to
  // set a disconnect handler on the screen manager we must bind our own remote
  // rather than using |LacrosService::GetRemote|, which returns a shared remote
  // that is unsuitable for setting a disconnect handler on, and is also thread
  // affine to a different thread.
  mojo::Remote<crosapi::mojom::ScreenManager> screen_manager_;
  mojo::Remote<crosapi::mojom::VideoCaptureDevice> device_;

  SEQUENCE_CHECKER(sequence_checker_);

  // Prevent display sleeping while content capture is in progress.
  mojo::Remote<device::mojom::WakeLock> wake_lock_;

  // Creates WeakPtrs for use on the device thread.
  base::WeakPtrFactory<VideoCaptureDeviceProxyLacros> weak_factory_{this};
};

}  // namespace content

#endif  // CONTENT_BROWSER_MEDIA_CAPTURE_VIDEO_CAPTURE_DEVICE_PROXY_LACROS_H_