| OLD | NEW | 
|---|
|  | (Empty) | 
| 1 /* |  | 
| 2  *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. |  | 
| 3  * |  | 
| 4  *  Use of this source code is governed by a BSD-style license |  | 
| 5  *  that can be found in the LICENSE file in the root of the source |  | 
| 6  *  tree. An additional intellectual property rights grant can be found |  | 
| 7  *  in the file PATENTS.  All contributing project authors may |  | 
| 8  *  be found in the AUTHORS file in the root of the source tree. |  | 
| 9  */ |  | 
| 10 #include <algorithm> |  | 
| 11 #include <sstream> |  | 
| 12 #include <string> |  | 
| 13 |  | 
| 14 #include "testing/gtest/include/gtest/gtest.h" |  | 
| 15 |  | 
| 16 #include "webrtc/base/checks.h" |  | 
| 17 #include "webrtc/base/scoped_ptr.h" |  | 
| 18 #include "webrtc/base/thread_annotations.h" |  | 
| 19 #include "webrtc/call.h" |  | 
| 20 #include "webrtc/modules/audio_coding/main/interface/audio_coding_module.h" |  | 
| 21 #include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h" |  | 
| 22 #include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h" |  | 
| 23 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h" |  | 
| 24 #include "webrtc/system_wrappers/interface/rtp_to_ntp.h" |  | 
| 25 #include "webrtc/test/call_test.h" |  | 
| 26 #include "webrtc/test/direct_transport.h" |  | 
| 27 #include "webrtc/test/encoder_settings.h" |  | 
| 28 #include "webrtc/test/fake_audio_device.h" |  | 
| 29 #include "webrtc/test/fake_decoder.h" |  | 
| 30 #include "webrtc/test/fake_encoder.h" |  | 
| 31 #include "webrtc/test/frame_generator.h" |  | 
| 32 #include "webrtc/test/frame_generator_capturer.h" |  | 
| 33 #include "webrtc/test/rtp_rtcp_observer.h" |  | 
| 34 #include "webrtc/test/testsupport/fileutils.h" |  | 
| 35 #include "webrtc/test/testsupport/perf_test.h" |  | 
| 36 #include "webrtc/video/transport_adapter.h" |  | 
| 37 #include "webrtc/voice_engine/include/voe_base.h" |  | 
| 38 #include "webrtc/voice_engine/include/voe_codec.h" |  | 
| 39 #include "webrtc/voice_engine/include/voe_network.h" |  | 
| 40 #include "webrtc/voice_engine/include/voe_rtp_rtcp.h" |  | 
| 41 #include "webrtc/voice_engine/include/voe_video_sync.h" |  | 
| 42 |  | 
| 43 namespace webrtc { |  | 
| 44 |  | 
| 45 class CallPerfTest : public test::CallTest { |  | 
| 46  protected: |  | 
| 47   void TestAudioVideoSync(bool fec, bool create_audio_first); |  | 
| 48 |  | 
| 49   void TestCpuOveruse(LoadObserver::Load tested_load, int encode_delay_ms); |  | 
| 50 |  | 
| 51   void TestMinTransmitBitrate(bool pad_to_min_bitrate); |  | 
| 52 |  | 
| 53   void TestCaptureNtpTime(const FakeNetworkPipe::Config& net_config, |  | 
| 54                           int threshold_ms, |  | 
| 55                           int start_time_ms, |  | 
| 56                           int run_time_ms); |  | 
| 57 }; |  | 
| 58 |  | 
| 59 class SyncRtcpObserver : public test::RtpRtcpObserver { |  | 
| 60  public: |  | 
| 61   explicit SyncRtcpObserver(const FakeNetworkPipe::Config& config) |  | 
| 62       : test::RtpRtcpObserver(CallPerfTest::kLongTimeoutMs, config) {} |  | 
| 63 |  | 
| 64   Action OnSendRtcp(const uint8_t* packet, size_t length) override { |  | 
| 65     RTCPUtility::RTCPParserV2 parser(packet, length, true); |  | 
| 66     EXPECT_TRUE(parser.IsValid()); |  | 
| 67 |  | 
| 68     for (RTCPUtility::RTCPPacketTypes packet_type = parser.Begin(); |  | 
| 69          packet_type != RTCPUtility::RTCPPacketTypes::kInvalid; |  | 
| 70          packet_type = parser.Iterate()) { |  | 
| 71       if (packet_type == RTCPUtility::RTCPPacketTypes::kSr) { |  | 
| 72         const RTCPUtility::RTCPPacket& packet = parser.Packet(); |  | 
| 73         RtcpMeasurement ntp_rtp_pair( |  | 
| 74             packet.SR.NTPMostSignificant, |  | 
| 75             packet.SR.NTPLeastSignificant, |  | 
| 76             packet.SR.RTPTimestamp); |  | 
| 77         StoreNtpRtpPair(ntp_rtp_pair); |  | 
| 78       } |  | 
| 79     } |  | 
| 80     return SEND_PACKET; |  | 
| 81   } |  | 
| 82 |  | 
| 83   int64_t RtpTimestampToNtp(uint32_t timestamp) const { |  | 
| 84     rtc::CritScope lock(&crit_); |  | 
| 85     int64_t timestamp_in_ms = -1; |  | 
| 86     if (ntp_rtp_pairs_.size() == 2) { |  | 
| 87       // TODO(stefan): We can't EXPECT_TRUE on this call due to a bug in the |  | 
| 88       // RTCP sender where it sends RTCP SR before any RTP packets, which leads |  | 
| 89       // to a bogus NTP/RTP mapping. |  | 
| 90       RtpToNtpMs(timestamp, ntp_rtp_pairs_, ×tamp_in_ms); |  | 
| 91       return timestamp_in_ms; |  | 
| 92     } |  | 
| 93     return -1; |  | 
| 94   } |  | 
| 95 |  | 
| 96  private: |  | 
| 97   void StoreNtpRtpPair(RtcpMeasurement ntp_rtp_pair) { |  | 
| 98     rtc::CritScope lock(&crit_); |  | 
| 99     for (RtcpList::iterator it = ntp_rtp_pairs_.begin(); |  | 
| 100          it != ntp_rtp_pairs_.end(); |  | 
| 101          ++it) { |  | 
| 102       if (ntp_rtp_pair.ntp_secs == it->ntp_secs && |  | 
| 103           ntp_rtp_pair.ntp_frac == it->ntp_frac) { |  | 
| 104         // This RTCP has already been added to the list. |  | 
| 105         return; |  | 
| 106       } |  | 
| 107     } |  | 
| 108     // We need two RTCP SR reports to map between RTP and NTP. More than two |  | 
| 109     // will not improve the mapping. |  | 
| 110     if (ntp_rtp_pairs_.size() == 2) { |  | 
| 111       ntp_rtp_pairs_.pop_back(); |  | 
| 112     } |  | 
| 113     ntp_rtp_pairs_.push_front(ntp_rtp_pair); |  | 
| 114   } |  | 
| 115 |  | 
| 116   mutable rtc::CriticalSection crit_; |  | 
| 117   RtcpList ntp_rtp_pairs_ GUARDED_BY(crit_); |  | 
| 118 }; |  | 
| 119 |  | 
| 120 class VideoRtcpAndSyncObserver : public SyncRtcpObserver, public VideoRenderer { |  | 
| 121   static const int kInSyncThresholdMs = 50; |  | 
| 122   static const int kStartupTimeMs = 2000; |  | 
| 123   static const int kMinRunTimeMs = 30000; |  | 
| 124 |  | 
| 125  public: |  | 
| 126   VideoRtcpAndSyncObserver(Clock* clock, |  | 
| 127                            int voe_channel, |  | 
| 128                            VoEVideoSync* voe_sync, |  | 
| 129                            SyncRtcpObserver* audio_observer) |  | 
| 130       : SyncRtcpObserver(FakeNetworkPipe::Config()), |  | 
| 131         clock_(clock), |  | 
| 132         voe_channel_(voe_channel), |  | 
| 133         voe_sync_(voe_sync), |  | 
| 134         audio_observer_(audio_observer), |  | 
| 135         creation_time_ms_(clock_->TimeInMilliseconds()), |  | 
| 136         first_time_in_sync_(-1) {} |  | 
| 137 |  | 
| 138   void RenderFrame(const VideoFrame& video_frame, |  | 
| 139                    int time_to_render_ms) override { |  | 
| 140     int64_t now_ms = clock_->TimeInMilliseconds(); |  | 
| 141     uint32_t playout_timestamp = 0; |  | 
| 142     if (voe_sync_->GetPlayoutTimestamp(voe_channel_, playout_timestamp) != 0) |  | 
| 143       return; |  | 
| 144     int64_t latest_audio_ntp = |  | 
| 145         audio_observer_->RtpTimestampToNtp(playout_timestamp); |  | 
| 146     int64_t latest_video_ntp = RtpTimestampToNtp(video_frame.timestamp()); |  | 
| 147     if (latest_audio_ntp < 0 || latest_video_ntp < 0) |  | 
| 148       return; |  | 
| 149     int time_until_render_ms = |  | 
| 150         std::max(0, static_cast<int>(video_frame.render_time_ms() - now_ms)); |  | 
| 151     latest_video_ntp += time_until_render_ms; |  | 
| 152     int64_t stream_offset = latest_audio_ntp - latest_video_ntp; |  | 
| 153     std::stringstream ss; |  | 
| 154     ss << stream_offset; |  | 
| 155     webrtc::test::PrintResult("stream_offset", |  | 
| 156                               "", |  | 
| 157                               "synchronization", |  | 
| 158                               ss.str(), |  | 
| 159                               "ms", |  | 
| 160                               false); |  | 
| 161     int64_t time_since_creation = now_ms - creation_time_ms_; |  | 
| 162     // During the first couple of seconds audio and video can falsely be |  | 
| 163     // estimated as being synchronized. We don't want to trigger on those. |  | 
| 164     if (time_since_creation < kStartupTimeMs) |  | 
| 165       return; |  | 
| 166     if (std::abs(latest_audio_ntp - latest_video_ntp) < kInSyncThresholdMs) { |  | 
| 167       if (first_time_in_sync_ == -1) { |  | 
| 168         first_time_in_sync_ = now_ms; |  | 
| 169         webrtc::test::PrintResult("sync_convergence_time", |  | 
| 170                                   "", |  | 
| 171                                   "synchronization", |  | 
| 172                                   time_since_creation, |  | 
| 173                                   "ms", |  | 
| 174                                   false); |  | 
| 175       } |  | 
| 176       if (time_since_creation > kMinRunTimeMs) |  | 
| 177         observation_complete_->Set(); |  | 
| 178     } |  | 
| 179   } |  | 
| 180 |  | 
| 181   bool IsTextureSupported() const override { return false; } |  | 
| 182 |  | 
| 183  private: |  | 
| 184   Clock* const clock_; |  | 
| 185   int voe_channel_; |  | 
| 186   VoEVideoSync* voe_sync_; |  | 
| 187   SyncRtcpObserver* audio_observer_; |  | 
| 188   int64_t creation_time_ms_; |  | 
| 189   int64_t first_time_in_sync_; |  | 
| 190 }; |  | 
| 191 |  | 
| 192 void CallPerfTest::TestAudioVideoSync(bool fec, bool create_audio_first) { |  | 
| 193   const char* kSyncGroup = "av_sync"; |  | 
| 194   class AudioPacketReceiver : public PacketReceiver { |  | 
| 195    public: |  | 
| 196     AudioPacketReceiver(int channel, VoENetwork* voe_network) |  | 
| 197         : channel_(channel), |  | 
| 198           voe_network_(voe_network), |  | 
| 199           parser_(RtpHeaderParser::Create()) {} |  | 
| 200     DeliveryStatus DeliverPacket(MediaType media_type, |  | 
| 201                                  const uint8_t* packet, |  | 
| 202                                  size_t length, |  | 
| 203                                  const PacketTime& packet_time) override { |  | 
| 204       EXPECT_TRUE(media_type == MediaType::ANY || |  | 
| 205                   media_type == MediaType::AUDIO); |  | 
| 206       int ret; |  | 
| 207       if (parser_->IsRtcp(packet, length)) { |  | 
| 208         ret = voe_network_->ReceivedRTCPPacket(channel_, packet, length); |  | 
| 209       } else { |  | 
| 210         ret = voe_network_->ReceivedRTPPacket(channel_, packet, length, |  | 
| 211                                               PacketTime()); |  | 
| 212       } |  | 
| 213       return ret == 0 ? DELIVERY_OK : DELIVERY_PACKET_ERROR; |  | 
| 214     } |  | 
| 215 |  | 
| 216    private: |  | 
| 217     int channel_; |  | 
| 218     VoENetwork* voe_network_; |  | 
| 219     rtc::scoped_ptr<RtpHeaderParser> parser_; |  | 
| 220   }; |  | 
| 221 |  | 
| 222   VoiceEngine* voice_engine = VoiceEngine::Create(); |  | 
| 223   VoEBase* voe_base = VoEBase::GetInterface(voice_engine); |  | 
| 224   VoECodec* voe_codec = VoECodec::GetInterface(voice_engine); |  | 
| 225   VoENetwork* voe_network = VoENetwork::GetInterface(voice_engine); |  | 
| 226   VoEVideoSync* voe_sync = VoEVideoSync::GetInterface(voice_engine); |  | 
| 227   const std::string audio_filename = |  | 
| 228       test::ResourcePath("voice_engine/audio_long16", "pcm"); |  | 
| 229   ASSERT_STRNE("", audio_filename.c_str()); |  | 
| 230   test::FakeAudioDevice fake_audio_device(Clock::GetRealTimeClock(), |  | 
| 231                                           audio_filename); |  | 
| 232   EXPECT_EQ(0, voe_base->Init(&fake_audio_device, nullptr)); |  | 
| 233   int channel = voe_base->CreateChannel(); |  | 
| 234 |  | 
| 235   FakeNetworkPipe::Config net_config; |  | 
| 236   net_config.queue_delay_ms = 500; |  | 
| 237   net_config.loss_percent = 5; |  | 
| 238   SyncRtcpObserver audio_observer(net_config); |  | 
| 239   VideoRtcpAndSyncObserver observer(Clock::GetRealTimeClock(), |  | 
| 240                                     channel, |  | 
| 241                                     voe_sync, |  | 
| 242                                     &audio_observer); |  | 
| 243 |  | 
| 244   Call::Config receiver_config; |  | 
| 245   receiver_config.voice_engine = voice_engine; |  | 
| 246   CreateCalls(Call::Config(), receiver_config); |  | 
| 247 |  | 
| 248   CodecInst isac = {103, "ISAC", 16000, 480, 1, 32000}; |  | 
| 249   EXPECT_EQ(0, voe_codec->SetSendCodec(channel, isac)); |  | 
| 250 |  | 
| 251   AudioPacketReceiver voe_packet_receiver(channel, voe_network); |  | 
| 252   audio_observer.SetReceivers(&voe_packet_receiver, &voe_packet_receiver); |  | 
| 253 |  | 
| 254   internal::TransportAdapter transport_adapter(audio_observer.SendTransport()); |  | 
| 255   transport_adapter.Enable(); |  | 
| 256   EXPECT_EQ(0, |  | 
| 257             voe_network->RegisterExternalTransport(channel, transport_adapter)); |  | 
| 258 |  | 
| 259   observer.SetReceivers(receiver_call_->Receiver(), sender_call_->Receiver()); |  | 
| 260 |  | 
| 261   test::FakeDecoder fake_decoder; |  | 
| 262 |  | 
| 263   CreateSendConfig(1, observer.SendTransport()); |  | 
| 264   CreateMatchingReceiveConfigs(observer.ReceiveTransport()); |  | 
| 265 |  | 
| 266   send_config_.rtp.nack.rtp_history_ms = kNackRtpHistoryMs; |  | 
| 267   if (fec) { |  | 
| 268     send_config_.rtp.fec.red_payload_type = kRedPayloadType; |  | 
| 269     send_config_.rtp.fec.ulpfec_payload_type = kUlpfecPayloadType; |  | 
| 270     receive_configs_[0].rtp.fec.red_payload_type = kRedPayloadType; |  | 
| 271     receive_configs_[0].rtp.fec.ulpfec_payload_type = kUlpfecPayloadType; |  | 
| 272   } |  | 
| 273   receive_configs_[0].rtp.nack.rtp_history_ms = 1000; |  | 
| 274   receive_configs_[0].renderer = &observer; |  | 
| 275   receive_configs_[0].sync_group = kSyncGroup; |  | 
| 276 |  | 
| 277   AudioReceiveStream::Config audio_config; |  | 
| 278   audio_config.voe_channel_id = channel; |  | 
| 279   audio_config.sync_group = kSyncGroup; |  | 
| 280 |  | 
| 281   AudioReceiveStream* audio_receive_stream = nullptr; |  | 
| 282 |  | 
| 283   if (create_audio_first) { |  | 
| 284     audio_receive_stream = |  | 
| 285         receiver_call_->CreateAudioReceiveStream(audio_config); |  | 
| 286     CreateStreams(); |  | 
| 287   } else { |  | 
| 288     CreateStreams(); |  | 
| 289     audio_receive_stream = |  | 
| 290         receiver_call_->CreateAudioReceiveStream(audio_config); |  | 
| 291   } |  | 
| 292 |  | 
| 293   CreateFrameGeneratorCapturer(); |  | 
| 294 |  | 
| 295   Start(); |  | 
| 296 |  | 
| 297   fake_audio_device.Start(); |  | 
| 298   EXPECT_EQ(0, voe_base->StartPlayout(channel)); |  | 
| 299   EXPECT_EQ(0, voe_base->StartReceive(channel)); |  | 
| 300   EXPECT_EQ(0, voe_base->StartSend(channel)); |  | 
| 301 |  | 
| 302   EXPECT_EQ(kEventSignaled, observer.Wait()) |  | 
| 303       << "Timed out while waiting for audio and video to be synchronized."; |  | 
| 304 |  | 
| 305   EXPECT_EQ(0, voe_base->StopSend(channel)); |  | 
| 306   EXPECT_EQ(0, voe_base->StopReceive(channel)); |  | 
| 307   EXPECT_EQ(0, voe_base->StopPlayout(channel)); |  | 
| 308   fake_audio_device.Stop(); |  | 
| 309 |  | 
| 310   Stop(); |  | 
| 311   observer.StopSending(); |  | 
| 312   audio_observer.StopSending(); |  | 
| 313 |  | 
| 314   voe_base->DeleteChannel(channel); |  | 
| 315   voe_base->Release(); |  | 
| 316   voe_codec->Release(); |  | 
| 317   voe_network->Release(); |  | 
| 318   voe_sync->Release(); |  | 
| 319 |  | 
| 320   DestroyStreams(); |  | 
| 321 |  | 
| 322   receiver_call_->DestroyAudioReceiveStream(audio_receive_stream); |  | 
| 323 |  | 
| 324   VoiceEngine::Delete(voice_engine); |  | 
| 325 } |  | 
| 326 |  | 
| 327 TEST_F(CallPerfTest, PlaysOutAudioAndVideoInSyncWithAudioCreatedFirst) { |  | 
| 328   TestAudioVideoSync(false, true); |  | 
| 329 } |  | 
| 330 |  | 
| 331 TEST_F(CallPerfTest, PlaysOutAudioAndVideoInSyncWithVideoCreatedFirst) { |  | 
| 332   TestAudioVideoSync(false, false); |  | 
| 333 } |  | 
| 334 |  | 
| 335 TEST_F(CallPerfTest, PlaysOutAudioAndVideoInSyncWithFec) { |  | 
| 336   TestAudioVideoSync(true, false); |  | 
| 337 } |  | 
| 338 |  | 
| 339 void CallPerfTest::TestCaptureNtpTime(const FakeNetworkPipe::Config& net_config, |  | 
| 340                                       int threshold_ms, |  | 
| 341                                       int start_time_ms, |  | 
| 342                                       int run_time_ms) { |  | 
| 343   class CaptureNtpTimeObserver : public test::EndToEndTest, |  | 
| 344                                  public VideoRenderer { |  | 
| 345    public: |  | 
| 346     CaptureNtpTimeObserver(const FakeNetworkPipe::Config& config, |  | 
| 347                            int threshold_ms, |  | 
| 348                            int start_time_ms, |  | 
| 349                            int run_time_ms) |  | 
| 350         : EndToEndTest(kLongTimeoutMs, config), |  | 
| 351           clock_(Clock::GetRealTimeClock()), |  | 
| 352           threshold_ms_(threshold_ms), |  | 
| 353           start_time_ms_(start_time_ms), |  | 
| 354           run_time_ms_(run_time_ms), |  | 
| 355           creation_time_ms_(clock_->TimeInMilliseconds()), |  | 
| 356           capturer_(nullptr), |  | 
| 357           rtp_start_timestamp_set_(false), |  | 
| 358           rtp_start_timestamp_(0) {} |  | 
| 359 |  | 
| 360    private: |  | 
| 361     void RenderFrame(const VideoFrame& video_frame, |  | 
| 362                      int time_to_render_ms) override { |  | 
| 363       if (video_frame.ntp_time_ms() <= 0) { |  | 
| 364         // Haven't got enough RTCP SR in order to calculate the capture ntp |  | 
| 365         // time. |  | 
| 366         return; |  | 
| 367       } |  | 
| 368 |  | 
| 369       int64_t now_ms = clock_->TimeInMilliseconds(); |  | 
| 370       int64_t time_since_creation = now_ms - creation_time_ms_; |  | 
| 371       if (time_since_creation < start_time_ms_) { |  | 
| 372         // Wait for |start_time_ms_| before start measuring. |  | 
| 373         return; |  | 
| 374       } |  | 
| 375 |  | 
| 376       if (time_since_creation > run_time_ms_) { |  | 
| 377         observation_complete_->Set(); |  | 
| 378       } |  | 
| 379 |  | 
| 380       FrameCaptureTimeList::iterator iter = |  | 
| 381           capture_time_list_.find(video_frame.timestamp()); |  | 
| 382       EXPECT_TRUE(iter != capture_time_list_.end()); |  | 
| 383 |  | 
| 384       // The real capture time has been wrapped to uint32_t before converted |  | 
| 385       // to rtp timestamp in the sender side. So here we convert the estimated |  | 
| 386       // capture time to a uint32_t 90k timestamp also for comparing. |  | 
| 387       uint32_t estimated_capture_timestamp = |  | 
| 388           90 * static_cast<uint32_t>(video_frame.ntp_time_ms()); |  | 
| 389       uint32_t real_capture_timestamp = iter->second; |  | 
| 390       int time_offset_ms = real_capture_timestamp - estimated_capture_timestamp; |  | 
| 391       time_offset_ms = time_offset_ms / 90; |  | 
| 392       std::stringstream ss; |  | 
| 393       ss << time_offset_ms; |  | 
| 394 |  | 
| 395       webrtc::test::PrintResult( |  | 
| 396           "capture_ntp_time", "", "real - estimated", ss.str(), "ms", true); |  | 
| 397       EXPECT_TRUE(std::abs(time_offset_ms) < threshold_ms_); |  | 
| 398     } |  | 
| 399 |  | 
| 400     bool IsTextureSupported() const override { return false; } |  | 
| 401 |  | 
| 402     virtual Action OnSendRtp(const uint8_t* packet, size_t length) { |  | 
| 403       RTPHeader header; |  | 
| 404       EXPECT_TRUE(parser_->Parse(packet, length, &header)); |  | 
| 405 |  | 
| 406       if (!rtp_start_timestamp_set_) { |  | 
| 407         // Calculate the rtp timestamp offset in order to calculate the real |  | 
| 408         // capture time. |  | 
| 409         uint32_t first_capture_timestamp = |  | 
| 410             90 * static_cast<uint32_t>(capturer_->first_frame_capture_time()); |  | 
| 411         rtp_start_timestamp_ = header.timestamp - first_capture_timestamp; |  | 
| 412         rtp_start_timestamp_set_ = true; |  | 
| 413       } |  | 
| 414 |  | 
| 415       uint32_t capture_timestamp = header.timestamp - rtp_start_timestamp_; |  | 
| 416       capture_time_list_.insert( |  | 
| 417           capture_time_list_.end(), |  | 
| 418           std::make_pair(header.timestamp, capture_timestamp)); |  | 
| 419       return SEND_PACKET; |  | 
| 420     } |  | 
| 421 |  | 
| 422     void OnFrameGeneratorCapturerCreated( |  | 
| 423         test::FrameGeneratorCapturer* frame_generator_capturer) override { |  | 
| 424       capturer_ = frame_generator_capturer; |  | 
| 425     } |  | 
| 426 |  | 
| 427     void ModifyConfigs(VideoSendStream::Config* send_config, |  | 
| 428                        std::vector<VideoReceiveStream::Config>* receive_configs, |  | 
| 429                        VideoEncoderConfig* encoder_config) override { |  | 
| 430       (*receive_configs)[0].renderer = this; |  | 
| 431       // Enable the receiver side rtt calculation. |  | 
| 432       (*receive_configs)[0].rtp.rtcp_xr.receiver_reference_time_report = true; |  | 
| 433     } |  | 
| 434 |  | 
| 435     void PerformTest() override { |  | 
| 436       EXPECT_EQ(kEventSignaled, Wait()) << "Timed out while waiting for " |  | 
| 437                                            "estimated capture NTP time to be " |  | 
| 438                                            "within bounds."; |  | 
| 439     } |  | 
| 440 |  | 
| 441     Clock* clock_; |  | 
| 442     int threshold_ms_; |  | 
| 443     int start_time_ms_; |  | 
| 444     int run_time_ms_; |  | 
| 445     int64_t creation_time_ms_; |  | 
| 446     test::FrameGeneratorCapturer* capturer_; |  | 
| 447     bool rtp_start_timestamp_set_; |  | 
| 448     uint32_t rtp_start_timestamp_; |  | 
| 449     typedef std::map<uint32_t, uint32_t> FrameCaptureTimeList; |  | 
| 450     FrameCaptureTimeList capture_time_list_; |  | 
| 451   } test(net_config, threshold_ms, start_time_ms, run_time_ms); |  | 
| 452 |  | 
| 453   RunBaseTest(&test); |  | 
| 454 } |  | 
| 455 |  | 
| 456 TEST_F(CallPerfTest, CaptureNtpTimeWithNetworkDelay) { |  | 
| 457   FakeNetworkPipe::Config net_config; |  | 
| 458   net_config.queue_delay_ms = 100; |  | 
| 459   // TODO(wu): lower the threshold as the calculation/estimatation becomes more |  | 
| 460   // accurate. |  | 
| 461   const int kThresholdMs = 100; |  | 
| 462   const int kStartTimeMs = 10000; |  | 
| 463   const int kRunTimeMs = 20000; |  | 
| 464   TestCaptureNtpTime(net_config, kThresholdMs, kStartTimeMs, kRunTimeMs); |  | 
| 465 } |  | 
| 466 |  | 
| 467 TEST_F(CallPerfTest, CaptureNtpTimeWithNetworkJitter) { |  | 
| 468   FakeNetworkPipe::Config net_config; |  | 
| 469   net_config.queue_delay_ms = 100; |  | 
| 470   net_config.delay_standard_deviation_ms = 10; |  | 
| 471   // TODO(wu): lower the threshold as the calculation/estimatation becomes more |  | 
| 472   // accurate. |  | 
| 473   const int kThresholdMs = 100; |  | 
| 474   const int kStartTimeMs = 10000; |  | 
| 475   const int kRunTimeMs = 20000; |  | 
| 476   TestCaptureNtpTime(net_config, kThresholdMs, kStartTimeMs, kRunTimeMs); |  | 
| 477 } |  | 
| 478 |  | 
| 479 void CallPerfTest::TestCpuOveruse(LoadObserver::Load tested_load, |  | 
| 480                                   int encode_delay_ms) { |  | 
| 481   class LoadObserver : public test::SendTest, public webrtc::LoadObserver { |  | 
| 482    public: |  | 
| 483     LoadObserver(LoadObserver::Load tested_load, int encode_delay_ms) |  | 
| 484         : SendTest(kLongTimeoutMs), |  | 
| 485           tested_load_(tested_load), |  | 
| 486           encoder_(Clock::GetRealTimeClock(), encode_delay_ms) {} |  | 
| 487 |  | 
| 488     void OnLoadUpdate(Load load) override { |  | 
| 489       if (load == tested_load_) |  | 
| 490         observation_complete_->Set(); |  | 
| 491     } |  | 
| 492 |  | 
| 493     void ModifyConfigs(VideoSendStream::Config* send_config, |  | 
| 494                        std::vector<VideoReceiveStream::Config>* receive_configs, |  | 
| 495                        VideoEncoderConfig* encoder_config) override { |  | 
| 496       send_config->overuse_callback = this; |  | 
| 497       send_config->encoder_settings.encoder = &encoder_; |  | 
| 498     } |  | 
| 499 |  | 
| 500     void PerformTest() override { |  | 
| 501       EXPECT_EQ(kEventSignaled, Wait()) |  | 
| 502           << "Timed out before receiving an overuse callback."; |  | 
| 503     } |  | 
| 504 |  | 
| 505     LoadObserver::Load tested_load_; |  | 
| 506     test::DelayedEncoder encoder_; |  | 
| 507   } test(tested_load, encode_delay_ms); |  | 
| 508 |  | 
| 509   RunBaseTest(&test); |  | 
| 510 } |  | 
| 511 |  | 
| 512 TEST_F(CallPerfTest, ReceivesCpuUnderuse) { |  | 
| 513   const int kEncodeDelayMs = 2; |  | 
| 514   TestCpuOveruse(LoadObserver::kUnderuse, kEncodeDelayMs); |  | 
| 515 } |  | 
| 516 |  | 
| 517 TEST_F(CallPerfTest, ReceivesCpuOveruse) { |  | 
| 518   const int kEncodeDelayMs = 35; |  | 
| 519   TestCpuOveruse(LoadObserver::kOveruse, kEncodeDelayMs); |  | 
| 520 } |  | 
| 521 |  | 
| 522 void CallPerfTest::TestMinTransmitBitrate(bool pad_to_min_bitrate) { |  | 
| 523   static const int kMaxEncodeBitrateKbps = 30; |  | 
| 524   static const int kMinTransmitBitrateBps = 150000; |  | 
| 525   static const int kMinAcceptableTransmitBitrate = 130; |  | 
| 526   static const int kMaxAcceptableTransmitBitrate = 170; |  | 
| 527   static const int kNumBitrateObservationsInRange = 100; |  | 
| 528   static const int kAcceptableBitrateErrorMargin = 15;  // +- 7 |  | 
| 529   class BitrateObserver : public test::EndToEndTest, public PacketReceiver { |  | 
| 530    public: |  | 
| 531     explicit BitrateObserver(bool using_min_transmit_bitrate) |  | 
| 532         : EndToEndTest(kLongTimeoutMs), |  | 
| 533           send_stream_(nullptr), |  | 
| 534           send_transport_receiver_(nullptr), |  | 
| 535           pad_to_min_bitrate_(using_min_transmit_bitrate), |  | 
| 536           num_bitrate_observations_in_range_(0) {} |  | 
| 537 |  | 
| 538    private: |  | 
| 539     void SetReceivers(PacketReceiver* send_transport_receiver, |  | 
| 540                       PacketReceiver* receive_transport_receiver) override { |  | 
| 541       send_transport_receiver_ = send_transport_receiver; |  | 
| 542       test::RtpRtcpObserver::SetReceivers(this, receive_transport_receiver); |  | 
| 543     } |  | 
| 544 |  | 
| 545     DeliveryStatus DeliverPacket(MediaType media_type, |  | 
| 546                                  const uint8_t* packet, |  | 
| 547                                  size_t length, |  | 
| 548                                  const PacketTime& packet_time) override { |  | 
| 549       VideoSendStream::Stats stats = send_stream_->GetStats(); |  | 
| 550       if (stats.substreams.size() > 0) { |  | 
| 551         RTC_DCHECK_EQ(1u, stats.substreams.size()); |  | 
| 552         int bitrate_kbps = |  | 
| 553             stats.substreams.begin()->second.total_bitrate_bps / 1000; |  | 
| 554         if (bitrate_kbps > 0) { |  | 
| 555           test::PrintResult( |  | 
| 556               "bitrate_stats_", |  | 
| 557               (pad_to_min_bitrate_ ? "min_transmit_bitrate" |  | 
| 558                                    : "without_min_transmit_bitrate"), |  | 
| 559               "bitrate_kbps", |  | 
| 560               static_cast<size_t>(bitrate_kbps), |  | 
| 561               "kbps", |  | 
| 562               false); |  | 
| 563           if (pad_to_min_bitrate_) { |  | 
| 564             if (bitrate_kbps > kMinAcceptableTransmitBitrate && |  | 
| 565                 bitrate_kbps < kMaxAcceptableTransmitBitrate) { |  | 
| 566               ++num_bitrate_observations_in_range_; |  | 
| 567             } |  | 
| 568           } else { |  | 
| 569             // Expect bitrate stats to roughly match the max encode bitrate. |  | 
| 570             if (bitrate_kbps > (kMaxEncodeBitrateKbps - |  | 
| 571                                 kAcceptableBitrateErrorMargin / 2) && |  | 
| 572                 bitrate_kbps < (kMaxEncodeBitrateKbps + |  | 
| 573                                 kAcceptableBitrateErrorMargin / 2)) { |  | 
| 574               ++num_bitrate_observations_in_range_; |  | 
| 575             } |  | 
| 576           } |  | 
| 577           if (num_bitrate_observations_in_range_ == |  | 
| 578               kNumBitrateObservationsInRange) |  | 
| 579             observation_complete_->Set(); |  | 
| 580         } |  | 
| 581       } |  | 
| 582       return send_transport_receiver_->DeliverPacket(media_type, packet, length, |  | 
| 583                                                      packet_time); |  | 
| 584     } |  | 
| 585 |  | 
| 586     void OnStreamsCreated( |  | 
| 587         VideoSendStream* send_stream, |  | 
| 588         const std::vector<VideoReceiveStream*>& receive_streams) override { |  | 
| 589       send_stream_ = send_stream; |  | 
| 590     } |  | 
| 591 |  | 
| 592     void ModifyConfigs(VideoSendStream::Config* send_config, |  | 
| 593                        std::vector<VideoReceiveStream::Config>* receive_configs, |  | 
| 594                        VideoEncoderConfig* encoder_config) override { |  | 
| 595       if (pad_to_min_bitrate_) { |  | 
| 596         encoder_config->min_transmit_bitrate_bps = kMinTransmitBitrateBps; |  | 
| 597       } else { |  | 
| 598         RTC_DCHECK_EQ(0, encoder_config->min_transmit_bitrate_bps); |  | 
| 599       } |  | 
| 600     } |  | 
| 601 |  | 
| 602     void PerformTest() override { |  | 
| 603       EXPECT_EQ(kEventSignaled, Wait()) |  | 
| 604           << "Timeout while waiting for send-bitrate stats."; |  | 
| 605     } |  | 
| 606 |  | 
| 607     VideoSendStream* send_stream_; |  | 
| 608     PacketReceiver* send_transport_receiver_; |  | 
| 609     const bool pad_to_min_bitrate_; |  | 
| 610     int num_bitrate_observations_in_range_; |  | 
| 611   } test(pad_to_min_bitrate); |  | 
| 612 |  | 
| 613   fake_encoder_.SetMaxBitrate(kMaxEncodeBitrateKbps); |  | 
| 614   RunBaseTest(&test); |  | 
| 615 } |  | 
| 616 |  | 
| 617 TEST_F(CallPerfTest, PadsToMinTransmitBitrate) { TestMinTransmitBitrate(true); } |  | 
| 618 |  | 
| 619 TEST_F(CallPerfTest, NoPadWithoutMinTransmitBitrate) { |  | 
| 620   TestMinTransmitBitrate(false); |  | 
| 621 } |  | 
| 622 |  | 
| 623 TEST_F(CallPerfTest, KeepsHighBitrateWhenReconfiguringSender) { |  | 
| 624   static const uint32_t kInitialBitrateKbps = 400; |  | 
| 625   static const uint32_t kReconfigureThresholdKbps = 600; |  | 
| 626   static const uint32_t kPermittedReconfiguredBitrateDiffKbps = 100; |  | 
| 627 |  | 
| 628   class BitrateObserver : public test::EndToEndTest, public test::FakeEncoder { |  | 
| 629    public: |  | 
| 630     BitrateObserver() |  | 
| 631         : EndToEndTest(kDefaultTimeoutMs), |  | 
| 632           FakeEncoder(Clock::GetRealTimeClock()), |  | 
| 633           time_to_reconfigure_(webrtc::EventWrapper::Create()), |  | 
| 634           encoder_inits_(0), |  | 
| 635           last_set_bitrate_(0), |  | 
| 636           send_stream_(nullptr) {} |  | 
| 637 |  | 
| 638     int32_t InitEncode(const VideoCodec* config, |  | 
| 639                        int32_t number_of_cores, |  | 
| 640                        size_t max_payload_size) override { |  | 
| 641       if (encoder_inits_ == 0) { |  | 
| 642         EXPECT_EQ(kInitialBitrateKbps, config->startBitrate) |  | 
| 643             << "Encoder not initialized at expected bitrate."; |  | 
| 644       } |  | 
| 645       ++encoder_inits_; |  | 
| 646       if (encoder_inits_ == 2) { |  | 
| 647         EXPECT_GE(last_set_bitrate_, kReconfigureThresholdKbps); |  | 
| 648         EXPECT_NEAR(config->startBitrate, |  | 
| 649                     last_set_bitrate_, |  | 
| 650                     kPermittedReconfiguredBitrateDiffKbps) |  | 
| 651             << "Encoder reconfigured with bitrate too far away from last set."; |  | 
| 652         observation_complete_->Set(); |  | 
| 653       } |  | 
| 654       return FakeEncoder::InitEncode(config, number_of_cores, max_payload_size); |  | 
| 655     } |  | 
| 656 |  | 
| 657     int32_t SetRates(uint32_t new_target_bitrate_kbps, |  | 
| 658                      uint32_t framerate) override { |  | 
| 659       last_set_bitrate_ = new_target_bitrate_kbps; |  | 
| 660       if (encoder_inits_ == 1 && |  | 
| 661           new_target_bitrate_kbps > kReconfigureThresholdKbps) { |  | 
| 662         time_to_reconfigure_->Set(); |  | 
| 663       } |  | 
| 664       return FakeEncoder::SetRates(new_target_bitrate_kbps, framerate); |  | 
| 665     } |  | 
| 666 |  | 
| 667     Call::Config GetSenderCallConfig() override { |  | 
| 668       Call::Config config = EndToEndTest::GetSenderCallConfig(); |  | 
| 669       config.bitrate_config.start_bitrate_bps = kInitialBitrateKbps * 1000; |  | 
| 670       return config; |  | 
| 671     } |  | 
| 672 |  | 
| 673     void ModifyConfigs(VideoSendStream::Config* send_config, |  | 
| 674                        std::vector<VideoReceiveStream::Config>* receive_configs, |  | 
| 675                        VideoEncoderConfig* encoder_config) override { |  | 
| 676       send_config->encoder_settings.encoder = this; |  | 
| 677       encoder_config->streams[0].min_bitrate_bps = 50000; |  | 
| 678       encoder_config->streams[0].target_bitrate_bps = |  | 
| 679           encoder_config->streams[0].max_bitrate_bps = 2000000; |  | 
| 680 |  | 
| 681       encoder_config_ = *encoder_config; |  | 
| 682     } |  | 
| 683 |  | 
| 684     void OnStreamsCreated( |  | 
| 685         VideoSendStream* send_stream, |  | 
| 686         const std::vector<VideoReceiveStream*>& receive_streams) override { |  | 
| 687       send_stream_ = send_stream; |  | 
| 688     } |  | 
| 689 |  | 
| 690     void PerformTest() override { |  | 
| 691       ASSERT_EQ(kEventSignaled, time_to_reconfigure_->Wait(kDefaultTimeoutMs)) |  | 
| 692           << "Timed out before receiving an initial high bitrate."; |  | 
| 693       encoder_config_.streams[0].width *= 2; |  | 
| 694       encoder_config_.streams[0].height *= 2; |  | 
| 695       EXPECT_TRUE(send_stream_->ReconfigureVideoEncoder(encoder_config_)); |  | 
| 696       EXPECT_EQ(kEventSignaled, Wait()) |  | 
| 697           << "Timed out while waiting for a couple of high bitrate estimates " |  | 
| 698              "after reconfiguring the send stream."; |  | 
| 699     } |  | 
| 700 |  | 
| 701    private: |  | 
| 702     rtc::scoped_ptr<webrtc::EventWrapper> time_to_reconfigure_; |  | 
| 703     int encoder_inits_; |  | 
| 704     uint32_t last_set_bitrate_; |  | 
| 705     VideoSendStream* send_stream_; |  | 
| 706     VideoEncoderConfig encoder_config_; |  | 
| 707   } test; |  | 
| 708 |  | 
| 709   RunBaseTest(&test); |  | 
| 710 } |  | 
| 711 |  | 
| 712 }  // namespace webrtc |  | 
| OLD | NEW | 
|---|