summaryrefslogtreecommitdiff
path: root/chromium/media/remoting/receiver_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/media/remoting/receiver_unittest.cc')
-rw-r--r--chromium/media/remoting/receiver_unittest.cc471
1 files changed, 471 insertions, 0 deletions
diff --git a/chromium/media/remoting/receiver_unittest.cc b/chromium/media/remoting/receiver_unittest.cc
new file mode 100644
index 00000000000..94cb8cc50ef
--- /dev/null
+++ b/chromium/media/remoting/receiver_unittest.cc
@@ -0,0 +1,471 @@
+// Copyright 2020 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 "media/remoting/receiver.h"
+
+#include "base/check.h"
+#include "base/optional.h"
+#include "base/test/gmock_callback_support.h"
+#include "base/test/task_environment.h"
+#include "media/base/audio_decoder_config.h"
+#include "media/base/media_util.h"
+#include "media/base/mock_filters.h"
+#include "media/base/renderer.h"
+#include "media/base/test_helpers.h"
+#include "media/base/video_decoder_config.h"
+#include "media/remoting/mock_receiver_controller.h"
+#include "media/remoting/proto_enum_utils.h"
+#include "media/remoting/proto_utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::test::RunOnceCallback;
+using testing::_;
+using testing::AtLeast;
+using testing::NiceMock;
+using testing::StrictMock;
+
+namespace media {
+namespace remoting {
+
+class MockSender {
+ public:
+ MockSender(RpcBroker* rpc_broker, int remote_handle)
+ : rpc_broker_(rpc_broker),
+ rpc_handle_(rpc_broker->GetUniqueHandle()),
+ remote_handle_(remote_handle) {
+ rpc_broker_->RegisterMessageReceiverCallback(
+ rpc_handle_, base::BindRepeating(&MockSender::OnReceivedRpc,
+ base::Unretained(this)));
+ }
+
+ MOCK_METHOD(void, AcquireRendererDone, ());
+ MOCK_METHOD(void, InitializeCallback, (bool));
+ MOCK_METHOD(void, FlushUntilCallback, ());
+ MOCK_METHOD(void, OnTimeUpdate, (int64_t, int64_t));
+ MOCK_METHOD(void, OnBufferingStateChange, (BufferingState));
+ MOCK_METHOD(void, OnEnded, ());
+ MOCK_METHOD(void, OnFatalError, ());
+ MOCK_METHOD(void, OnAudioConfigChange, (AudioDecoderConfig));
+ MOCK_METHOD(void, OnVideoConfigChange, (VideoDecoderConfig));
+ MOCK_METHOD(void, OnVideoNaturalSizeChange, (gfx::Size));
+ MOCK_METHOD(void, OnVideoOpacityChange, (bool));
+ MOCK_METHOD(void, OnStatisticsUpdate, (PipelineStatistics));
+ MOCK_METHOD(void, OnWaiting, ());
+
+ void OnReceivedRpc(std::unique_ptr<pb::RpcMessage> message) {
+ DCHECK(message);
+ switch (message->proc()) {
+ case pb::RpcMessage::RPC_ACQUIRE_RENDERER_DONE:
+ AcquireRendererDone();
+ break;
+ case pb::RpcMessage::RPC_R_INITIALIZE_CALLBACK:
+ InitializeCallback(message->boolean_value());
+ break;
+ case pb::RpcMessage::RPC_R_FLUSHUNTIL_CALLBACK:
+ FlushUntilCallback();
+ break;
+ case pb::RpcMessage::RPC_RC_ONTIMEUPDATE: {
+ DCHECK(message->has_rendererclient_ontimeupdate_rpc());
+ const int64_t time_usec =
+ message->rendererclient_ontimeupdate_rpc().time_usec();
+ const int64_t max_time_usec =
+ message->rendererclient_ontimeupdate_rpc().max_time_usec();
+ OnTimeUpdate(time_usec, max_time_usec);
+ break;
+ }
+ case pb::RpcMessage::RPC_RC_ONBUFFERINGSTATECHANGE: {
+ base::Optional<BufferingState> state = ToMediaBufferingState(
+ message->rendererclient_onbufferingstatechange_rpc().state());
+ if (state.has_value())
+ OnBufferingStateChange(state.value());
+ break;
+ }
+ case pb::RpcMessage::RPC_RC_ONENDED:
+ OnEnded();
+ break;
+ case pb::RpcMessage::RPC_RC_ONERROR:
+ OnFatalError();
+ break;
+ case pb::RpcMessage::RPC_RC_ONAUDIOCONFIGCHANGE: {
+ DCHECK(message->has_rendererclient_onaudioconfigchange_rpc());
+ const auto* audio_config_message =
+ message->mutable_rendererclient_onaudioconfigchange_rpc();
+ const pb::AudioDecoderConfig pb_audio_config =
+ audio_config_message->audio_decoder_config();
+ AudioDecoderConfig out_audio_config;
+ ConvertProtoToAudioDecoderConfig(pb_audio_config, &out_audio_config);
+ DCHECK(out_audio_config.IsValidConfig());
+ OnAudioConfigChange(out_audio_config);
+ break;
+ }
+ case pb::RpcMessage::RPC_RC_ONVIDEOCONFIGCHANGE: {
+ DCHECK(message->has_rendererclient_onvideoconfigchange_rpc());
+ const auto* video_config_message =
+ message->mutable_rendererclient_onvideoconfigchange_rpc();
+ const pb::VideoDecoderConfig pb_video_config =
+ video_config_message->video_decoder_config();
+ VideoDecoderConfig out_video_config;
+ ConvertProtoToVideoDecoderConfig(pb_video_config, &out_video_config);
+ DCHECK(out_video_config.IsValidConfig());
+
+ OnVideoConfigChange(out_video_config);
+ break;
+ }
+ case pb::RpcMessage::RPC_RC_ONVIDEONATURALSIZECHANGE: {
+ DCHECK(message->has_rendererclient_onvideonatualsizechange_rpc());
+
+ gfx::Size size(
+ message->rendererclient_onvideonatualsizechange_rpc().width(),
+ message->rendererclient_onvideonatualsizechange_rpc().height());
+ OnVideoNaturalSizeChange(size);
+ break;
+ }
+ case pb::RpcMessage::RPC_RC_ONVIDEOOPACITYCHANGE:
+ OnVideoOpacityChange(message->boolean_value());
+ break;
+ case pb::RpcMessage::RPC_RC_ONSTATISTICSUPDATE: {
+ DCHECK(message->has_rendererclient_onstatisticsupdate_rpc());
+ auto rpc_message = message->rendererclient_onstatisticsupdate_rpc();
+ PipelineStatistics statistics;
+ statistics.audio_bytes_decoded = rpc_message.audio_bytes_decoded();
+ statistics.video_bytes_decoded = rpc_message.video_bytes_decoded();
+ statistics.video_frames_decoded = rpc_message.video_frames_decoded();
+ statistics.video_frames_dropped = rpc_message.video_frames_dropped();
+ statistics.audio_memory_usage = rpc_message.audio_memory_usage();
+ statistics.video_memory_usage = rpc_message.video_memory_usage();
+ OnStatisticsUpdate(statistics);
+ break;
+ }
+ case pb::RpcMessage::RPC_RC_ONWAITINGFORDECRYPTIONKEY:
+ OnWaiting();
+ break;
+
+ default:
+ VLOG(1) << "Unknown RPC: " << message->proc();
+ }
+ }
+
+ void SendRpcAcquireRenderer() {
+ auto rpc = std::make_unique<pb::RpcMessage>();
+ rpc->set_handle(RpcBroker::kAcquireRendererHandle);
+ rpc->set_proc(pb::RpcMessage::RPC_ACQUIRE_RENDERER);
+ rpc->set_integer_value(rpc_handle_);
+ rpc_broker_->SendMessageToRemote(std::move(rpc));
+ }
+
+ void SendRpcInitialize() {
+ auto rpc = std::make_unique<pb::RpcMessage>();
+ rpc->set_handle(remote_handle_);
+ rpc->set_proc(pb::RpcMessage::RPC_R_INITIALIZE);
+ rpc_broker_->SendMessageToRemote(std::move(rpc));
+ }
+
+ void SendRpcSetPlaybackRate(double playback_rate) {
+ auto rpc = std::make_unique<pb::RpcMessage>();
+ rpc->set_handle(remote_handle_);
+ rpc->set_proc(pb::RpcMessage::RPC_R_SETPLAYBACKRATE);
+ rpc->set_double_value(playback_rate);
+ rpc_broker_->SendMessageToRemote(std::move(rpc));
+ }
+
+ void SendRpcFlushUntil(uint32_t audio_count, uint32_t video_count) {
+ auto rpc = std::make_unique<pb::RpcMessage>();
+ rpc->set_handle(remote_handle_);
+ rpc->set_proc(pb::RpcMessage::RPC_R_FLUSHUNTIL);
+ pb::RendererFlushUntil* message = rpc->mutable_renderer_flushuntil_rpc();
+ message->set_audio_count(audio_count);
+ message->set_video_count(video_count);
+ message->set_callback_handle(rpc_handle_);
+ rpc_broker_->SendMessageToRemote(std::move(rpc));
+ }
+
+ void SendRpcStartPlayingFrom(base::TimeDelta time) {
+ auto rpc = std::make_unique<pb::RpcMessage>();
+ rpc->set_handle(remote_handle_);
+ rpc->set_proc(pb::RpcMessage::RPC_R_STARTPLAYINGFROM);
+ rpc->set_integer64_value(time.InMicroseconds());
+ rpc_broker_->SendMessageToRemote(std::move(rpc));
+ }
+
+ void SendRpcSetVolume(float volume) {
+ auto rpc = std::make_unique<pb::RpcMessage>();
+ rpc->set_handle(remote_handle_);
+ rpc->set_proc(pb::RpcMessage::RPC_R_SETVOLUME);
+ rpc->set_double_value(volume);
+ rpc_broker_->SendMessageToRemote(std::move(rpc));
+ }
+
+ private:
+ RpcBroker* const rpc_broker_;
+ const int rpc_handle_;
+ const int remote_handle_;
+};
+
+class ReceiverTest : public ::testing::Test {
+ public:
+ ReceiverTest() = default;
+
+ void SetUp() override {
+ mock_controller_ = MockReceiverController::GetInstance();
+ mock_controller_->Initialize(
+ mock_controller_->mock_remotee()->BindNewPipeAndPassRemote());
+ mock_remotee_ = mock_controller_->mock_remotee();
+
+ rpc_broker_ = mock_controller_->rpc_broker();
+ receiver_renderer_handle_ = rpc_broker_->GetUniqueHandle();
+
+ mock_sender_ = std::make_unique<StrictMock<MockSender>>(
+ rpc_broker_, receiver_renderer_handle_);
+
+ rpc_broker_->RegisterMessageReceiverCallback(
+ RpcBroker::kAcquireRendererHandle,
+ base::BindRepeating(&ReceiverTest::OnReceivedRpc,
+ weak_factory_.GetWeakPtr()));
+ }
+
+ void TearDown() override {
+ rpc_broker_->UnregisterMessageReceiverCallback(
+ RpcBroker::kAcquireRendererHandle);
+ }
+
+ void OnReceivedRpc(std::unique_ptr<media::remoting::pb::RpcMessage> message) {
+ DCHECK(message);
+ EXPECT_EQ(message->proc(),
+ media::remoting::pb::RpcMessage::RPC_ACQUIRE_RENDERER);
+ OnAcquireRenderer(std::move(message));
+ }
+
+ void OnAcquireRenderer(
+ std::unique_ptr<media::remoting::pb::RpcMessage> message) {
+ DCHECK(message->has_integer_value());
+ DCHECK(message->integer_value() != RpcBroker::kInvalidHandle);
+
+ if (sender_renderer_handle_ == RpcBroker::kInvalidHandle) {
+ sender_renderer_handle_ = message->integer_value();
+ SetRemoteHandle();
+ }
+ }
+
+ void OnAcquireRendererDone(int receiver_renderer_handle) {
+ DVLOG(3) << __func__
+ << ": Issues RPC_ACQUIRE_RENDERER_DONE RPC message. remote_handle="
+ << sender_renderer_handle_
+ << " rpc_handle=" << receiver_renderer_handle;
+ auto rpc = std::make_unique<pb::RpcMessage>();
+ rpc->set_handle(sender_renderer_handle_);
+ rpc->set_proc(pb::RpcMessage::RPC_ACQUIRE_RENDERER_DONE);
+ rpc->set_integer_value(receiver_renderer_handle);
+ rpc_broker_->SendMessageToRemote(std::move(rpc));
+ }
+
+ void CreateReceiver() {
+ auto renderer = std::make_unique<NiceMock<MockRenderer>>();
+ mock_renderer_ = renderer.get();
+ receiver_ = std::make_unique<Receiver>(
+ receiver_renderer_handle_, sender_renderer_handle_, mock_controller_,
+ base::ThreadTaskRunnerHandle::Get(), std::move(renderer),
+ base::BindOnce(&ReceiverTest::OnAcquireRendererDone,
+ weak_factory_.GetWeakPtr()));
+ }
+
+ void SetRemoteHandle() {
+ if (!receiver_)
+ return;
+ receiver_->SetRemoteHandle(sender_renderer_handle_);
+ }
+
+ void InitializeReceiver() {
+ receiver_->Initialize(&mock_media_resource_, nullptr,
+ base::BindOnce(&ReceiverTest::OnRendererInitialized,
+ weak_factory_.GetWeakPtr()));
+ }
+
+ MOCK_METHOD(void, OnRendererInitialized, (PipelineStatus));
+
+ base::test::TaskEnvironment task_environment_;
+
+ int sender_renderer_handle_ = RpcBroker::kInvalidHandle;
+ int receiver_renderer_handle_ = RpcBroker::kInvalidHandle;
+
+ MockMediaResource mock_media_resource_;
+ MockRenderer* mock_renderer_;
+ std::unique_ptr<MockSender> mock_sender_;
+
+ RpcBroker* rpc_broker_;
+ MockRemotee* mock_remotee_;
+ MockReceiverController* mock_controller_;
+ std::unique_ptr<Receiver> receiver_;
+
+ base::WeakPtrFactory<ReceiverTest> weak_factory_{this};
+};
+
+TEST_F(ReceiverTest, AcquireRendererBeforeCreateReceiver) {
+ mock_sender_->SendRpcAcquireRenderer();
+ EXPECT_CALL(*mock_sender_, AcquireRendererDone()).Times(1);
+ CreateReceiver();
+ task_environment_.RunUntilIdle();
+}
+
+TEST_F(ReceiverTest, AcquireRendererAfterCreateReceiver) {
+ CreateReceiver();
+ EXPECT_CALL(*mock_sender_, AcquireRendererDone()).Times(1);
+ mock_sender_->SendRpcAcquireRenderer();
+ task_environment_.RunUntilIdle();
+}
+
+// |Receiver::Initialize| will be called by the local pipeline, and the
+// |Receiver::RpcInitialize| will be called once it received the
+// RPC_R_INITIALIZE messages, so these two initialization functions are possible
+// to be called in difference orders.
+//
+// Call |Receiver::Initialize| first, then send RPC_R_INITIALIZE.
+TEST_F(ReceiverTest, InitializeBeforeRpcInitialize) {
+ EXPECT_CALL(*mock_sender_, AcquireRendererDone()).Times(1);
+ mock_sender_->SendRpcAcquireRenderer();
+ CreateReceiver();
+
+ EXPECT_CALL(*mock_renderer_,
+ OnInitialize(&mock_media_resource_, receiver_.get(), _))
+ .WillOnce(RunOnceCallback<2>(PipelineStatus::PIPELINE_OK));
+ EXPECT_CALL(*this, OnRendererInitialized(PipelineStatus::PIPELINE_OK))
+ .Times(1);
+ EXPECT_CALL(*mock_sender_, InitializeCallback(true)).Times(1);
+
+ InitializeReceiver();
+ mock_sender_->SendRpcInitialize();
+ task_environment_.RunUntilIdle();
+}
+
+// Send RPC_R_INITIALIZE first, then call |Receiver::Initialize|.
+TEST_F(ReceiverTest, InitializeAfterRpcInitialize) {
+ EXPECT_CALL(*mock_sender_, AcquireRendererDone()).Times(1);
+ mock_sender_->SendRpcAcquireRenderer();
+ CreateReceiver();
+
+ EXPECT_CALL(*mock_renderer_,
+ OnInitialize(&mock_media_resource_, receiver_.get(), _))
+ .WillOnce(RunOnceCallback<2>(PipelineStatus::PIPELINE_OK));
+ EXPECT_CALL(*this, OnRendererInitialized(PipelineStatus::PIPELINE_OK))
+ .Times(1);
+ EXPECT_CALL(*mock_sender_, InitializeCallback(true)).Times(1);
+
+ mock_sender_->SendRpcInitialize();
+ InitializeReceiver();
+ task_environment_.RunUntilIdle();
+}
+
+TEST_F(ReceiverTest, RpcRendererMessages) {
+ EXPECT_CALL(*mock_sender_, AcquireRendererDone()).Times(1);
+ mock_sender_->SendRpcAcquireRenderer();
+ CreateReceiver();
+ mock_sender_->SendRpcInitialize();
+ InitializeReceiver();
+ task_environment_.RunUntilIdle();
+
+ // SetVolume
+ const float volume = 0.5;
+ EXPECT_CALL(*mock_renderer_, SetVolume(volume)).Times(1);
+ mock_sender_->SendRpcSetVolume(volume);
+ task_environment_.RunUntilIdle();
+
+ EXPECT_CALL(*mock_sender_, OnTimeUpdate(_, _)).Times(AtLeast(1));
+
+ // SetPlaybackRate
+ const double playback_rate = 1.2;
+ EXPECT_CALL(*mock_renderer_, SetPlaybackRate(playback_rate)).Times(1);
+ mock_sender_->SendRpcSetPlaybackRate(playback_rate);
+ task_environment_.RunUntilIdle();
+
+ // Flush
+ const uint32_t flush_audio_count = 10;
+ const uint32_t flush_video_count = 20;
+ EXPECT_CALL(*mock_renderer_, OnFlush(_)).WillOnce(RunOnceCallback<0>());
+ EXPECT_CALL(*mock_sender_, FlushUntilCallback()).Times(1);
+ mock_sender_->SendRpcFlushUntil(flush_audio_count, flush_video_count);
+ task_environment_.RunUntilIdle();
+ EXPECT_EQ(flush_audio_count, mock_remotee_->flush_audio_count());
+ EXPECT_EQ(flush_video_count, mock_remotee_->flush_video_count());
+
+ // StartPlayingFrom
+ const base::TimeDelta time = base::TimeDelta::FromSeconds(100);
+ EXPECT_CALL(*mock_renderer_, StartPlayingFrom(time)).Times(1);
+ mock_sender_->SendRpcStartPlayingFrom(time);
+ task_environment_.RunUntilIdle();
+}
+
+TEST_F(ReceiverTest, RendererClientInterface) {
+ EXPECT_CALL(*mock_sender_, AcquireRendererDone()).Times(1);
+ mock_sender_->SendRpcAcquireRenderer();
+ CreateReceiver();
+ mock_sender_->SendRpcInitialize();
+ InitializeReceiver();
+ task_environment_.RunUntilIdle();
+
+ // OnBufferingStateChange
+ EXPECT_CALL(*mock_sender_, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH))
+ .Times(1);
+ receiver_->OnBufferingStateChange(BUFFERING_HAVE_ENOUGH,
+ BUFFERING_CHANGE_REASON_UNKNOWN);
+ task_environment_.RunUntilIdle();
+
+ // OnEnded
+ EXPECT_CALL(*mock_sender_, OnEnded()).Times(1);
+ receiver_->OnEnded();
+ task_environment_.RunUntilIdle();
+
+ // OnError
+ EXPECT_CALL(*mock_sender_, OnFatalError()).Times(1);
+ receiver_->OnError(PipelineStatus::AUDIO_RENDERER_ERROR);
+ task_environment_.RunUntilIdle();
+
+ // OnAudioConfigChange
+ const auto kNewAudioConfig = TestAudioConfig::Normal();
+ EXPECT_CALL(*mock_sender_,
+ OnAudioConfigChange(DecoderConfigEq(kNewAudioConfig)))
+ .Times(1);
+ receiver_->OnAudioConfigChange(kNewAudioConfig);
+ task_environment_.RunUntilIdle();
+
+ // OnVideoConfigChange
+ const auto kNewVideoConfig = TestVideoConfig::Normal();
+ EXPECT_CALL(*mock_sender_,
+ OnVideoConfigChange(DecoderConfigEq(kNewVideoConfig)))
+ .Times(1);
+ receiver_->OnVideoConfigChange(kNewVideoConfig);
+ task_environment_.RunUntilIdle();
+
+ // OnVideoNaturalSizeChange
+ const gfx::Size size(100, 200);
+ EXPECT_CALL(*mock_sender_, OnVideoNaturalSizeChange(size)).Times(1);
+ receiver_->OnVideoNaturalSizeChange(size);
+ task_environment_.RunUntilIdle();
+ EXPECT_EQ(size, mock_remotee_->changed_size());
+
+ // OnVideoOpacityChange
+ const bool opaque = true;
+ EXPECT_CALL(*mock_sender_, OnVideoOpacityChange(opaque)).Times(1);
+ receiver_->OnVideoOpacityChange(opaque);
+ task_environment_.RunUntilIdle();
+
+ // OnStatisticsUpdate
+ PipelineStatistics statistics;
+ statistics.audio_bytes_decoded = 100;
+ statistics.video_bytes_decoded = 200;
+ statistics.video_frames_decoded = 300;
+ statistics.video_frames_dropped = 400;
+ statistics.audio_memory_usage = 500;
+ statistics.video_memory_usage = 600;
+ EXPECT_CALL(*mock_sender_, OnStatisticsUpdate(statistics)).Times(1);
+ receiver_->OnStatisticsUpdate(statistics);
+ task_environment_.RunUntilIdle();
+
+ // OnWaiting
+ EXPECT_CALL(*mock_sender_, OnWaiting()).Times(1);
+ receiver_->OnWaiting(WaitingReason::kNoDecryptionKey);
+ task_environment_.RunUntilIdle();
+}
+
+} // namespace remoting
+} // namespace media