1f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org/*
2f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
3f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org *
4f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org *  Use of this source code is governed by a BSD-style license
5f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org *  that can be found in the LICENSE file in the root of the source
6f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org *  tree. An additional intellectual property rights grant can be found
7f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org *  in the file PATENTS.  All contributing project authors may
8f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org *  be found in the AUTHORS file in the root of the source tree.
9f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org */
10f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org#include <assert.h>
11f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org
12f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org#include <algorithm>
13f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org#include <sstream>
14f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org#include <string>
15f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org
16f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org#include "testing/gtest/include/gtest/gtest.h"
17f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org
18d54aa969545bd9c5ccc0077dd6645e742bf11418pbos@webrtc.org#include "webrtc/base/thread_annotations.h"
19f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org#include "webrtc/call.h"
2070e2ce90d527388f9829a7d084dfa3b2a525bb49henrik.lundin@webrtc.org#include "webrtc/modules/audio_coding/main/interface/audio_coding_module.h"
21f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org#include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h"
22f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org#include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
23f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
24d2fb259b3bc61c68f368929510215a7ee7d00fdawu@webrtc.org#include "webrtc/system_wrappers/interface/rtp_to_ntp.h"
25f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org#include "webrtc/system_wrappers/interface/scoped_ptr.h"
26eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org#include "webrtc/test/call_test.h"
27f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org#include "webrtc/test/direct_transport.h"
28e2a7a77646b23fb3704d267e6079e04bde493543pbos@webrtc.org#include "webrtc/test/encoder_settings.h"
29f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org#include "webrtc/test/fake_audio_device.h"
30f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org#include "webrtc/test/fake_decoder.h"
31f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org#include "webrtc/test/fake_encoder.h"
32f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org#include "webrtc/test/frame_generator.h"
33f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org#include "webrtc/test/frame_generator_capturer.h"
34f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org#include "webrtc/test/rtp_rtcp_observer.h"
35f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org#include "webrtc/test/testsupport/fileutils.h"
36f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org#include "webrtc/test/testsupport/perf_test.h"
37f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org#include "webrtc/video/transport_adapter.h"
38f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org#include "webrtc/voice_engine/include/voe_base.h"
39f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org#include "webrtc/voice_engine/include/voe_codec.h"
40f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org#include "webrtc/voice_engine/include/voe_network.h"
41f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org#include "webrtc/voice_engine/include/voe_rtp_rtcp.h"
42f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org#include "webrtc/voice_engine/include/voe_video_sync.h"
43f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org
44f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.orgnamespace webrtc {
45f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org
46eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.orgclass CallPerfTest : public test::CallTest {
478ef65486bf136f11d8dc9c637f94d7c08b687120asapersson@webrtc.org protected:
48d01c49138f5c9c49c86251094f72759ee2c4705fstefan@webrtc.org  void TestAudioVideoSync(bool fec);
49d01c49138f5c9c49c86251094f72759ee2c4705fstefan@webrtc.org
503f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org  void TestMinTransmitBitrate(bool pad_to_min_bitrate);
513f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org
52093fc0b0b0b9ca4fe56a32e17c9c418382e802f0wu@webrtc.org  void TestCaptureNtpTime(const FakeNetworkPipe::Config& net_config,
53093fc0b0b0b9ca4fe56a32e17c9c418382e802f0wu@webrtc.org                          int threshold_ms,
54093fc0b0b0b9ca4fe56a32e17c9c418382e802f0wu@webrtc.org                          int start_time_ms,
55093fc0b0b0b9ca4fe56a32e17c9c418382e802f0wu@webrtc.org                          int run_time_ms);
56f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org};
57f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org
58f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.orgclass SyncRtcpObserver : public test::RtpRtcpObserver {
59f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org public:
60aacdb9f6eed4ceedc8db73865384e29444abcda2stefan@webrtc.org  explicit SyncRtcpObserver(const FakeNetworkPipe::Config& config)
61eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org      : test::RtpRtcpObserver(CallPerfTest::kLongTimeoutMs, config),
62c476e64d056c5e342bc5b23eecd493abf6d85d7fpbos@webrtc.org        crit_(CriticalSectionWrapper::CreateCriticalSection()) {}
63f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org
64f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  virtual Action OnSendRtcp(const uint8_t* packet, size_t length) OVERRIDE {
65f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org    RTCPUtility::RTCPParserV2 parser(packet, length, true);
66f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org    EXPECT_TRUE(parser.IsValid());
67f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org
68f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org    for (RTCPUtility::RTCPPacketTypes packet_type = parser.Begin();
69f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org         packet_type != RTCPUtility::kRtcpNotValidCode;
70f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org         packet_type = parser.Iterate()) {
71f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org      if (packet_type == RTCPUtility::kRtcpSrCode) {
72f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org        const RTCPUtility::RTCPPacket& packet = parser.Packet();
73d2fb259b3bc61c68f368929510215a7ee7d00fdawu@webrtc.org        RtcpMeasurement ntp_rtp_pair(
74f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org            packet.SR.NTPMostSignificant,
75f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org            packet.SR.NTPLeastSignificant,
76f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org            packet.SR.RTPTimestamp);
77f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org        StoreNtpRtpPair(ntp_rtp_pair);
78f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org      }
79f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org    }
80f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org    return SEND_PACKET;
81f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  }
82f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org
83f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  int64_t RtpTimestampToNtp(uint32_t timestamp) const {
84c476e64d056c5e342bc5b23eecd493abf6d85d7fpbos@webrtc.org    CriticalSectionScoped lock(crit_.get());
85f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org    int64_t timestamp_in_ms = -1;
86f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org    if (ntp_rtp_pairs_.size() == 2) {
87f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org      // TODO(stefan): We can't EXPECT_TRUE on this call due to a bug in the
88f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org      // RTCP sender where it sends RTCP SR before any RTP packets, which leads
89f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org      // to a bogus NTP/RTP mapping.
90d2fb259b3bc61c68f368929510215a7ee7d00fdawu@webrtc.org      RtpToNtpMs(timestamp, ntp_rtp_pairs_, &timestamp_in_ms);
91f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org      return timestamp_in_ms;
92f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org    }
93f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org    return -1;
94f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  }
95f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org
96f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org private:
97d2fb259b3bc61c68f368929510215a7ee7d00fdawu@webrtc.org  void StoreNtpRtpPair(RtcpMeasurement ntp_rtp_pair) {
98c476e64d056c5e342bc5b23eecd493abf6d85d7fpbos@webrtc.org    CriticalSectionScoped lock(crit_.get());
99d2fb259b3bc61c68f368929510215a7ee7d00fdawu@webrtc.org    for (RtcpList::iterator it = ntp_rtp_pairs_.begin();
100f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org         it != ntp_rtp_pairs_.end();
101f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org         ++it) {
102f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org      if (ntp_rtp_pair.ntp_secs == it->ntp_secs &&
103f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org          ntp_rtp_pair.ntp_frac == it->ntp_frac) {
104f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org        // This RTCP has already been added to the list.
105f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org        return;
106f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org      }
107f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org    }
108f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org    // We need two RTCP SR reports to map between RTP and NTP. More than two
109f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org    // will not improve the mapping.
110f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org    if (ntp_rtp_pairs_.size() == 2) {
111f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org      ntp_rtp_pairs_.pop_back();
112f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org    }
113f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org    ntp_rtp_pairs_.push_front(ntp_rtp_pair);
114f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  }
115f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org
116c476e64d056c5e342bc5b23eecd493abf6d85d7fpbos@webrtc.org  const scoped_ptr<CriticalSectionWrapper> crit_;
117d2fb259b3bc61c68f368929510215a7ee7d00fdawu@webrtc.org  RtcpList ntp_rtp_pairs_ GUARDED_BY(crit_);
118f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org};
119f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org
120f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.orgclass VideoRtcpAndSyncObserver : public SyncRtcpObserver, public VideoRenderer {
121f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  static const int kInSyncThresholdMs = 50;
122f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  static const int kStartupTimeMs = 2000;
123f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  static const int kMinRunTimeMs = 30000;
124f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org
125f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org public:
126f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  VideoRtcpAndSyncObserver(Clock* clock,
127f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org                           int voe_channel,
128f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org                           VoEVideoSync* voe_sync,
1296cee2bafdd7b97c6b3893d67690ed2e37ada6ef1henrik.lundin@webrtc.org                           SyncRtcpObserver* audio_observer)
130aacdb9f6eed4ceedc8db73865384e29444abcda2stefan@webrtc.org      : SyncRtcpObserver(FakeNetworkPipe::Config()),
131f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org        clock_(clock),
132f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org        voe_channel_(voe_channel),
133f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org        voe_sync_(voe_sync),
134f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org        audio_observer_(audio_observer),
135f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org        creation_time_ms_(clock_->TimeInMilliseconds()),
1366cee2bafdd7b97c6b3893d67690ed2e37ada6ef1henrik.lundin@webrtc.org        first_time_in_sync_(-1) {}
137f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org
138f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  virtual void RenderFrame(const I420VideoFrame& video_frame,
139f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org                           int time_to_render_ms) OVERRIDE {
140f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org    int64_t now_ms = clock_->TimeInMilliseconds();
141f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org    uint32_t playout_timestamp = 0;
142f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org    if (voe_sync_->GetPlayoutTimestamp(voe_channel_, playout_timestamp) != 0)
143f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org      return;
144f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org    int64_t latest_audio_ntp =
145f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org        audio_observer_->RtpTimestampToNtp(playout_timestamp);
146f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org    int64_t latest_video_ntp = RtpTimestampToNtp(video_frame.timestamp());
147f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org    if (latest_audio_ntp < 0 || latest_video_ntp < 0)
148f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org      return;
149f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org    int time_until_render_ms =
150f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org        std::max(0, static_cast<int>(video_frame.render_time_ms() - now_ms));
151f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org    latest_video_ntp += time_until_render_ms;
152f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org    int64_t stream_offset = latest_audio_ntp - latest_video_ntp;
153f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org    std::stringstream ss;
154f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org    ss << stream_offset;
15570e2ce90d527388f9829a7d084dfa3b2a525bb49henrik.lundin@webrtc.org    webrtc::test::PrintResult("stream_offset",
1566cee2bafdd7b97c6b3893d67690ed2e37ada6ef1henrik.lundin@webrtc.org                              "",
15770e2ce90d527388f9829a7d084dfa3b2a525bb49henrik.lundin@webrtc.org                              "synchronization",
15870e2ce90d527388f9829a7d084dfa3b2a525bb49henrik.lundin@webrtc.org                              ss.str(),
15970e2ce90d527388f9829a7d084dfa3b2a525bb49henrik.lundin@webrtc.org                              "ms",
16070e2ce90d527388f9829a7d084dfa3b2a525bb49henrik.lundin@webrtc.org                              false);
161f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org    int64_t time_since_creation = now_ms - creation_time_ms_;
162f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org    // During the first couple of seconds audio and video can falsely be
163f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org    // estimated as being synchronized. We don't want to trigger on those.
164f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org    if (time_since_creation < kStartupTimeMs)
165f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org      return;
1662a25b6c685c7d6323a8fdaf514a7b36f4f2d827dpbos@webrtc.org    if (std::abs(latest_audio_ntp - latest_video_ntp) < kInSyncThresholdMs) {
167f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org      if (first_time_in_sync_ == -1) {
168f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org        first_time_in_sync_ = now_ms;
169f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org        webrtc::test::PrintResult("sync_convergence_time",
1706cee2bafdd7b97c6b3893d67690ed2e37ada6ef1henrik.lundin@webrtc.org                                  "",
171f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org                                  "synchronization",
172f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org                                  time_since_creation,
173f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org                                  "ms",
174f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org                                  false);
175f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org      }
176f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org      if (time_since_creation > kMinRunTimeMs)
177f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org        observation_complete_->Set();
178f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org    }
179f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  }
180f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org
181f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org private:
182c476e64d056c5e342bc5b23eecd493abf6d85d7fpbos@webrtc.org  Clock* const clock_;
183f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  int voe_channel_;
184f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  VoEVideoSync* voe_sync_;
185f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  SyncRtcpObserver* audio_observer_;
186f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  int64_t creation_time_ms_;
187f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  int64_t first_time_in_sync_;
188f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org};
189f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org
190d01c49138f5c9c49c86251094f72759ee2c4705fstefan@webrtc.orgvoid CallPerfTest::TestAudioVideoSync(bool fec) {
191eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org  class AudioPacketReceiver : public PacketReceiver {
192eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org   public:
193eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org    AudioPacketReceiver(int channel, VoENetwork* voe_network)
194eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org        : channel_(channel),
195eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org          voe_network_(voe_network),
196eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org          parser_(RtpHeaderParser::Create()) {}
197eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org    virtual DeliveryStatus DeliverPacket(const uint8_t* packet,
198eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org                                         size_t length) OVERRIDE {
199eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org      int ret;
200eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org      if (parser_->IsRtcp(packet, static_cast<int>(length))) {
201eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org        ret = voe_network_->ReceivedRTCPPacket(
202eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org            channel_, packet, static_cast<unsigned int>(length));
203eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org      } else {
204eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org        ret = voe_network_->ReceivedRTPPacket(
205eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org            channel_, packet, static_cast<unsigned int>(length), PacketTime());
206eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org      }
207eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org      return ret == 0 ? DELIVERY_OK : DELIVERY_PACKET_ERROR;
208eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org    }
209eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org
210eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org   private:
211eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org    int channel_;
212eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org    VoENetwork* voe_network_;
213eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org    scoped_ptr<RtpHeaderParser> parser_;
214eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org  };
215eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org
216f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  VoiceEngine* voice_engine = VoiceEngine::Create();
217f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  VoEBase* voe_base = VoEBase::GetInterface(voice_engine);
218f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  VoECodec* voe_codec = VoECodec::GetInterface(voice_engine);
219f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  VoENetwork* voe_network = VoENetwork::GetInterface(voice_engine);
220f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  VoEVideoSync* voe_sync = VoEVideoSync::GetInterface(voice_engine);
221f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  const std::string audio_filename =
222f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org      test::ResourcePath("voice_engine/audio_long16", "pcm");
223f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  ASSERT_STRNE("", audio_filename.c_str());
224f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  test::FakeAudioDevice fake_audio_device(Clock::GetRealTimeClock(),
225f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org                                          audio_filename);
226f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  EXPECT_EQ(0, voe_base->Init(&fake_audio_device, NULL));
2276cee2bafdd7b97c6b3893d67690ed2e37ada6ef1henrik.lundin@webrtc.org  int channel = voe_base->CreateChannel();
228f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org
229aacdb9f6eed4ceedc8db73865384e29444abcda2stefan@webrtc.org  FakeNetworkPipe::Config net_config;
230aacdb9f6eed4ceedc8db73865384e29444abcda2stefan@webrtc.org  net_config.queue_delay_ms = 500;
231d01c49138f5c9c49c86251094f72759ee2c4705fstefan@webrtc.org  net_config.loss_percent = 5;
232aacdb9f6eed4ceedc8db73865384e29444abcda2stefan@webrtc.org  SyncRtcpObserver audio_observer(net_config);
23370e2ce90d527388f9829a7d084dfa3b2a525bb49henrik.lundin@webrtc.org  VideoRtcpAndSyncObserver observer(Clock::GetRealTimeClock(),
23470e2ce90d527388f9829a7d084dfa3b2a525bb49henrik.lundin@webrtc.org                                    channel,
23570e2ce90d527388f9829a7d084dfa3b2a525bb49henrik.lundin@webrtc.org                                    voe_sync,
2366cee2bafdd7b97c6b3893d67690ed2e37ada6ef1henrik.lundin@webrtc.org                                    &audio_observer);
237f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org
238f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  Call::Config receiver_config(observer.ReceiveTransport());
239f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  receiver_config.voice_engine = voice_engine;
240eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org  CreateCalls(Call::Config(observer.SendTransport()), receiver_config);
241eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org
242f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  CodecInst isac = {103, "ISAC", 16000, 480, 1, 32000};
243f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  EXPECT_EQ(0, voe_codec->SetSendCodec(channel, isac));
244f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org
245eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org  AudioPacketReceiver voe_packet_receiver(channel, voe_network);
246f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  audio_observer.SetReceivers(&voe_packet_receiver, &voe_packet_receiver);
247f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org
248f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  internal::TransportAdapter transport_adapter(audio_observer.SendTransport());
2490a298154b3a4781f0294d3877f77feb58e33eeb7sprang@webrtc.org  transport_adapter.Enable();
250f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  EXPECT_EQ(0,
251f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org            voe_network->RegisterExternalTransport(channel, transport_adapter));
252f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org
253eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org  observer.SetReceivers(receiver_call_->Receiver(), sender_call_->Receiver());
254f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org
255f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  test::FakeDecoder fake_decoder;
256f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org
257eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org  CreateSendConfig(1);
258eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org  CreateMatchingReceiveConfigs();
259eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org
260d01c49138f5c9c49c86251094f72759ee2c4705fstefan@webrtc.org  send_config_.rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
261d01c49138f5c9c49c86251094f72759ee2c4705fstefan@webrtc.org  if (fec) {
262d01c49138f5c9c49c86251094f72759ee2c4705fstefan@webrtc.org    send_config_.rtp.fec.red_payload_type = kRedPayloadType;
263d01c49138f5c9c49c86251094f72759ee2c4705fstefan@webrtc.org    send_config_.rtp.fec.ulpfec_payload_type = kUlpfecPayloadType;
264d01c49138f5c9c49c86251094f72759ee2c4705fstefan@webrtc.org    receive_configs_[0].rtp.fec.red_payload_type = kRedPayloadType;
265d01c49138f5c9c49c86251094f72759ee2c4705fstefan@webrtc.org    receive_configs_[0].rtp.fec.ulpfec_payload_type = kUlpfecPayloadType;
266d01c49138f5c9c49c86251094f72759ee2c4705fstefan@webrtc.org  }
267d01c49138f5c9c49c86251094f72759ee2c4705fstefan@webrtc.org  receive_configs_[0].rtp.nack.rtp_history_ms = 1000;
26888b558febb8e8f42df6c7482efe76795c3fed399pbos@webrtc.org  receive_configs_[0].renderer = &observer;
26988b558febb8e8f42df6c7482efe76795c3fed399pbos@webrtc.org  receive_configs_[0].audio_channel_id = channel;
270eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org
271eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org  CreateStreams();
272eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org
273eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org  CreateFrameGeneratorCapturer();
274eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org
275eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org  Start();
276f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org
277f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  fake_audio_device.Start();
278f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  EXPECT_EQ(0, voe_base->StartPlayout(channel));
279f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  EXPECT_EQ(0, voe_base->StartReceive(channel));
280f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  EXPECT_EQ(0, voe_base->StartSend(channel));
281f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org
282f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  EXPECT_EQ(kEventSignaled, observer.Wait())
283f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org      << "Timed out while waiting for audio and video to be synchronized.";
284f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org
285f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  EXPECT_EQ(0, voe_base->StopSend(channel));
286f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  EXPECT_EQ(0, voe_base->StopReceive(channel));
287f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  EXPECT_EQ(0, voe_base->StopPlayout(channel));
288f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  fake_audio_device.Stop();
289f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org
290eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org  Stop();
291f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  observer.StopSending();
292f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  audio_observer.StopSending();
293f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org
294f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  voe_base->DeleteChannel(channel);
295f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  voe_base->Release();
296f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  voe_codec->Release();
297f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  voe_network->Release();
298f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org  voe_sync->Release();
2998ef65486bf136f11d8dc9c637f94d7c08b687120asapersson@webrtc.org
300eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org  DestroyStreams();
301093fc0b0b0b9ca4fe56a32e17c9c418382e802f0wu@webrtc.org
302eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org  VoiceEngine::Delete(voice_engine);
303eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org}
304093fc0b0b0b9ca4fe56a32e17c9c418382e802f0wu@webrtc.org
305d01c49138f5c9c49c86251094f72759ee2c4705fstefan@webrtc.orgTEST_F(CallPerfTest, PlaysOutAudioAndVideoInSync) {
306d01c49138f5c9c49c86251094f72759ee2c4705fstefan@webrtc.org  TestAudioVideoSync(false);
307d01c49138f5c9c49c86251094f72759ee2c4705fstefan@webrtc.org}
308d01c49138f5c9c49c86251094f72759ee2c4705fstefan@webrtc.org
309d01c49138f5c9c49c86251094f72759ee2c4705fstefan@webrtc.orgTEST_F(CallPerfTest, PlaysOutAudioAndVideoInSyncWithFec) {
310d01c49138f5c9c49c86251094f72759ee2c4705fstefan@webrtc.org  TestAudioVideoSync(true);
311d01c49138f5c9c49c86251094f72759ee2c4705fstefan@webrtc.org}
312d01c49138f5c9c49c86251094f72759ee2c4705fstefan@webrtc.org
313eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.orgvoid CallPerfTest::TestCaptureNtpTime(const FakeNetworkPipe::Config& net_config,
314eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org                                      int threshold_ms,
315eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org                                      int start_time_ms,
316eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org                                      int run_time_ms) {
317eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org  class CaptureNtpTimeObserver : public test::EndToEndTest,
318eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org                                 public VideoRenderer {
319eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org   public:
320eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org    CaptureNtpTimeObserver(const FakeNetworkPipe::Config& config,
321eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org                           int threshold_ms,
322eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org                           int start_time_ms,
323eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org                           int run_time_ms)
324eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org        : EndToEndTest(kLongTimeoutMs, config),
325eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org          clock_(Clock::GetRealTimeClock()),
326eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org          threshold_ms_(threshold_ms),
327eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org          start_time_ms_(start_time_ms),
328eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org          run_time_ms_(run_time_ms),
329eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org          creation_time_ms_(clock_->TimeInMilliseconds()),
330eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org          capturer_(NULL),
331eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org          rtp_start_timestamp_set_(false),
332eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org          rtp_start_timestamp_(0) {}
333093fc0b0b0b9ca4fe56a32e17c9c418382e802f0wu@webrtc.org
334eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org   private:
335eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org    virtual void RenderFrame(const I420VideoFrame& video_frame,
336eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org                             int time_to_render_ms) OVERRIDE {
337eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org      if (video_frame.ntp_time_ms() <= 0) {
338eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org        // Haven't got enough RTCP SR in order to calculate the capture ntp
339eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org        // time.
340eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org        return;
341eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org      }
342093fc0b0b0b9ca4fe56a32e17c9c418382e802f0wu@webrtc.org
343eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org      int64_t now_ms = clock_->TimeInMilliseconds();
344eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org      int64_t time_since_creation = now_ms - creation_time_ms_;
345eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org      if (time_since_creation < start_time_ms_) {
346eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org        // Wait for |start_time_ms_| before start measuring.
347eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org        return;
348eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org      }
349093fc0b0b0b9ca4fe56a32e17c9c418382e802f0wu@webrtc.org
350eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org      if (time_since_creation > run_time_ms_) {
351eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org        observation_complete_->Set();
352eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org      }
353093fc0b0b0b9ca4fe56a32e17c9c418382e802f0wu@webrtc.org
354eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org      FrameCaptureTimeList::iterator iter =
355eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org          capture_time_list_.find(video_frame.timestamp());
356eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org      EXPECT_TRUE(iter != capture_time_list_.end());
357eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org
358eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org      // The real capture time has been wrapped to uint32_t before converted
359eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org      // to rtp timestamp in the sender side. So here we convert the estimated
360eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org      // capture time to a uint32_t 90k timestamp also for comparing.
361eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org      uint32_t estimated_capture_timestamp =
362eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org          90 * static_cast<uint32_t>(video_frame.ntp_time_ms());
363eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org      uint32_t real_capture_timestamp = iter->second;
364eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org      int time_offset_ms = real_capture_timestamp - estimated_capture_timestamp;
365eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org      time_offset_ms = time_offset_ms / 90;
366eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org      std::stringstream ss;
367eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org      ss << time_offset_ms;
368eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org
369eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org      webrtc::test::PrintResult(
370eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org          "capture_ntp_time", "", "real - estimated", ss.str(), "ms", true);
371eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org      EXPECT_TRUE(std::abs(time_offset_ms) < threshold_ms_);
372093fc0b0b0b9ca4fe56a32e17c9c418382e802f0wu@webrtc.org    }
373093fc0b0b0b9ca4fe56a32e17c9c418382e802f0wu@webrtc.org
374eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org    virtual Action OnSendRtp(const uint8_t* packet, size_t length) {
375eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org      RTPHeader header;
3766aae61c2c693fa3425c73c420e7046e95486b592pbos@webrtc.org      EXPECT_TRUE(parser_->Parse(packet, length, &header));
377eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org
378eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org      if (!rtp_start_timestamp_set_) {
379eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org        // Calculate the rtp timestamp offset in order to calculate the real
380eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org        // capture time.
381eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org        uint32_t first_capture_timestamp =
382eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org            90 * static_cast<uint32_t>(capturer_->first_frame_capture_time());
383eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org        rtp_start_timestamp_ = header.timestamp - first_capture_timestamp;
384eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org        rtp_start_timestamp_set_ = true;
385eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org      }
386093fc0b0b0b9ca4fe56a32e17c9c418382e802f0wu@webrtc.org
387eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org      uint32_t capture_timestamp = header.timestamp - rtp_start_timestamp_;
388eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org      capture_time_list_.insert(
389eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org          capture_time_list_.end(),
390eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org          std::make_pair(header.timestamp, capture_timestamp));
391eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org      return SEND_PACKET;
392eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org    }
393093fc0b0b0b9ca4fe56a32e17c9c418382e802f0wu@webrtc.org
394eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org    virtual void OnFrameGeneratorCapturerCreated(
395eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org        test::FrameGeneratorCapturer* frame_generator_capturer) OVERRIDE {
396eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org      capturer_ = frame_generator_capturer;
397eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org    }
398093fc0b0b0b9ca4fe56a32e17c9c418382e802f0wu@webrtc.org
399eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org    virtual void ModifyConfigs(
400eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org        VideoSendStream::Config* send_config,
40188b558febb8e8f42df6c7482efe76795c3fed399pbos@webrtc.org        std::vector<VideoReceiveStream::Config>* receive_configs,
40258b5140b7535ae66c618cc64b0a955b8d47cc86cpbos@webrtc.org        VideoEncoderConfig* encoder_config) OVERRIDE {
40388b558febb8e8f42df6c7482efe76795c3fed399pbos@webrtc.org      (*receive_configs)[0].renderer = this;
404eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org      // Enable the receiver side rtt calculation.
40588b558febb8e8f42df6c7482efe76795c3fed399pbos@webrtc.org      (*receive_configs)[0].rtp.rtcp_xr.receiver_reference_time_report = true;
406eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org    }
407093fc0b0b0b9ca4fe56a32e17c9c418382e802f0wu@webrtc.org
408eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org    virtual void PerformTest() OVERRIDE {
409eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org      EXPECT_EQ(kEventSignaled, Wait()) << "Timed out while waiting for "
410eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org                                           "estimated capture NTP time to be "
411eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org                                           "within bounds.";
412eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org    }
413093fc0b0b0b9ca4fe56a32e17c9c418382e802f0wu@webrtc.org
414eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org    Clock* clock_;
415eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org    int threshold_ms_;
416eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org    int start_time_ms_;
417eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org    int run_time_ms_;
418eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org    int64_t creation_time_ms_;
419eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org    test::FrameGeneratorCapturer* capturer_;
420eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org    bool rtp_start_timestamp_set_;
421eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org    uint32_t rtp_start_timestamp_;
422eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org    typedef std::map<uint32_t, uint32_t> FrameCaptureTimeList;
423eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org    FrameCaptureTimeList capture_time_list_;
424eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org  } test(net_config, threshold_ms, start_time_ms, run_time_ms);
425eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org
426eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org  RunBaseTest(&test);
427093fc0b0b0b9ca4fe56a32e17c9c418382e802f0wu@webrtc.org}
428093fc0b0b0b9ca4fe56a32e17c9c418382e802f0wu@webrtc.org
4291ef9cee4e53d42bec5761fdae0d963b163ba17aawu@webrtc.orgTEST_F(CallPerfTest, CaptureNtpTimeWithNetworkDelay) {
430093fc0b0b0b9ca4fe56a32e17c9c418382e802f0wu@webrtc.org  FakeNetworkPipe::Config net_config;
431093fc0b0b0b9ca4fe56a32e17c9c418382e802f0wu@webrtc.org  net_config.queue_delay_ms = 100;
432093fc0b0b0b9ca4fe56a32e17c9c418382e802f0wu@webrtc.org  // TODO(wu): lower the threshold as the calculation/estimatation becomes more
433093fc0b0b0b9ca4fe56a32e17c9c418382e802f0wu@webrtc.org  // accurate.
4341ef9cee4e53d42bec5761fdae0d963b163ba17aawu@webrtc.org  const int kThresholdMs = 100;
435093fc0b0b0b9ca4fe56a32e17c9c418382e802f0wu@webrtc.org  const int kStartTimeMs = 10000;
436093fc0b0b0b9ca4fe56a32e17c9c418382e802f0wu@webrtc.org  const int kRunTimeMs = 20000;
437093fc0b0b0b9ca4fe56a32e17c9c418382e802f0wu@webrtc.org  TestCaptureNtpTime(net_config, kThresholdMs, kStartTimeMs, kRunTimeMs);
438093fc0b0b0b9ca4fe56a32e17c9c418382e802f0wu@webrtc.org}
439093fc0b0b0b9ca4fe56a32e17c9c418382e802f0wu@webrtc.org
4401cbc360c03fcad0ebed910d371530f48cb11951fwu@webrtc.orgTEST_F(CallPerfTest, CaptureNtpTimeWithNetworkJitter) {
441093fc0b0b0b9ca4fe56a32e17c9c418382e802f0wu@webrtc.org  FakeNetworkPipe::Config net_config;
4421cbc360c03fcad0ebed910d371530f48cb11951fwu@webrtc.org  net_config.queue_delay_ms = 100;
443093fc0b0b0b9ca4fe56a32e17c9c418382e802f0wu@webrtc.org  net_config.delay_standard_deviation_ms = 10;
444093fc0b0b0b9ca4fe56a32e17c9c418382e802f0wu@webrtc.org  // TODO(wu): lower the threshold as the calculation/estimatation becomes more
445093fc0b0b0b9ca4fe56a32e17c9c418382e802f0wu@webrtc.org  // accurate.
4461cbc360c03fcad0ebed910d371530f48cb11951fwu@webrtc.org  const int kThresholdMs = 100;
447093fc0b0b0b9ca4fe56a32e17c9c418382e802f0wu@webrtc.org  const int kStartTimeMs = 10000;
448093fc0b0b0b9ca4fe56a32e17c9c418382e802f0wu@webrtc.org  const int kRunTimeMs = 20000;
449093fc0b0b0b9ca4fe56a32e17c9c418382e802f0wu@webrtc.org  TestCaptureNtpTime(net_config, kThresholdMs, kStartTimeMs, kRunTimeMs);
450093fc0b0b0b9ca4fe56a32e17c9c418382e802f0wu@webrtc.org}
451093fc0b0b0b9ca4fe56a32e17c9c418382e802f0wu@webrtc.org
4528ef65486bf136f11d8dc9c637f94d7c08b687120asapersson@webrtc.orgTEST_F(CallPerfTest, RegisterCpuOveruseObserver) {
4538ef65486bf136f11d8dc9c637f94d7c08b687120asapersson@webrtc.org  // Verifies that either a normal or overuse callback is triggered.
454eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org  class OveruseCallbackObserver : public test::SendTest,
4558ef65486bf136f11d8dc9c637f94d7c08b687120asapersson@webrtc.org                                  public webrtc::OveruseCallback {
4568ef65486bf136f11d8dc9c637f94d7c08b687120asapersson@webrtc.org   public:
457eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org    OveruseCallbackObserver() : SendTest(kLongTimeoutMs) {}
4588ef65486bf136f11d8dc9c637f94d7c08b687120asapersson@webrtc.org
4598ef65486bf136f11d8dc9c637f94d7c08b687120asapersson@webrtc.org    virtual void OnOveruse() OVERRIDE {
4608ef65486bf136f11d8dc9c637f94d7c08b687120asapersson@webrtc.org      observation_complete_->Set();
4618ef65486bf136f11d8dc9c637f94d7c08b687120asapersson@webrtc.org    }
462eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org
4638ef65486bf136f11d8dc9c637f94d7c08b687120asapersson@webrtc.org    virtual void OnNormalUse() OVERRIDE {
4648ef65486bf136f11d8dc9c637f94d7c08b687120asapersson@webrtc.org      observation_complete_->Set();
4658ef65486bf136f11d8dc9c637f94d7c08b687120asapersson@webrtc.org    }
4668ef65486bf136f11d8dc9c637f94d7c08b687120asapersson@webrtc.org
467eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org    virtual Call::Config GetSenderCallConfig() OVERRIDE {
468eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org      Call::Config config(SendTransport());
469eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org      config.overuse_callback = this;
470eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org      return config;
471eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org    }
472eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org
473eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org    virtual void PerformTest() OVERRIDE {
474eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org      EXPECT_EQ(kEventSignaled, Wait())
475eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org          << "Timed out before receiving an overuse callback.";
476eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org    }
477eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org  } test;
4788ef65486bf136f11d8dc9c637f94d7c08b687120asapersson@webrtc.org
479eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org  RunBaseTest(&test);
4808ef65486bf136f11d8dc9c637f94d7c08b687120asapersson@webrtc.org}
4813f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org
4823f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.orgvoid CallPerfTest::TestMinTransmitBitrate(bool pad_to_min_bitrate) {
4833f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org  static const int kMaxEncodeBitrateKbps = 30;
4841d61e3a79d4a5c6693c959f59d9f9cc6c1bfb359pbos@webrtc.org  static const int kMinTransmitBitrateBps = 150000;
4853f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org  static const int kMinAcceptableTransmitBitrate = 130;
4863f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org  static const int kMaxAcceptableTransmitBitrate = 170;
4873f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org  static const int kNumBitrateObservationsInRange = 100;
488eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org  class BitrateObserver : public test::EndToEndTest, public PacketReceiver {
4893f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org   public:
4903f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org    explicit BitrateObserver(bool using_min_transmit_bitrate)
491eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org        : EndToEndTest(kLongTimeoutMs),
4923f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org          send_stream_(NULL),
4933f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org          send_transport_receiver_(NULL),
494eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org          pad_to_min_bitrate_(using_min_transmit_bitrate),
4953f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org          num_bitrate_observations_in_range_(0) {}
4963f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org
497eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org   private:
4983f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org    virtual void SetReceivers(PacketReceiver* send_transport_receiver,
4993f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org                              PacketReceiver* receive_transport_receiver)
5003f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org        OVERRIDE {
5013f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org      send_transport_receiver_ = send_transport_receiver;
5023f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org      test::RtpRtcpObserver::SetReceivers(this, receive_transport_receiver);
5033f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org    }
5043f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org
505bc57e0f1a00227c0cec3d429fc58cc442d07b509pbos@webrtc.org    virtual DeliveryStatus DeliverPacket(const uint8_t* packet,
506bc57e0f1a00227c0cec3d429fc58cc442d07b509pbos@webrtc.org                                         size_t length) OVERRIDE {
5073f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org      VideoSendStream::Stats stats = send_stream_->GetStats();
5083f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org      if (stats.substreams.size() > 0) {
5093f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org        assert(stats.substreams.size() == 1);
5103f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org        int bitrate_kbps = stats.substreams.begin()->second.bitrate_bps / 1000;
5113f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org        if (bitrate_kbps > 0) {
5123f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org          test::PrintResult(
5133f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org              "bitrate_stats_",
514eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org              (pad_to_min_bitrate_ ? "min_transmit_bitrate"
515eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org                                   : "without_min_transmit_bitrate"),
5163f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org              "bitrate_kbps",
5173f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org              static_cast<size_t>(bitrate_kbps),
5183f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org              "kbps",
5193f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org              false);
520eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org          if (pad_to_min_bitrate_) {
5213f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org            if (bitrate_kbps > kMinAcceptableTransmitBitrate &&
5223f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org                bitrate_kbps < kMaxAcceptableTransmitBitrate) {
5233f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org              ++num_bitrate_observations_in_range_;
5243f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org            }
5253f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org          } else {
5263f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org            // Expect bitrate stats to roughly match the max encode bitrate.
5273f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org            if (bitrate_kbps > kMaxEncodeBitrateKbps - 5 &&
5283f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org                bitrate_kbps < kMaxEncodeBitrateKbps + 5) {
5293f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org              ++num_bitrate_observations_in_range_;
5303f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org            }
5313f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org          }
5323f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org          if (num_bitrate_observations_in_range_ ==
5333f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org              kNumBitrateObservationsInRange)
5343f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org            observation_complete_->Set();
5353f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org        }
5363f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org      }
5373f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org      return send_transport_receiver_->DeliverPacket(packet, length);
5383f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org    }
5393f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org
54088b558febb8e8f42df6c7482efe76795c3fed399pbos@webrtc.org    virtual void OnStreamsCreated(
54188b558febb8e8f42df6c7482efe76795c3fed399pbos@webrtc.org        VideoSendStream* send_stream,
54288b558febb8e8f42df6c7482efe76795c3fed399pbos@webrtc.org        const std::vector<VideoReceiveStream*>& receive_streams) OVERRIDE {
543eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org      send_stream_ = send_stream;
544eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org    }
545eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org
546eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org    virtual void ModifyConfigs(
547eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org        VideoSendStream::Config* send_config,
54888b558febb8e8f42df6c7482efe76795c3fed399pbos@webrtc.org        std::vector<VideoReceiveStream::Config>* receive_configs,
54958b5140b7535ae66c618cc64b0a955b8d47cc86cpbos@webrtc.org        VideoEncoderConfig* encoder_config) OVERRIDE {
550eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org      if (pad_to_min_bitrate_) {
551eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org        send_config->rtp.min_transmit_bitrate_bps = kMinTransmitBitrateBps;
552eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org      } else {
553eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org        assert(send_config->rtp.min_transmit_bitrate_bps == 0);
554eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org      }
555eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org    }
556eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org
557eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org    virtual void PerformTest() OVERRIDE {
558eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org      EXPECT_EQ(kEventSignaled, Wait())
559eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org          << "Timeout while waiting for send-bitrate stats.";
560eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org    }
561eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org
5623f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org    VideoSendStream* send_stream_;
5633f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org    PacketReceiver* send_transport_receiver_;
564eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org    const bool pad_to_min_bitrate_;
5653f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org    int num_bitrate_observations_in_range_;
566eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org  } test(pad_to_min_bitrate);
5673f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org
5683f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org  fake_encoder_.SetMaxBitrate(kMaxEncodeBitrateKbps);
569eb67a6be101fe1ac8f2a4c062dbe6250f2e36bc0pbos@webrtc.org  RunBaseTest(&test);
5703f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org}
5713f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org
5723f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.orgTEST_F(CallPerfTest, PadsToMinTransmitBitrate) { TestMinTransmitBitrate(true); }
5733f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org
5743f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.orgTEST_F(CallPerfTest, NoPadWithoutMinTransmitBitrate) {
5753f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org  TestMinTransmitBitrate(false);
5763f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org}
5773f83f9cae99b605aee71b46839e902653baeb3f6pbos@webrtc.org
578f94ccd41be08c937f523b2749544f07011203905pbos@webrtc.org}  // namespace webrtc
579