| // Copyright 2017 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. |
| |
| #include "content/browser/renderer_host/media/service_video_capture_device_launcher.h" |
| |
| #include <utility> |
| |
| #include "base/bind.h" |
| #include "base/bind_helpers.h" |
| #include "base/task/post_task.h" |
| #include "content/browser/renderer_host/media/service_launched_video_capture_device.h" |
| #include "content/public/browser/browser_task_traits.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "media/capture/video/video_capture_device.h" |
| #include "media/capture/video/video_frame_receiver_on_task_runner.h" |
| #include "mojo/public/cpp/bindings/strong_binding.h" |
| #include "services/video_capture/public/cpp/receiver_media_to_mojo_adapter.h" |
| |
| namespace content { |
| |
| namespace { |
| |
| void ConcludeLaunchDeviceWithSuccess( |
| video_capture::mojom::VideoSourcePtr source, |
| video_capture::mojom::PushVideoStreamSubscriptionPtr subscription, |
| base::OnceClosure connection_lost_cb, |
| VideoCaptureDeviceLauncher::Callbacks* callbacks, |
| base::OnceClosure done_cb) { |
| subscription->Activate(); |
| callbacks->OnDeviceLaunched( |
| std::make_unique<ServiceLaunchedVideoCaptureDevice>( |
| std::move(source), std::move(subscription), |
| std::move(connection_lost_cb))); |
| std::move(done_cb).Run(); |
| } |
| |
| void ConcludeLaunchDeviceWithFailure( |
| bool abort_requested, |
| media::VideoCaptureError error, |
| scoped_refptr<RefCountedVideoSourceProvider> service_connection, |
| VideoCaptureDeviceLauncher::Callbacks* callbacks, |
| base::OnceClosure done_cb) { |
| service_connection.reset(); |
| if (abort_requested) |
| callbacks->OnDeviceLaunchAborted(); |
| else |
| callbacks->OnDeviceLaunchFailed(error); |
| std::move(done_cb).Run(); |
| } |
| |
| } // anonymous namespace |
| |
| ServiceVideoCaptureDeviceLauncher::ServiceVideoCaptureDeviceLauncher( |
| ConnectToDeviceFactoryCB connect_to_source_provider_cb) |
| : connect_to_source_provider_cb_(std::move(connect_to_source_provider_cb)), |
| state_(State::READY_TO_LAUNCH), |
| callbacks_(nullptr) {} |
| |
| ServiceVideoCaptureDeviceLauncher::~ServiceVideoCaptureDeviceLauncher() { |
| DCHECK(sequence_checker_.CalledOnValidSequence()); |
| DCHECK(state_ == State::READY_TO_LAUNCH); |
| } |
| |
| void ServiceVideoCaptureDeviceLauncher::LaunchDeviceAsync( |
| const std::string& device_id, |
| blink::mojom::MediaStreamType stream_type, |
| const media::VideoCaptureParams& params, |
| base::WeakPtr<media::VideoFrameReceiver> receiver, |
| base::OnceClosure connection_lost_cb, |
| Callbacks* callbacks, |
| base::OnceClosure done_cb) { |
| DCHECK(sequence_checker_.CalledOnValidSequence()); |
| DCHECK(state_ == State::READY_TO_LAUNCH); |
| |
| if (stream_type != blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE) { |
| // This launcher only supports MediaStreamType::DEVICE_VIDEO_CAPTURE. |
| NOTREACHED(); |
| return; |
| } |
| |
| connect_to_source_provider_cb_.Run(&service_connection_); |
| if (!service_connection_->source_provider().is_bound()) { |
| // This can happen when the connection to the service was lost. |
| ConcludeLaunchDeviceWithFailure( |
| false, |
| media::VideoCaptureError:: |
| kServiceDeviceLauncherLostConnectionToDeviceFactoryDuringDeviceStart, |
| std::move(service_connection_), callbacks, std::move(done_cb)); |
| return; |
| } |
| |
| if (receiver) { |
| std::ostringstream string_stream; |
| string_stream |
| << "ServiceVideoCaptureDeviceLauncher::LaunchDeviceAsync: Asking " |
| "video capture service to create source for device_id = " |
| << device_id; |
| receiver->OnLog(string_stream.str()); |
| } |
| |
| // Ownership of |done_cb| is moved to |this|. It is not sufficient to attach |
| // it to the callback passed to CreatePushSubscription(), because the |
| // connection to the service may get torn down before |callbacks| are |
| // invoked. |
| done_cb_ = std::move(done_cb); |
| callbacks_ = callbacks; |
| video_capture::mojom::VideoSourcePtr source; |
| service_connection_->source_provider()->GetVideoSource( |
| device_id, mojo::MakeRequest(&source)); |
| |
| auto receiver_adapter = |
| std::make_unique<video_capture::ReceiverMediaToMojoAdapter>( |
| std::make_unique<media::VideoFrameReceiverOnTaskRunner>( |
| std::move(receiver), base::CreateSingleThreadTaskRunnerWithTraits( |
| {BrowserThread::IO}))); |
| video_capture::mojom::ReceiverPtr receiver_proxy; |
| mojo::MakeStrongBinding<video_capture::mojom::Receiver>( |
| std::move(receiver_adapter), mojo::MakeRequest(&receiver_proxy)); |
| |
| video_capture::mojom::PushVideoStreamSubscriptionPtr subscription; |
| // Create message pipe so that we can subsequently call |
| // subscription.set_connection_error_handler(). |
| auto subscription_request = mojo::MakeRequest(&subscription); |
| // Use of Unretained(this) is safe, because |done_cb_| guarantees that |this| |
| // stays alive. |
| subscription.set_connection_error_handler( |
| base::BindOnce(&ServiceVideoCaptureDeviceLauncher:: |
| OnConnectionLostWhileWaitingForCallback, |
| base::Unretained(this))); |
| |
| // TODO(crbug.com/925083) |
| media::VideoCaptureParams new_params = params; |
| new_params.power_line_frequency = |
| media::VideoCaptureDevice::GetPowerLineFrequency(params); |
| |
| // Note that we set |force_reopen_with_new_settings| to true in order |
| // to avoid the situation that a requests to open (or reopen) a device |
| // that has just been closed with different settings ends up getting the old |
| // settings, because from the perspective of the service, the device was still |
| // in use. In order to be able to set |force_reopen_with_new_settings|, we |
| // have to refactor code here and upstream to wait for a callback from the |
| // service indicating that the device closing is complete. |
| source->CreatePushSubscription( |
| std::move(receiver_proxy), new_params, |
| true /*force_reopen_with_new_settings*/, std::move(subscription_request), |
| base::BindOnce( |
| // Use of Unretained |this| is safe, because |done_cb_| guarantees |
| // that |this| stays alive. |
| &ServiceVideoCaptureDeviceLauncher::OnCreatePushSubscriptionCallback, |
| base::Unretained(this), std::move(source), std::move(subscription), |
| std::move(connection_lost_cb))); |
| state_ = State::DEVICE_START_IN_PROGRESS; |
| } |
| |
| void ServiceVideoCaptureDeviceLauncher::AbortLaunch() { |
| DCHECK(sequence_checker_.CalledOnValidSequence()); |
| if (state_ == State::DEVICE_START_IN_PROGRESS) |
| state_ = State::DEVICE_START_ABORTING; |
| } |
| |
| void ServiceVideoCaptureDeviceLauncher::OnCreatePushSubscriptionCallback( |
| video_capture::mojom::VideoSourcePtr source, |
| video_capture::mojom::PushVideoStreamSubscriptionPtr subscription, |
| base::OnceClosure connection_lost_cb, |
| video_capture::mojom::CreatePushSubscriptionResultCode result_code, |
| const media::VideoCaptureParams& params) { |
| DCHECK(sequence_checker_.CalledOnValidSequence()); |
| DCHECK(callbacks_); |
| DCHECK(done_cb_); |
| subscription.set_connection_error_handler(base::DoNothing()); |
| const bool abort_requested = (state_ == State::DEVICE_START_ABORTING); |
| state_ = State::READY_TO_LAUNCH; |
| Callbacks* callbacks = callbacks_; |
| callbacks_ = nullptr; |
| switch (result_code) { |
| case video_capture::mojom::CreatePushSubscriptionResultCode:: |
| kCreatedWithRequestedSettings: // Fall through. |
| case video_capture::mojom::CreatePushSubscriptionResultCode:: |
| kCreatedWithDifferentSettings: |
| if (abort_requested) { |
| subscription.reset(); |
| source.reset(); |
| service_connection_.reset(); |
| callbacks->OnDeviceLaunchAborted(); |
| std::move(done_cb_).Run(); |
| return; |
| } |
| ConcludeLaunchDeviceWithSuccess( |
| std::move(source), std::move(subscription), |
| std::move(connection_lost_cb), callbacks, std::move(done_cb_)); |
| return; |
| case video_capture::mojom::CreatePushSubscriptionResultCode::kFailed: |
| ConcludeLaunchDeviceWithFailure( |
| abort_requested, |
| media::VideoCaptureError:: |
| kServiceDeviceLauncherServiceRespondedWithDeviceNotFound, |
| std::move(service_connection_), callbacks, std::move(done_cb_)); |
| return; |
| } |
| } |
| |
| void ServiceVideoCaptureDeviceLauncher:: |
| OnConnectionLostWhileWaitingForCallback() { |
| DCHECK(sequence_checker_.CalledOnValidSequence()); |
| DCHECK(callbacks_); |
| const bool abort_requested = (state_ == State::DEVICE_START_ABORTING); |
| state_ = State::READY_TO_LAUNCH; |
| Callbacks* callbacks = callbacks_; |
| callbacks_ = nullptr; |
| ConcludeLaunchDeviceWithFailure( |
| abort_requested, |
| media::VideoCaptureError:: |
| kServiceDeviceLauncherConnectionLostWhileWaitingForCallback, |
| std::move(service_connection_), callbacks, std::move(done_cb_)); |
| } |
| |
| } // namespace content |