/* * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ #include #include #include #include #include "api/test/create_frame_generator.h" #include "call/call.h" #include "call/fake_network_pipe.h" #include "call/simulated_network.h" #include "rtc_base/checks.h" #include "rtc_base/event.h" #include "rtc_base/logging.h" #include "rtc_base/synchronization/mutex.h" #include "rtc_base/task_queue_for_test.h" #include "rtc_base/thread_annotations.h" #include "test/call_test.h" #include "test/direct_transport.h" #include "test/encoder_settings.h" #include "test/fake_decoder.h" #include "test/fake_encoder.h" #include "test/frame_generator_capturer.h" #include "test/gtest.h" namespace webrtc { namespace { // Note: If you consider to re-use this class, think twice and instead consider // writing tests that don't depend on the logging system. class LogObserver { public: LogObserver() { rtc::LogMessage::AddLogToStream(&callback_, rtc::LS_INFO); } ~LogObserver() { rtc::LogMessage::RemoveLogToStream(&callback_); } void PushExpectedLogLine(const std::string& expected_log_line) { callback_.PushExpectedLogLine(expected_log_line); } bool Wait() { return callback_.Wait(); } private: class Callback : public rtc::LogSink { public: void OnLogMessage(const std::string& message) override { MutexLock lock(&mutex_); // Ignore log lines that are due to missing AST extensions, these are // logged when we switch back from AST to TOF until the wrapping bitrate // estimator gives up on using AST. if (message.find("BitrateEstimator") != std::string::npos && message.find("packet is missing") == std::string::npos) { received_log_lines_.push_back(message); } int num_popped = 0; while (!received_log_lines_.empty() && !expected_log_lines_.empty()) { std::string a = received_log_lines_.front(); std::string b = expected_log_lines_.front(); received_log_lines_.pop_front(); expected_log_lines_.pop_front(); num_popped++; EXPECT_TRUE(a.find(b) != std::string::npos) << a << " != " << b; } if (expected_log_lines_.empty()) { if (num_popped > 0) { done_.Set(); } return; } } bool Wait() { return done_.Wait(test::CallTest::kDefaultTimeoutMs); } void PushExpectedLogLine(const std::string& expected_log_line) { MutexLock lock(&mutex_); expected_log_lines_.push_back(expected_log_line); } private: typedef std::list Strings; Mutex mutex_; Strings received_log_lines_ RTC_GUARDED_BY(mutex_); Strings expected_log_lines_ RTC_GUARDED_BY(mutex_); rtc::Event done_; }; Callback callback_; }; } // namespace static const int kTOFExtensionId = 4; static const int kASTExtensionId = 5; class BitrateEstimatorTest : public test::CallTest { public: BitrateEstimatorTest() : receive_config_(nullptr) {} virtual ~BitrateEstimatorTest() { EXPECT_TRUE(streams_.empty()); } virtual void SetUp() { SendTask(RTC_FROM_HERE, task_queue(), [this]() { CreateCalls(); send_transport_.reset(new test::DirectTransport( task_queue(), std::make_unique( Clock::GetRealTimeClock(), std::make_unique( BuiltInNetworkBehaviorConfig())), sender_call_.get(), payload_type_map_)); send_transport_->SetReceiver(receiver_call_->Receiver()); receive_transport_.reset(new test::DirectTransport( task_queue(), std::make_unique( Clock::GetRealTimeClock(), std::make_unique( BuiltInNetworkBehaviorConfig())), receiver_call_.get(), payload_type_map_)); receive_transport_->SetReceiver(sender_call_->Receiver()); VideoSendStream::Config video_send_config(send_transport_.get()); video_send_config.rtp.ssrcs.push_back(kVideoSendSsrcs[0]); video_send_config.encoder_settings.encoder_factory = &fake_encoder_factory_; video_send_config.encoder_settings.bitrate_allocator_factory = bitrate_allocator_factory_.get(); video_send_config.rtp.payload_name = "FAKE"; video_send_config.rtp.payload_type = kFakeVideoSendPayloadType; SetVideoSendConfig(video_send_config); VideoEncoderConfig video_encoder_config; test::FillEncoderConfiguration(kVideoCodecVP8, 1, &video_encoder_config); SetVideoEncoderConfig(video_encoder_config); receive_config_ = VideoReceiveStream::Config(receive_transport_.get()); // receive_config_.decoders will be set by every stream separately. receive_config_.rtp.remote_ssrc = GetVideoSendConfig()->rtp.ssrcs[0]; receive_config_.rtp.local_ssrc = kReceiverLocalVideoSsrc; receive_config_.rtp.extensions.push_back( RtpExtension(RtpExtension::kTimestampOffsetUri, kTOFExtensionId)); receive_config_.rtp.extensions.push_back( RtpExtension(RtpExtension::kAbsSendTimeUri, kASTExtensionId)); }); } virtual void TearDown() { SendTask(RTC_FROM_HERE, task_queue(), [this]() { for (auto* stream : streams_) { stream->StopSending(); delete stream; } streams_.clear(); send_transport_.reset(); receive_transport_.reset(); DestroyCalls(); }); } protected: friend class Stream; class Stream { public: explicit Stream(BitrateEstimatorTest* test) : test_(test), is_sending_receiving_(false), send_stream_(nullptr), frame_generator_capturer_(), decoder_factory_( []() { return std::make_unique(); }) { test_->GetVideoSendConfig()->rtp.ssrcs[0]++; send_stream_ = test_->sender_call_->CreateVideoSendStream( test_->GetVideoSendConfig()->Copy(), test_->GetVideoEncoderConfig()->Copy()); RTC_DCHECK_EQ(1, test_->GetVideoEncoderConfig()->number_of_streams); frame_generator_capturer_ = std::make_unique( test->clock_, test::CreateSquareFrameGenerator(kDefaultWidth, kDefaultHeight, absl::nullopt, absl::nullopt), kDefaultFramerate, *test->task_queue_factory_); frame_generator_capturer_->Init(); send_stream_->SetSource(frame_generator_capturer_.get(), DegradationPreference::MAINTAIN_FRAMERATE); send_stream_->Start(); VideoReceiveStream::Decoder decoder; test_->receive_config_.decoder_factory = &decoder_factory_; decoder.payload_type = test_->GetVideoSendConfig()->rtp.payload_type; decoder.video_format = SdpVideoFormat(test_->GetVideoSendConfig()->rtp.payload_name); test_->receive_config_.decoders.clear(); test_->receive_config_.decoders.push_back(decoder); test_->receive_config_.rtp.remote_ssrc = test_->GetVideoSendConfig()->rtp.ssrcs[0]; test_->receive_config_.rtp.local_ssrc++; test_->receive_config_.renderer = &test->fake_renderer_; video_receive_stream_ = test_->receiver_call_->CreateVideoReceiveStream( test_->receive_config_.Copy()); video_receive_stream_->Start(); is_sending_receiving_ = true; } ~Stream() { EXPECT_FALSE(is_sending_receiving_); test_->sender_call_->DestroyVideoSendStream(send_stream_); frame_generator_capturer_.reset(nullptr); send_stream_ = nullptr; if (video_receive_stream_) { test_->receiver_call_->DestroyVideoReceiveStream(video_receive_stream_); video_receive_stream_ = nullptr; } } void StopSending() { if (is_sending_receiving_) { send_stream_->Stop(); if (video_receive_stream_) { video_receive_stream_->Stop(); } is_sending_receiving_ = false; } } private: BitrateEstimatorTest* test_; bool is_sending_receiving_; VideoSendStream* send_stream_; VideoReceiveStream* video_receive_stream_; std::unique_ptr frame_generator_capturer_; test::FunctionVideoDecoderFactory decoder_factory_; }; LogObserver receiver_log_; std::unique_ptr send_transport_; std::unique_ptr receive_transport_; VideoReceiveStream::Config receive_config_; std::vector streams_; }; static const char* kAbsSendTimeLog = "RemoteBitrateEstimatorAbsSendTime: Instantiating."; static const char* kSingleStreamLog = "RemoteBitrateEstimatorSingleStream: Instantiating."; TEST_F(BitrateEstimatorTest, InstantiatesTOFPerDefaultForVideo) { SendTask(RTC_FROM_HERE, task_queue(), [this]() { GetVideoSendConfig()->rtp.extensions.push_back( RtpExtension(RtpExtension::kTimestampOffsetUri, kTOFExtensionId)); receiver_log_.PushExpectedLogLine(kSingleStreamLog); receiver_log_.PushExpectedLogLine(kSingleStreamLog); streams_.push_back(new Stream(this)); }); EXPECT_TRUE(receiver_log_.Wait()); } TEST_F(BitrateEstimatorTest, ImmediatelySwitchToASTForVideo) { SendTask(RTC_FROM_HERE, task_queue(), [this]() { GetVideoSendConfig()->rtp.extensions.push_back( RtpExtension(RtpExtension::kAbsSendTimeUri, kASTExtensionId)); receiver_log_.PushExpectedLogLine(kSingleStreamLog); receiver_log_.PushExpectedLogLine(kSingleStreamLog); receiver_log_.PushExpectedLogLine("Switching to absolute send time RBE."); receiver_log_.PushExpectedLogLine(kAbsSendTimeLog); streams_.push_back(new Stream(this)); }); EXPECT_TRUE(receiver_log_.Wait()); } TEST_F(BitrateEstimatorTest, SwitchesToASTForVideo) { SendTask(RTC_FROM_HERE, task_queue(), [this]() { GetVideoSendConfig()->rtp.extensions.push_back( RtpExtension(RtpExtension::kTimestampOffsetUri, kTOFExtensionId)); receiver_log_.PushExpectedLogLine(kSingleStreamLog); receiver_log_.PushExpectedLogLine(kSingleStreamLog); streams_.push_back(new Stream(this)); }); EXPECT_TRUE(receiver_log_.Wait()); SendTask(RTC_FROM_HERE, task_queue(), [this]() { GetVideoSendConfig()->rtp.extensions[0] = RtpExtension(RtpExtension::kAbsSendTimeUri, kASTExtensionId); receiver_log_.PushExpectedLogLine("Switching to absolute send time RBE."); receiver_log_.PushExpectedLogLine(kAbsSendTimeLog); streams_.push_back(new Stream(this)); }); EXPECT_TRUE(receiver_log_.Wait()); } // This test is flaky. See webrtc:5790. TEST_F(BitrateEstimatorTest, DISABLED_SwitchesToASTThenBackToTOFForVideo) { SendTask(RTC_FROM_HERE, task_queue(), [this]() { GetVideoSendConfig()->rtp.extensions.push_back( RtpExtension(RtpExtension::kTimestampOffsetUri, kTOFExtensionId)); receiver_log_.PushExpectedLogLine(kSingleStreamLog); receiver_log_.PushExpectedLogLine(kAbsSendTimeLog); receiver_log_.PushExpectedLogLine(kSingleStreamLog); streams_.push_back(new Stream(this)); }); EXPECT_TRUE(receiver_log_.Wait()); SendTask(RTC_FROM_HERE, task_queue(), [this]() { GetVideoSendConfig()->rtp.extensions[0] = RtpExtension(RtpExtension::kAbsSendTimeUri, kASTExtensionId); receiver_log_.PushExpectedLogLine(kAbsSendTimeLog); receiver_log_.PushExpectedLogLine("Switching to absolute send time RBE."); streams_.push_back(new Stream(this)); }); EXPECT_TRUE(receiver_log_.Wait()); SendTask(RTC_FROM_HERE, task_queue(), [this]() { GetVideoSendConfig()->rtp.extensions[0] = RtpExtension(RtpExtension::kTimestampOffsetUri, kTOFExtensionId); receiver_log_.PushExpectedLogLine(kAbsSendTimeLog); receiver_log_.PushExpectedLogLine( "WrappingBitrateEstimator: Switching to transmission time offset RBE."); streams_.push_back(new Stream(this)); streams_[0]->StopSending(); streams_[1]->StopSending(); }); EXPECT_TRUE(receiver_log_.Wait()); } } // namespace webrtc