blob: b74579765a9cb2492ac8036bfc1e19a788dfda99 [file] [log] [blame]
// 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 "media/cast/openscreen/rpc_call_message_handler.h"
#include "base/check.h"
#include "base/logging.h"
#include "media/base/demuxer_stream.h"
#include "media/cast/openscreen/remoting_proto_enum_utils.h"
#include "media/cast/openscreen/remoting_proto_utils.h"
#include "third_party/openscreen/src/cast/streaming/remoting.pb.h"
namespace media::cast {
namespace {
template <typename T>
absl::optional<media::AudioDecoderConfig> ExtractAudioConfig(
const T& config_container) {
if (!config_container.has_audio_decoder_config()) {
return absl::nullopt;
}
const auto& audio_message = config_container.audio_decoder_config();
media::AudioDecoderConfig config;
ConvertProtoToAudioDecoderConfig(audio_message, &config);
if (!config.IsValidConfig()) {
return absl::nullopt;
}
return config;
}
template <typename T>
absl::optional<media::VideoDecoderConfig> ExtractVideoConfig(
const T& config_container) {
if (!config_container.has_video_decoder_config()) {
return absl::nullopt;
}
const auto& video_message = config_container.video_decoder_config();
media::VideoDecoderConfig config;
ConvertProtoToVideoDecoderConfig(video_message, &config);
if (!config.IsValidConfig()) {
return absl::nullopt;
}
return config;
}
bool DispatchInitializationAcquireRendererRpcCall(
openscreen::cast::RpcMessage* message,
RpcInitializationCallMessageHandler* client) {
if (!message->has_integer_value()) {
LOG(ERROR)
<< "RPC_ACQUIRE_RENDERER with no integer_value() property received";
return false;
}
client->OnRpcAcquireRenderer(message->integer_value());
return true;
}
bool DispatchInitializationAcquireDemuxerRpcCall(
openscreen::cast::RpcMessage* message,
RpcInitializationCallMessageHandler* client) {
if (!message->has_acquire_demuxer_rpc()) {
LOG(ERROR) << "RPC_ACQUIRE_DEMUXER with no acquire_demuxer_rpc() "
"property received";
return false;
}
const auto rpc = message->acquire_demuxer_rpc();
client->OnRpcAcquireDemuxer(rpc.audio_demuxer_handle(),
rpc.video_demuxer_handle());
return true;
}
bool DispatchRendererFlushUntilRpcCall(openscreen::cast::RpcMessage* message,
RpcRendererCallMessageHandler* client) {
if (!message->has_renderer_flushuntil_rpc()) {
LOG(ERROR) << "RPC_R_FLUSHUNTIL with no renderer_flushuntil_rpc() "
"property received";
return false;
}
const openscreen::cast::RendererFlushUntil flush_message =
message->renderer_flushuntil_rpc();
client->OnRpcFlush(flush_message.audio_count(), flush_message.video_count());
return true;
}
bool DispatchRendererStartPlayingFromRpcCall(
openscreen::cast::RpcMessage* message,
RpcRendererCallMessageHandler* client) {
if (!message->has_integer64_value()) {
LOG(ERROR)
<< "RPC_R_STARTPLAYINGFROM with no integer64_value() property received";
return false;
}
const base::TimeDelta time = base::Microseconds(message->integer64_value());
client->OnRpcStartPlayingFrom(time);
return true;
}
bool DispatchRendererSetPlaybackRateRpcCall(
openscreen::cast::RpcMessage* message,
RpcRendererCallMessageHandler* client) {
if (!message->has_double_value()) {
LOG(ERROR)
<< "RPC_R_SETPLAYBACKRATE with no double_value() property received";
return false;
}
client->OnRpcSetPlaybackRate(message->double_value());
return true;
}
bool DispatchRendererSetVolumeRpcCall(openscreen::cast::RpcMessage* message,
RpcRendererCallMessageHandler* client) {
if (!message->has_double_value()) {
LOG(ERROR) << "RPC_R_SETVOLUME with no double_value() property received";
return false;
}
client->OnRpcSetVolume(message->double_value());
return true;
}
bool DispatchDemuxerStreamInitializeCBRpcCall(
openscreen::cast::RpcMessage* message,
RpcDemuxerStreamCBMessageHandler* client) {
if (!message->has_demuxerstream_initializecb_rpc()) {
LOG(ERROR) << "RPC_DS_INITIALIZE_CALLBACK with no "
"demuxerstream_initializecb_rpc() property received";
return false;
}
const auto& callback_message = message->demuxerstream_initializecb_rpc();
client->OnRpcInitializeCallback(message->handle(),
ExtractAudioConfig(callback_message),
ExtractVideoConfig(callback_message));
return true;
}
bool DispatchDemuxerStreamReadUntilCBRpcCall(
openscreen::cast::RpcMessage* message,
RpcDemuxerStreamCBMessageHandler* client) {
if (!message->has_demuxerstream_readuntilcb_rpc()) {
LOG(ERROR) << "RPC_DS_READUNTIL with no "
"demuxerstream_readuntilcb_rpc() property received";
return false;
}
const auto& rpc_message = message->demuxerstream_readuntilcb_rpc();
auto audio_config = ExtractAudioConfig(rpc_message);
auto video_config = ExtractVideoConfig(rpc_message);
const auto status = ToDemuxerStreamStatus(rpc_message.status());
if ((audio_config || video_config) &&
status != media::DemuxerStream::kConfigChanged) {
LOG(ERROR) << "RPC_DS_READUNTIL with status != kConfigChanged contains "
"a new config";
return false;
}
if (!audio_config && !video_config &&
status == media::DemuxerStream::kConfigChanged) {
LOG(ERROR) << "RPC_DS_READUNTIL with status = kConfigChanged contains "
"no config";
return false;
}
const uint32_t total_frames_received = rpc_message.count();
client->OnRpcReadUntilCallback(message->handle(), std::move(audio_config),
std::move(video_config),
total_frames_received);
return true;
}
bool DispatchDemuxerStreamEnableBitstreamConverterCBRpcCall(
openscreen::cast::RpcMessage* message,
RpcDemuxerStreamCBMessageHandler* client) {
if (!message->has_boolean_value()) {
LOG(ERROR) << "RPC_DS_ENABLEBITSTREAMCONVERTER_CALLBACK with no "
"boolean_value() property received";
return false;
}
client->OnRpcEnableBitstreamConverterCallback(message->handle(),
message->boolean_value());
return true;
}
} // namespace
RpcInitializationCallMessageHandler::~RpcInitializationCallMessageHandler() =
default;
RpcRendererCallMessageHandler::~RpcRendererCallMessageHandler() = default;
RpcDemuxerStreamCBMessageHandler::~RpcDemuxerStreamCBMessageHandler() = default;
bool DispatchInitializationRpcCall(
openscreen::cast::RpcMessage* message,
RpcInitializationCallMessageHandler* client) {
DCHECK(message);
DCHECK(client);
switch (message->proc()) {
case openscreen::cast::RpcMessage::RPC_ACQUIRE_RENDERER:
return DispatchInitializationAcquireRendererRpcCall(message, client);
case openscreen::cast::RpcMessage::RPC_ACQUIRE_DEMUXER:
return DispatchInitializationAcquireDemuxerRpcCall(message, client);
default:
return false;
}
}
bool DispatchRendererRpcCall(openscreen::cast::RpcMessage* message,
RpcRendererCallMessageHandler* client) {
DCHECK(message);
DCHECK(client);
switch (message->proc()) {
case openscreen::cast::RpcMessage::RPC_R_INITIALIZE:
client->OnRpcInitialize();
return true;
case openscreen::cast::RpcMessage::RPC_R_FLUSHUNTIL:
return DispatchRendererFlushUntilRpcCall(message, client);
case openscreen::cast::RpcMessage::RPC_R_STARTPLAYINGFROM:
return DispatchRendererStartPlayingFromRpcCall(message, client);
case openscreen::cast::RpcMessage::RPC_R_SETPLAYBACKRATE:
return DispatchRendererSetPlaybackRateRpcCall(message, client);
case openscreen::cast::RpcMessage::RPC_R_SETVOLUME:
return DispatchRendererSetVolumeRpcCall(message, client);
default:
return false;
}
}
bool DispatchDemuxerStreamCBRpcCall(openscreen::cast::RpcMessage* message,
RpcDemuxerStreamCBMessageHandler* client) {
DCHECK(message);
DCHECK(client);
switch (message->proc()) {
case openscreen::cast::RpcMessage::RPC_DS_INITIALIZE_CALLBACK:
return DispatchDemuxerStreamInitializeCBRpcCall(message, client);
case openscreen::cast::RpcMessage::RPC_DS_READUNTIL_CALLBACK:
return DispatchDemuxerStreamReadUntilCBRpcCall(message, client);
case openscreen::cast::RpcMessage::RPC_DS_ENABLEBITSTREAMCONVERTER_CALLBACK:
return DispatchDemuxerStreamEnableBitstreamConverterCBRpcCall(message,
client);
default:
return false;
}
}
} // namespace media::cast