123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419 |
- // Copyright 2022 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.
- #ifndef ASH_CAPTURE_MODE_CAPTURE_MODE_CAMERA_CONTROLLER_H_
- #define ASH_CAPTURE_MODE_CAPTURE_MODE_CAMERA_CONTROLLER_H_
- #include <string>
- #include <vector>
- #include "ash/ash_export.h"
- #include "ash/capture_mode/capture_mode_types.h"
- #include "ash/public/cpp/system_tray_observer.h"
- #include "base/callback_forward.h"
- #include "base/memory/weak_ptr.h"
- #include "base/observer_list.h"
- #include "base/observer_list_types.h"
- #include "base/system/system_monitor.h"
- #include "base/timer/timer.h"
- #include "media/base/video_facing.h"
- #include "media/capture/video/video_capture_device_info.h"
- #include "media/capture/video_capture_types.h"
- #include "mojo/public/cpp/bindings/remote.h"
- #include "services/video_capture/public/mojom/video_source_provider.mojom.h"
- #include "ui/views/widget/unique_widget_ptr.h"
- namespace gfx {
- class Rect;
- } // namespace gfx
- namespace ash {
- class CameraPreviewView;
- class CaptureModeDelegate;
- // The ID used internally in capture mode to identify the camera.
- class ASH_EXPORT CameraId {
- public:
- CameraId() = default;
- CameraId(std::string model_id, int number);
- CameraId(const CameraId&) = default;
- CameraId(CameraId&&) = default;
- CameraId& operator=(const CameraId&) = default;
- CameraId& operator=(CameraId&&) = default;
- ~CameraId() = default;
- bool is_valid() const { return !model_id_or_display_name_.empty(); }
- const std::string& model_id_or_display_name() const {
- return model_id_or_display_name_;
- }
- int number() const { return number_; }
- bool operator==(const CameraId& rhs) const {
- return model_id_or_display_name_ == rhs.model_id_or_display_name_ &&
- number_ == rhs.number_;
- }
- bool operator!=(const CameraId& rhs) const { return !(*this == rhs); }
- bool operator<(const CameraId& rhs) const;
- std::string ToString() const;
- private:
- // A unique hardware ID of the camera device in the form of
- // "[Vendor ID]:[Product ID]" (e.g. "0c45:6713"). Note that if multiple
- // cameras from the same vendor and of the same model are connected to the
- // device, they will all have the same `model_id`.
- // Note that in some cases, `media::VideoCaptureDeviceDescriptor::model_id`
- // may not be present. In this case, this will be filled by the camera's
- // display name.
- std::string model_id_or_display_name_;
- // A number that disambiguates cameras of the same type. For example if we
- // have two connected cameras of the same type, the first one will have
- // `number` set to 1, and the second's will be 2.
- int number_ = 0;
- };
- struct CameraInfo {
- CameraInfo(CameraId camera_id,
- std::string device_id,
- std::string display_name,
- const media::VideoCaptureFormats& supported_formats,
- media::VideoFacingMode camera_facing_mode);
- CameraInfo(CameraInfo&&);
- CameraInfo& operator=(CameraInfo&&);
- ~CameraInfo();
- // The ID used to identify the camera device internally to the capture mode
- // code, which should be more stable than the below `device_id` which may
- // change multiple times for the same camera.
- CameraId camera_id;
- // The ID of the camera device given to it by the system in its current
- // connection instance (e.g. "/dev/video2"). Note that the same camera device
- // can disconnect and reconnect with a different `device_id` (e.g. when the
- // cable is flaky). This ID is used to identify the camera to the video source
- // provider in the video capture service.
- std::string device_id;
- // The name of the camera device as shown to the end user (e.g. "Integrated
- // Webcam").
- std::string display_name;
- // A list of supported capture formats by this camera. This list is sorted
- // (See `media::VideoCaptureSystemImpl::DevicesInfoReady()`) by the frame size
- // area, then by frame width, then by the *largest* frame rate.
- media::VideoCaptureFormats supported_formats;
- // Whether the camera is facing the user (e.g. for internal front cameras), or
- // the environment (e.g. internal rear cameras), or unknown (e.g. usually for
- // external USB cameras).
- media::VideoFacingMode camera_facing_mode;
- };
- using CameraInfoList = std::vector<CameraInfo>;
- // Controls detecting camera devices additions and removals and keeping a list
- // of all currently connected cameras to the device. It also tracks all the
- // capture mode selfie camera settings.
- class ASH_EXPORT CaptureModeCameraController
- : public base::SystemMonitor::DevicesChangedObserver,
- public SystemTrayObserver {
- public:
- class Observer : public base::CheckedObserver {
- public:
- // Called to notify the observer that the list of `available_cameras_` has
- // changed, and provides that list as `cameras`.
- virtual void OnAvailableCamerasChanged(const CameraInfoList& cameras) = 0;
- // Called to notify the observer that a camera with `camera_id` was selected
- // and will be used to show a camera preview when possible.
- // Note that when `camera_id.is_valid()` is false, it means no camera is
- // currently selected.
- virtual void OnSelectedCameraChanged(const CameraId& camera_id) = 0;
- protected:
- ~Observer() override = default;
- };
- explicit CaptureModeCameraController(CaptureModeDelegate* delegate);
- CaptureModeCameraController(const CaptureModeCameraController&) = delete;
- CaptureModeCameraController& operator=(const CaptureModeCameraController&) =
- delete;
- ~CaptureModeCameraController() override;
- const CameraInfoList& available_cameras() const { return available_cameras_; }
- const CameraId& selected_camera() const { return selected_camera_; }
- views::Widget* camera_preview_widget() const {
- return camera_preview_widget_.get();
- }
- CameraPreviewView* camera_preview_view() const {
- return camera_preview_view_;
- }
- bool should_show_preview() const { return should_show_preview_; }
- CameraPreviewSnapPosition camera_preview_snap_position() const {
- return camera_preview_snap_position_;
- }
- bool is_drag_in_progress() const { return is_drag_in_progress_; }
- bool is_camera_preview_collapsed() const {
- return is_camera_preview_collapsed_;
- }
- void AddObserver(Observer* observer);
- void RemoveObserver(Observer* observer);
- // Selects the first camera in the `available_cameras_` list (if any), and
- // only if no other camera is already selected.
- void MaybeSelectFirstCamera();
- // Returns true if camera support is disabled by admins via
- // the `SystemFeaturesDisableList` policy, false otherwise.
- bool IsCameraDisabledByPolicy() const;
- // Returns the display name of `selected_camera_`. Returns an empty string if
- // the selected camera is not set.
- std::string GetDisplayNameOfSelectedCamera() const;
- // Sets the currently selected camera to the whose ID is the given
- // `camera_id`. If `camera_id` is invalid (see CameraId::is_valid()), this
- // clears the selected camera.
- void SetSelectedCamera(CameraId camera_id);
- // Sets `should_show_preview_` to the given `value`, and refreshes the state
- // of the camera preview.
- void SetShouldShowPreview(bool value);
- // Updates the parent of the `camera_preview_widget_` when necessary. E.g,
- // capture source type changes, selected recording window changes etc.
- void MaybeReparentPreviewWidget();
- // Sets `camera_preview_snap_position_` and updates the preview widget's
- // bounds accordingly. If `animate` is set to true, the camera preview will
- // animate to its new snap position.
- void SetCameraPreviewSnapPosition(CameraPreviewSnapPosition value,
- bool animate = false);
- // Updates the bounds and visibility of `camera_preview_widget_` according to
- // the current state of the capture surface within which the camera preview
- // is confined and snapped to one of its corners. If `animate` is set to true,
- // the widget will animate to the new target bounds.
- void MaybeUpdatePreviewWidget(bool animate = false);
- // Handles drag events forwarded from `camera_preview_view_`.
- void StartDraggingPreview(const gfx::PointF& screen_location);
- void ContinueDraggingPreview(const gfx::PointF& screen_location);
- void EndDraggingPreview(const gfx::PointF& screen_location, bool is_touch);
- // Updates the bounds of the preview widget and the value of
- // `is_camera_preview_collapsed_` when the resize button is pressed.
- void ToggleCameraPreviewSize();
- // Called when a capture session gets started so we can refresh the cameras
- // list, since the cros-camera service might have not been running when we
- // tried to refresh the cameras at the beginning. (See
- // http://b/230917107#comment12 for more details).
- void OnCaptureSessionStarted();
- void OnRecordingStarted(bool is_in_projector_mode);
- void OnRecordingEnded();
- // Called when the `CameraVideoFrameHandler` of the current
- // `camera_preview_widget_` encounters a fatal error. This is considered a
- // camera disconnection, and sometimes doesn't get reported via
- // `OnDevicesChanged()` below, or may get delayed a lot. We manually remove
- // the current camera from `available_cameras_`, delete its preview, and
- // request a new list of cameras from the video capture service.
- // https://crbug/1316230.
- void OnFrameHandlerFatalError();
- // Called when the device is shutting down. After this call, we don't do any
- // operations that interacts with the video capture service.
- void OnShuttingDown();
- // As `camera_preview_view_` is a
- // CaptureModeSessionFocusCycler::HighlightableView. This will show the focus
- // ring and trigger setting a11y focus on the camera preview. Note, this is
- // only for focusing the preview while recording is in progress.
- void PseudoFocusCameraPreview();
- void OnActiveUserSessionChanged();
- // base::SystemMonitor::DevicesChangedObserver:
- void OnDevicesChanged(base::SystemMonitor::DeviceType device_type) override;
- // SystemTrayObserver:
- void OnSystemTrayBubbleShown() override;
- void OnFocusLeavingSystemTray(bool reverse) override {}
- void SetOnCameraListReceivedForTesting(base::OnceClosure callback) {
- on_camera_list_received_for_test_ = std::move(callback);
- }
- base::OneShotTimer* camera_reconnect_timer_for_test() {
- return &camera_reconnect_timer_;
- }
- private:
- friend class CaptureModeTestApi;
- // Called to connect to the video capture services's video source provider for
- // the first time, or when the connection to it is lost. It also queries the
- // list of currently available cameras by calling the below
- // GetCameraDevices().
- void ReconnectToVideoSourceProvider();
- // Retrieves the list of currently available cameras from the video source
- // provider.
- void GetCameraDevices();
- // Called back asynchronously by the video source provider to give us the list
- // of currently available camera `devices`. The ID used to make the request to
- // which this reply belongs is `request_id`. We will ignore any replies for
- // any older requests than the `most_recent_request_id_`.
- using RequestId = size_t;
- void OnCameraDevicesReceived(
- RequestId request_id,
- const std::vector<media::VideoCaptureDeviceInfo>& devices);
- // Shows or hides a preview of the currently selected camera depending on
- // whether it's currently allowed and whether one is currently selected.
- void RefreshCameraPreview();
- // Triggered when the `camera_reconnect_timer_` fires, indicating that a
- // previously `selected_camera_` remained disconnected for longer than the
- // allowed grace period, and therefore it will be cleared.
- void OnSelectedCameraDisconnected();
- // Returns the bounds of the preview widget which doesn't intersect with
- // system tray, which should be confined within the given `confine_bounds`,
- // and have the given `preview_size`. Always tries the current
- // `camera_preview_snap_position_` first. Once a snap position with which the
- // preview has no collisions is found, it will be set in
- // `camera_preview_snap_position_`. If the camera preview at all possible snap
- // positions intersects with system tray, returns the bounds for the current
- // `camera_preview_snap_position_`.
- gfx::Rect CalculatePreviewWidgetTargetBounds(const gfx::Rect& confine_bounds,
- const gfx::Size& preview_size);
- // Called by `CalculatePreviewWidgetTargetBounds` above. Returns the bounds of
- // the preview widget that matches the coordinate system of the given
- // `confine_bounds` with the given `preview_size` at the given
- // `snap_position`.
- gfx::Rect GetPreviewWidgetBoundsForSnapPosition(
- const gfx::Rect& confine_bounds,
- const gfx::Size& preview_size,
- CameraPreviewSnapPosition snap_position) const;
- // Returns the new snap position of the camera preview on drag ended.
- CameraPreviewSnapPosition CalculateSnapPositionOnDragEnded() const;
- // Returns the current bounds of camemra preview widget that match the
- // coordinate system of the confine bounds.
- gfx::Rect GetCurrentBoundsMatchingConfineBoundsCoordinates() const;
- // Does post works for camera preview after RefreshCameraPreview(). It
- // triggers a11y alert based on `was_preview_visible_before` and the current
- // visibility of `camera_preview_widget_`. `was_preview_visible_before` is the
- // visibility of the camera preview when RefreshCameraPreview() was called.
- // It also triggers floating windows bounds update to avoid overlap between
- // camera preview and floating windows, such as PIP windows and some a11y
- // panels.
- void RunPostRefreshCameraPreview(bool was_preview_visible_before);
- // Sets the given `target_bounds` on the camera preview widget, potentially
- // animating to it if `animate` is true. Returns true if the bounds actually
- // changed from the current.
- bool SetCameraPreviewBounds(const gfx::Rect& target_bounds, bool animate);
- // Owned by CaptureModeController and guaranteed to be not null and to outlive
- // `this`.
- CaptureModeDelegate* const delegate_;
- // The remote end to the video source provider that exists in the video
- // capture service.
- mojo::Remote<video_capture::mojom::VideoSourceProvider>
- video_source_provider_remote_;
- CameraInfoList available_cameras_;
- // The currently selected camera. If its `is_valid()` is false, then no camera
- // is currently selected.
- CameraId selected_camera_;
- base::ObserverList<Observer> observers_;
- // If bound, will be invoked at the end of the scope of
- // `OnCameraDevicesReceived()` regardless of whether there was a change in the
- // available cameras or not, which is different from the behavior of
- // `Observer::OnAvailableCamerasChanged()` which is called only when there is
- // a change.
- base::OnceClosure on_camera_list_received_for_test_;
- // The camera preview widget and its contents view.
- views::UniqueWidgetPtr camera_preview_widget_;
- CameraPreviewView* camera_preview_view_ = nullptr;
- // A timer used to give a `selected_camera_` that got disconnected a grace
- // period, so if it reconnects again within this period, its ID is kept around
- // in `selected_camera_`, otherwise the ID is cleared, effectively resetting
- // back the camera setting to "Off".
- base::OneShotTimer camera_reconnect_timer_;
- // Set to true when a preview of the currently selected camera (if any) should
- // be shown. This happens when CaptureModeSession is started and switched to
- // a video recording mode before recording starts. It is reset back to false
- // when:
- // - Video recording ends.
- // - The selected camera is disconnected for longer than a grace period during
- // recording.
- // - The capture mode session ends without starting any recording.
- // - The capture mode session is switched to an image capture mode.
- bool should_show_preview_ = false;
- // The ID used for the most recent request made to the video source provider
- // to get the list of cameras in GetCameraDevices(). More recent requests will
- // have a larger value IDs than older requests.
- RequestId most_recent_request_id_ = 0;
- CameraPreviewSnapPosition camera_preview_snap_position_ =
- CameraPreviewSnapPosition::kBottomRight;
- // The location of the previous drag event in screen coordinate.
- gfx::PointF previous_location_in_screen_;
- // True when the dragging for `camera_preview_view_` is in progress.
- bool is_drag_in_progress_ = false;
- // True if the camera preview is collapsed. Its value will be updated when
- // the resize button is clicked. The size of the preview widget and the icon
- // of the resize button will be updated based on it.
- bool is_camera_preview_collapsed_ = false;
- // True if it's the first time to update the camera preview's bounds after
- // it's created.
- bool is_first_bounds_update_ = false;
- // True when the device is shutting down, and we should no longer make any
- // requests to the video capture service.
- bool is_shutting_down_ = false;
- // Valid only during recording to track the number of camera disconnections
- // while recording is in progress.
- absl::optional<int> in_recording_camera_disconnections_;
- // Will be set to true the first time the number of connected cameras is
- // reported.
- bool did_report_number_of_cameras_before_ = false;
- // Will be set to true the first user logs in. And we should only request the
- // camera devices after the first user logs in.
- bool did_first_user_login_ = false;
- base::WeakPtrFactory<CaptureModeCameraController> weak_ptr_factory_{this};
- };
- } // namespace ash
- #endif // ASH_CAPTURE_MODE_CAPTURE_MODE_CAMERA_CONTROLLER_H_
|