capture_mode_camera_controller.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. // Copyright 2022 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef ASH_CAPTURE_MODE_CAPTURE_MODE_CAMERA_CONTROLLER_H_
  5. #define ASH_CAPTURE_MODE_CAPTURE_MODE_CAMERA_CONTROLLER_H_
  6. #include <string>
  7. #include <vector>
  8. #include "ash/ash_export.h"
  9. #include "ash/capture_mode/capture_mode_types.h"
  10. #include "ash/public/cpp/system_tray_observer.h"
  11. #include "base/callback_forward.h"
  12. #include "base/memory/weak_ptr.h"
  13. #include "base/observer_list.h"
  14. #include "base/observer_list_types.h"
  15. #include "base/system/system_monitor.h"
  16. #include "base/timer/timer.h"
  17. #include "media/base/video_facing.h"
  18. #include "media/capture/video/video_capture_device_info.h"
  19. #include "media/capture/video_capture_types.h"
  20. #include "mojo/public/cpp/bindings/remote.h"
  21. #include "services/video_capture/public/mojom/video_source_provider.mojom.h"
  22. #include "ui/views/widget/unique_widget_ptr.h"
  23. namespace gfx {
  24. class Rect;
  25. } // namespace gfx
  26. namespace ash {
  27. class CameraPreviewView;
  28. class CaptureModeDelegate;
  29. // The ID used internally in capture mode to identify the camera.
  30. class ASH_EXPORT CameraId {
  31. public:
  32. CameraId() = default;
  33. CameraId(std::string model_id, int number);
  34. CameraId(const CameraId&) = default;
  35. CameraId(CameraId&&) = default;
  36. CameraId& operator=(const CameraId&) = default;
  37. CameraId& operator=(CameraId&&) = default;
  38. ~CameraId() = default;
  39. bool is_valid() const { return !model_id_or_display_name_.empty(); }
  40. const std::string& model_id_or_display_name() const {
  41. return model_id_or_display_name_;
  42. }
  43. int number() const { return number_; }
  44. bool operator==(const CameraId& rhs) const {
  45. return model_id_or_display_name_ == rhs.model_id_or_display_name_ &&
  46. number_ == rhs.number_;
  47. }
  48. bool operator!=(const CameraId& rhs) const { return !(*this == rhs); }
  49. bool operator<(const CameraId& rhs) const;
  50. std::string ToString() const;
  51. private:
  52. // A unique hardware ID of the camera device in the form of
  53. // "[Vendor ID]:[Product ID]" (e.g. "0c45:6713"). Note that if multiple
  54. // cameras from the same vendor and of the same model are connected to the
  55. // device, they will all have the same `model_id`.
  56. // Note that in some cases, `media::VideoCaptureDeviceDescriptor::model_id`
  57. // may not be present. In this case, this will be filled by the camera's
  58. // display name.
  59. std::string model_id_or_display_name_;
  60. // A number that disambiguates cameras of the same type. For example if we
  61. // have two connected cameras of the same type, the first one will have
  62. // `number` set to 1, and the second's will be 2.
  63. int number_ = 0;
  64. };
  65. struct CameraInfo {
  66. CameraInfo(CameraId camera_id,
  67. std::string device_id,
  68. std::string display_name,
  69. const media::VideoCaptureFormats& supported_formats,
  70. media::VideoFacingMode camera_facing_mode);
  71. CameraInfo(CameraInfo&&);
  72. CameraInfo& operator=(CameraInfo&&);
  73. ~CameraInfo();
  74. // The ID used to identify the camera device internally to the capture mode
  75. // code, which should be more stable than the below `device_id` which may
  76. // change multiple times for the same camera.
  77. CameraId camera_id;
  78. // The ID of the camera device given to it by the system in its current
  79. // connection instance (e.g. "/dev/video2"). Note that the same camera device
  80. // can disconnect and reconnect with a different `device_id` (e.g. when the
  81. // cable is flaky). This ID is used to identify the camera to the video source
  82. // provider in the video capture service.
  83. std::string device_id;
  84. // The name of the camera device as shown to the end user (e.g. "Integrated
  85. // Webcam").
  86. std::string display_name;
  87. // A list of supported capture formats by this camera. This list is sorted
  88. // (See `media::VideoCaptureSystemImpl::DevicesInfoReady()`) by the frame size
  89. // area, then by frame width, then by the *largest* frame rate.
  90. media::VideoCaptureFormats supported_formats;
  91. // Whether the camera is facing the user (e.g. for internal front cameras), or
  92. // the environment (e.g. internal rear cameras), or unknown (e.g. usually for
  93. // external USB cameras).
  94. media::VideoFacingMode camera_facing_mode;
  95. };
  96. using CameraInfoList = std::vector<CameraInfo>;
  97. // Controls detecting camera devices additions and removals and keeping a list
  98. // of all currently connected cameras to the device. It also tracks all the
  99. // capture mode selfie camera settings.
  100. class ASH_EXPORT CaptureModeCameraController
  101. : public base::SystemMonitor::DevicesChangedObserver,
  102. public SystemTrayObserver {
  103. public:
  104. class Observer : public base::CheckedObserver {
  105. public:
  106. // Called to notify the observer that the list of `available_cameras_` has
  107. // changed, and provides that list as `cameras`.
  108. virtual void OnAvailableCamerasChanged(const CameraInfoList& cameras) = 0;
  109. // Called to notify the observer that a camera with `camera_id` was selected
  110. // and will be used to show a camera preview when possible.
  111. // Note that when `camera_id.is_valid()` is false, it means no camera is
  112. // currently selected.
  113. virtual void OnSelectedCameraChanged(const CameraId& camera_id) = 0;
  114. protected:
  115. ~Observer() override = default;
  116. };
  117. explicit CaptureModeCameraController(CaptureModeDelegate* delegate);
  118. CaptureModeCameraController(const CaptureModeCameraController&) = delete;
  119. CaptureModeCameraController& operator=(const CaptureModeCameraController&) =
  120. delete;
  121. ~CaptureModeCameraController() override;
  122. const CameraInfoList& available_cameras() const { return available_cameras_; }
  123. const CameraId& selected_camera() const { return selected_camera_; }
  124. views::Widget* camera_preview_widget() const {
  125. return camera_preview_widget_.get();
  126. }
  127. CameraPreviewView* camera_preview_view() const {
  128. return camera_preview_view_;
  129. }
  130. bool should_show_preview() const { return should_show_preview_; }
  131. CameraPreviewSnapPosition camera_preview_snap_position() const {
  132. return camera_preview_snap_position_;
  133. }
  134. bool is_drag_in_progress() const { return is_drag_in_progress_; }
  135. bool is_camera_preview_collapsed() const {
  136. return is_camera_preview_collapsed_;
  137. }
  138. void AddObserver(Observer* observer);
  139. void RemoveObserver(Observer* observer);
  140. // Selects the first camera in the `available_cameras_` list (if any), and
  141. // only if no other camera is already selected.
  142. void MaybeSelectFirstCamera();
  143. // Returns true if camera support is disabled by admins via
  144. // the `SystemFeaturesDisableList` policy, false otherwise.
  145. bool IsCameraDisabledByPolicy() const;
  146. // Returns the display name of `selected_camera_`. Returns an empty string if
  147. // the selected camera is not set.
  148. std::string GetDisplayNameOfSelectedCamera() const;
  149. // Sets the currently selected camera to the whose ID is the given
  150. // `camera_id`. If `camera_id` is invalid (see CameraId::is_valid()), this
  151. // clears the selected camera.
  152. void SetSelectedCamera(CameraId camera_id);
  153. // Sets `should_show_preview_` to the given `value`, and refreshes the state
  154. // of the camera preview.
  155. void SetShouldShowPreview(bool value);
  156. // Updates the parent of the `camera_preview_widget_` when necessary. E.g,
  157. // capture source type changes, selected recording window changes etc.
  158. void MaybeReparentPreviewWidget();
  159. // Sets `camera_preview_snap_position_` and updates the preview widget's
  160. // bounds accordingly. If `animate` is set to true, the camera preview will
  161. // animate to its new snap position.
  162. void SetCameraPreviewSnapPosition(CameraPreviewSnapPosition value,
  163. bool animate = false);
  164. // Updates the bounds and visibility of `camera_preview_widget_` according to
  165. // the current state of the capture surface within which the camera preview
  166. // is confined and snapped to one of its corners. If `animate` is set to true,
  167. // the widget will animate to the new target bounds.
  168. void MaybeUpdatePreviewWidget(bool animate = false);
  169. // Handles drag events forwarded from `camera_preview_view_`.
  170. void StartDraggingPreview(const gfx::PointF& screen_location);
  171. void ContinueDraggingPreview(const gfx::PointF& screen_location);
  172. void EndDraggingPreview(const gfx::PointF& screen_location, bool is_touch);
  173. // Updates the bounds of the preview widget and the value of
  174. // `is_camera_preview_collapsed_` when the resize button is pressed.
  175. void ToggleCameraPreviewSize();
  176. // Called when a capture session gets started so we can refresh the cameras
  177. // list, since the cros-camera service might have not been running when we
  178. // tried to refresh the cameras at the beginning. (See
  179. // http://b/230917107#comment12 for more details).
  180. void OnCaptureSessionStarted();
  181. void OnRecordingStarted(bool is_in_projector_mode);
  182. void OnRecordingEnded();
  183. // Called when the `CameraVideoFrameHandler` of the current
  184. // `camera_preview_widget_` encounters a fatal error. This is considered a
  185. // camera disconnection, and sometimes doesn't get reported via
  186. // `OnDevicesChanged()` below, or may get delayed a lot. We manually remove
  187. // the current camera from `available_cameras_`, delete its preview, and
  188. // request a new list of cameras from the video capture service.
  189. // https://crbug/1316230.
  190. void OnFrameHandlerFatalError();
  191. // Called when the device is shutting down. After this call, we don't do any
  192. // operations that interacts with the video capture service.
  193. void OnShuttingDown();
  194. // As `camera_preview_view_` is a
  195. // CaptureModeSessionFocusCycler::HighlightableView. This will show the focus
  196. // ring and trigger setting a11y focus on the camera preview. Note, this is
  197. // only for focusing the preview while recording is in progress.
  198. void PseudoFocusCameraPreview();
  199. void OnActiveUserSessionChanged();
  200. // base::SystemMonitor::DevicesChangedObserver:
  201. void OnDevicesChanged(base::SystemMonitor::DeviceType device_type) override;
  202. // SystemTrayObserver:
  203. void OnSystemTrayBubbleShown() override;
  204. void OnFocusLeavingSystemTray(bool reverse) override {}
  205. void SetOnCameraListReceivedForTesting(base::OnceClosure callback) {
  206. on_camera_list_received_for_test_ = std::move(callback);
  207. }
  208. base::OneShotTimer* camera_reconnect_timer_for_test() {
  209. return &camera_reconnect_timer_;
  210. }
  211. private:
  212. friend class CaptureModeTestApi;
  213. // Called to connect to the video capture services's video source provider for
  214. // the first time, or when the connection to it is lost. It also queries the
  215. // list of currently available cameras by calling the below
  216. // GetCameraDevices().
  217. void ReconnectToVideoSourceProvider();
  218. // Retrieves the list of currently available cameras from the video source
  219. // provider.
  220. void GetCameraDevices();
  221. // Called back asynchronously by the video source provider to give us the list
  222. // of currently available camera `devices`. The ID used to make the request to
  223. // which this reply belongs is `request_id`. We will ignore any replies for
  224. // any older requests than the `most_recent_request_id_`.
  225. using RequestId = size_t;
  226. void OnCameraDevicesReceived(
  227. RequestId request_id,
  228. const std::vector<media::VideoCaptureDeviceInfo>& devices);
  229. // Shows or hides a preview of the currently selected camera depending on
  230. // whether it's currently allowed and whether one is currently selected.
  231. void RefreshCameraPreview();
  232. // Triggered when the `camera_reconnect_timer_` fires, indicating that a
  233. // previously `selected_camera_` remained disconnected for longer than the
  234. // allowed grace period, and therefore it will be cleared.
  235. void OnSelectedCameraDisconnected();
  236. // Returns the bounds of the preview widget which doesn't intersect with
  237. // system tray, which should be confined within the given `confine_bounds`,
  238. // and have the given `preview_size`. Always tries the current
  239. // `camera_preview_snap_position_` first. Once a snap position with which the
  240. // preview has no collisions is found, it will be set in
  241. // `camera_preview_snap_position_`. If the camera preview at all possible snap
  242. // positions intersects with system tray, returns the bounds for the current
  243. // `camera_preview_snap_position_`.
  244. gfx::Rect CalculatePreviewWidgetTargetBounds(const gfx::Rect& confine_bounds,
  245. const gfx::Size& preview_size);
  246. // Called by `CalculatePreviewWidgetTargetBounds` above. Returns the bounds of
  247. // the preview widget that matches the coordinate system of the given
  248. // `confine_bounds` with the given `preview_size` at the given
  249. // `snap_position`.
  250. gfx::Rect GetPreviewWidgetBoundsForSnapPosition(
  251. const gfx::Rect& confine_bounds,
  252. const gfx::Size& preview_size,
  253. CameraPreviewSnapPosition snap_position) const;
  254. // Returns the new snap position of the camera preview on drag ended.
  255. CameraPreviewSnapPosition CalculateSnapPositionOnDragEnded() const;
  256. // Returns the current bounds of camemra preview widget that match the
  257. // coordinate system of the confine bounds.
  258. gfx::Rect GetCurrentBoundsMatchingConfineBoundsCoordinates() const;
  259. // Does post works for camera preview after RefreshCameraPreview(). It
  260. // triggers a11y alert based on `was_preview_visible_before` and the current
  261. // visibility of `camera_preview_widget_`. `was_preview_visible_before` is the
  262. // visibility of the camera preview when RefreshCameraPreview() was called.
  263. // It also triggers floating windows bounds update to avoid overlap between
  264. // camera preview and floating windows, such as PIP windows and some a11y
  265. // panels.
  266. void RunPostRefreshCameraPreview(bool was_preview_visible_before);
  267. // Sets the given `target_bounds` on the camera preview widget, potentially
  268. // animating to it if `animate` is true. Returns true if the bounds actually
  269. // changed from the current.
  270. bool SetCameraPreviewBounds(const gfx::Rect& target_bounds, bool animate);
  271. // Owned by CaptureModeController and guaranteed to be not null and to outlive
  272. // `this`.
  273. CaptureModeDelegate* const delegate_;
  274. // The remote end to the video source provider that exists in the video
  275. // capture service.
  276. mojo::Remote<video_capture::mojom::VideoSourceProvider>
  277. video_source_provider_remote_;
  278. CameraInfoList available_cameras_;
  279. // The currently selected camera. If its `is_valid()` is false, then no camera
  280. // is currently selected.
  281. CameraId selected_camera_;
  282. base::ObserverList<Observer> observers_;
  283. // If bound, will be invoked at the end of the scope of
  284. // `OnCameraDevicesReceived()` regardless of whether there was a change in the
  285. // available cameras or not, which is different from the behavior of
  286. // `Observer::OnAvailableCamerasChanged()` which is called only when there is
  287. // a change.
  288. base::OnceClosure on_camera_list_received_for_test_;
  289. // The camera preview widget and its contents view.
  290. views::UniqueWidgetPtr camera_preview_widget_;
  291. CameraPreviewView* camera_preview_view_ = nullptr;
  292. // A timer used to give a `selected_camera_` that got disconnected a grace
  293. // period, so if it reconnects again within this period, its ID is kept around
  294. // in `selected_camera_`, otherwise the ID is cleared, effectively resetting
  295. // back the camera setting to "Off".
  296. base::OneShotTimer camera_reconnect_timer_;
  297. // Set to true when a preview of the currently selected camera (if any) should
  298. // be shown. This happens when CaptureModeSession is started and switched to
  299. // a video recording mode before recording starts. It is reset back to false
  300. // when:
  301. // - Video recording ends.
  302. // - The selected camera is disconnected for longer than a grace period during
  303. // recording.
  304. // - The capture mode session ends without starting any recording.
  305. // - The capture mode session is switched to an image capture mode.
  306. bool should_show_preview_ = false;
  307. // The ID used for the most recent request made to the video source provider
  308. // to get the list of cameras in GetCameraDevices(). More recent requests will
  309. // have a larger value IDs than older requests.
  310. RequestId most_recent_request_id_ = 0;
  311. CameraPreviewSnapPosition camera_preview_snap_position_ =
  312. CameraPreviewSnapPosition::kBottomRight;
  313. // The location of the previous drag event in screen coordinate.
  314. gfx::PointF previous_location_in_screen_;
  315. // True when the dragging for `camera_preview_view_` is in progress.
  316. bool is_drag_in_progress_ = false;
  317. // True if the camera preview is collapsed. Its value will be updated when
  318. // the resize button is clicked. The size of the preview widget and the icon
  319. // of the resize button will be updated based on it.
  320. bool is_camera_preview_collapsed_ = false;
  321. // True if it's the first time to update the camera preview's bounds after
  322. // it's created.
  323. bool is_first_bounds_update_ = false;
  324. // True when the device is shutting down, and we should no longer make any
  325. // requests to the video capture service.
  326. bool is_shutting_down_ = false;
  327. // Valid only during recording to track the number of camera disconnections
  328. // while recording is in progress.
  329. absl::optional<int> in_recording_camera_disconnections_;
  330. // Will be set to true the first time the number of connected cameras is
  331. // reported.
  332. bool did_report_number_of_cameras_before_ = false;
  333. // Will be set to true the first user logs in. And we should only request the
  334. // camera devices after the first user logs in.
  335. bool did_first_user_login_ = false;
  336. base::WeakPtrFactory<CaptureModeCameraController> weak_ptr_factory_{this};
  337. };
  338. } // namespace ash
  339. #endif // ASH_CAPTURE_MODE_CAPTURE_MODE_CAMERA_CONTROLLER_H_