blob: eb0384609a5578976ee809123ebbdd38498f656a [file] [log] [blame]
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_ASH_MEDIA_CLIENT_IMPL_H_
#define CHROME_BROWSER_UI_ASH_MEDIA_CLIENT_IMPL_H_
#include "ash/public/cpp/media_client.h"
#include "ash/public/cpp/media_controller.h"
#include "ash/public/cpp/session/session_observer.h"
#include "base/containers/flat_map.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "base/synchronization/lock.h"
#include "base/time/time.h"
#include "chrome/browser/ash/camera_mic/vm_camera_mic_manager.h"
#include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
#include "chrome/browser/ui/browser_list_observer.h"
#include "components/services/app_service/public/cpp/app_capability_access_cache.h"
#include "media/capture/video/chromeos/camera_hal_dispatcher_impl.h"
#include "media/capture/video/chromeos/mojom/cros_camera_service.mojom.h"
#include "services/video_capture/public/mojom/video_source_provider.mojom.h"
#include "ui/base/accelerators/media_keys_listener.h"
namespace apps {
class AppRegistryCache;
} // namespace apps
class MediaClientImpl : public ash::MediaClient,
public ash::VmCameraMicManager::Observer,
public ash::SessionObserver,
public apps::AppCapabilityAccessCache::Observer,
public BrowserListObserver,
public MediaCaptureDevicesDispatcher::Observer,
public media::CameraPrivacySwitchObserver,
public media::CameraActiveClientObserver {
public:
MediaClientImpl();
MediaClientImpl(const MediaClientImpl&) = delete;
MediaClientImpl& operator=(const MediaClientImpl&) = delete;
~MediaClientImpl() override;
// Initializes and set as client for ash.
void Init();
// Tests can provide a mock mojo interface for the ash controller.
void InitForTesting(ash::MediaController* controller);
// Returns a pointer to the singleton MediaClient, or nullptr if none exists.
static MediaClientImpl* Get();
// ash::MediaClient:
void HandleMediaNextTrack() override;
void HandleMediaPlayPause() override;
void HandleMediaPlay() override;
void HandleMediaPause() override;
void HandleMediaStop() override;
void HandleMediaPrevTrack() override;
void HandleMediaSeekBackward() override;
void HandleMediaSeekForward() override;
void RequestCaptureState() override;
void SuspendMediaSessions() override;
// MediaCaptureDevicesDispatcher::Observer:
void OnRequestUpdate(int render_process_id,
int render_frame_id,
blink::mojom::MediaStreamType stream_type,
const content::MediaRequestState state) override;
// BrowserListObserver:
void OnBrowserSetLastActive(Browser* browser) override;
// ash::VmCameraMicManager::Observer
void OnVmCameraMicActiveChanged(ash::VmCameraMicManager* manager) override;
// media::CameraPrivacySwitchObserver:
void OnCameraHWPrivacySwitchStateChanged(
const std::string& device_id,
cros::mojom::CameraPrivacySwitchState state) override;
void OnCameraSWPrivacySwitchStateChanged(
cros::mojom::CameraPrivacySwitchState state) override;
// media::CameraActiveClientObserver:
void OnActiveClientChange(
cros::mojom::CameraClientType type,
bool is_active,
const base::flat_set<std::string>& device_ids) override;
// apps::AppCapabilityAccessCache::Observer:
void OnCapabilityAccessUpdate(
const apps::CapabilityAccessUpdate& update) override;
void OnAppCapabilityAccessCacheWillBeDestroyed(
apps::AppCapabilityAccessCache* cache) override;
// ash::SessionObserver:
void OnActiveUserSessionChanged(const AccountId& account_id) override;
// Enables/disables custom media key handling when |context| is the active
// browser. Media keys will be forwarded to |delegate|.
void EnableCustomMediaKeyHandler(content::BrowserContext* context,
ui::MediaKeysListener::Delegate* delegate);
void DisableCustomMediaKeyHandler(content::BrowserContext* context,
ui::MediaKeysListener::Delegate* delegate);
// Returns the (short) name of the app attempting to use the camera, or an
// empty string if the short name is not available. Publicly visible for
// testing.
static std::string GetNameOfAppAccessingCamera(
apps::AppCapabilityAccessCache* capability_cache,
apps::AppRegistryCache* registry_cache);
private:
friend class MediaClientAppUsingCameraInBrowserEnvironmentTest;
// Sets |is_forcing_media_client_key_handling_| to true if
// |GetCurrentMediaKeyDelegate| returns a delegate. This will also mirror the
// value of |is_forcing_media_client_key_handling_| to Ash.
void UpdateForceMediaClientKeyHandling();
// Gets the current media key delegate that we should forward media keys to.
// This will be the delegate that is associated with the current active
// browser. If there is no delegate registered or there is no active browser
// then this will return |nullptr|.
ui::MediaKeysListener::Delegate* GetCurrentMediaKeyDelegate() const;
// Returns the media capture state for the current user at
// |user_index|. (Note that this isn't stable, see implementation comment on
// RequestCaptureState()).
ash::MediaCaptureState GetMediaCaptureStateByIndex(int user_index);
// Handles the media key action for the key with |code|. If there is a
// |GetCurrentMediaKeyDelegate| then the action will be forwarded to the
// delegate. Otherwise, we will forward the action to the extensions API.
void HandleMediaAction(ui::KeyboardCode code);
// Shows a notification informing the user that an app is trying to use the
// camera while the camera hardware privacy switch is turned on. If
// `resurface` is false the notification text will be updated but the
// notification won't be brought to the users attention again.
void ShowCameraOffNotification(const std::string& device_id,
const std::string& device_name,
bool resurface = true);
// Removes the camera notification with the give id `notification_id` and
// updates the internal data structures of the class accordingly.
void RemoveCameraOffNotificationByID(const std::string& notification_id);
void OnGetSourceInfosByCameraHWPrivacySwitchStateChanged(
const std::string& device_id,
cros::mojom::CameraPrivacySwitchState state,
const std::vector<media::VideoCaptureDeviceInfo>& devices);
void OnGetSourceInfosByActiveClientChanged(
const base::flat_set<std::string>& active_device_ids,
const std::vector<media::VideoCaptureDeviceInfo>& devices);
// Returns true if the device (camera) with id `device_id` is being actively
// used by a client.
bool IsDeviceActive(const std::string& device_id);
void OnGetSourceInfosByCameraSWPrivacySwitchStateChanged(
const std::vector<media::VideoCaptureDeviceInfo>& devices);
void OnGetCameraSWPrivacySwitchState(
cros::mojom::CameraPrivacySwitchState state);
ash::MediaController* media_controller_ = nullptr;
base::flat_map<content::BrowserContext*, ui::MediaKeysListener::Delegate*>
media_key_delegates_;
// If true then ash will always forward media keys to |this| instead of trying
// to handle them first.
bool is_forcing_media_client_key_handling_ = false;
content::BrowserContext* active_context_ = nullptr;
ash::MediaCaptureState vm_media_capture_state_ =
ash::MediaCaptureState::kNone;
// The most recent observed camera privacy switch state.
base::flat_map<std::string, cros::mojom::CameraPrivacySwitchState>
device_id_to_camera_privacy_switch_state_;
int active_camera_client_count_ = 0;
// Most recent time the notification that the camera privacy switch is on was
// shown.
base::TimeTicks camera_switch_notification_shown_timestamp_;
mojo::Remote<video_capture::mojom::VideoSourceProvider>
video_source_provider_remote_;
// Points an active app (short)name to the last (device id, device name) pair
// that the app used.
base::flat_map<std::string, std::pair<std::string, std::string>>
last_device_for_app_;
// Points each CameraClientType to a set which contains the id of the devices
// the CameraClientType is currently using.
base::flat_map<cros::mojom::CameraClientType, base::flat_set<std::string>>
devices_used_by_client_;
// IDs of the existing camera hardware switch notifications in the message
// center.
base::flat_set<std::string> existing_notifications_;
// Stores the state of the camera software privacy switch state locally.
cros::mojom::CameraPrivacySwitchState camera_sw_privacy_switch_state_ =
cros::mojom::CameraPrivacySwitchState::UNKNOWN;
SEQUENCE_CHECKER(sequence_checker_);
base::WeakPtrFactory<MediaClientImpl> weak_ptr_factory_{this};
};
#endif // CHROME_BROWSER_UI_ASH_MEDIA_CLIENT_IMPL_H_