#ifndef MEDIA_CAPTURE_VIDEO_CHROMEOS_CAMERA_HAL_DISPATCHER_IMPL_H_
#define MEDIA_CAPTURE_VIDEO_CHROMEOS_CAMERA_HAL_DISPATCHER_IMPL_H_
#include <memory>
#include <set>
#include <vector>
#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/singleton.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list_threadsafe.h"
#include "base/observer_list_types.h"
#include "base/scoped_observation_traits.h"
#include "base/synchronization/lock.h"
#include "base/synchronization/waitable_event.h"
#include "base/task/sequenced_task_runner.h"
#include "base/thread_annotations.h"
#include "base/threading/thread.h"
#include "base/unguessable_token.h"
#include "chromeos/ash/components/mojo_service_manager/mojom/mojo_service_manager.mojom.h"
#include "media/capture/capture_export.h"
#include "media/capture/video/chromeos/mojo_service_manager_observer.h"
#include "media/capture/video/chromeos/mojom/cros_camera_service.mojom.h"
#include "media/capture/video/chromeos/token_manager.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
#include "mojo/public/cpp/bindings/remote.h"
namespace base {
class SingleThreadTaskRunner;
class WaitableEvent;
}
namespace ash {
class CameraEffectsController;
}
namespace media {
class CAPTURE_EXPORT CameraClientObserver {
public:
CameraClientObserver(cros::mojom::CameraClientType type,
base::UnguessableToken auth_token)
: type_(type), auth_token_(auth_token) {}
virtual ~CameraClientObserver();
virtual void OnChannelCreated(
mojo::PendingRemote<cros::mojom::CameraModule> camera_module) = 0;
cros::mojom::CameraClientType GetType() { return type_; }
const base::UnguessableToken GetAuthToken() { return auth_token_; }
bool Authenticate(TokenManager* token_manager);
private:
cros::mojom::CameraClientType type_;
base::UnguessableToken auth_token_;
};
class CAPTURE_EXPORT CameraActiveClientObserver : public base::CheckedObserver {
public:
virtual void OnActiveClientChange(
cros::mojom::CameraClientType type,
bool is_new_active_client,
const base::flat_set<std::string>& active_device_ids) {}
};
class CAPTURE_EXPORT CameraPrivacySwitchObserver
: public base::CheckedObserver {
public:
~CameraPrivacySwitchObserver() override = default;
virtual void OnCameraHWPrivacySwitchStateChanged(
const std::string& device_id,
cros::mojom::CameraPrivacySwitchState state) {}
virtual void OnCameraSWPrivacySwitchStateChanged(
cros::mojom::CameraPrivacySwitchState state) {}
};
class CAPTURE_EXPORT CameraEffectObserver : public base::CheckedObserver {
public:
~CameraEffectObserver() override = default;
virtual void OnCameraEffectChanged(
const cros::mojom::EffectsConfigPtr& new_effects) {}
};
class CAPTURE_EXPORT CameraHalDispatcherImpl final
: public cros::mojom::CameraHalDispatcher,
public cros::mojom::CrosCameraServiceObserver,
public chromeos::mojo_service_manager::mojom::ServiceProvider {
public:
using CameraEffectsControllerCallback =
base::RepeatingCallback<void(cros::mojom::EffectsConfigPtr,
cros::mojom::SetEffectResult)>;
using CameraEffectObserverCallback =
base::OnceCallback<void(cros::mojom::EffectsConfigPtr)>;
static CameraHalDispatcherImpl* GetInstance();
CameraHalDispatcherImpl(const CameraHalDispatcherImpl&) = delete;
CameraHalDispatcherImpl& operator=(const CameraHalDispatcherImpl&) = delete;
bool Start();
void AddClientObserver(CameraClientObserver* observer,
base::OnceCallback<void(int32_t)> result_callback);
bool IsStarted();
void AddActiveClientObserver(CameraActiveClientObserver* observer);
void RemoveActiveClientObserver(CameraActiveClientObserver* observer);
void RemoveClientObservers(
std::vector<CameraClientObserver*> client_observers);
base::flat_map<std::string, cros::mojom::CameraPrivacySwitchState>
AddCameraPrivacySwitchObserver(CameraPrivacySwitchObserver* observer);
void RemoveCameraPrivacySwitchObserver(CameraPrivacySwitchObserver* observer);
void AddCameraEffectObserver(CameraEffectObserver* observer);
void RemoveCameraEffectObserver(CameraEffectObserver* observer);
void GetCameraSWPrivacySwitchState(
cros::mojom::CrosCameraService::GetCameraSWPrivacySwitchStateCallback
callback);
void SetCameraSWPrivacySwitchState(
cros::mojom::CameraPrivacySwitchState state);
void RegisterPluginVmToken(const base::UnguessableToken& token);
void UnregisterPluginVmToken(const base::UnguessableToken& token);
void AddCameraIdToDeviceIdEntry(int32_t camera_id,
const std::string& device_id);
void RegisterClientWithToken(
mojo::PendingRemote<cros::mojom::CameraHalClient> client,
cros::mojom::CameraClientType type,
const base::UnguessableToken& auth_token,
RegisterClientWithTokenCallback callback) final;
void CameraDeviceActivityChange(int32_t camera_id,
bool opened,
cros::mojom::CameraClientType type) final;
void CameraPrivacySwitchStateChange(
cros::mojom::CameraPrivacySwitchState state,
int32_t camera_id) final;
void CameraSWPrivacySwitchStateChange(
cros::mojom::CameraPrivacySwitchState state) final;
void CameraEffectChange(cros::mojom::EffectsConfigPtr config) final;
void AutoFramingStateChange(cros::mojom::CameraAutoFramingState state) final;
base::UnguessableToken GetTokenForTrustedClient(
cros::mojom::CameraClientType type);
void SetAutoFramingState(cros::mojom::CameraAutoFramingState state);
void GetAutoFramingSupported(
cros::mojom::CrosCameraService::GetAutoFramingSupportedCallback callback);
void SetCameraEffectsControllerCallback(
CameraEffectsControllerCallback camera_effects__controller_callback);
void SetCameraEffects(cros::mojom::EffectsConfigPtr config);
private:
friend struct base::DefaultSingletonTraits<CameraHalDispatcherImpl>;
friend class CameraHalDispatcherImplTest;
class VCDInfoObserverImpl;
CameraHalDispatcherImpl();
~CameraHalDispatcherImpl() final;
bool StartThreads();
void GetCameraSWPrivacySwitchStateOnProxyThread(
cros::mojom::CrosCameraService::GetCameraSWPrivacySwitchStateCallback
callback);
void SetCameraSWPrivacySwitchStateOnProxyThread(
cros::mojom::CameraPrivacySwitchState state);
void AddClientObserverOnProxyThread(
CameraClientObserver* observer,
base::OnceCallback<void(int32_t)> result_callback,
base::WaitableEvent* added);
void EstablishMojoChannel(CameraClientObserver* client_observer);
void OnPeerConnected(mojo::ScopedMessagePipeHandle message_pipe);
void OnCameraServiceConnectionError();
void OnCameraHalClientConnectionError(CameraClientObserver* client);
void OnGetCameraModule(
CameraClientObserver* client_observer,
mojo::PendingRemote<cros::mojom::CameraModule> camera_module);
void CleanupClientOnProxyThread(CameraClientObserver* client_observer);
void RemoveClientObserversOnProxyThread(
std::vector<CameraClientObserver*> client_observers,
base::WaitableEvent* removed);
void RegisterClientWithTokenOnProxyThread(
mojo::PendingRemote<cros::mojom::CameraHalClient> client,
cros::mojom::CameraClientType type,
base::UnguessableToken token,
RegisterClientWithTokenCallback callback);
void SetAutoFramingStateOnProxyThread(
cros::mojom::CameraAutoFramingState state);
void GetAutoFramingSupportedOnProxyThread(
cros::mojom::CrosCameraService::GetAutoFramingSupportedCallback callback);
void SetCameraEffectsOnProxyThread(cros::mojom::EffectsConfigPtr config,
bool is_from_register);
void SetInitialCameraEffectsOnProxyThread(
cros::mojom::EffectsConfigPtr config);
void OnSetCameraEffectsCompleteOnProxyThread(
cros::mojom::EffectsConfigPtr config,
bool is_from_register,
cros::mojom::SetEffectResult result);
void BindCameraServiceOnProxyThread(
mojo::PendingRemote<cros::mojom::CrosCameraService> camera_service);
void TryConnectToCameraService();
std::string GetDeviceIdFromCameraId(int32_t camera_id);
base::flat_set<std::string> GetDeviceIdsFromCameraIds(
const base::flat_set<int32_t>& camera_ids);
void StopOnProxyThread();
TokenManager* GetTokenManagerForTesting();
void Request(
chromeos::mojo_service_manager::mojom::ProcessIdentityPtr identity,
mojo::ScopedMessagePipeHandle receiver) override;
base::Thread proxy_thread_;
scoped_refptr<base::SingleThreadTaskRunner> proxy_task_runner_;
mojo::ReceiverSet<cros::mojom::CameraHalDispatcher> receiver_set_;
mojo::Remote<cros::mojom::CrosCameraService> camera_service_;
mojo::Receiver<cros::mojom::CrosCameraServiceObserver>
camera_service_observer_receiver_;
std::set<raw_ptr<CameraClientObserver, SetExperimental>> client_observers_;
TokenManager token_manager_;
base::Lock opened_camera_id_map_lock_;
base::flat_map<cros::mojom::CameraClientType, base::flat_set<int32_t>>
opened_camera_id_map_ GUARDED_BY(opened_camera_id_map_lock_);
scoped_refptr<base::ObserverListThreadSafe<CameraActiveClientObserver>>
active_client_observers_;
base::Lock device_id_to_hw_privacy_switch_state_lock_;
base::flat_map<std::string, cros::mojom::CameraPrivacySwitchState>
device_id_to_hw_privacy_switch_state_
GUARDED_BY(device_id_to_hw_privacy_switch_state_lock_);
cros::mojom::CameraAutoFramingState current_auto_framing_state_ =
cros::mojom::CameraAutoFramingState::OFF;
cros::mojom::CrosCameraService::GetAutoFramingSupportedCallback
auto_framing_supported_callback_;
cros::mojom::EffectsConfigPtr current_effects_;
cros::mojom::EffectsConfigPtr initial_effects_;
scoped_refptr<base::ObserverListThreadSafe<CameraPrivacySwitchObserver>>
privacy_switch_observers_;
scoped_refptr<base::ObserverListThreadSafe<CameraEffectObserver>>
camera_effect_observers_;
std::map<CameraClientObserver*, std::unique_ptr<CameraClientObserver>>
mojo_client_observers_;
base::Lock camera_id_to_device_id_lock_;
base::flat_map<int32_t, std::string> camera_id_to_device_id_
GUARDED_BY(camera_id_to_device_id_lock_);
mojo::Receiver<chromeos::mojo_service_manager::mojom::ServiceProvider>
provider_receiver_{this};
std::unique_ptr<MojoServiceManagerObserver> mojo_service_manager_observer_;
std::unique_ptr<VCDInfoObserverImpl> vcd_info_observer_impl_;
base::WeakPtrFactory<CameraHalDispatcherImpl> weak_factory_{this};
};
}
namespace base {
template <>
struct ScopedObservationTraits<media::CameraHalDispatcherImpl,
media::CameraEffectObserver> {
static void AddObserver(media::CameraHalDispatcherImpl* source,
media::CameraEffectObserver* observer) {
source->AddCameraEffectObserver(observer);
}
static void RemoveObserver(media::CameraHalDispatcherImpl* source,
media::CameraEffectObserver* observer) {
source->RemoveCameraEffectObserver(observer);
}
};
}
#endif