| // 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. |
| |
| #include "chrome/browser/ash/camera_presence_notifier.h" |
| |
| #include "base/functional/callback_helpers.h" |
| #include "base/memory/singleton.h" |
| #include "base/time/time.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/video_capture_service.h" |
| #include "services/video_capture/public/mojom/video_capture_service.mojom.h" |
| |
| namespace ash { |
| |
| namespace { |
| |
| // Interval between checks for camera presence. |
| const int kCameraCheckIntervalSeconds = 3; |
| |
| // Adapts the CameraPresenceCallback as CameraCountCallback |
| CameraPresenceNotifier::CameraCountCallback Adapt( |
| CameraPresenceNotifier::CameraPresenceCallback presence_callback) { |
| return base::BindRepeating([](int count) { return count > 0; }) |
| .Then(presence_callback); |
| } |
| |
| } // namespace |
| |
| CameraPresenceNotifier::CameraPresenceNotifier(CameraCountCallback callback) |
| : callback_(callback) { |
| DCHECK(callback_) << "Notifier must be created with a non-null callback."; |
| |
| content::GetVideoCaptureService().ConnectToVideoSourceProvider( |
| video_source_provider_remote_.BindNewPipeAndPassReceiver()); |
| video_source_provider_remote_.set_disconnect_handler(base::BindOnce( |
| &CameraPresenceNotifier::VideoSourceProviderDisconnectHandler, |
| weak_factory_.GetWeakPtr())); |
| } |
| |
| CameraPresenceNotifier::CameraPresenceNotifier(CameraPresenceCallback callback) |
| : CameraPresenceNotifier(Adapt(callback)) {} |
| |
| CameraPresenceNotifier::~CameraPresenceNotifier() { |
| // video_source_provider_remote_ expects to be released on the sequence where |
| // it was created. |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| } |
| |
| void CameraPresenceNotifier::VideoSourceProviderDisconnectHandler() { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| LOG(ERROR) << "VideoSourceProvider is Disconnected"; |
| callback_ = base::NullCallback(); |
| } |
| |
| void CameraPresenceNotifier::Start() { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| // Always pass through First Run on start to ensure an event is emitted ASAP. |
| state_ = State::kFirstRun; |
| CheckCameraPresence(); |
| camera_check_timer_.Start( |
| FROM_HERE, base::Seconds(kCameraCheckIntervalSeconds), |
| base::BindRepeating(&CameraPresenceNotifier::CheckCameraPresence, |
| weak_factory_.GetWeakPtr())); |
| } |
| |
| void CameraPresenceNotifier::Stop() { |
| state_ = State::kStopped; |
| camera_check_timer_.Stop(); |
| } |
| |
| void CameraPresenceNotifier::CheckCameraPresence() { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| video_source_provider_remote_->GetSourceInfos(base::BindOnce( |
| &CameraPresenceNotifier::OnGotSourceInfos, weak_factory_.GetWeakPtr())); |
| } |
| |
| void CameraPresenceNotifier::OnGotSourceInfos( |
| const std::vector<media::VideoCaptureDeviceInfo>& devices) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| const int camera_count = devices.size(); |
| |
| const bool count_changed = (camera_count != camera_count_on_last_check_); |
| camera_count_on_last_check_ = camera_count; |
| |
| if (state_ == State::kStopped) |
| return; |
| |
| bool run_callback = (state_ == State::kFirstRun || count_changed); |
| state_ = State::kStarted; |
| if (callback_ && run_callback) |
| callback_.Run(camera_count_on_last_check_); |
| } |
| |
| } // namespace ash |