1 // Copyright 2020 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/remoting/receiver.h"
9 #include "base/check.h"
10 #include "base/memory/raw_ptr.h"
11 #include "base/task/single_thread_task_runner.h"
12 #include "base/test/gmock_callback_support.h"
13 #include "base/test/task_environment.h"
14 #include "media/base/audio_decoder_config.h"
15 #include "media/base/media_util.h"
16 #include "media/base/mock_filters.h"
17 #include "media/base/renderer.h"
18 #include "media/base/test_helpers.h"
19 #include "media/base/video_decoder_config.h"
20 #include "media/cast/openscreen/remoting_proto_enum_utils.h"
21 #include "media/cast/openscreen/remoting_proto_utils.h"
22 #include "media/remoting/mock_receiver_controller.h"
23 #include "testing/gmock/include/gmock/gmock.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25 #include "third_party/abseil-cpp/absl/types/optional.h"
27 using base::test::RunOnceCallback;
28 using openscreen::cast::RpcMessenger;
30 using testing::AtLeast;
31 using testing::NiceMock;
32 using testing::StrictMock;
39 MockSender(RpcMessenger* rpc_messenger, int remote_handle)
40 : rpc_messenger_(rpc_messenger),
41 rpc_handle_(rpc_messenger->GetUniqueHandle()),
42 remote_handle_(remote_handle) {
43 rpc_messenger_->RegisterMessageReceiverCallback(
44 rpc_handle_, [this](std::unique_ptr<openscreen::cast::RpcMessage> rpc) {
45 this->OnReceivedRpc(std::move(rpc));
49 MOCK_METHOD(void, AcquireRendererDone, ());
50 MOCK_METHOD(void, InitializeCallback, (bool));
51 MOCK_METHOD(void, FlushUntilCallback, ());
52 MOCK_METHOD(void, OnTimeUpdate, (int64_t, int64_t));
53 MOCK_METHOD(void, OnBufferingStateChange, (BufferingState));
54 MOCK_METHOD(void, OnEnded, ());
55 MOCK_METHOD(void, OnFatalError, ());
56 MOCK_METHOD(void, OnAudioConfigChange, (AudioDecoderConfig));
57 MOCK_METHOD(void, OnVideoConfigChange, (VideoDecoderConfig));
58 MOCK_METHOD(void, OnVideoNaturalSizeChange, (gfx::Size));
59 MOCK_METHOD(void, OnVideoOpacityChange, (bool));
60 MOCK_METHOD(void, OnStatisticsUpdate, (PipelineStatistics));
61 MOCK_METHOD(void, OnWaiting, ());
63 void OnReceivedRpc(std::unique_ptr<openscreen::cast::RpcMessage> message) {
65 switch (message->proc()) {
66 case openscreen::cast::RpcMessage::RPC_ACQUIRE_RENDERER_DONE:
67 AcquireRendererDone();
69 case openscreen::cast::RpcMessage::RPC_R_INITIALIZE_CALLBACK:
70 InitializeCallback(message->boolean_value());
72 case openscreen::cast::RpcMessage::RPC_R_FLUSHUNTIL_CALLBACK:
75 case openscreen::cast::RpcMessage::RPC_RC_ONTIMEUPDATE: {
76 DCHECK(message->has_rendererclient_ontimeupdate_rpc());
77 const int64_t time_usec =
78 message->rendererclient_ontimeupdate_rpc().time_usec();
79 const int64_t max_time_usec =
80 message->rendererclient_ontimeupdate_rpc().max_time_usec();
81 OnTimeUpdate(time_usec, max_time_usec);
84 case openscreen::cast::RpcMessage::RPC_RC_ONBUFFERINGSTATECHANGE: {
85 absl::optional<BufferingState> state =
86 media::cast::ToMediaBufferingState(
87 message->rendererclient_onbufferingstatechange_rpc().state());
88 if (state.has_value())
89 OnBufferingStateChange(state.value());
92 case openscreen::cast::RpcMessage::RPC_RC_ONENDED:
95 case openscreen::cast::RpcMessage::RPC_RC_ONERROR:
98 case openscreen::cast::RpcMessage::RPC_RC_ONAUDIOCONFIGCHANGE: {
99 DCHECK(message->has_rendererclient_onaudioconfigchange_rpc());
100 const auto* audio_config_message =
101 message->mutable_rendererclient_onaudioconfigchange_rpc();
102 const openscreen::cast::AudioDecoderConfig pb_audio_config =
103 audio_config_message->audio_decoder_config();
104 AudioDecoderConfig out_audio_config;
105 media::cast::ConvertProtoToAudioDecoderConfig(pb_audio_config,
107 DCHECK(out_audio_config.IsValidConfig());
108 OnAudioConfigChange(out_audio_config);
111 case openscreen::cast::RpcMessage::RPC_RC_ONVIDEOCONFIGCHANGE: {
112 DCHECK(message->has_rendererclient_onvideoconfigchange_rpc());
113 const auto* video_config_message =
114 message->mutable_rendererclient_onvideoconfigchange_rpc();
115 const openscreen::cast::VideoDecoderConfig pb_video_config =
116 video_config_message->video_decoder_config();
117 VideoDecoderConfig out_video_config;
118 media::cast::ConvertProtoToVideoDecoderConfig(pb_video_config,
120 DCHECK(out_video_config.IsValidConfig());
122 OnVideoConfigChange(out_video_config);
125 case openscreen::cast::RpcMessage::RPC_RC_ONVIDEONATURALSIZECHANGE: {
126 DCHECK(message->has_rendererclient_onvideonatualsizechange_rpc());
129 message->rendererclient_onvideonatualsizechange_rpc().width(),
130 message->rendererclient_onvideonatualsizechange_rpc().height());
131 OnVideoNaturalSizeChange(size);
134 case openscreen::cast::RpcMessage::RPC_RC_ONVIDEOOPACITYCHANGE:
135 OnVideoOpacityChange(message->boolean_value());
137 case openscreen::cast::RpcMessage::RPC_RC_ONSTATISTICSUPDATE: {
138 DCHECK(message->has_rendererclient_onstatisticsupdate_rpc());
139 auto rpc_message = message->rendererclient_onstatisticsupdate_rpc();
140 PipelineStatistics statistics;
141 statistics.audio_bytes_decoded = rpc_message.audio_bytes_decoded();
142 statistics.video_bytes_decoded = rpc_message.video_bytes_decoded();
143 statistics.video_frames_decoded = rpc_message.video_frames_decoded();
144 statistics.video_frames_dropped = rpc_message.video_frames_dropped();
145 statistics.audio_memory_usage = rpc_message.audio_memory_usage();
146 statistics.video_memory_usage = rpc_message.video_memory_usage();
147 OnStatisticsUpdate(statistics);
152 VLOG(1) << "Unknown RPC: " << message->proc();
156 void SendRpcAcquireRenderer() {
157 openscreen::cast::RpcMessage rpc;
158 rpc.set_handle(RpcMessenger::kAcquireRendererHandle);
159 rpc.set_proc(openscreen::cast::RpcMessage::RPC_ACQUIRE_RENDERER);
160 rpc.set_integer_value(rpc_handle_);
161 rpc_messenger_->SendMessageToRemote(rpc);
164 void SendRpcInitialize() {
165 openscreen::cast::RpcMessage rpc;
166 rpc.set_handle(remote_handle_);
167 rpc.set_proc(openscreen::cast::RpcMessage::RPC_R_INITIALIZE);
168 rpc_messenger_->SendMessageToRemote(rpc);
171 void SendRpcSetPlaybackRate(double playback_rate) {
172 openscreen::cast::RpcMessage rpc;
173 rpc.set_handle(remote_handle_);
174 rpc.set_proc(openscreen::cast::RpcMessage::RPC_R_SETPLAYBACKRATE);
175 rpc.set_double_value(playback_rate);
176 rpc_messenger_->SendMessageToRemote(rpc);
179 void SendRpcFlushUntil(uint32_t audio_count, uint32_t video_count) {
180 openscreen::cast::RpcMessage rpc;
181 rpc.set_handle(remote_handle_);
182 rpc.set_proc(openscreen::cast::RpcMessage::RPC_R_FLUSHUNTIL);
183 openscreen::cast::RendererFlushUntil* message =
184 rpc.mutable_renderer_flushuntil_rpc();
185 message->set_audio_count(audio_count);
186 message->set_video_count(video_count);
187 message->set_callback_handle(rpc_handle_);
188 rpc_messenger_->SendMessageToRemote(rpc);
191 void SendRpcStartPlayingFrom(base::TimeDelta time) {
192 openscreen::cast::RpcMessage rpc;
193 rpc.set_handle(remote_handle_);
194 rpc.set_proc(openscreen::cast::RpcMessage::RPC_R_STARTPLAYINGFROM);
195 rpc.set_integer64_value(time.InMicroseconds());
196 rpc_messenger_->SendMessageToRemote(rpc);
199 void SendRpcSetVolume(float volume) {
200 openscreen::cast::RpcMessage rpc;
201 rpc.set_handle(remote_handle_);
202 rpc.set_proc(openscreen::cast::RpcMessage::RPC_R_SETVOLUME);
203 rpc.set_double_value(volume);
204 rpc_messenger_->SendMessageToRemote(rpc);
208 const raw_ptr<RpcMessenger> rpc_messenger_;
209 const int rpc_handle_;
210 const int remote_handle_;
213 class ReceiverTest : public ::testing::Test {
215 ReceiverTest() = default;
217 void SetUp() override {
218 mock_controller_ = MockReceiverController::GetInstance();
219 mock_controller_->Initialize(
220 mock_controller_->mock_remotee()->BindNewPipeAndPassRemote());
221 mock_remotee_ = mock_controller_->mock_remotee();
223 rpc_messenger_ = mock_controller_->rpc_messenger();
224 receiver_renderer_handle_ = rpc_messenger_->GetUniqueHandle();
226 mock_sender_ = std::make_unique<StrictMock<MockSender>>(
227 rpc_messenger_, receiver_renderer_handle_);
229 rpc_messenger_->RegisterMessageReceiverCallback(
230 RpcMessenger::kAcquireRendererHandle,
231 [ptr = weak_factory_.GetWeakPtr()](
232 std::unique_ptr<openscreen::cast::RpcMessage> message) {
234 ptr->OnReceivedRpc(std::move(message));
239 void TearDown() override {
240 rpc_messenger_->UnregisterMessageReceiverCallback(
241 RpcMessenger::kAcquireRendererHandle);
244 void OnReceivedRpc(std::unique_ptr<openscreen::cast::RpcMessage> message) {
246 EXPECT_EQ(message->proc(),
247 openscreen::cast::RpcMessage::RPC_ACQUIRE_RENDERER);
248 OnAcquireRenderer(std::move(message));
251 void OnAcquireRenderer(
252 std::unique_ptr<openscreen::cast::RpcMessage> message) {
253 DCHECK(message->has_integer_value());
254 DCHECK(message->integer_value() != RpcMessenger::kInvalidHandle);
256 if (sender_renderer_handle_ == RpcMessenger::kInvalidHandle) {
257 sender_renderer_handle_ = message->integer_value();
262 void OnAcquireRendererDone(int receiver_renderer_handle) {
264 << ": Issues RPC_ACQUIRE_RENDERER_DONE RPC message. remote_handle="
265 << sender_renderer_handle_
266 << " rpc_handle=" << receiver_renderer_handle;
267 openscreen::cast::RpcMessage rpc;
268 rpc.set_handle(sender_renderer_handle_);
269 rpc.set_proc(openscreen::cast::RpcMessage::RPC_ACQUIRE_RENDERER_DONE);
270 rpc.set_integer_value(receiver_renderer_handle);
271 rpc_messenger_->SendMessageToRemote(rpc);
274 void CreateReceiver() {
275 auto renderer = std::make_unique<NiceMock<MockRenderer>>();
276 mock_renderer_ = renderer.get();
277 receiver_ = std::make_unique<Receiver>(
278 receiver_renderer_handle_, sender_renderer_handle_, mock_controller_,
279 base::SingleThreadTaskRunner::GetCurrentDefault(), std::move(renderer),
280 base::BindOnce(&ReceiverTest::OnAcquireRendererDone,
281 weak_factory_.GetWeakPtr()));
284 void SetRemoteHandle() {
287 receiver_->SetRemoteHandle(sender_renderer_handle_);
290 void InitializeReceiver() {
291 receiver_->Initialize(&mock_media_resource_, nullptr,
292 base::BindOnce(&ReceiverTest::OnRendererInitialized,
293 weak_factory_.GetWeakPtr()));
296 MOCK_METHOD(void, OnRendererInitialized, (PipelineStatus));
298 base::test::TaskEnvironment task_environment_;
300 int sender_renderer_handle_ = RpcMessenger::kInvalidHandle;
301 int receiver_renderer_handle_ = RpcMessenger::kInvalidHandle;
303 MockMediaResource mock_media_resource_;
304 std::unique_ptr<MockSender> mock_sender_;
305 raw_ptr<RpcMessenger> rpc_messenger_ = nullptr;
306 raw_ptr<MockRemotee> mock_remotee_;
307 raw_ptr<MockReceiverController> mock_controller_ = nullptr;
308 std::unique_ptr<Receiver> receiver_;
309 raw_ptr<MockRenderer> mock_renderer_ = nullptr;
311 base::WeakPtrFactory<ReceiverTest> weak_factory_{this};
314 TEST_F(ReceiverTest, AcquireRendererBeforeCreateReceiver) {
315 mock_sender_->SendRpcAcquireRenderer();
316 EXPECT_CALL(*mock_sender_, AcquireRendererDone()).Times(1);
318 task_environment_.RunUntilIdle();
321 TEST_F(ReceiverTest, AcquireRendererAfterCreateReceiver) {
323 EXPECT_CALL(*mock_sender_, AcquireRendererDone()).Times(1);
324 mock_sender_->SendRpcAcquireRenderer();
325 task_environment_.RunUntilIdle();
328 // |Receiver::Initialize| will be called by the local pipeline, and the
329 // |Receiver::RpcInitialize| will be called once it received the
330 // RPC_R_INITIALIZE messages, so these two initialization functions are possible
331 // to be called in difference orders.
333 // Call |Receiver::Initialize| first, then send RPC_R_INITIALIZE.
334 TEST_F(ReceiverTest, InitializeBeforeRpcInitialize) {
335 EXPECT_CALL(*mock_sender_, AcquireRendererDone()).Times(1);
336 mock_sender_->SendRpcAcquireRenderer();
339 EXPECT_CALL(*mock_renderer_,
340 OnInitialize(&mock_media_resource_, receiver_.get(), _))
341 .WillOnce(RunOnceCallback<2>(PIPELINE_OK));
342 EXPECT_CALL(*this, OnRendererInitialized(HasStatusCode(PIPELINE_OK)))
344 EXPECT_CALL(*mock_sender_, InitializeCallback(true)).Times(1);
346 InitializeReceiver();
347 mock_sender_->SendRpcInitialize();
348 task_environment_.RunUntilIdle();
351 // Send RPC_R_INITIALIZE first, then call |Receiver::Initialize|.
352 TEST_F(ReceiverTest, InitializeAfterRpcInitialize) {
353 EXPECT_CALL(*mock_sender_, AcquireRendererDone()).Times(1);
354 mock_sender_->SendRpcAcquireRenderer();
357 EXPECT_CALL(*mock_renderer_,
358 OnInitialize(&mock_media_resource_, receiver_.get(), _))
359 .WillOnce(RunOnceCallback<2>(PIPELINE_OK));
360 EXPECT_CALL(*this, OnRendererInitialized(HasStatusCode(PIPELINE_OK)))
362 EXPECT_CALL(*mock_sender_, InitializeCallback(true)).Times(1);
364 mock_sender_->SendRpcInitialize();
365 InitializeReceiver();
366 task_environment_.RunUntilIdle();
369 TEST_F(ReceiverTest, RpcRendererMessages) {
370 EXPECT_CALL(*mock_sender_, AcquireRendererDone()).Times(1);
371 mock_sender_->SendRpcAcquireRenderer();
373 mock_sender_->SendRpcInitialize();
374 InitializeReceiver();
375 task_environment_.RunUntilIdle();
378 const float volume = 0.5;
379 EXPECT_CALL(*mock_renderer_, SetVolume(volume)).Times(1);
380 mock_sender_->SendRpcSetVolume(volume);
381 task_environment_.RunUntilIdle();
383 EXPECT_CALL(*mock_sender_, OnTimeUpdate(_, _)).Times(AtLeast(1));
386 const double playback_rate = 1.2;
387 EXPECT_CALL(*mock_renderer_, SetPlaybackRate(playback_rate)).Times(1);
388 mock_sender_->SendRpcSetPlaybackRate(playback_rate);
389 task_environment_.RunUntilIdle();
392 const uint32_t flush_audio_count = 10;
393 const uint32_t flush_video_count = 20;
394 EXPECT_CALL(*mock_renderer_, OnFlush(_)).WillOnce(RunOnceCallback<0>());
395 EXPECT_CALL(*mock_sender_, FlushUntilCallback()).Times(1);
396 mock_sender_->SendRpcFlushUntil(flush_audio_count, flush_video_count);
397 task_environment_.RunUntilIdle();
398 EXPECT_EQ(flush_audio_count, mock_remotee_->flush_audio_count());
399 EXPECT_EQ(flush_video_count, mock_remotee_->flush_video_count());
402 const base::TimeDelta time = base::Seconds(100);
403 EXPECT_CALL(*mock_renderer_, StartPlayingFrom(time)).Times(1);
404 mock_sender_->SendRpcStartPlayingFrom(time);
405 task_environment_.RunUntilIdle();
408 TEST_F(ReceiverTest, RendererClientInterface) {
409 EXPECT_CALL(*mock_sender_, AcquireRendererDone()).Times(1);
410 mock_sender_->SendRpcAcquireRenderer();
412 mock_sender_->SendRpcInitialize();
413 InitializeReceiver();
414 task_environment_.RunUntilIdle();
416 // OnBufferingStateChange
417 EXPECT_CALL(*mock_sender_, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH))
419 receiver_->OnBufferingStateChange(BUFFERING_HAVE_ENOUGH,
420 BUFFERING_CHANGE_REASON_UNKNOWN);
421 task_environment_.RunUntilIdle();
424 EXPECT_CALL(*mock_sender_, OnEnded()).Times(1);
425 receiver_->OnEnded();
426 task_environment_.RunUntilIdle();
429 EXPECT_CALL(*mock_sender_, OnFatalError()).Times(1);
430 receiver_->OnError(AUDIO_RENDERER_ERROR);
431 task_environment_.RunUntilIdle();
433 // OnAudioConfigChange
434 const auto kNewAudioConfig = TestAudioConfig::Normal();
435 EXPECT_CALL(*mock_sender_,
436 OnAudioConfigChange(DecoderConfigEq(kNewAudioConfig)))
438 receiver_->OnAudioConfigChange(kNewAudioConfig);
439 task_environment_.RunUntilIdle();
441 // OnVideoConfigChange
442 const auto kNewVideoConfig = TestVideoConfig::Normal();
443 EXPECT_CALL(*mock_sender_,
444 OnVideoConfigChange(DecoderConfigEq(kNewVideoConfig)))
446 receiver_->OnVideoConfigChange(kNewVideoConfig);
447 task_environment_.RunUntilIdle();
449 // OnVideoNaturalSizeChange
450 const gfx::Size size(100, 200);
451 EXPECT_CALL(*mock_sender_, OnVideoNaturalSizeChange(size)).Times(1);
452 receiver_->OnVideoNaturalSizeChange(size);
453 task_environment_.RunUntilIdle();
454 EXPECT_EQ(size, mock_remotee_->changed_size());
456 // OnVideoOpacityChange
457 const bool opaque = true;
458 EXPECT_CALL(*mock_sender_, OnVideoOpacityChange(opaque)).Times(1);
459 receiver_->OnVideoOpacityChange(opaque);
460 task_environment_.RunUntilIdle();
462 // OnStatisticsUpdate
463 PipelineStatistics statistics;
464 statistics.audio_bytes_decoded = 100;
465 statistics.video_bytes_decoded = 200;
466 statistics.video_frames_decoded = 300;
467 statistics.video_frames_dropped = 400;
468 statistics.audio_memory_usage = 500;
469 statistics.video_memory_usage = 600;
470 EXPECT_CALL(*mock_sender_, OnStatisticsUpdate(statistics)).Times(1);
471 receiver_->OnStatisticsUpdate(statistics);
472 task_environment_.RunUntilIdle();
475 } // namespace remoting