// 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/stream_provider.h" #include "base/test/task_environment.h" #include "media/base/audio_decoder_config.h" #include "media/base/demuxer_stream.h" #include "media/base/media_util.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 testing::NiceMock; namespace { constexpr int kBufferSize = 10; } // namespace namespace media { namespace remoting { class StreamProviderTest : public testing::Test { public: StreamProviderTest() : audio_config_(TestAudioConfig::Normal()), video_config_(TestVideoConfig::Normal()), audio_buffer_(new DecoderBuffer(kBufferSize)), video_buffer_(DecoderBuffer::CreateEOSBuffer()) {} void SetUp() override { mock_controller_ = MockReceiverController::GetInstance(); mock_controller_->Initialize( mock_controller_->mock_remotee()->BindNewPipeAndPassRemote()); mock_remotee_ = mock_controller_->mock_remotee(); stream_provider_ = std::make_unique( mock_controller_, base::ThreadTaskRunnerHandle::Get()); rpc_broker_ = mock_controller_->rpc_broker(); sender_audio_demuxer_stream_handle_ = rpc_broker_->GetUniqueHandle(); sender_video_demuxer_stream_handle_ = rpc_broker_->GetUniqueHandle(); rpc_broker_->RegisterMessageReceiverCallback( sender_audio_demuxer_stream_handle_, base::BindRepeating(&StreamProviderTest::OnDemuxerStreamReceivedRpc, base::Unretained(this), DemuxerStream::Type::AUDIO)); rpc_broker_->RegisterMessageReceiverCallback( sender_video_demuxer_stream_handle_, base::BindRepeating(&StreamProviderTest::OnDemuxerStreamReceivedRpc, base::Unretained(this), DemuxerStream::Type::VIDEO)); } void TearDown() override { stream_provider_.reset(); task_environment_.RunUntilIdle(); } void OnDemuxerStreamReceivedRpc(DemuxerStream::Type type, std::unique_ptr message) { DCHECK(message); switch (message->proc()) { case pb::RpcMessage::RPC_DS_INITIALIZE: if (type == DemuxerStream::Type::AUDIO) { receiver_audio_demuxer_stream_handle_ = message->integer_value(); } else if (type == DemuxerStream::Type::VIDEO) { receiver_video_demuxer_stream_handle_ = message->integer_value(); } else { NOTREACHED(); } RpcInitializeCallback(type); break; case pb::RpcMessage::RPC_DS_READUNTIL: ReadUntil(type); break; default: DVLOG(1) << __func__ << "Unknown supported message."; } } void RpcInitializeCallback(DemuxerStream::Type type) { // Issues RPC_DS_INITIALIZE_CALLBACK RPC message. auto rpc = std::make_unique(); rpc->set_handle(type == DemuxerStream::Type::AUDIO ? receiver_audio_demuxer_stream_handle_ : receiver_video_demuxer_stream_handle_); rpc->set_proc(pb::RpcMessage::RPC_DS_INITIALIZE_CALLBACK); auto* init_cb_message = rpc->mutable_demuxerstream_initializecb_rpc(); init_cb_message->set_type(type); switch (type) { case DemuxerStream::Type::AUDIO: { pb::AudioDecoderConfig* audio_message = init_cb_message->mutable_audio_decoder_config(); ConvertAudioDecoderConfigToProto(audio_config_, audio_message); break; } case DemuxerStream::Type::VIDEO: { pb::VideoDecoderConfig* video_message = init_cb_message->mutable_video_decoder_config(); ConvertVideoDecoderConfigToProto(video_config_, video_message); break; } default: NOTREACHED(); } rpc_broker_->SendMessageToRemote(std::move(rpc)); } void ReadUntil(DemuxerStream::Type type) { switch (type) { case DemuxerStream::Type::AUDIO: SendAudioFrame(); break; case DemuxerStream::Type::VIDEO: SendVideoFrame(); break; default: NOTREACHED(); } } void SendRpcAcquireDemuxer() { auto rpc = std::make_unique(); rpc->set_handle(RpcBroker::kAcquireDemuxerHandle); rpc->set_proc(pb::RpcMessage::RPC_ACQUIRE_DEMUXER); pb::AcquireDemuxer* message = rpc->mutable_acquire_demuxer_rpc(); message->set_audio_demuxer_handle(sender_audio_demuxer_stream_handle_); message->set_video_demuxer_handle(sender_video_demuxer_stream_handle_); rpc_broker_->SendMessageToRemote(std::move(rpc)); } void OnStreamProviderInitialized(PipelineStatus status) { EXPECT_EQ(PipelineStatus::PIPELINE_OK, status); stream_provider_initialized_ = true; audio_stream_ = stream_provider_->GetFirstStream(DemuxerStream::Type::AUDIO); video_stream_ = stream_provider_->GetFirstStream(DemuxerStream::Type::VIDEO); EXPECT_TRUE(audio_stream_); EXPECT_TRUE(video_stream_); } void InitializeDemuxer() { DCHECK(stream_provider_); stream_provider_->Initialize( nullptr, base::BindOnce(&StreamProviderTest::OnStreamProviderInitialized, base::Unretained(this))); } void SendAudioFrame() { mock_remotee_->SendAudioFrame(0, audio_buffer_); SendRpcReadUntilCallback(DemuxerStream::Type::AUDIO); } void SendVideoFrame() { mock_remotee_->SendVideoFrame(0, video_buffer_); SendRpcReadUntilCallback(DemuxerStream::Type::VIDEO); } void SendRpcReadUntilCallback(DemuxerStream::Type type) { // Issues RPC_DS_READUNTIL_CALLBACK RPC message. auto rpc = std::make_unique(); rpc->set_handle(type == DemuxerStream::Type::AUDIO ? receiver_audio_demuxer_stream_handle_ : receiver_video_demuxer_stream_handle_); rpc->set_proc(pb::RpcMessage::RPC_DS_READUNTIL_CALLBACK); auto* message = rpc->mutable_demuxerstream_readuntilcb_rpc(); message->set_count(0); message->set_status( ToProtoDemuxerStreamStatus(DemuxerStream::Status::kOk).value()); rpc_broker_->SendMessageToRemote(std::move(rpc)); } void FlushUntil(uint32_t flush_audio_count, uint32_t flush_video_count) { mock_remotee_->OnFlushUntil(flush_audio_count, flush_video_count); } uint32_t GetAudioCurrentFrameCount() { return stream_provider_->audio_stream_->current_frame_count_; } uint32_t GetVideoCurrentFrameCount() { return stream_provider_->video_stream_->current_frame_count_; } void OnBufferReadFromDemuxerStream(DemuxerStream::Type type, DemuxerStream::Status status, scoped_refptr buffer) { EXPECT_EQ(status, DemuxerStream::Status::kOk); switch (type) { case DemuxerStream::Type::AUDIO: received_audio_buffer_ = buffer; break; case DemuxerStream::Type::VIDEO: received_video_buffer_ = buffer; break; default: NOTREACHED(); } } base::test::TaskEnvironment task_environment_; AudioDecoderConfig audio_config_; VideoDecoderConfig video_config_; DemuxerStream* audio_stream_; DemuxerStream* video_stream_; scoped_refptr audio_buffer_; scoped_refptr video_buffer_; bool stream_provider_initialized_{false}; scoped_refptr received_audio_buffer_; scoped_refptr received_video_buffer_; int sender_audio_demuxer_stream_handle_ = RpcBroker::kInvalidHandle; int sender_video_demuxer_stream_handle_ = RpcBroker::kInvalidHandle; int receiver_audio_demuxer_stream_handle_ = RpcBroker::kInvalidHandle; int receiver_video_demuxer_stream_handle_ = RpcBroker::kInvalidHandle; RpcBroker* rpc_broker_; MockReceiverController* mock_controller_; MockRemotee* mock_remotee_; std::unique_ptr stream_provider_; }; TEST_F(StreamProviderTest, InitializeBeforeRpcAcquireDemuxer) { InitializeDemuxer(); EXPECT_FALSE(stream_provider_initialized_); SendRpcAcquireDemuxer(); task_environment_.RunUntilIdle(); EXPECT_TRUE(mock_remotee_->audio_stream_.is_bound()); EXPECT_TRUE(mock_remotee_->video_stream_.is_bound()); EXPECT_TRUE(stream_provider_initialized_); // 1 audio stream and 1 video stream EXPECT_EQ(size_t(2), stream_provider_->GetAllStreams().size()); } TEST_F(StreamProviderTest, InitializeAfterRpcAcquireDemuxer) { SendRpcAcquireDemuxer(); EXPECT_FALSE(stream_provider_initialized_); InitializeDemuxer(); task_environment_.RunUntilIdle(); EXPECT_TRUE(mock_remotee_->audio_stream_.is_bound()); EXPECT_TRUE(mock_remotee_->video_stream_.is_bound()); EXPECT_TRUE(stream_provider_initialized_); // 1 audio stream and 1 video stream EXPECT_EQ(size_t(2), stream_provider_->GetAllStreams().size()); } TEST_F(StreamProviderTest, ReadBuffer) { InitializeDemuxer(); SendRpcAcquireDemuxer(); task_environment_.RunUntilIdle(); EXPECT_TRUE(mock_remotee_->audio_stream_.is_bound()); EXPECT_TRUE(mock_remotee_->video_stream_.is_bound()); EXPECT_TRUE(stream_provider_initialized_); audio_stream_->Read( base::BindOnce(&StreamProviderTest::OnBufferReadFromDemuxerStream, base::Unretained(this), DemuxerStream::Type::AUDIO)); task_environment_.RunUntilIdle(); EXPECT_EQ(audio_buffer_->data_size(), received_audio_buffer_->data_size()); EXPECT_EQ(audio_buffer_->end_of_stream(), received_audio_buffer_->end_of_stream()); EXPECT_EQ(audio_buffer_->is_key_frame(), received_audio_buffer_->is_key_frame()); video_stream_->Read( base::BindOnce(&StreamProviderTest::OnBufferReadFromDemuxerStream, base::Unretained(this), DemuxerStream::Type::VIDEO)); task_environment_.RunUntilIdle(); EXPECT_EQ(video_buffer_->end_of_stream(), received_video_buffer_->end_of_stream()); } TEST_F(StreamProviderTest, FlushUntil) { InitializeDemuxer(); SendRpcAcquireDemuxer(); task_environment_.RunUntilIdle(); EXPECT_TRUE(mock_remotee_->audio_stream_.is_bound()); EXPECT_TRUE(mock_remotee_->video_stream_.is_bound()); EXPECT_TRUE(stream_provider_initialized_); uint32_t flush_audio_count = 10; uint32_t flush_video_count = 20; FlushUntil(flush_audio_count, flush_video_count); task_environment_.RunUntilIdle(); EXPECT_EQ(GetAudioCurrentFrameCount(), flush_audio_count); EXPECT_EQ(GetVideoCurrentFrameCount(), flush_video_count); } } // namespace remoting } // namespace media