blob: 10185c85ccbdb4e6f4557637129f4154820d8513 [file] [log] [blame]
// Copyright 2021 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 "components/cast_streaming/browser/playback_command_dispatcher.h"
#include "base/bind.h"
#include "base/task/bind_post_task.h"
#include "components/cast_streaming/browser/renderer_rpc_call_translator.h"
#include "components/cast_streaming/public/rpc_call_message_handler.h"
#include "media/mojo/mojom/renderer.mojom.h"
#include "mojo/public/cpp/bindings/remote.h"
namespace cast_streaming {
PlaybackCommandDispatcher::PlaybackCommandDispatcher(
scoped_refptr<base::SequencedTaskRunner> task_runner,
mojo::AssociatedRemote<mojom::RendererController> control_configuration)
: RpcInitializationCallHandlerBase(base::BindRepeating(
&PlaybackCommandDispatcher::SendRemotingRpcMessageToRemote,
base::Unretained(this))),
task_runner_(std::move(task_runner)),
weak_factory_(this) {
// Create a muxer using the "real" media::mojom::Renderer instance that
// connects to the remote media::Renderer.
mojo::Remote<media::mojom::Renderer> renderer;
control_configuration->SetPlaybackController(
renderer.BindNewPipeAndPassReceiver(),
base::BindOnce(&PlaybackCommandDispatcher::OnSetPlaybackControllerDone,
weak_factory_.GetWeakPtr()));
muxer_ = std::make_unique<RendererControlMultiplexer>(std::move(renderer),
task_runner_);
// Create a "fake" media::mojom::Renderer so that the RpcCallTranslator can
// pass commands to the |muxer_|.
mojo::Remote<media::mojom::Renderer> translators_renderer;
RegisterCommandSource(translators_renderer.BindNewPipeAndPassReceiver());
call_translator_ = std::make_unique<remoting::RendererRpcCallTranslator>(
std::move(translators_renderer));
}
PlaybackCommandDispatcher::~PlaybackCommandDispatcher() {
OnRemotingSessionEnded();
}
void PlaybackCommandDispatcher::RegisterCommandSource(
mojo::PendingReceiver<media::mojom::Renderer> controls) {
muxer_->RegisterController(std::move(controls));
}
void PlaybackCommandDispatcher::OnRemotingSessionNegotiated(
openscreen::cast::RpcMessenger* messenger) {
DCHECK(messenger);
messenger_ = messenger;
handle_ = messenger_->GetUniqueHandle();
// Include the |handle_| in the callback so that it will persist even upon
// re-negotiation.
auto message_processor_callback = base::BindPostTask(
task_runner_,
base::BindRepeating(
&PlaybackCommandDispatcher::SendRemotingRpcMessageToRemote,
weak_factory_.GetWeakPtr(), handle_),
FROM_HERE);
call_translator_->SetMessageProcessor(std::move(message_processor_callback));
auto message_receiver_callback = base::BindPostTask(
task_runner_,
base::BindRepeating(
&PlaybackCommandDispatcher::ProcessRemotingRpcMessageFromRemote,
weak_factory_.GetWeakPtr()),
FROM_HERE);
messenger_->RegisterMessageReceiverCallback(
handle_, [cb = std::move(message_receiver_callback)](
std::unique_ptr<openscreen::cast::RpcMessage> message) {
cb.Run(std::move(message));
});
demuxer_stream_handler_ = std::make_unique<remoting::RpcDemuxerStreamHandler>(
this, messenger_,
base::BindRepeating(
&PlaybackCommandDispatcher::SendRemotingRpcMessageToRemote,
base::Unretained(this)));
}
void PlaybackCommandDispatcher::ConfigureRemotingAsync(
Dispatcher* dispatcher,
const openscreen::cast::ReceiverSession* session,
openscreen::cast::ReceiverSession::ConfiguredReceivers receivers) {
DCHECK(dispatcher);
DCHECK(session);
DCHECK(demuxer_stream_handler_);
DCHECK(!streaming_init_info_);
streaming_dispatcher_ = dispatcher;
receiver_session_ = session;
absl::optional<StreamingInitializationInfo::AudioStreamInfo>
audio_stream_info;
if (receivers.audio_receiver) {
auto no_buffers_cb = base::BindPostTask(
task_runner_,
base::BindRepeating(
&remoting::RpcDemuxerStreamHandler::RequestMoreAudioBuffers,
demuxer_stream_handler_->GetWeakPtr()),
FROM_HERE);
auto error_cb = base::BindPostTask(
task_runner_,
base::BindRepeating(&remoting::RpcDemuxerStreamHandler::OnAudioError,
demuxer_stream_handler_->GetWeakPtr()),
FROM_HERE);
audio_stream_info.emplace(media::AudioDecoderConfig(),
receivers.audio_receiver,
std::move(no_buffers_cb), std::move(error_cb));
}
absl::optional<StreamingInitializationInfo::VideoStreamInfo>
video_stream_info;
if (receivers.video_receiver) {
auto no_buffers_cb = base::BindPostTask(
task_runner_,
base::BindRepeating(
&remoting::RpcDemuxerStreamHandler::RequestMoreVideoBuffers,
demuxer_stream_handler_->GetWeakPtr()),
FROM_HERE);
auto error_cb = base::BindPostTask(
task_runner_,
base::BindRepeating(&remoting::RpcDemuxerStreamHandler::OnVideoError,
demuxer_stream_handler_->GetWeakPtr()),
FROM_HERE);
video_stream_info.emplace(media::VideoDecoderConfig(),
receivers.video_receiver,
std::move(no_buffers_cb), std::move(error_cb));
}
streaming_init_info_.emplace(receiver_session_, std::move(audio_stream_info),
std::move(video_stream_info));
}
void PlaybackCommandDispatcher::OnRemotingSessionEnded() {
demuxer_stream_handler_.reset();
if (messenger_) {
messenger_->UnregisterMessageReceiverCallback(handle_);
messenger_ = nullptr;
}
streaming_init_info_ = absl::nullopt;
}
void PlaybackCommandDispatcher::SendRemotingRpcMessageToRemote(
openscreen::cast::RpcMessenger::Handle handle,
std::unique_ptr<openscreen::cast::RpcMessage> message) {
DCHECK(message);
DCHECK(task_runner_->RunsTasksInCurrentSequence());
if (!messenger_) {
return;
}
message->set_handle(handle);
messenger_->SendMessageToRemote(*message);
}
void PlaybackCommandDispatcher::ProcessRemotingRpcMessageFromRemote(
std::unique_ptr<openscreen::cast::RpcMessage> message) {
DCHECK(message);
DCHECK(task_runner_->RunsTasksInCurrentSequence());
const bool did_dispatch_as_initialization_call =
remoting::DispatchInitializationRpcCall(message.get(), this);
if (did_dispatch_as_initialization_call) {
return;
}
const bool did_dispatch_as_renderer_call =
call_translator_ &&
remoting::DispatchRendererRpcCall(message.get(), call_translator_.get());
if (did_dispatch_as_renderer_call) {
return;
}
const bool did_dispatch_as_demuxer_stream_callback =
demuxer_stream_handler_ &&
remoting::DispatchDemuxerStreamCBRpcCall(message.get(),
demuxer_stream_handler_.get());
if (did_dispatch_as_demuxer_stream_callback) {
return;
}
LOG(ERROR) << "Unhandled RPC Message for command " << message->proc();
}
void PlaybackCommandDispatcher::OnSetPlaybackControllerDone() {
has_set_playback_controller_call_returned_ = true;
if (acquire_renderer_cb_) {
std::move(acquire_renderer_cb_).Run();
}
}
void PlaybackCommandDispatcher::RpcAcquireRendererAsync(AcquireRendererCB cb) {
acquire_renderer_cb_ = base::BindOnce(std::move(cb), handle_);
if (has_set_playback_controller_call_returned_) {
std::move(acquire_renderer_cb_).Run();
}
}
void PlaybackCommandDispatcher::OnRpcAcquireDemuxer(
openscreen::cast::RpcMessenger::Handle audio_stream_handle,
openscreen::cast::RpcMessenger::Handle video_stream_handle) {
if (demuxer_stream_handler_) {
demuxer_stream_handler_->OnRpcAcquireDemuxer(audio_stream_handle,
video_stream_handle);
}
}
void PlaybackCommandDispatcher::OnNewAudioConfig(
media::AudioDecoderConfig config) {
DCHECK(streaming_init_info_);
DCHECK(streaming_dispatcher_);
if (!streaming_init_info_->audio_stream_info) {
LOG(ERROR) << "Received Audio config for a remoting session where audio is "
"not supported";
return;
}
streaming_init_info_->audio_stream_info->config = std::move(config);
if (!streaming_init_info_->video_stream_info ||
!streaming_init_info_->video_stream_info->config.Matches(
media::VideoDecoderConfig())) {
// |streaming_init_info_| is intentionally copied here.
streaming_dispatcher_->StartStreamingSession(streaming_init_info_.value());
}
}
void PlaybackCommandDispatcher::OnNewVideoConfig(
media::VideoDecoderConfig config) {
DCHECK(streaming_init_info_);
DCHECK(streaming_dispatcher_);
if (!streaming_init_info_->video_stream_info) {
LOG(ERROR) << "Received Video config for a remoting session where video is "
"not supported";
return;
}
streaming_init_info_->video_stream_info->config = std::move(config);
if (!streaming_init_info_->audio_stream_info ||
!streaming_init_info_->audio_stream_info->config.Matches(
media::AudioDecoderConfig())) {
// |streaming_init_info_| is intentionally copied here.
streaming_dispatcher_->StartStreamingSession(streaming_init_info_.value());
}
}
} // namespace cast_streaming