| /* | 
 |  *  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 <string> | 
 |  | 
 | #include "testing/gtest/include/gtest/gtest.h" | 
 |  | 
 | #include "webrtc/base/checks.h" | 
 | #include "webrtc/base/scoped_ptr.h" | 
 | #include "webrtc/base/thread_annotations.h" | 
 | #include "webrtc/call.h" | 
 | #include "webrtc/system_wrappers/interface/critical_section_wrapper.h" | 
 | #include "webrtc/system_wrappers/interface/event_wrapper.h" | 
 | #include "webrtc/system_wrappers/interface/trace.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" | 
 |  | 
 | namespace webrtc { | 
 | namespace { | 
 | // Note: consider to write tests that don't depend on the trace system instead | 
 | // of re-using this class. | 
 | class TraceObserver { | 
 |  public: | 
 |   TraceObserver() { | 
 |     Trace::set_level_filter(kTraceTerseInfo); | 
 |  | 
 |     Trace::CreateTrace(); | 
 |     Trace::SetTraceCallback(&callback_); | 
 |  | 
 |     // Call webrtc trace to initialize the tracer that would otherwise trigger a | 
 |     // data-race if left to be initialized by multiple threads (i.e. threads | 
 |     // spawned by test::DirectTransport members in BitrateEstimatorTest). | 
 |     WEBRTC_TRACE(kTraceStateInfo, | 
 |                  kTraceUtility, | 
 |                  -1, | 
 |                  "Instantiate without data races."); | 
 |   } | 
 |  | 
 |   ~TraceObserver() { | 
 |     Trace::SetTraceCallback(nullptr); | 
 |     Trace::ReturnTrace(); | 
 |   } | 
 |  | 
 |   void PushExpectedLogLine(const std::string& expected_log_line) { | 
 |     callback_.PushExpectedLogLine(expected_log_line); | 
 |   } | 
 |  | 
 |   EventTypeWrapper Wait() { | 
 |     return callback_.Wait(); | 
 |   } | 
 |  | 
 |  private: | 
 |   class Callback : public TraceCallback { | 
 |    public: | 
 |     Callback() | 
 |         : crit_sect_(CriticalSectionWrapper::CreateCriticalSection()), | 
 |           done_(EventWrapper::Create()) {} | 
 |  | 
 |     void Print(TraceLevel level, const char* message, int length) override { | 
 |       CriticalSectionScoped lock(crit_sect_.get()); | 
 |       std::string msg(message); | 
 |       if (msg.find("BitrateEstimator") != std::string::npos) { | 
 |         received_log_lines_.push_back(msg); | 
 |       } | 
 |       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); | 
 |       } | 
 |       if (expected_log_lines_.size() <= 0) { | 
 |         if (num_popped > 0) { | 
 |           done_->Set(); | 
 |         } | 
 |         return; | 
 |       } | 
 |     } | 
 |  | 
 |     EventTypeWrapper Wait() { | 
 |       return done_->Wait(test::CallTest::kDefaultTimeoutMs); | 
 |     } | 
 |  | 
 |     void PushExpectedLogLine(const std::string& expected_log_line) { | 
 |       CriticalSectionScoped lock(crit_sect_.get()); | 
 |       expected_log_lines_.push_back(expected_log_line); | 
 |     } | 
 |  | 
 |    private: | 
 |     typedef std::list<std::string> Strings; | 
 |     const rtc::scoped_ptr<CriticalSectionWrapper> crit_sect_; | 
 |     Strings received_log_lines_ GUARDED_BY(crit_sect_); | 
 |     Strings expected_log_lines_ GUARDED_BY(crit_sect_); | 
 |     rtc::scoped_ptr<EventWrapper> done_; | 
 |   }; | 
 |  | 
 |   Callback callback_; | 
 | }; | 
 | }  // namespace | 
 |  | 
 | static const int kTOFExtensionId = 4; | 
 | static const int kASTExtensionId = 5; | 
 |  | 
 | class BitrateEstimatorTest : public test::CallTest { | 
 |  public: | 
 |   BitrateEstimatorTest() | 
 |       : receiver_trace_(), | 
 |         send_transport_(), | 
 |         receive_transport_(), | 
 |         sender_call_(), | 
 |         receiver_call_(), | 
 |         receive_config_(), | 
 |         streams_() { | 
 |   } | 
 |  | 
 |   virtual ~BitrateEstimatorTest() { | 
 |     EXPECT_TRUE(streams_.empty()); | 
 |   } | 
 |  | 
 |   virtual void SetUp() { | 
 |     Call::Config receiver_call_config(&receive_transport_); | 
 |     receiver_call_.reset(Call::Create(receiver_call_config)); | 
 |  | 
 |     Call::Config sender_call_config(&send_transport_); | 
 |     sender_call_.reset(Call::Create(sender_call_config)); | 
 |  | 
 |     send_transport_.SetReceiver(receiver_call_->Receiver()); | 
 |     receive_transport_.SetReceiver(sender_call_->Receiver()); | 
 |  | 
 |     send_config_ = VideoSendStream::Config(); | 
 |     send_config_.rtp.ssrcs.push_back(kSendSsrcs[0]); | 
 |     // Encoders will be set separately per stream. | 
 |     send_config_.encoder_settings.encoder = nullptr; | 
 |     send_config_.encoder_settings.payload_name = "FAKE"; | 
 |     send_config_.encoder_settings.payload_type = kFakeSendPayloadType; | 
 |     encoder_config_.streams = test::CreateVideoStreams(1); | 
 |  | 
 |     receive_config_ = VideoReceiveStream::Config(); | 
 |     // receive_config_.decoders will be set by every stream separately. | 
 |     receive_config_.rtp.remote_ssrc = send_config_.rtp.ssrcs[0]; | 
 |     receive_config_.rtp.local_ssrc = kReceiverLocalSsrc; | 
 |     receive_config_.rtp.extensions.push_back( | 
 |         RtpExtension(RtpExtension::kTOffset, kTOFExtensionId)); | 
 |     receive_config_.rtp.extensions.push_back( | 
 |         RtpExtension(RtpExtension::kAbsSendTime, 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(); | 
 |   } | 
 |  | 
 |  protected: | 
 |   friend class Stream; | 
 |  | 
 |   class Stream { | 
 |    public: | 
 |     explicit Stream(BitrateEstimatorTest* test) | 
 |         : test_(test), | 
 |           is_sending_receiving_(false), | 
 |           send_stream_(nullptr), | 
 |           receive_stream_(nullptr), | 
 |           frame_generator_capturer_(), | 
 |           fake_encoder_(Clock::GetRealTimeClock()), | 
 |           fake_decoder_() { | 
 |       test_->send_config_.rtp.ssrcs[0]++; | 
 |       test_->send_config_.encoder_settings.encoder = &fake_encoder_; | 
 |       send_stream_ = test_->sender_call_->CreateVideoSendStream( | 
 |           test_->send_config_, test_->encoder_config_); | 
 |       DCHECK_EQ(1u, test_->encoder_config_.streams.size()); | 
 |       frame_generator_capturer_.reset(test::FrameGeneratorCapturer::Create( | 
 |           send_stream_->Input(), | 
 |           test_->encoder_config_.streams[0].width, | 
 |           test_->encoder_config_.streams[0].height, | 
 |           30, | 
 |           Clock::GetRealTimeClock())); | 
 |       send_stream_->Start(); | 
 |       frame_generator_capturer_->Start(); | 
 |  | 
 |       VideoReceiveStream::Decoder decoder; | 
 |       decoder.decoder = &fake_decoder_; | 
 |       decoder.payload_type = test_->send_config_.encoder_settings.payload_type; | 
 |       decoder.payload_name = test_->send_config_.encoder_settings.payload_name; | 
 |       test_->receive_config_.decoders.push_back(decoder); | 
 |       test_->receive_config_.rtp.remote_ssrc = test_->send_config_.rtp.ssrcs[0]; | 
 |       test_->receive_config_.rtp.local_ssrc++; | 
 |       receive_stream_ = test_->receiver_call_->CreateVideoReceiveStream( | 
 |           test_->receive_config_); | 
 |       receive_stream_->Start(); | 
 |  | 
 |       is_sending_receiving_ = true; | 
 |     } | 
 |  | 
 |     ~Stream() { | 
 |       frame_generator_capturer_.reset(nullptr); | 
 |       test_->sender_call_->DestroyVideoSendStream(send_stream_); | 
 |       send_stream_ = nullptr; | 
 |       test_->receiver_call_->DestroyVideoReceiveStream(receive_stream_); | 
 |       receive_stream_ = nullptr; | 
 |     } | 
 |  | 
 |     void StopSending() { | 
 |       if (is_sending_receiving_) { | 
 |         frame_generator_capturer_->Stop(); | 
 |         send_stream_->Stop(); | 
 |         receive_stream_->Stop(); | 
 |         is_sending_receiving_ = false; | 
 |       } | 
 |     } | 
 |  | 
 |    private: | 
 |     BitrateEstimatorTest* test_; | 
 |     bool is_sending_receiving_; | 
 |     VideoSendStream* send_stream_; | 
 |     VideoReceiveStream* receive_stream_; | 
 |     rtc::scoped_ptr<test::FrameGeneratorCapturer> frame_generator_capturer_; | 
 |     test::FakeEncoder fake_encoder_; | 
 |     test::FakeDecoder fake_decoder_; | 
 |   }; | 
 |  | 
 |   TraceObserver receiver_trace_; | 
 |   test::DirectTransport send_transport_; | 
 |   test::DirectTransport receive_transport_; | 
 |   rtc::scoped_ptr<Call> sender_call_; | 
 |   rtc::scoped_ptr<Call> receiver_call_; | 
 |   VideoReceiveStream::Config receive_config_; | 
 |   std::vector<Stream*> streams_; | 
 | }; | 
 |  | 
 | TEST_F(BitrateEstimatorTest, InstantiatesTOFPerDefault) { | 
 |   send_config_.rtp.extensions.push_back( | 
 |       RtpExtension(RtpExtension::kTOffset, kTOFExtensionId)); | 
 |   receiver_trace_.PushExpectedLogLine( | 
 |       "RemoteBitrateEstimatorFactory: Instantiating."); | 
 |   receiver_trace_.PushExpectedLogLine( | 
 |       "RemoteBitrateEstimatorFactory: Instantiating."); | 
 |   streams_.push_back(new Stream(this)); | 
 |   EXPECT_EQ(kEventSignaled, receiver_trace_.Wait()); | 
 | } | 
 |  | 
 | TEST_F(BitrateEstimatorTest, ImmediatelySwitchToAST) { | 
 |   send_config_.rtp.extensions.push_back( | 
 |       RtpExtension(RtpExtension::kAbsSendTime, kASTExtensionId)); | 
 |   receiver_trace_.PushExpectedLogLine( | 
 |       "RemoteBitrateEstimatorFactory: Instantiating."); | 
 |   receiver_trace_.PushExpectedLogLine( | 
 |       "RemoteBitrateEstimatorFactory: Instantiating."); | 
 |   receiver_trace_.PushExpectedLogLine("Switching to absolute send time RBE."); | 
 |   receiver_trace_.PushExpectedLogLine( | 
 |       "AbsoluteSendTimeRemoteBitrateEstimatorFactory: Instantiating."); | 
 |   streams_.push_back(new Stream(this)); | 
 |   EXPECT_EQ(kEventSignaled, receiver_trace_.Wait()); | 
 | } | 
 |  | 
 | TEST_F(BitrateEstimatorTest, SwitchesToAST) { | 
 |   send_config_.rtp.extensions.push_back( | 
 |       RtpExtension(RtpExtension::kTOffset, kTOFExtensionId)); | 
 |   receiver_trace_.PushExpectedLogLine( | 
 |       "RemoteBitrateEstimatorFactory: Instantiating."); | 
 |   receiver_trace_.PushExpectedLogLine( | 
 |       "RemoteBitrateEstimatorFactory: Instantiating."); | 
 |   streams_.push_back(new Stream(this)); | 
 |   EXPECT_EQ(kEventSignaled, receiver_trace_.Wait()); | 
 |  | 
 |   send_config_.rtp.extensions[0] = | 
 |       RtpExtension(RtpExtension::kAbsSendTime, kASTExtensionId); | 
 |   receiver_trace_.PushExpectedLogLine("Switching to absolute send time RBE."); | 
 |   receiver_trace_.PushExpectedLogLine( | 
 |       "AbsoluteSendTimeRemoteBitrateEstimatorFactory: Instantiating."); | 
 |   streams_.push_back(new Stream(this)); | 
 |   EXPECT_EQ(kEventSignaled, receiver_trace_.Wait()); | 
 | } | 
 |  | 
 | TEST_F(BitrateEstimatorTest, SwitchesToASTThenBackToTOF) { | 
 |   send_config_.rtp.extensions.push_back( | 
 |       RtpExtension(RtpExtension::kTOffset, kTOFExtensionId)); | 
 |   receiver_trace_.PushExpectedLogLine( | 
 |       "RemoteBitrateEstimatorFactory: Instantiating."); | 
 |   receiver_trace_.PushExpectedLogLine( | 
 |       "RemoteBitrateEstimatorFactory: Instantiating."); | 
 |   streams_.push_back(new Stream(this)); | 
 |   EXPECT_EQ(kEventSignaled, receiver_trace_.Wait()); | 
 |  | 
 |   send_config_.rtp.extensions[0] = | 
 |       RtpExtension(RtpExtension::kAbsSendTime, kASTExtensionId); | 
 |   receiver_trace_.PushExpectedLogLine("Switching to absolute send time RBE."); | 
 |   receiver_trace_.PushExpectedLogLine( | 
 |       "AbsoluteSendTimeRemoteBitrateEstimatorFactory: Instantiating."); | 
 |   streams_.push_back(new Stream(this)); | 
 |   EXPECT_EQ(kEventSignaled, receiver_trace_.Wait()); | 
 |  | 
 |   send_config_.rtp.extensions[0] = | 
 |       RtpExtension(RtpExtension::kTOffset, kTOFExtensionId); | 
 |   receiver_trace_.PushExpectedLogLine( | 
 |       "WrappingBitrateEstimator: Switching to transmission time offset RBE."); | 
 |   receiver_trace_.PushExpectedLogLine( | 
 |       "RemoteBitrateEstimatorFactory: Instantiating."); | 
 |   streams_.push_back(new Stream(this)); | 
 |   streams_[0]->StopSending(); | 
 |   streams_[1]->StopSending(); | 
 |   EXPECT_EQ(kEventSignaled, receiver_trace_.Wait()); | 
 | } | 
 | }  // namespace webrtc |