| // Copyright 2021 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/cast_receiver/browser/streaming_receiver_session_client.h" |
| |
| #include <algorithm> |
| #include <utility> |
| |
| #include "base/containers/contains.h" |
| #include "base/logging.h" |
| #include "base/strings/string_util.h" |
| #include "base/task/sequenced_task_runner.h" |
| #include "components/cast/message_port/platform_message_port.h" |
| #include "components/cast_receiver/browser/streaming_controller_base.h" |
| #include "components/cast_streaming/common/public/cast_streaming_url.h" |
| #include "media/base/video_decoder_config.h" |
| |
| namespace cast_receiver { |
| |
| constexpr base::TimeDelta |
| StreamingReceiverSessionClient::kMaxAVSettingsWaitTime; |
| |
| StreamingReceiverSessionClient::StreamingReceiverSessionClient( |
| scoped_refptr<base::SequencedTaskRunner> task_runner, |
| network::NetworkContextGetter network_context_getter, |
| std::unique_ptr<cast_api_bindings::MessagePort> message_port, |
| content::WebContents* web_contents, |
| Handler* handler, |
| cast_receiver::StreamingConfigManager* config_manager, |
| bool supports_audio, |
| bool supports_video) |
| : StreamingReceiverSessionClient( |
| std::move(task_runner), |
| std::move(network_context_getter), |
| StreamingControllerBase::Create(std::move(message_port), |
| web_contents), |
| handler, |
| config_manager, |
| supports_audio, |
| supports_video) {} |
| |
| StreamingReceiverSessionClient::StreamingReceiverSessionClient( |
| scoped_refptr<base::SequencedTaskRunner> task_runner, |
| network::NetworkContextGetter network_context_getter, |
| std::unique_ptr<StreamingController> streaming_controller, |
| Handler* handler, |
| cast_receiver::StreamingConfigManager* config_manager, |
| bool supports_audio, |
| bool supports_video) |
| : handler_(handler), |
| task_runner_(std::move(task_runner)), |
| streaming_controller_(std::move(streaming_controller)), |
| supports_audio_(supports_audio), |
| supports_video_(supports_video), |
| weak_factory_(this) { |
| DCHECK(handler_); |
| DCHECK(task_runner_); |
| DCHECK(!network_context_getter.is_null()); |
| DCHECK(config_manager); |
| |
| cast_streaming::SetNetworkContextGetter(std::move(network_context_getter)); |
| |
| DVLOG(1) << "Streaming Receiver Session start pending..."; |
| config_manager->AddConfigObserver(*this); |
| if (config_manager->has_config()) { |
| // TODO(crbug.com/1359568): This may not behave correctly if the config is |
| // updated before the pushed task runs. |
| task_runner_->PostTask( |
| FROM_HERE, |
| base::BindOnce(&StreamingReceiverSessionClient::OnStreamingConfigSet, |
| weak_factory_.GetWeakPtr(), config_manager->config())); |
| return; |
| } |
| |
| task_runner_->PostDelayedTask( |
| FROM_HERE, |
| base::BindOnce(&StreamingReceiverSessionClient::VerifyAVSettingsReceived, |
| weak_factory_.GetWeakPtr()), |
| kMaxAVSettingsWaitTime); |
| } |
| |
| StreamingReceiverSessionClient::~StreamingReceiverSessionClient() { |
| DVLOG(1) << "StreamingReceiverSessionClient state when destroyed" |
| << "\n\tIs Healthy: " << is_healthy() |
| << "\n\tLaunch called: " << is_streaming_launch_pending() |
| << "\n\tAV Settings Received: " << has_received_av_settings(); |
| |
| cast_streaming::SetNetworkContextGetter({}); |
| } |
| |
| StreamingReceiverSessionClient::Handler::~Handler() = default; |
| |
| void StreamingReceiverSessionClient::LaunchStreamingReceiverAsync() { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| DCHECK(!is_streaming_launch_pending()); |
| |
| streaming_state_ |= LaunchState::kLaunchCalled; |
| streaming_controller_->StartPlaybackAsync( |
| base::BindOnce(&StreamingReceiverSessionClient::OnPlaybackStarted, |
| weak_factory_.GetWeakPtr())); |
| } |
| |
| void StreamingReceiverSessionClient::VerifyAVSettingsReceived() { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| if (streaming_state_ & LaunchState::kAVSettingsReceived) { |
| return; |
| } |
| |
| LOG(ERROR) << "AVSettings not received within the allocated amount of time"; |
| TriggerError(); |
| } |
| |
| void StreamingReceiverSessionClient::OnPlaybackStarted() { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| streaming_state_ |= LaunchState::kLaunched; |
| handler_->OnStreamingSessionStarted(); |
| } |
| |
| void StreamingReceiverSessionClient::OnStreamingConfigSet( |
| const cast_streaming::ReceiverConfig& config) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
| |
| // Make a copy so that it can be mofidied locally. |
| cast_streaming::ReceiverConfig constraints = config; |
| |
| if (streaming_state_ == LaunchState::kError) { |
| LOG(WARNING) << "Config received after an error!"; |
| return; |
| } |
| |
| if (!supports_audio_) { |
| LOG(WARNING) << "Disallowing audio for this streaming session!"; |
| constraints.audio_codecs.clear(); |
| constraints.audio_limits.clear(); |
| } |
| if (!supports_video_) { |
| LOG(WARNING) << "Disallowing video for this streaming session!"; |
| constraints.video_codecs.clear(); |
| constraints.video_limits.clear(); |
| } |
| if (supports_audio_ && supports_video_) { |
| DVLOG(1) << "Allowing both audio and video for this streaming session!"; |
| } |
| |
| streaming_state_ |= LaunchState::kAVSettingsReceived; |
| if (!has_streaming_launched()) { |
| streaming_controller_->InitializeReceiverSession(config, this); |
| return; |
| } |
| |
| // TODO(crbug.com/1359568): Handle receiving a new config after streaming has |
| // already started. |
| LOG(WARNING) |
| << "Received updated streaming config during an ongoing session!"; |
| } |
| |
| void StreamingReceiverSessionClient::OnStreamingSessionEnded() { |
| // The streaming session will only "end" (as opposed to being "renegotated" |
| // when a new config is sent or the stream changes between mirroring and |
| // remoting) when the session completely exits. This occurs either when there |
| // is an error in the runtime or the when sender-side ends the streaming |
| // session. |
| // |
| // In either case, the result is an unsupported state for the |
| // StreamingRuntimeApplication, so an error. |
| TriggerError(); |
| } |
| |
| void StreamingReceiverSessionClient::TriggerError() { |
| if (!is_healthy()) { |
| return; |
| } |
| |
| streaming_state_ |= LaunchState::kError; |
| handler_->OnError(); |
| } |
| |
| } // namespace cast_receiver |