blob: c31db3102d5a7f517b3f8ed9644183d941cf17c0 [file] [log] [blame]
// Copyright 2020 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_streaming/browser/receiver_session_impl.h"
#include "base/task/sequenced_task_runner.h"
#include "components/cast_streaming/browser/public/network_context_getter.h"
#include "components/cast_streaming/browser/receiver_config_conversions.h"
#include "components/cast_streaming/public/features.h"
#include "media/base/audio_decoder_config.h"
#include "media/base/video_decoder_config.h"
namespace cast_streaming {
// static
std::unique_ptr<ReceiverSession> ReceiverSession::Create(
std::unique_ptr<ReceiverSession::AVConstraints> av_constraints,
ReceiverSession::MessagePortProvider message_port_provider,
ReceiverSession::Client* client) {
return std::make_unique<ReceiverSessionImpl>(
std::move(av_constraints), std::move(message_port_provider), client);
}
// static
std::unique_ptr<ReceiverSession> ReceiverSession::Create(
const ReceiverConfig& av_constraints,
ReceiverSession::MessagePortProvider message_port_provider,
ReceiverSession::Client* client) {
return Create(std::make_unique<ReceiverSession::AVConstraints>(
ToOpenscreenConstraints(av_constraints)),
std::move(message_port_provider), client);
}
ReceiverSessionImpl::ReceiverSessionImpl(
std::unique_ptr<ReceiverSession::AVConstraints> av_constraints,
ReceiverSession::MessagePortProvider message_port_provider,
ReceiverSession::Client* client)
: message_port_provider_(std::move(message_port_provider)),
av_constraints_(std::move(av_constraints)),
client_(client),
weak_factory_(this) {
// TODO(crbug.com/1218495): Validate the provided codecs against build flags.
DCHECK(av_constraints_);
DCHECK(message_port_provider_);
}
ReceiverSessionImpl::~ReceiverSessionImpl() = default;
void ReceiverSessionImpl::StartStreamingAsync(
mojo::AssociatedRemote<mojom::DemuxerConnector> demuxer_connector) {
DCHECK(!IsCastRemotingEnabled());
StartStreamingAsyncInternal(std::move(demuxer_connector));
}
void ReceiverSessionImpl::StartStreamingAsync(
mojo::AssociatedRemote<mojom::DemuxerConnector> demuxer_connector,
mojo::AssociatedRemote<mojom::RendererController> renderer_controller) {
DCHECK(IsCastRemotingEnabled());
DCHECK(!renderer_control_config_);
external_renderer_controls_ =
std::make_unique<RendererControllerImpl>(base::BindOnce(
&ReceiverSessionImpl::OnMojoDisconnect, weak_factory_.GetWeakPtr()));
renderer_control_config_.emplace(std::move(renderer_controller),
external_renderer_controls_->Bind());
StartStreamingAsyncInternal(std::move(demuxer_connector));
}
void ReceiverSessionImpl::StartStreamingAsyncInternal(
mojo::AssociatedRemote<mojom::DemuxerConnector> demuxer_connector) {
DCHECK(HasNetworkContextGetter());
DVLOG(1) << __func__;
demuxer_connector_ = std::move(demuxer_connector);
demuxer_connector_->EnableReceiver(base::BindOnce(
&ReceiverSessionImpl::OnReceiverEnabled, weak_factory_.GetWeakPtr()));
demuxer_connector_.set_disconnect_handler(base::BindOnce(
&ReceiverSessionImpl::OnMojoDisconnect, weak_factory_.GetWeakPtr()));
}
ReceiverSession::RendererController*
ReceiverSessionImpl::GetRendererControls() {
DCHECK(external_renderer_controls_);
return external_renderer_controls_.get();
}
void ReceiverSessionImpl::OnReceiverEnabled() {
DVLOG(1) << __func__;
DCHECK(message_port_provider_);
cast_streaming_session_.Start(this, std::move(renderer_control_config_),
std::move(av_constraints_),
std::move(message_port_provider_).Run(),
base::SequencedTaskRunner::GetCurrentDefault());
}
void ReceiverSessionImpl::OnSessionInitialization(
StreamingInitializationInfo initialization_info,
absl::optional<mojo::ScopedDataPipeConsumerHandle> audio_pipe_consumer,
absl::optional<mojo::ScopedDataPipeConsumerHandle> video_pipe_consumer) {
DVLOG(1) << __func__;
DCHECK_EQ(!!initialization_info.audio_stream_info, !!audio_pipe_consumer);
DCHECK_EQ(!!initialization_info.video_stream_info, !!video_pipe_consumer);
DCHECK(audio_pipe_consumer || video_pipe_consumer);
mojom::AudioStreamInitializationInfoPtr audio_info;
if (audio_pipe_consumer) {
mojo::PendingRemote<mojom::AudioBufferRequester> audio_receiver;
audio_demuxer_stream_data_provider_ =
std::make_unique<AudioDemuxerStreamDataProvider>(
audio_receiver.InitWithNewPipeAndPassReceiver(),
cast_streaming_session_.GetAudioBufferRequester(),
base::BindOnce(&ReceiverSessionImpl::OnMojoDisconnect,
weak_factory_.GetWeakPtr()),
std::move(initialization_info.audio_stream_info->config));
audio_demuxer_stream_data_provider_->SetClient(std::move(
initialization_info.audio_stream_info->demuxer_stream_client));
audio_info = mojom::AudioStreamInitializationInfo::New(
std::move(audio_receiver),
mojom::AudioStreamInfo::New(
audio_demuxer_stream_data_provider_->config(),
std::move(std::move(audio_pipe_consumer.value()))));
}
mojom::VideoStreamInitializationInfoPtr video_info;
if (video_pipe_consumer) {
mojo::PendingRemote<mojom::VideoBufferRequester> video_receiver;
video_demuxer_stream_data_provider_ =
std::make_unique<VideoDemuxerStreamDataProvider>(
video_receiver.InitWithNewPipeAndPassReceiver(),
cast_streaming_session_.GetVideoBufferRequester(),
base::BindOnce(&ReceiverSessionImpl::OnMojoDisconnect,
weak_factory_.GetWeakPtr()),
std::move(initialization_info.video_stream_info->config));
video_demuxer_stream_data_provider_->SetClient(std::move(
initialization_info.video_stream_info->demuxer_stream_client));
video_info = mojom::VideoStreamInitializationInfo::New(
std::move(video_receiver),
mojom::VideoStreamInfo::New(
video_demuxer_stream_data_provider_->config(),
std::move(std::move(video_pipe_consumer.value()))));
}
demuxer_connector_->OnStreamsInitialized(std::move(audio_info),
std::move(video_info));
PreloadBuffersAndStartPlayback();
InformClientOfConfigChange();
}
void ReceiverSessionImpl::OnAudioBufferReceived(
media::mojom::DecoderBufferPtr buffer) {
DVLOG(3) << __func__;
DCHECK(audio_demuxer_stream_data_provider_);
audio_demuxer_stream_data_provider_->ProvideBuffer(std::move(buffer));
}
void ReceiverSessionImpl::OnVideoBufferReceived(
media::mojom::DecoderBufferPtr buffer) {
DVLOG(3) << __func__;
DCHECK(video_demuxer_stream_data_provider_);
video_demuxer_stream_data_provider_->ProvideBuffer(std::move(buffer));
}
void ReceiverSessionImpl::OnSessionReinitializationPending() {
if (audio_demuxer_stream_data_provider_) {
audio_demuxer_stream_data_provider_->WaitForNewStreamInfo();
}
if (video_demuxer_stream_data_provider_) {
video_demuxer_stream_data_provider_->WaitForNewStreamInfo();
}
}
void ReceiverSessionImpl::OnSessionReinitialization(
StreamingInitializationInfo initialization_info,
absl::optional<mojo::ScopedDataPipeConsumerHandle> audio_pipe_consumer,
absl::optional<mojo::ScopedDataPipeConsumerHandle> video_pipe_consumer) {
DVLOG(1) << __func__;
DCHECK(audio_pipe_consumer || video_pipe_consumer);
DCHECK_EQ(!!audio_pipe_consumer, !!initialization_info.audio_stream_info);
DCHECK_EQ(!!video_pipe_consumer, !!initialization_info.video_stream_info);
DCHECK_EQ(!!audio_pipe_consumer, !!audio_demuxer_stream_data_provider_);
DCHECK_EQ(!!video_pipe_consumer, !!video_demuxer_stream_data_provider_);
if (audio_pipe_consumer) {
if (!audio_demuxer_stream_data_provider_->config().Matches(
initialization_info.audio_stream_info->config)) {
audio_demuxer_stream_data_provider_->SetClient(std::move(
initialization_info.audio_stream_info->demuxer_stream_client));
audio_demuxer_stream_data_provider_->OnNewStreamInfo(
std::move(initialization_info.audio_stream_info->config),
std::move(*audio_pipe_consumer));
} else {
DVLOG(1) << "Skipping application of new AudioDecoderConfig as no "
"config parameters have changed";
}
}
if (video_pipe_consumer) {
if (!video_demuxer_stream_data_provider_->config().Matches(
initialization_info.video_stream_info->config)) {
video_demuxer_stream_data_provider_->SetClient(std::move(
initialization_info.video_stream_info->demuxer_stream_client));
video_demuxer_stream_data_provider_->OnNewStreamInfo(
std::move(initialization_info.video_stream_info->config),
std::move(*video_pipe_consumer));
} else {
DVLOG(1) << "Skipping application of new VideoDecoderConfig as no "
"config parameters have changed";
}
}
PreloadBuffersAndStartPlayback();
InformClientOfConfigChange();
}
void ReceiverSessionImpl::InformClientOfConfigChange() {
if (client_) {
if (audio_demuxer_stream_data_provider_) {
client_->OnAudioConfigUpdated(
audio_demuxer_stream_data_provider_->config());
}
if (video_demuxer_stream_data_provider_) {
client_->OnVideoConfigUpdated(
video_demuxer_stream_data_provider_->config());
}
}
}
void ReceiverSessionImpl::OnSessionEnded() {
DVLOG(1) << __func__;
// Tear down the Mojo connection.
demuxer_connector_.reset();
// Tear down all remaining Mojo objects if needed. This is necessary if the
// Cast Streaming Session ending was initiated by the receiver component.
audio_demuxer_stream_data_provider_.reset();
video_demuxer_stream_data_provider_.reset();
}
void ReceiverSessionImpl::PreloadBuffersAndStartPlayback() {
DCHECK(audio_demuxer_stream_data_provider_ ||
video_demuxer_stream_data_provider_);
DVLOG(1) << __func__;
if (audio_demuxer_stream_data_provider_) {
audio_demuxer_stream_data_provider_->PreloadBuffer(
cast_streaming_session_.GetAudioBufferPreloader());
}
if (video_demuxer_stream_data_provider_) {
video_demuxer_stream_data_provider_->PreloadBuffer(
cast_streaming_session_.GetVideoBufferPreloader());
}
}
void ReceiverSessionImpl::OnMojoDisconnect() {
DVLOG(1) << __func__;
// Close the underlying connection.
if (message_port_provider_) {
av_constraints_ = std::make_unique<ReceiverSession::AVConstraints>();
std::move(message_port_provider_).Run().reset();
}
// Close the Cast Streaming Session. OnSessionEnded() will be called as part
// of the Session shutdown, which will tear down the Mojo connection.
if (cast_streaming_session_.is_running()) {
cast_streaming_session_.Stop();
}
// Tear down all remaining Mojo objects.
audio_demuxer_stream_data_provider_.reset();
video_demuxer_stream_data_provider_.reset();
}
ReceiverSessionImpl::RendererControllerImpl::RendererControllerImpl(
base::OnceCallback<void()> on_mojo_disconnect)
: on_mojo_disconnect_(std::move(on_mojo_disconnect)) {
DCHECK(on_mojo_disconnect_);
}
ReceiverSessionImpl::RendererControllerImpl::~RendererControllerImpl() =
default;
bool ReceiverSessionImpl::RendererControllerImpl::IsValid() const {
return renderer_controls_.is_bound() && renderer_controls_.is_connected();
}
void ReceiverSessionImpl::RendererControllerImpl::SetVolume(float volume) {
DCHECK(IsValid());
renderer_controls_->SetVolume(volume);
}
mojo::PendingReceiver<media::mojom::Renderer>
ReceiverSessionImpl::RendererControllerImpl::Bind() {
auto receiver = renderer_controls_.BindNewPipeAndPassReceiver();
renderer_controls_.set_disconnect_handler(std::move(on_mojo_disconnect_));
return receiver;
}
} // namespace cast_streaming