| /* | 
 |  *  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 <functional> | 
 | #include <list> | 
 | #include <memory> | 
 | #include <string> | 
 |  | 
 | #include "webrtc/base/checks.h" | 
 | #include "webrtc/base/event.h" | 
 | #include "webrtc/base/logging.h" | 
 | #include "webrtc/base/thread_annotations.h" | 
 | #include "webrtc/call/call.h" | 
 | #include "webrtc/test/call_test.h" | 
 | #include "webrtc/test/direct_transport.h" | 
 | #include "webrtc/test/encoder_settings.h" | 
 | #include "webrtc/test/fake_decoder.h" | 
 | #include "webrtc/test/fake_encoder.h" | 
 | #include "webrtc/test/frame_generator_capturer.h" | 
 | #include "webrtc/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: | 
 |     Callback() : done_(false, false) {} | 
 |  | 
 |     void OnLogMessage(const std::string& message) override { | 
 |       rtc::CritScope lock(&crit_sect_); | 
 |       // 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_.size() <= 0) { | 
 |         if (num_popped > 0) { | 
 |           done_.Set(); | 
 |         } | 
 |         return; | 
 |       } | 
 |     } | 
 |  | 
 |     bool Wait() { return done_.Wait(test::CallTest::kDefaultTimeoutMs); } | 
 |  | 
 |     void PushExpectedLogLine(const std::string& expected_log_line) { | 
 |       rtc::CritScope lock(&crit_sect_); | 
 |       expected_log_lines_.push_back(expected_log_line); | 
 |     } | 
 |  | 
 |    private: | 
 |     typedef std::list<std::string> Strings; | 
 |     rtc::CriticalSection crit_sect_; | 
 |     Strings received_log_lines_ GUARDED_BY(crit_sect_); | 
 |     Strings expected_log_lines_ GUARDED_BY(crit_sect_); | 
 |     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() { | 
 |     Call::Config config(&event_log_); | 
 |     receiver_call_.reset(Call::Create(config)); | 
 |     sender_call_.reset(Call::Create(config)); | 
 |  | 
 |     send_transport_.reset( | 
 |         new test::DirectTransport(sender_call_.get(), MediaType::VIDEO)); | 
 |     send_transport_->SetReceiver(receiver_call_->Receiver()); | 
 |     receive_transport_.reset( | 
 |         new test::DirectTransport(receiver_call_.get(), MediaType::VIDEO)); | 
 |     receive_transport_->SetReceiver(sender_call_->Receiver()); | 
 |  | 
 |     video_send_config_ = VideoSendStream::Config(send_transport_.get()); | 
 |     video_send_config_.rtp.ssrcs.push_back(kVideoSendSsrcs[0]); | 
 |     // Encoders will be set separately per stream. | 
 |     video_send_config_.encoder_settings.encoder = nullptr; | 
 |     video_send_config_.encoder_settings.payload_name = "FAKE"; | 
 |     video_send_config_.encoder_settings.payload_type = | 
 |         kFakeVideoSendPayloadType; | 
 |     test::FillEncoderConfiguration(1, &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 = video_send_config_.rtp.ssrcs[0]; | 
 |     receive_config_.rtp.local_ssrc = kReceiverLocalVideoSsrc; | 
 |     receive_config_.rtp.remb = true; | 
 |     receive_config_.rtp.extensions.push_back( | 
 |         RtpExtension(RtpExtension::kTimestampOffsetUri, kTOFExtensionId)); | 
 |     receive_config_.rtp.extensions.push_back( | 
 |         RtpExtension(RtpExtension::kAbsSendTimeUri, kASTExtensionId)); | 
 |   } | 
 |  | 
 |   virtual void TearDown() { | 
 |     std::for_each(streams_.begin(), streams_.end(), | 
 |                   std::mem_fun(&Stream::StopSending)); | 
 |  | 
 |     send_transport_->StopSending(); | 
 |     receive_transport_->StopSending(); | 
 |  | 
 |     while (!streams_.empty()) { | 
 |       delete streams_.back(); | 
 |       streams_.pop_back(); | 
 |     } | 
 |  | 
 |     receiver_call_.reset(); | 
 |     sender_call_.reset(); | 
 |   } | 
 |  | 
 |  protected: | 
 |   friend class Stream; | 
 |  | 
 |   class Stream { | 
 |    public: | 
 |     explicit Stream(BitrateEstimatorTest* test) | 
 |         : test_(test), | 
 |           is_sending_receiving_(false), | 
 |           send_stream_(nullptr), | 
 |           frame_generator_capturer_(), | 
 |           fake_encoder_(Clock::GetRealTimeClock()), | 
 |           fake_decoder_() { | 
 |       test_->video_send_config_.rtp.ssrcs[0]++; | 
 |       test_->video_send_config_.encoder_settings.encoder = &fake_encoder_; | 
 |       send_stream_ = test_->sender_call_->CreateVideoSendStream( | 
 |           test_->video_send_config_.Copy(), | 
 |           test_->video_encoder_config_.Copy()); | 
 |       RTC_DCHECK_EQ(1, test_->video_encoder_config_.number_of_streams); | 
 |       frame_generator_capturer_.reset(test::FrameGeneratorCapturer::Create( | 
 |           kDefaultWidth, kDefaultHeight, kDefaultFramerate, | 
 |           Clock::GetRealTimeClock())); | 
 |       send_stream_->SetSource( | 
 |           frame_generator_capturer_.get(), | 
 |           VideoSendStream::DegradationPreference::kBalanced); | 
 |       send_stream_->Start(); | 
 |       frame_generator_capturer_->Start(); | 
 |  | 
 |       VideoReceiveStream::Decoder decoder; | 
 |       decoder.decoder = &fake_decoder_; | 
 |       decoder.payload_type = | 
 |           test_->video_send_config_.encoder_settings.payload_type; | 
 |       decoder.payload_name = | 
 |           test_->video_send_config_.encoder_settings.payload_name; | 
 |       test_->receive_config_.decoders.clear(); | 
 |       test_->receive_config_.decoders.push_back(decoder); | 
 |       test_->receive_config_.rtp.remote_ssrc = | 
 |           test_->video_send_config_.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_) { | 
 |         frame_generator_capturer_->Stop(); | 
 |         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<test::FrameGeneratorCapturer> frame_generator_capturer_; | 
 |     test::FakeEncoder fake_encoder_; | 
 |     test::FakeDecoder fake_decoder_; | 
 |   }; | 
 |  | 
 |   LogObserver receiver_log_; | 
 |   std::unique_ptr<test::DirectTransport> send_transport_; | 
 |   std::unique_ptr<test::DirectTransport> receive_transport_; | 
 |   std::unique_ptr<Call> sender_call_; | 
 |   std::unique_ptr<Call> receiver_call_; | 
 |   VideoReceiveStream::Config receive_config_; | 
 |   std::vector<Stream*> streams_; | 
 | }; | 
 |  | 
 | static const char* kAbsSendTimeLog = | 
 |     "RemoteBitrateEstimatorAbsSendTime: Instantiating."; | 
 | static const char* kSingleStreamLog = | 
 |     "RemoteBitrateEstimatorSingleStream: Instantiating."; | 
 |  | 
 | TEST_F(BitrateEstimatorTest, InstantiatesTOFPerDefaultForVideo) { | 
 |   video_send_config_.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) { | 
 |   video_send_config_.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) { | 
 |   video_send_config_.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()); | 
 |  | 
 |   video_send_config_.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) { | 
 |   video_send_config_.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()); | 
 |  | 
 |   video_send_config_.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()); | 
 |  | 
 |   video_send_config_.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 |