blob: 888e47b892955dae3e5a5884bbe7026d2317e968 [file] [log] [blame]
pbos@webrtc.org119a1cc2013-08-20 13:14:07 +00001/*
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 */
henrik.lundin@webrtc.org1a3a6e52013-10-28 10:16:14 +000010#include <algorithm> // max
11
pbos@webrtc.org119a1cc2013-08-20 13:14:07 +000012#include "testing/gtest/include/gtest/gtest.h"
pbos@webrtc.org16e03b72013-10-28 16:32:01 +000013
14#include "webrtc/call.h"
henrik.lundin@webrtc.orgba975e22013-10-23 11:04:57 +000015#include "webrtc/common_video/interface/i420_video_frame.h"
wuchengli@chromium.orgf425b552014-06-20 12:04:05 +000016#include "webrtc/common_video/interface/native_handle.h"
17#include "webrtc/common_video/interface/texture_video_frame.h"
pbos@webrtc.org16e03b72013-10-28 16:32:01 +000018#include "webrtc/frame_callback.h"
pbos@webrtc.org119a1cc2013-08-20 13:14:07 +000019#include "webrtc/modules/rtp_rtcp/interface/rtp_header_parser.h"
pbos@webrtc.org709e2972014-03-19 10:59:52 +000020#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h"
pbos@webrtc.orgdf531a22013-09-10 14:56:33 +000021#include "webrtc/modules/rtp_rtcp/source/rtcp_sender.h"
pbos@webrtc.org013d9942013-08-22 09:42:17 +000022#include "webrtc/modules/rtp_rtcp/source/rtcp_utility.h"
henrik.lundin@webrtc.orgba975e22013-10-23 11:04:57 +000023#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
pbos@webrtc.org119a1cc2013-08-20 13:14:07 +000024#include "webrtc/system_wrappers/interface/event_wrapper.h"
wuchengli@chromium.orgf425b552014-06-20 12:04:05 +000025#include "webrtc/system_wrappers/interface/ref_count.h"
pbos@webrtc.org119a1cc2013-08-20 13:14:07 +000026#include "webrtc/system_wrappers/interface/scoped_ptr.h"
wuchengli@chromium.orgf425b552014-06-20 12:04:05 +000027#include "webrtc/system_wrappers/interface/scoped_vector.h"
pbos@webrtc.org29023282013-09-11 10:14:56 +000028#include "webrtc/system_wrappers/interface/sleep.h"
pbos@webrtc.orgdf531a22013-09-10 14:56:33 +000029#include "webrtc/system_wrappers/interface/thread_wrapper.h"
stefan@webrtc.org168f23f2014-07-11 13:44:02 +000030#include "webrtc/system_wrappers/interface/logging.h"
pbos@webrtc.org994d0b72014-06-27 08:47:52 +000031#include "webrtc/test/call_test.h"
pbos@webrtc.org709e2972014-03-19 10:59:52 +000032#include "webrtc/test/configurable_frame_size_encoder.h"
pbos@webrtc.org16e03b72013-10-28 16:32:01 +000033#include "webrtc/test/null_transport.h"
pbos@webrtc.org709e2972014-03-19 10:59:52 +000034#include "webrtc/test/testsupport/perf_test.h"
pbos@webrtc.org16e03b72013-10-28 16:32:01 +000035#include "webrtc/video/transport_adapter.h"
36#include "webrtc/video_send_stream.h"
pbos@webrtc.org119a1cc2013-08-20 13:14:07 +000037
38namespace webrtc {
39
sprang@webrtc.org346094c2014-02-18 08:40:33 +000040enum VideoFormat { kGeneric, kVP8, };
41
wuchengli@chromium.orgf425b552014-06-20 12:04:05 +000042void ExpectEqualFrames(const I420VideoFrame& frame1,
43 const I420VideoFrame& frame2);
44void ExpectEqualTextureFrames(const I420VideoFrame& frame1,
45 const I420VideoFrame& frame2);
46void ExpectEqualBufferFrames(const I420VideoFrame& frame1,
47 const I420VideoFrame& frame2);
48void ExpectEqualFramesVector(const std::vector<I420VideoFrame*>& frames1,
49 const std::vector<I420VideoFrame*>& frames2);
50I420VideoFrame* CreateI420VideoFrame(int width, int height, uint8_t data);
51
52class FakeNativeHandle : public NativeHandle {
53 public:
54 FakeNativeHandle() {}
55 virtual ~FakeNativeHandle() {}
56 virtual void* GetHandle() { return NULL; }
57};
58
pbos@webrtc.org994d0b72014-06-27 08:47:52 +000059class VideoSendStreamTest : public test::CallTest {
pbos@webrtc.org013d9942013-08-22 09:42:17 +000060 protected:
stefan@webrtc.org69969e22013-11-15 12:32:15 +000061 void TestNackRetransmission(uint32_t retransmit_ssrc,
stefan@webrtc.orgcb254aa2014-06-12 15:12:25 +000062 uint8_t retransmit_payload_type);
sprang@webrtc.org346094c2014-02-18 08:40:33 +000063 void TestPacketFragmentationSize(VideoFormat format, bool with_fec);
pbos@webrtc.org013d9942013-08-22 09:42:17 +000064};
65
pbos@webrtc.orgf777cf22014-01-10 18:47:32 +000066TEST_F(VideoSendStreamTest, CanStartStartedStream) {
67 test::NullTransport transport;
68 Call::Config call_config(&transport);
pbos@webrtc.org994d0b72014-06-27 08:47:52 +000069 CreateSenderCall(call_config);
pbos@webrtc.orgf777cf22014-01-10 18:47:32 +000070
pbos@webrtc.org994d0b72014-06-27 08:47:52 +000071 CreateSendConfig(1);
72 CreateStreams();
73 send_stream_->Start();
74 send_stream_->Start();
75 DestroyStreams();
pbos@webrtc.orgf777cf22014-01-10 18:47:32 +000076}
77
78TEST_F(VideoSendStreamTest, CanStopStoppedStream) {
79 test::NullTransport transport;
80 Call::Config call_config(&transport);
pbos@webrtc.org994d0b72014-06-27 08:47:52 +000081 CreateSenderCall(call_config);
pbos@webrtc.orgf777cf22014-01-10 18:47:32 +000082
pbos@webrtc.org994d0b72014-06-27 08:47:52 +000083 CreateSendConfig(1);
84 CreateStreams();
85 send_stream_->Stop();
86 send_stream_->Stop();
87 DestroyStreams();
pbos@webrtc.orgf777cf22014-01-10 18:47:32 +000088}
89
pbos@webrtc.org013d9942013-08-22 09:42:17 +000090TEST_F(VideoSendStreamTest, SupportsCName) {
91 static std::string kCName = "PjQatC14dGfbVwGPUOA9IH7RlsFDbWl4AhXEiDsBizo=";
pbos@webrtc.org994d0b72014-06-27 08:47:52 +000092 class CNameObserver : public test::SendTest {
pbos@webrtc.org013d9942013-08-22 09:42:17 +000093 public:
pbos@webrtc.org994d0b72014-06-27 08:47:52 +000094 CNameObserver() : SendTest(kDefaultTimeoutMs) {}
pbos@webrtc.org013d9942013-08-22 09:42:17 +000095
pbos@webrtc.org994d0b72014-06-27 08:47:52 +000096 private:
stefan@webrtc.org69969e22013-11-15 12:32:15 +000097 virtual Action OnSendRtcp(const uint8_t* packet, size_t length) OVERRIDE {
pbos@webrtc.org013d9942013-08-22 09:42:17 +000098 RTCPUtility::RTCPParserV2 parser(packet, length, true);
99 EXPECT_TRUE(parser.IsValid());
100
101 RTCPUtility::RTCPPacketTypes packet_type = parser.Begin();
102 while (packet_type != RTCPUtility::kRtcpNotValidCode) {
103 if (packet_type == RTCPUtility::kRtcpSdesChunkCode) {
104 EXPECT_EQ(parser.Packet().CName.CName, kCName);
stefan@webrtc.org69969e22013-11-15 12:32:15 +0000105 observation_complete_->Set();
pbos@webrtc.org013d9942013-08-22 09:42:17 +0000106 }
107
108 packet_type = parser.Iterate();
109 }
110
stefan@webrtc.org69969e22013-11-15 12:32:15 +0000111 return SEND_PACKET;
pbos@webrtc.org013d9942013-08-22 09:42:17 +0000112 }
pbos@webrtc.org013d9942013-08-22 09:42:17 +0000113
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000114 virtual void ModifyConfigs(
115 VideoSendStream::Config* send_config,
pbos@webrtc.orgbe9d2a42014-06-30 13:19:09 +0000116 std::vector<VideoReceiveStream::Config>* receive_configs,
pbos@webrtc.orgbbe0a852014-09-19 12:30:25 +0000117 VideoEncoderConfig* encoder_config) OVERRIDE {
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000118 send_config->rtp.c_name = kCName;
119 }
pbos@webrtc.org013d9942013-08-22 09:42:17 +0000120
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000121 virtual void PerformTest() OVERRIDE {
122 EXPECT_EQ(kEventSignaled, Wait())
123 << "Timed out while waiting for RTCP with CNAME.";
124 }
125 } test;
pbos@webrtc.org013d9942013-08-22 09:42:17 +0000126
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000127 RunBaseTest(&test);
pbos@webrtc.org119a1cc2013-08-20 13:14:07 +0000128}
129
pbos@webrtc.org5c678ea2013-09-11 19:00:39 +0000130TEST_F(VideoSendStreamTest, SupportsAbsoluteSendTime) {
131 static const uint8_t kAbsSendTimeExtensionId = 13;
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000132 class AbsoluteSendTimeObserver : public test::SendTest {
pbos@webrtc.org5c678ea2013-09-11 19:00:39 +0000133 public:
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000134 AbsoluteSendTimeObserver() : SendTest(kDefaultTimeoutMs) {
stefan@webrtc.org69969e22013-11-15 12:32:15 +0000135 EXPECT_TRUE(parser_->RegisterRtpHeaderExtension(
pbos@webrtc.org5c678ea2013-09-11 19:00:39 +0000136 kRtpExtensionAbsoluteSendTime, kAbsSendTimeExtensionId));
137 }
138
stefan@webrtc.org69969e22013-11-15 12:32:15 +0000139 virtual Action OnSendRtp(const uint8_t* packet, size_t length) OVERRIDE {
pbos@webrtc.org5c678ea2013-09-11 19:00:39 +0000140 RTPHeader header;
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000141 EXPECT_TRUE(parser_->Parse(packet, length, &header));
pbos@webrtc.org5c678ea2013-09-11 19:00:39 +0000142
pbos@webrtc.org5ab75672013-12-16 12:24:44 +0000143 EXPECT_FALSE(header.extension.hasTransmissionTimeOffset);
144 EXPECT_TRUE(header.extension.hasAbsoluteSendTime);
145 EXPECT_EQ(header.extension.transmissionTimeOffset, 0);
146 EXPECT_GT(header.extension.absoluteSendTime, 0u);
147 observation_complete_->Set();
pbos@webrtc.org5c678ea2013-09-11 19:00:39 +0000148
stefan@webrtc.org69969e22013-11-15 12:32:15 +0000149 return SEND_PACKET;
pbos@webrtc.org5c678ea2013-09-11 19:00:39 +0000150 }
pbos@webrtc.org5c678ea2013-09-11 19:00:39 +0000151
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000152 virtual void ModifyConfigs(
153 VideoSendStream::Config* send_config,
pbos@webrtc.orgbe9d2a42014-06-30 13:19:09 +0000154 std::vector<VideoReceiveStream::Config>* receive_configs,
pbos@webrtc.orgbbe0a852014-09-19 12:30:25 +0000155 VideoEncoderConfig* encoder_config) OVERRIDE {
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000156 send_config->rtp.extensions.push_back(
157 RtpExtension(RtpExtension::kAbsSendTime, kAbsSendTimeExtensionId));
158 }
pbos@webrtc.orgdde16f12014-08-05 23:35:43 +0000159
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000160 virtual void PerformTest() OVERRIDE {
161 EXPECT_EQ(kEventSignaled, Wait())
162 << "Timed out while waiting for single RTP packet.";
163 }
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000164 } test;
pbos@webrtc.org5c678ea2013-09-11 19:00:39 +0000165
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000166 RunBaseTest(&test);
pbos@webrtc.org5c678ea2013-09-11 19:00:39 +0000167}
168
pbos@webrtc.org29023282013-09-11 10:14:56 +0000169TEST_F(VideoSendStreamTest, SupportsTransmissionTimeOffset) {
170 static const uint8_t kTOffsetExtensionId = 13;
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000171 class TransmissionTimeOffsetObserver : public test::SendTest {
pbos@webrtc.org29023282013-09-11 10:14:56 +0000172 public:
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000173 TransmissionTimeOffsetObserver()
174 : SendTest(kDefaultTimeoutMs), encoder_(Clock::GetRealTimeClock()) {
stefan@webrtc.org69969e22013-11-15 12:32:15 +0000175 EXPECT_TRUE(parser_->RegisterRtpHeaderExtension(
pbos@webrtc.org29023282013-09-11 10:14:56 +0000176 kRtpExtensionTransmissionTimeOffset, kTOffsetExtensionId));
177 }
178
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000179 private:
stefan@webrtc.org69969e22013-11-15 12:32:15 +0000180 virtual Action OnSendRtp(const uint8_t* packet, size_t length) OVERRIDE {
pbos@webrtc.org29023282013-09-11 10:14:56 +0000181 RTPHeader header;
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000182 EXPECT_TRUE(parser_->Parse(packet, length, &header));
pbos@webrtc.org29023282013-09-11 10:14:56 +0000183
pbos@webrtc.org5ab75672013-12-16 12:24:44 +0000184 EXPECT_TRUE(header.extension.hasTransmissionTimeOffset);
185 EXPECT_FALSE(header.extension.hasAbsoluteSendTime);
pbos@webrtc.org29023282013-09-11 10:14:56 +0000186 EXPECT_GT(header.extension.transmissionTimeOffset, 0);
pbos@webrtc.org5ab75672013-12-16 12:24:44 +0000187 EXPECT_EQ(header.extension.absoluteSendTime, 0u);
stefan@webrtc.org69969e22013-11-15 12:32:15 +0000188 observation_complete_->Set();
pbos@webrtc.org29023282013-09-11 10:14:56 +0000189
stefan@webrtc.org69969e22013-11-15 12:32:15 +0000190 return SEND_PACKET;
pbos@webrtc.org29023282013-09-11 10:14:56 +0000191 }
pbos@webrtc.org29023282013-09-11 10:14:56 +0000192
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000193 virtual void ModifyConfigs(
194 VideoSendStream::Config* send_config,
pbos@webrtc.orgbe9d2a42014-06-30 13:19:09 +0000195 std::vector<VideoReceiveStream::Config>* receive_configs,
pbos@webrtc.orgbbe0a852014-09-19 12:30:25 +0000196 VideoEncoderConfig* encoder_config) OVERRIDE {
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000197 send_config->encoder_settings.encoder = &encoder_;
198 send_config->rtp.extensions.push_back(
199 RtpExtension(RtpExtension::kTOffset, kTOffsetExtensionId));
200 }
pbos@webrtc.org29023282013-09-11 10:14:56 +0000201
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000202 virtual void PerformTest() OVERRIDE {
203 EXPECT_EQ(kEventSignaled, Wait())
204 << "Timed out while waiting single RTP packet.";
205 }
pbos@webrtc.org29023282013-09-11 10:14:56 +0000206
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000207 class DelayedEncoder : public test::FakeEncoder {
208 public:
209 explicit DelayedEncoder(Clock* clock) : test::FakeEncoder(clock) {}
210 virtual int32_t Encode(
211 const I420VideoFrame& input_image,
212 const CodecSpecificInfo* codec_specific_info,
213 const std::vector<VideoFrameType>* frame_types) OVERRIDE {
214 // A delay needs to be introduced to assure that we get a timestamp
215 // offset.
216 SleepMs(5);
217 return FakeEncoder::Encode(
218 input_image, codec_specific_info, frame_types);
219 }
220 };
221
222 DelayedEncoder encoder_;
223 } test;
224
225 RunBaseTest(&test);
pbos@webrtc.org29023282013-09-11 10:14:56 +0000226}
227
henrik.lundin@webrtc.orgba975e22013-10-23 11:04:57 +0000228class FakeReceiveStatistics : public NullReceiveStatistics {
pbos@webrtc.org0e63e762013-09-20 11:56:26 +0000229 public:
henrik.lundin@webrtc.orgba975e22013-10-23 11:04:57 +0000230 FakeReceiveStatistics(uint32_t send_ssrc,
231 uint32_t last_sequence_number,
232 uint32_t cumulative_lost,
233 uint8_t fraction_lost)
pbos@webrtc.org0e63e762013-09-20 11:56:26 +0000234 : lossy_stats_(new LossyStatistician(last_sequence_number,
235 cumulative_lost,
236 fraction_lost)) {
237 stats_map_[send_ssrc] = lossy_stats_.get();
238 }
239
240 virtual StatisticianMap GetActiveStatisticians() const OVERRIDE {
241 return stats_map_;
242 }
243
244 virtual StreamStatistician* GetStatistician(uint32_t ssrc) const OVERRIDE {
245 return lossy_stats_.get();
246 }
247
248 private:
249 class LossyStatistician : public StreamStatistician {
250 public:
251 LossyStatistician(uint32_t extended_max_sequence_number,
252 uint32_t cumulative_lost,
253 uint8_t fraction_lost) {
254 stats_.fraction_lost = fraction_lost;
255 stats_.cumulative_lost = cumulative_lost;
256 stats_.extended_max_sequence_number = extended_max_sequence_number;
257 }
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000258 virtual bool GetStatistics(RtcpStatistics* statistics,
259 bool reset) OVERRIDE {
pbos@webrtc.org0e63e762013-09-20 11:56:26 +0000260 *statistics = stats_;
261 return true;
262 }
263 virtual void GetDataCounters(uint32_t* bytes_received,
264 uint32_t* packets_received) const OVERRIDE {
265 *bytes_received = 0;
266 *packets_received = 0;
267 }
268 virtual uint32_t BitrateReceived() const OVERRIDE { return 0; }
269 virtual void ResetStatistics() OVERRIDE {}
270 virtual bool IsRetransmitOfOldPacket(const RTPHeader& header,
271 int min_rtt) const OVERRIDE {
272 return false;
273 }
274
275 virtual bool IsPacketInOrder(uint16_t sequence_number) const OVERRIDE {
276 return true;
277 }
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000278
279 RtcpStatistics stats_;
pbos@webrtc.org0e63e762013-09-20 11:56:26 +0000280 };
281
282 scoped_ptr<LossyStatistician> lossy_stats_;
283 StatisticianMap stats_map_;
284};
285
pbos@webrtc.org724947b2013-12-11 16:26:16 +0000286TEST_F(VideoSendStreamTest, SwapsI420VideoFrames) {
287 static const size_t kWidth = 320;
288 static const size_t kHeight = 240;
289
290 test::NullTransport transport;
291 Call::Config call_config(&transport);
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000292 CreateSenderCall(call_config);
pbos@webrtc.org724947b2013-12-11 16:26:16 +0000293
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000294 CreateSendConfig(1);
295 CreateStreams();
296 send_stream_->Start();
pbos@webrtc.org724947b2013-12-11 16:26:16 +0000297
298 I420VideoFrame frame;
299 frame.CreateEmptyFrame(
300 kWidth, kHeight, kWidth, (kWidth + 1) / 2, (kWidth + 1) / 2);
301 uint8_t* old_y_buffer = frame.buffer(kYPlane);
302
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000303 send_stream_->Input()->SwapFrame(&frame);
pbos@webrtc.org724947b2013-12-11 16:26:16 +0000304
305 EXPECT_NE(frame.buffer(kYPlane), old_y_buffer);
306
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000307 DestroyStreams();
pbos@webrtc.org724947b2013-12-11 16:26:16 +0000308}
309
pbos@webrtc.org0e63e762013-09-20 11:56:26 +0000310TEST_F(VideoSendStreamTest, SupportsFec) {
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000311 class FecObserver : public test::SendTest {
pbos@webrtc.org0e63e762013-09-20 11:56:26 +0000312 public:
313 FecObserver()
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000314 : SendTest(kDefaultTimeoutMs),
stefan@webrtc.org69969e22013-11-15 12:32:15 +0000315 transport_adapter_(SendTransport()),
pbos@webrtc.org0e63e762013-09-20 11:56:26 +0000316 send_count_(0),
317 received_media_(false),
sprang@webrtc.orgd9b95602014-01-27 13:03:02 +0000318 received_fec_(false) {
319 transport_adapter_.Enable();
320 }
pbos@webrtc.org0e63e762013-09-20 11:56:26 +0000321
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000322 private:
stefan@webrtc.org69969e22013-11-15 12:32:15 +0000323 virtual Action OnSendRtp(const uint8_t* packet, size_t length) OVERRIDE {
pbos@webrtc.org0e63e762013-09-20 11:56:26 +0000324 RTPHeader header;
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000325 EXPECT_TRUE(parser_->Parse(packet, length, &header));
pbos@webrtc.org0e63e762013-09-20 11:56:26 +0000326
327 // Send lossy receive reports to trigger FEC enabling.
328 if (send_count_++ % 2 != 0) {
329 // Receive statistics reporting having lost 50% of the packets.
henrik.lundin@webrtc.orgba975e22013-10-23 11:04:57 +0000330 FakeReceiveStatistics lossy_receive_stats(
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000331 kSendSsrcs[0], header.sequenceNumber, send_count_ / 2, 127);
pbos@webrtc.org0e63e762013-09-20 11:56:26 +0000332 RTCPSender rtcp_sender(
333 0, false, Clock::GetRealTimeClock(), &lossy_receive_stats);
334 EXPECT_EQ(0, rtcp_sender.RegisterSendTransport(&transport_adapter_));
335
336 rtcp_sender.SetRTCPStatus(kRtcpNonCompound);
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000337 rtcp_sender.SetRemoteSSRC(kSendSsrcs[0]);
pbos@webrtc.org0e63e762013-09-20 11:56:26 +0000338
339 RTCPSender::FeedbackState feedback_state;
340
341 EXPECT_EQ(0, rtcp_sender.SendRTCP(feedback_state, kRtcpRr));
342 }
343
344 EXPECT_EQ(kRedPayloadType, header.payloadType);
345
346 uint8_t encapsulated_payload_type = packet[header.headerLength];
347
348 if (encapsulated_payload_type == kUlpfecPayloadType) {
349 received_fec_ = true;
350 } else {
351 received_media_ = true;
352 }
353
354 if (received_media_ && received_fec_)
stefan@webrtc.org69969e22013-11-15 12:32:15 +0000355 observation_complete_->Set();
pbos@webrtc.org0e63e762013-09-20 11:56:26 +0000356
stefan@webrtc.org69969e22013-11-15 12:32:15 +0000357 return SEND_PACKET;
pbos@webrtc.org0e63e762013-09-20 11:56:26 +0000358 }
359
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000360 virtual void ModifyConfigs(
361 VideoSendStream::Config* send_config,
pbos@webrtc.orgbe9d2a42014-06-30 13:19:09 +0000362 std::vector<VideoReceiveStream::Config>* receive_configs,
pbos@webrtc.orgbbe0a852014-09-19 12:30:25 +0000363 VideoEncoderConfig* encoder_config) OVERRIDE {
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000364 send_config->rtp.fec.red_payload_type = kRedPayloadType;
365 send_config->rtp.fec.ulpfec_payload_type = kUlpfecPayloadType;
366 }
367
368 virtual void PerformTest() OVERRIDE {
369 EXPECT_TRUE(Wait()) << "Timed out waiting for FEC and media packets.";
370 }
371
pbos@webrtc.org0e63e762013-09-20 11:56:26 +0000372 internal::TransportAdapter transport_adapter_;
pbos@webrtc.org0e63e762013-09-20 11:56:26 +0000373 int send_count_;
374 bool received_media_;
375 bool received_fec_;
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000376 } test;
pbos@webrtc.org0e63e762013-09-20 11:56:26 +0000377
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000378 RunBaseTest(&test);
pbos@webrtc.org0e63e762013-09-20 11:56:26 +0000379}
380
stefan@webrtc.org69969e22013-11-15 12:32:15 +0000381void VideoSendStreamTest::TestNackRetransmission(
382 uint32_t retransmit_ssrc,
stefan@webrtc.orgcb254aa2014-06-12 15:12:25 +0000383 uint8_t retransmit_payload_type) {
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000384 class NackObserver : public test::SendTest {
pbos@webrtc.orgdf531a22013-09-10 14:56:33 +0000385 public:
stefan@webrtc.org69969e22013-11-15 12:32:15 +0000386 explicit NackObserver(uint32_t retransmit_ssrc,
387 uint8_t retransmit_payload_type)
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000388 : SendTest(kDefaultTimeoutMs),
stefan@webrtc.org69969e22013-11-15 12:32:15 +0000389 transport_adapter_(SendTransport()),
pbos@webrtc.orgdf531a22013-09-10 14:56:33 +0000390 send_count_(0),
pbos@webrtc.org5860de02013-09-16 13:01:47 +0000391 retransmit_ssrc_(retransmit_ssrc),
stefan@webrtc.org69969e22013-11-15 12:32:15 +0000392 retransmit_payload_type_(retransmit_payload_type),
sprang@webrtc.orgd9b95602014-01-27 13:03:02 +0000393 nacked_sequence_number_(-1) {
394 transport_adapter_.Enable();
395 }
pbos@webrtc.orgdf531a22013-09-10 14:56:33 +0000396
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000397 private:
stefan@webrtc.org69969e22013-11-15 12:32:15 +0000398 virtual Action OnSendRtp(const uint8_t* packet, size_t length) OVERRIDE {
pbos@webrtc.orgdf531a22013-09-10 14:56:33 +0000399 RTPHeader header;
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000400 EXPECT_TRUE(parser_->Parse(packet, length, &header));
pbos@webrtc.orgdf531a22013-09-10 14:56:33 +0000401
402 // Nack second packet after receiving the third one.
403 if (++send_count_ == 3) {
pbos@webrtc.orge7223e72014-01-23 16:14:34 +0000404 uint16_t nack_sequence_number = header.sequenceNumber - 1;
405 nacked_sequence_number_ = nack_sequence_number;
pbos@webrtc.org0e63e762013-09-20 11:56:26 +0000406 NullReceiveStatistics null_stats;
407 RTCPSender rtcp_sender(
408 0, false, Clock::GetRealTimeClock(), &null_stats);
409 EXPECT_EQ(0, rtcp_sender.RegisterSendTransport(&transport_adapter_));
410
411 rtcp_sender.SetRTCPStatus(kRtcpNonCompound);
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000412 rtcp_sender.SetRemoteSSRC(kSendSsrcs[0]);
pbos@webrtc.org0e63e762013-09-20 11:56:26 +0000413
414 RTCPSender::FeedbackState feedback_state;
415
416 EXPECT_EQ(0,
417 rtcp_sender.SendRTCP(
pbos@webrtc.orge7223e72014-01-23 16:14:34 +0000418 feedback_state, kRtcpNack, 1, &nack_sequence_number));
pbos@webrtc.orgdf531a22013-09-10 14:56:33 +0000419 }
420
pbos@webrtc.org5860de02013-09-16 13:01:47 +0000421 uint16_t sequence_number = header.sequenceNumber;
422
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000423 if (header.ssrc == retransmit_ssrc_ &&
424 retransmit_ssrc_ != kSendSsrcs[0]) {
425 // Not kSendSsrcs[0], assume correct RTX packet. Extract sequence
426 // number.
pbos@webrtc.org5860de02013-09-16 13:01:47 +0000427 const uint8_t* rtx_header = packet + header.headerLength;
428 sequence_number = (rtx_header[0] << 8) + rtx_header[1];
429 }
430
431 if (sequence_number == nacked_sequence_number_) {
432 EXPECT_EQ(retransmit_ssrc_, header.ssrc);
stefan@webrtc.org69969e22013-11-15 12:32:15 +0000433 EXPECT_EQ(retransmit_payload_type_, header.payloadType);
434 observation_complete_->Set();
pbos@webrtc.org5860de02013-09-16 13:01:47 +0000435 }
pbos@webrtc.orgdf531a22013-09-10 14:56:33 +0000436
stefan@webrtc.org69969e22013-11-15 12:32:15 +0000437 return SEND_PACKET;
pbos@webrtc.orgdf531a22013-09-10 14:56:33 +0000438 }
henrik.lundin@webrtc.orgba975e22013-10-23 11:04:57 +0000439
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000440 virtual void ModifyConfigs(
441 VideoSendStream::Config* send_config,
pbos@webrtc.orgbe9d2a42014-06-30 13:19:09 +0000442 std::vector<VideoReceiveStream::Config>* receive_configs,
pbos@webrtc.orgbbe0a852014-09-19 12:30:25 +0000443 VideoEncoderConfig* encoder_config) OVERRIDE {
pbos@webrtc.orgbe9d2a42014-06-30 13:19:09 +0000444 send_config->rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000445 send_config->rtp.rtx.payload_type = retransmit_payload_type_;
446 if (retransmit_ssrc_ != kSendSsrcs[0])
447 send_config->rtp.rtx.ssrcs.push_back(retransmit_ssrc_);
448 }
449
450 virtual void PerformTest() OVERRIDE {
451 EXPECT_EQ(kEventSignaled, Wait())
452 << "Timed out while waiting for NACK retransmission.";
453 }
454
pbos@webrtc.org0e63e762013-09-20 11:56:26 +0000455 internal::TransportAdapter transport_adapter_;
pbos@webrtc.orgdf531a22013-09-10 14:56:33 +0000456 int send_count_;
pbos@webrtc.org5860de02013-09-16 13:01:47 +0000457 uint32_t retransmit_ssrc_;
stefan@webrtc.org69969e22013-11-15 12:32:15 +0000458 uint8_t retransmit_payload_type_;
pbos@webrtc.orge7223e72014-01-23 16:14:34 +0000459 int nacked_sequence_number_;
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000460 } test(retransmit_ssrc, retransmit_payload_type);
pbos@webrtc.orgdf531a22013-09-10 14:56:33 +0000461
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000462 RunBaseTest(&test);
pbos@webrtc.orgdf531a22013-09-10 14:56:33 +0000463}
464
pbos@webrtc.org5860de02013-09-16 13:01:47 +0000465TEST_F(VideoSendStreamTest, RetransmitsNack) {
466 // Normal NACKs should use the send SSRC.
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000467 TestNackRetransmission(kSendSsrcs[0], kFakeSendPayloadType);
pbos@webrtc.org5860de02013-09-16 13:01:47 +0000468}
469
470TEST_F(VideoSendStreamTest, RetransmitsNackOverRtx) {
471 // NACKs over RTX should use a separate SSRC.
pbos@webrtc.org2bb1bda2014-07-07 13:06:48 +0000472 TestNackRetransmission(kSendRtxSsrcs[0], kSendRtxPayloadType);
pbos@webrtc.org5860de02013-09-16 13:01:47 +0000473}
474
sprang@webrtc.org346094c2014-02-18 08:40:33 +0000475void VideoSendStreamTest::TestPacketFragmentationSize(VideoFormat format,
476 bool with_fec) {
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000477 // Use a fake encoder to output a frame of every size in the range [90, 290],
478 // for each size making sure that the exact number of payload bytes received
479 // is correct and that packets are fragmented to respect max packet size.
480 static const uint32_t kMaxPacketSize = 128;
481 static const uint32_t start = 90;
482 static const uint32_t stop = 290;
483
sprang@webrtc.org8b881922013-12-10 10:05:17 +0000484 // Observer that verifies that the expected number of packets and bytes
485 // arrive for each frame size, from start_size to stop_size.
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000486 class FrameFragmentationTest : public test::SendTest,
487 public EncodedFrameObserver {
sprang@webrtc.org5d957e22013-10-16 11:37:54 +0000488 public:
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000489 FrameFragmentationTest(uint32_t max_packet_size,
490 uint32_t start_size,
491 uint32_t stop_size,
492 bool test_generic_packetization,
493 bool use_fec)
494 : SendTest(kLongTimeoutMs),
sprang@webrtc.org346094c2014-02-18 08:40:33 +0000495 transport_adapter_(SendTransport()),
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000496 encoder_(stop),
sprang@webrtc.org8b881922013-12-10 10:05:17 +0000497 max_packet_size_(max_packet_size),
sprang@webrtc.org346094c2014-02-18 08:40:33 +0000498 stop_size_(stop_size),
499 test_generic_packetization_(test_generic_packetization),
500 use_fec_(use_fec),
501 packet_count_(0),
sprang@webrtc.org8b881922013-12-10 10:05:17 +0000502 accumulated_size_(0),
503 accumulated_payload_(0),
sprang@webrtc.org346094c2014-02-18 08:40:33 +0000504 fec_packet_received_(false),
sprang@webrtc.org8b881922013-12-10 10:05:17 +0000505 current_size_rtp_(start_size),
sprang@webrtc.org346094c2014-02-18 08:40:33 +0000506 current_size_frame_(start_size) {
sprang@webrtc.org8b881922013-12-10 10:05:17 +0000507 // Fragmentation required, this test doesn't make sense without it.
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000508 encoder_.SetFrameSize(start);
sprang@webrtc.org8b881922013-12-10 10:05:17 +0000509 assert(stop_size > max_packet_size);
sprang@webrtc.org346094c2014-02-18 08:40:33 +0000510 transport_adapter_.Enable();
sprang@webrtc.org8b881922013-12-10 10:05:17 +0000511 }
sprang@webrtc.org5d957e22013-10-16 11:37:54 +0000512
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000513 private:
sprang@webrtc.org346094c2014-02-18 08:40:33 +0000514 virtual Action OnSendRtp(const uint8_t* packet, size_t size) OVERRIDE {
515 uint32_t length = static_cast<int>(size);
sprang@webrtc.org5d957e22013-10-16 11:37:54 +0000516 RTPHeader header;
sprang@webrtc.org346094c2014-02-18 08:40:33 +0000517 EXPECT_TRUE(parser_->Parse(packet, length, &header));
sprang@webrtc.org5d957e22013-10-16 11:37:54 +0000518
sprang@webrtc.org8b881922013-12-10 10:05:17 +0000519 EXPECT_LE(length, max_packet_size_);
sprang@webrtc.org5d957e22013-10-16 11:37:54 +0000520
sprang@webrtc.org346094c2014-02-18 08:40:33 +0000521 if (use_fec_) {
522 uint8_t payload_type = packet[header.headerLength];
523 bool is_fec = header.payloadType == kRedPayloadType &&
524 payload_type == kUlpfecPayloadType;
525 if (is_fec) {
526 fec_packet_received_ = true;
527 return SEND_PACKET;
528 }
529 }
530
sprang@webrtc.org5d957e22013-10-16 11:37:54 +0000531 accumulated_size_ += length;
sprang@webrtc.org346094c2014-02-18 08:40:33 +0000532
533 if (use_fec_)
534 TriggerLossReport(header);
535
536 if (test_generic_packetization_) {
537 uint32_t overhead = header.headerLength + header.paddingLength +
538 (1 /* Generic header */);
539 if (use_fec_)
540 overhead += 1; // RED for FEC header.
541 accumulated_payload_ += length - overhead;
542 }
sprang@webrtc.org5d957e22013-10-16 11:37:54 +0000543
sprang@webrtc.org8b881922013-12-10 10:05:17 +0000544 // Marker bit set indicates last packet of a frame.
sprang@webrtc.org5d957e22013-10-16 11:37:54 +0000545 if (header.markerBit) {
sprang@webrtc.org346094c2014-02-18 08:40:33 +0000546 if (use_fec_ && accumulated_payload_ == current_size_rtp_ - 1) {
547 // With FEC enabled, frame size is incremented asynchronously, so
548 // "old" frames one byte too small may arrive. Accept, but don't
549 // increase expected frame size.
550 accumulated_size_ = 0;
551 accumulated_payload_ = 0;
552 return SEND_PACKET;
553 }
554
sprang@webrtc.org8b881922013-12-10 10:05:17 +0000555 EXPECT_GE(accumulated_size_, current_size_rtp_);
sprang@webrtc.org346094c2014-02-18 08:40:33 +0000556 if (test_generic_packetization_) {
557 EXPECT_EQ(current_size_rtp_, accumulated_payload_);
558 }
sprang@webrtc.org8b881922013-12-10 10:05:17 +0000559
560 // Last packet of frame; reset counters.
561 accumulated_size_ = 0;
562 accumulated_payload_ = 0;
563 if (current_size_rtp_ == stop_size_) {
564 // Done! (Don't increase size again, might arrive more @ stop_size).
stefan@webrtc.org69969e22013-11-15 12:32:15 +0000565 observation_complete_->Set();
sprang@webrtc.org8b881922013-12-10 10:05:17 +0000566 } else {
sprang@webrtc.org346094c2014-02-18 08:40:33 +0000567 // Increase next expected frame size. If testing with FEC, make sure
568 // a FEC packet has been received for this frame size before
569 // proceeding, to make sure that redundancy packets don't exceed
570 // size limit.
571 if (!use_fec_) {
572 ++current_size_rtp_;
573 } else if (fec_packet_received_) {
574 fec_packet_received_ = false;
575 ++current_size_rtp_;
576 ++current_size_frame_;
577 }
sprang@webrtc.org5d957e22013-10-16 11:37:54 +0000578 }
sprang@webrtc.org5d957e22013-10-16 11:37:54 +0000579 }
580
stefan@webrtc.org69969e22013-11-15 12:32:15 +0000581 return SEND_PACKET;
sprang@webrtc.org5d957e22013-10-16 11:37:54 +0000582 }
583
sprang@webrtc.org346094c2014-02-18 08:40:33 +0000584 void TriggerLossReport(const RTPHeader& header) {
585 // Send lossy receive reports to trigger FEC enabling.
586 if (packet_count_++ % 2 != 0) {
587 // Receive statistics reporting having lost 50% of the packets.
588 FakeReceiveStatistics lossy_receive_stats(
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000589 kSendSsrcs[0], header.sequenceNumber, packet_count_ / 2, 127);
sprang@webrtc.org346094c2014-02-18 08:40:33 +0000590 RTCPSender rtcp_sender(
591 0, false, Clock::GetRealTimeClock(), &lossy_receive_stats);
592 EXPECT_EQ(0, rtcp_sender.RegisterSendTransport(&transport_adapter_));
593
594 rtcp_sender.SetRTCPStatus(kRtcpNonCompound);
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000595 rtcp_sender.SetRemoteSSRC(kSendSsrcs[0]);
sprang@webrtc.org346094c2014-02-18 08:40:33 +0000596
597 RTCPSender::FeedbackState feedback_state;
598
599 EXPECT_EQ(0, rtcp_sender.SendRTCP(feedback_state, kRtcpRr));
600 }
601 }
602
sprang@webrtc.org8b881922013-12-10 10:05:17 +0000603 virtual void EncodedFrameCallback(const EncodedFrame& encoded_frame) {
604 // Increase frame size for next encoded frame, in the context of the
605 // encoder thread.
sprang@webrtc.org346094c2014-02-18 08:40:33 +0000606 if (!use_fec_ &&
607 current_size_frame_.Value() < static_cast<int32_t>(stop_size_)) {
sprang@webrtc.org8b881922013-12-10 10:05:17 +0000608 ++current_size_frame_;
609 }
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000610 encoder_.SetFrameSize(current_size_frame_.Value());
sprang@webrtc.org8b881922013-12-10 10:05:17 +0000611 }
612
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000613 virtual void ModifyConfigs(
614 VideoSendStream::Config* send_config,
pbos@webrtc.orgbe9d2a42014-06-30 13:19:09 +0000615 std::vector<VideoReceiveStream::Config>* receive_configs,
pbos@webrtc.orgbbe0a852014-09-19 12:30:25 +0000616 VideoEncoderConfig* encoder_config) OVERRIDE {
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000617 if (use_fec_) {
618 send_config->rtp.fec.red_payload_type = kRedPayloadType;
619 send_config->rtp.fec.ulpfec_payload_type = kUlpfecPayloadType;
620 }
621
622 if (!test_generic_packetization_)
623 send_config->encoder_settings.payload_name = "VP8";
624
625 send_config->encoder_settings.encoder = &encoder_;
626 send_config->rtp.max_packet_size = kMaxPacketSize;
627 send_config->post_encode_callback = this;
628
629 // Add an extension header, to make the RTP header larger than the base
630 // length of 12 bytes.
631 static const uint8_t kAbsSendTimeExtensionId = 13;
632 send_config->rtp.extensions.push_back(
633 RtpExtension(RtpExtension::kAbsSendTime, kAbsSendTimeExtensionId));
634 }
635
636 virtual void PerformTest() OVERRIDE {
637 EXPECT_EQ(kEventSignaled, Wait())
638 << "Timed out while observing incoming RTP packets.";
639 }
640
sprang@webrtc.org346094c2014-02-18 08:40:33 +0000641 internal::TransportAdapter transport_adapter_;
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000642 test::ConfigurableFrameSizeEncoder encoder_;
sprang@webrtc.org8b881922013-12-10 10:05:17 +0000643
sprang@webrtc.org346094c2014-02-18 08:40:33 +0000644 const uint32_t max_packet_size_;
645 const uint32_t stop_size_;
646 const bool test_generic_packetization_;
647 const bool use_fec_;
648
649 uint32_t packet_count_;
650 uint32_t accumulated_size_;
651 uint32_t accumulated_payload_;
652 bool fec_packet_received_;
653
sprang@webrtc.org8b881922013-12-10 10:05:17 +0000654 uint32_t current_size_rtp_;
sprang@webrtc.org346094c2014-02-18 08:40:33 +0000655 Atomic32 current_size_frame_;
sprang@webrtc.org5d957e22013-10-16 11:37:54 +0000656 };
657
sprang@webrtc.org346094c2014-02-18 08:40:33 +0000658 // Don't auto increment if FEC is used; continue sending frame size until
659 // a FEC packet has been received.
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000660 FrameFragmentationTest test(
661 kMaxPacketSize, start, stop, format == kGeneric, with_fec);
sprang@webrtc.org8b881922013-12-10 10:05:17 +0000662
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000663 RunBaseTest(&test);
sprang@webrtc.org5d957e22013-10-16 11:37:54 +0000664}
665
sprang@webrtc.org346094c2014-02-18 08:40:33 +0000666// TODO(sprang): Is there any way of speeding up these tests?
667TEST_F(VideoSendStreamTest, FragmentsGenericAccordingToMaxPacketSize) {
668 TestPacketFragmentationSize(kGeneric, false);
669}
670
671TEST_F(VideoSendStreamTest, FragmentsGenericAccordingToMaxPacketSizeWithFec) {
672 TestPacketFragmentationSize(kGeneric, true);
673}
674
675TEST_F(VideoSendStreamTest, FragmentsVp8AccordingToMaxPacketSize) {
676 TestPacketFragmentationSize(kVP8, false);
677}
678
679TEST_F(VideoSendStreamTest, FragmentsVp8AccordingToMaxPacketSizeWithFec) {
680 TestPacketFragmentationSize(kVP8, true);
681}
682
henrik.lundin@webrtc.orgba975e22013-10-23 11:04:57 +0000683// The test will go through a number of phases.
684// 1. Start sending packets.
685// 2. As soon as the RTP stream has been detected, signal a low REMB value to
henrik.lundin@webrtc.orgce8e0932013-11-18 12:18:43 +0000686// suspend the stream.
687// 3. Wait until |kSuspendTimeFrames| have been captured without seeing any RTP
henrik.lundin@webrtc.orgba975e22013-10-23 11:04:57 +0000688// packets.
henrik.lundin@webrtc.orgce8e0932013-11-18 12:18:43 +0000689// 4. Signal a high REMB and then wait for the RTP stream to start again.
henrik.lundin@webrtc.orged8b2812014-03-18 08:43:29 +0000690// When the stream is detected again, and the stats show that the stream
691// is no longer suspended, the test ends.
henrik.lundin@webrtc.orgce8e0932013-11-18 12:18:43 +0000692TEST_F(VideoSendStreamTest, SuspendBelowMinBitrate) {
693 static const int kSuspendTimeFrames = 60; // Suspend for 2 seconds @ 30 fps.
henrik.lundin@webrtc.orgba975e22013-10-23 11:04:57 +0000694
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000695 class RembObserver : public test::SendTest, public I420FrameCallback {
henrik.lundin@webrtc.orgba975e22013-10-23 11:04:57 +0000696 public:
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000697 RembObserver()
698 : SendTest(kDefaultTimeoutMs),
henrik.lundin@webrtc.orgba975e22013-10-23 11:04:57 +0000699 transport_adapter_(&transport_),
700 clock_(Clock::GetRealTimeClock()),
pbos@webrtc.orgde1429e2014-04-28 13:00:21 +0000701 crit_(CriticalSectionWrapper::CreateCriticalSection()),
henrik.lundin@webrtc.orgce8e0932013-11-18 12:18:43 +0000702 test_state_(kBeforeSuspend),
henrik.lundin@webrtc.orgba975e22013-10-23 11:04:57 +0000703 rtp_count_(0),
704 last_sequence_number_(0),
henrik.lundin@webrtc.orgce8e0932013-11-18 12:18:43 +0000705 suspended_frame_count_(0),
henrik.lundin@webrtc.org1a3a6e52013-10-28 10:16:14 +0000706 low_remb_bps_(0),
pbos@webrtc.orgde1429e2014-04-28 13:00:21 +0000707 high_remb_bps_(0) {
sprang@webrtc.orgd9b95602014-01-27 13:03:02 +0000708 transport_adapter_.Enable();
709 }
henrik.lundin@webrtc.orgba975e22013-10-23 11:04:57 +0000710
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000711 private:
stefan@webrtc.org69969e22013-11-15 12:32:15 +0000712 virtual Action OnSendRtcp(const uint8_t* packet, size_t length) OVERRIDE {
henrik.lundin@webrtc.orgba975e22013-10-23 11:04:57 +0000713 // Receive statistics reporting having lost 0% of the packets.
714 // This is needed for the send-side bitrate controller to work properly.
pbos@webrtc.orgde1429e2014-04-28 13:00:21 +0000715 CriticalSectionScoped lock(crit_.get());
henrik.lundin@webrtc.orgba975e22013-10-23 11:04:57 +0000716 SendRtcpFeedback(0); // REMB is only sent if value is > 0.
stefan@webrtc.org69969e22013-11-15 12:32:15 +0000717 return SEND_PACKET;
henrik.lundin@webrtc.orgba975e22013-10-23 11:04:57 +0000718 }
719
stefan@webrtc.org69969e22013-11-15 12:32:15 +0000720 virtual Action OnSendRtp(const uint8_t* packet, size_t length) OVERRIDE {
pbos@webrtc.orgde1429e2014-04-28 13:00:21 +0000721 CriticalSectionScoped lock(crit_.get());
henrik.lundin@webrtc.orgba975e22013-10-23 11:04:57 +0000722 ++rtp_count_;
723 RTPHeader header;
pbos@webrtc.org62bafae2014-07-08 12:10:51 +0000724 EXPECT_TRUE(parser_->Parse(packet, length, &header));
henrik.lundin@webrtc.orgba975e22013-10-23 11:04:57 +0000725 last_sequence_number_ = header.sequenceNumber;
726
henrik.lundin@webrtc.orgce8e0932013-11-18 12:18:43 +0000727 if (test_state_ == kBeforeSuspend) {
728 // The stream has started. Try to suspend it.
henrik.lundin@webrtc.org1a3a6e52013-10-28 10:16:14 +0000729 SendRtcpFeedback(low_remb_bps_);
henrik.lundin@webrtc.orgce8e0932013-11-18 12:18:43 +0000730 test_state_ = kDuringSuspend;
731 } else if (test_state_ == kDuringSuspend) {
henrik.lundin@webrtc.org331d4402013-11-21 14:05:40 +0000732 if (header.paddingLength == 0) {
733 // Received non-padding packet during suspension period. Reset the
734 // counter.
henrik.lundin@webrtc.org331d4402013-11-21 14:05:40 +0000735 suspended_frame_count_ = 0;
736 }
henrik.lundin@webrtc.orgba975e22013-10-23 11:04:57 +0000737 } else if (test_state_ == kWaitingForPacket) {
henrik.lundin@webrtc.org331d4402013-11-21 14:05:40 +0000738 if (header.paddingLength == 0) {
henrik.lundin@webrtc.orged8b2812014-03-18 08:43:29 +0000739 // Non-padding packet observed. Test is almost complete. Will just
740 // have to wait for the stats to change.
741 test_state_ = kWaitingForStats;
742 }
743 } else if (test_state_ == kWaitingForStats) {
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000744 VideoSendStream::Stats stats = stream_->GetStats();
henrik.lundin@webrtc.orged8b2812014-03-18 08:43:29 +0000745 if (stats.suspended == false) {
746 // Stats flipped to false. Test is complete.
henrik.lundin@webrtc.org331d4402013-11-21 14:05:40 +0000747 observation_complete_->Set();
748 }
henrik.lundin@webrtc.orgba975e22013-10-23 11:04:57 +0000749 }
750
stefan@webrtc.org69969e22013-11-15 12:32:15 +0000751 return SEND_PACKET;
henrik.lundin@webrtc.orgba975e22013-10-23 11:04:57 +0000752 }
753
754 // This method implements the I420FrameCallback.
755 void FrameCallback(I420VideoFrame* video_frame) OVERRIDE {
pbos@webrtc.orgde1429e2014-04-28 13:00:21 +0000756 CriticalSectionScoped lock(crit_.get());
henrik.lundin@webrtc.orgce8e0932013-11-18 12:18:43 +0000757 if (test_state_ == kDuringSuspend &&
758 ++suspended_frame_count_ > kSuspendTimeFrames) {
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000759 VideoSendStream::Stats stats = stream_->GetStats();
henrik.lundin@webrtc.orgb10363f2014-03-13 13:31:21 +0000760 EXPECT_TRUE(stats.suspended);
henrik.lundin@webrtc.org1a3a6e52013-10-28 10:16:14 +0000761 SendRtcpFeedback(high_remb_bps_);
henrik.lundin@webrtc.orgba975e22013-10-23 11:04:57 +0000762 test_state_ = kWaitingForPacket;
763 }
764 }
765
pbos@webrtc.orgde1429e2014-04-28 13:00:21 +0000766 void set_low_remb_bps(int value) {
767 CriticalSectionScoped lock(crit_.get());
768 low_remb_bps_ = value;
769 }
henrik.lundin@webrtc.org1a3a6e52013-10-28 10:16:14 +0000770
pbos@webrtc.orgde1429e2014-04-28 13:00:21 +0000771 void set_high_remb_bps(int value) {
772 CriticalSectionScoped lock(crit_.get());
773 high_remb_bps_ = value;
774 }
henrik.lundin@webrtc.org1a3a6e52013-10-28 10:16:14 +0000775
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000776 virtual void SetReceivers(
777 PacketReceiver* send_transport_receiver,
778 PacketReceiver* receive_transport_receiver) OVERRIDE {
779 transport_.SetReceiver(send_transport_receiver);
780 }
pbos@webrtc.orgdef22b42013-10-29 10:12:10 +0000781
pbos@webrtc.orgbe9d2a42014-06-30 13:19:09 +0000782 virtual void OnStreamsCreated(
783 VideoSendStream* send_stream,
784 const std::vector<VideoReceiveStream*>& receive_streams) OVERRIDE {
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000785 stream_ = send_stream;
786 }
787
788 virtual void ModifyConfigs(
789 VideoSendStream::Config* send_config,
pbos@webrtc.orgbe9d2a42014-06-30 13:19:09 +0000790 std::vector<VideoReceiveStream::Config>* receive_configs,
pbos@webrtc.orgbbe0a852014-09-19 12:30:25 +0000791 VideoEncoderConfig* encoder_config) OVERRIDE {
pbos@webrtc.orgbe9d2a42014-06-30 13:19:09 +0000792 send_config->rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000793 send_config->pre_encode_callback = this;
794 send_config->suspend_below_min_bitrate = true;
pbos@webrtc.orgbbe0a852014-09-19 12:30:25 +0000795 int min_bitrate_bps = encoder_config->streams[0].min_bitrate_bps;
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000796 set_low_remb_bps(min_bitrate_bps - 10000);
797 int threshold_window = std::max(min_bitrate_bps / 10, 10000);
pbos@webrtc.orgbbe0a852014-09-19 12:30:25 +0000798 ASSERT_GT(encoder_config->streams[0].max_bitrate_bps,
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000799 min_bitrate_bps + threshold_window + 5000);
800 set_high_remb_bps(min_bitrate_bps + threshold_window + 5000);
801 }
802
803 virtual void PerformTest() OVERRIDE {
804 EXPECT_EQ(kEventSignaled, Wait())
805 << "Timed out during suspend-below-min-bitrate test.";
806 transport_.StopSending();
807 }
808
henrik.lundin@webrtc.orgba975e22013-10-23 11:04:57 +0000809 enum TestState {
henrik.lundin@webrtc.orgce8e0932013-11-18 12:18:43 +0000810 kBeforeSuspend,
811 kDuringSuspend,
henrik.lundin@webrtc.orgba975e22013-10-23 11:04:57 +0000812 kWaitingForPacket,
henrik.lundin@webrtc.orged8b2812014-03-18 08:43:29 +0000813 kWaitingForStats
henrik.lundin@webrtc.orgba975e22013-10-23 11:04:57 +0000814 };
815
pbos@webrtc.orgde1429e2014-04-28 13:00:21 +0000816 virtual void SendRtcpFeedback(int remb_value)
817 EXCLUSIVE_LOCKS_REQUIRED(crit_) {
henrik.lundin@webrtc.orgba975e22013-10-23 11:04:57 +0000818 FakeReceiveStatistics receive_stats(
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000819 kSendSsrcs[0], last_sequence_number_, rtp_count_, 0);
henrik.lundin@webrtc.orgba975e22013-10-23 11:04:57 +0000820 RTCPSender rtcp_sender(0, false, clock_, &receive_stats);
821 EXPECT_EQ(0, rtcp_sender.RegisterSendTransport(&transport_adapter_));
822
823 rtcp_sender.SetRTCPStatus(kRtcpNonCompound);
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000824 rtcp_sender.SetRemoteSSRC(kSendSsrcs[0]);
henrik.lundin@webrtc.orgba975e22013-10-23 11:04:57 +0000825 if (remb_value > 0) {
826 rtcp_sender.SetREMBStatus(true);
827 rtcp_sender.SetREMBData(remb_value, 0, NULL);
828 }
829 RTCPSender::FeedbackState feedback_state;
830 EXPECT_EQ(0, rtcp_sender.SendRTCP(feedback_state, kRtcpRr));
831 }
832
833 internal::TransportAdapter transport_adapter_;
834 test::DirectTransport transport_;
pbos@webrtc.orgde1429e2014-04-28 13:00:21 +0000835 Clock* const clock_;
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000836 VideoSendStream* stream_;
pbos@webrtc.orgde1429e2014-04-28 13:00:21 +0000837
838 const scoped_ptr<CriticalSectionWrapper> crit_;
839 TestState test_state_ GUARDED_BY(crit_);
840 int rtp_count_ GUARDED_BY(crit_);
841 int last_sequence_number_ GUARDED_BY(crit_);
842 int suspended_frame_count_ GUARDED_BY(crit_);
843 int low_remb_bps_ GUARDED_BY(crit_);
844 int high_remb_bps_ GUARDED_BY(crit_);
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000845 } test;
henrik.lundin@webrtc.orgba975e22013-10-23 11:04:57 +0000846
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000847 RunBaseTest(&test);
henrik.lundin@webrtc.orgba975e22013-10-23 11:04:57 +0000848}
849
stefan@webrtc.org4ab4fc02013-11-25 11:54:24 +0000850TEST_F(VideoSendStreamTest, NoPaddingWhenVideoIsMuted) {
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000851 class NoPaddingWhenVideoIsMuted : public test::SendTest {
stefan@webrtc.org4ab4fc02013-11-25 11:54:24 +0000852 public:
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000853 NoPaddingWhenVideoIsMuted()
854 : SendTest(kDefaultTimeoutMs),
stefan@webrtc.org4ab4fc02013-11-25 11:54:24 +0000855 clock_(Clock::GetRealTimeClock()),
stefan@webrtc.org4ab4fc02013-11-25 11:54:24 +0000856 transport_adapter_(ReceiveTransport()),
pbos@webrtc.orgde1429e2014-04-28 13:00:21 +0000857 crit_(CriticalSectionWrapper::CreateCriticalSection()),
858 last_packet_time_ms_(-1),
859 capturer_(NULL) {
sprang@webrtc.orgd9b95602014-01-27 13:03:02 +0000860 transport_adapter_.Enable();
861 }
stefan@webrtc.org4ab4fc02013-11-25 11:54:24 +0000862
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000863 private:
stefan@webrtc.org4ab4fc02013-11-25 11:54:24 +0000864 virtual Action OnSendRtp(const uint8_t* packet, size_t length) OVERRIDE {
pbos@webrtc.orgde1429e2014-04-28 13:00:21 +0000865 CriticalSectionScoped lock(crit_.get());
stefan@webrtc.org4ab4fc02013-11-25 11:54:24 +0000866 last_packet_time_ms_ = clock_->TimeInMilliseconds();
867 capturer_->Stop();
868 return SEND_PACKET;
869 }
870
871 virtual Action OnSendRtcp(const uint8_t* packet, size_t length) OVERRIDE {
pbos@webrtc.orgde1429e2014-04-28 13:00:21 +0000872 CriticalSectionScoped lock(crit_.get());
stefan@webrtc.org4ab4fc02013-11-25 11:54:24 +0000873 const int kVideoMutedThresholdMs = 10000;
pbos@webrtc.orgc279a5d2014-01-24 09:30:53 +0000874 if (last_packet_time_ms_ > 0 &&
875 clock_->TimeInMilliseconds() - last_packet_time_ms_ >
876 kVideoMutedThresholdMs)
stefan@webrtc.org4ab4fc02013-11-25 11:54:24 +0000877 observation_complete_->Set();
878 // Receive statistics reporting having lost 50% of the packets.
879 FakeReceiveStatistics receive_stats(kSendSsrcs[0], 1, 1, 0);
880 RTCPSender rtcp_sender(
881 0, false, Clock::GetRealTimeClock(), &receive_stats);
882 EXPECT_EQ(0, rtcp_sender.RegisterSendTransport(&transport_adapter_));
883
884 rtcp_sender.SetRTCPStatus(kRtcpNonCompound);
885 rtcp_sender.SetRemoteSSRC(kSendSsrcs[0]);
886
887 RTCPSender::FeedbackState feedback_state;
888
889 EXPECT_EQ(0, rtcp_sender.SendRTCP(feedback_state, kRtcpRr));
890 return SEND_PACKET;
891 }
892
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000893 virtual void SetReceivers(
894 PacketReceiver* send_transport_receiver,
895 PacketReceiver* receive_transport_receiver) OVERRIDE {
896 RtpRtcpObserver::SetReceivers(send_transport_receiver,
897 send_transport_receiver);
898 }
899
900 virtual size_t GetNumStreams() const OVERRIDE { return 3; }
901
902 virtual void OnFrameGeneratorCapturerCreated(
903 test::FrameGeneratorCapturer* frame_generator_capturer) {
904 CriticalSectionScoped lock(crit_.get());
905 capturer_ = frame_generator_capturer;
906 }
907
908 virtual void PerformTest() OVERRIDE {
909 EXPECT_EQ(kEventSignaled, Wait())
910 << "Timed out while waiting for RTP packets to stop being sent.";
911 }
912
pbos@webrtc.orgde1429e2014-04-28 13:00:21 +0000913 Clock* const clock_;
stefan@webrtc.org4ab4fc02013-11-25 11:54:24 +0000914 internal::TransportAdapter transport_adapter_;
pbos@webrtc.orgde1429e2014-04-28 13:00:21 +0000915 const scoped_ptr<CriticalSectionWrapper> crit_;
916 int64_t last_packet_time_ms_ GUARDED_BY(crit_);
917 test::FrameGeneratorCapturer* capturer_ GUARDED_BY(crit_);
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000918 } test;
stefan@webrtc.org4ab4fc02013-11-25 11:54:24 +0000919
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000920 RunBaseTest(&test);
stefan@webrtc.org4ab4fc02013-11-25 11:54:24 +0000921}
922
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000923TEST_F(VideoSendStreamTest, ProducesStats) {
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000924 class ProducesStats : public test::SendTest {
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000925 public:
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000926 ProducesStats()
927 : SendTest(kDefaultTimeoutMs),
sprang@webrtc.org60ad5fd2014-03-06 10:03:36 +0000928 stream_(NULL),
929 event_(EventWrapper::Create()) {}
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000930
931 virtual Action OnSendRtcp(const uint8_t* packet, size_t length) OVERRIDE {
sprang@webrtc.org60ad5fd2014-03-06 10:03:36 +0000932 event_->Set();
933
934 return SEND_PACKET;
935 }
936
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000937 private:
sprang@webrtc.org60ad5fd2014-03-06 10:03:36 +0000938 bool WaitForFilledStats() {
939 Clock* clock = Clock::GetRealTimeClock();
940 int64_t now = clock->TimeInMilliseconds();
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000941 int64_t stop_time = now + kDefaultTimeoutMs;
sprang@webrtc.org60ad5fd2014-03-06 10:03:36 +0000942 while (now < stop_time) {
943 int64_t time_left = stop_time - now;
944 if (time_left > 0 && event_->Wait(time_left) == kEventSignaled &&
945 CheckStats()) {
946 return true;
947 }
948 now = clock->TimeInMilliseconds();
949 }
950 return false;
951 }
952
953 bool CheckStats() {
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000954 VideoSendStream::Stats stats = stream_->GetStats();
955 // Check that all applicable data sources have been used.
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000956 if (stats.input_frame_rate > 0 && stats.encode_frame_rate > 0
957 && !stats.substreams.empty()) {
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000958 uint32_t ssrc = stats.substreams.begin()->first;
959 EXPECT_NE(
960 config_.rtp.ssrcs.end(),
961 std::find(
962 config_.rtp.ssrcs.begin(), config_.rtp.ssrcs.end(), ssrc));
963 // Check for data populated by various sources. RTCP excluded as this
964 // data is received from remote side. Tested in call tests instead.
sprang@webrtc.org60ad5fd2014-03-06 10:03:36 +0000965 const StreamStats& entry = stats.substreams[ssrc];
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000966 if (entry.key_frames > 0u && entry.bitrate_bps > 0 &&
stefan@webrtc.org168f23f2014-07-11 13:44:02 +0000967 entry.rtp_stats.packets > 0u && entry.avg_delay_ms > 0 &&
968 entry.max_delay_ms > 0) {
sprang@webrtc.org60ad5fd2014-03-06 10:03:36 +0000969 return true;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000970 }
971 }
sprang@webrtc.org60ad5fd2014-03-06 10:03:36 +0000972 return false;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000973 }
974
975 void SetConfig(const VideoSendStream::Config& config) { config_ = config; }
976
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000977 virtual void ModifyConfigs(
978 VideoSendStream::Config* send_config,
pbos@webrtc.orgbe9d2a42014-06-30 13:19:09 +0000979 std::vector<VideoReceiveStream::Config>* receive_configs,
pbos@webrtc.orgbbe0a852014-09-19 12:30:25 +0000980 VideoEncoderConfig* encoder_config) OVERRIDE {
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000981 SetConfig(*send_config);
982 }
983
pbos@webrtc.orgbe9d2a42014-06-30 13:19:09 +0000984 virtual void OnStreamsCreated(
985 VideoSendStream* send_stream,
986 const std::vector<VideoReceiveStream*>& receive_streams) OVERRIDE {
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000987 stream_ = send_stream;
988 }
989
990 virtual void PerformTest() OVERRIDE {
991 EXPECT_TRUE(WaitForFilledStats())
992 << "Timed out waiting for filled statistics.";
993 }
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000994
995 VideoSendStream* stream_;
996 VideoSendStream::Config config_;
sprang@webrtc.org60ad5fd2014-03-06 10:03:36 +0000997 scoped_ptr<EventWrapper> event_;
pbos@webrtc.org994d0b72014-06-27 08:47:52 +0000998 } test;
sprang@webrtc.orgccd42842014-01-07 09:54:34 +0000999
pbos@webrtc.org994d0b72014-06-27 08:47:52 +00001000 RunBaseTest(&test);
sprang@webrtc.orgccd42842014-01-07 09:54:34 +00001001}
1002
pbos@webrtc.org709e2972014-03-19 10:59:52 +00001003// This test first observes "high" bitrate use at which point it sends a REMB to
1004// indicate that it should be lowered significantly. The test then observes that
1005// the bitrate observed is sinking well below the min-transmit-bitrate threshold
1006// to verify that the min-transmit bitrate respects incoming REMB.
andresp@webrtc.org44caf012014-03-26 21:00:21 +00001007//
1008// Note that the test starts at "high" bitrate and does not ramp up to "higher"
1009// bitrate since no receiver block or remb is sent in the initial phase.
pbos@webrtc.org709e2972014-03-19 10:59:52 +00001010TEST_F(VideoSendStreamTest, MinTransmitBitrateRespectsRemb) {
1011 static const int kMinTransmitBitrateBps = 400000;
andresp@webrtc.org44caf012014-03-26 21:00:21 +00001012 static const int kHighBitrateBps = 150000;
pbos@webrtc.org709e2972014-03-19 10:59:52 +00001013 static const int kRembBitrateBps = 80000;
1014 static const int kRembRespectedBitrateBps = 100000;
pbos@webrtc.org994d0b72014-06-27 08:47:52 +00001015 class BitrateObserver : public test::SendTest, public PacketReceiver {
pbos@webrtc.org709e2972014-03-19 10:59:52 +00001016 public:
1017 BitrateObserver()
pbos@webrtc.org994d0b72014-06-27 08:47:52 +00001018 : SendTest(kDefaultTimeoutMs),
pbos@webrtc.org709e2972014-03-19 10:59:52 +00001019 feedback_transport_(ReceiveTransport()),
pbos@webrtc.org709e2972014-03-19 10:59:52 +00001020 bitrate_capped_(false) {
1021 RtpRtcp::Configuration config;
1022 feedback_transport_.Enable();
1023 config.outgoing_transport = &feedback_transport_;
1024 rtp_rtcp_.reset(RtpRtcp::CreateRtpRtcp(config));
1025 rtp_rtcp_->SetREMBStatus(true);
1026 rtp_rtcp_->SetRTCPStatus(kRtcpNonCompound);
1027 }
1028
pbos@webrtc.orgbe9d2a42014-06-30 13:19:09 +00001029 virtual void OnStreamsCreated(
1030 VideoSendStream* send_stream,
1031 const std::vector<VideoReceiveStream*>& receive_streams) OVERRIDE {
pbos@webrtc.org994d0b72014-06-27 08:47:52 +00001032 stream_ = send_stream;
pbos@webrtc.org709e2972014-03-19 10:59:52 +00001033 }
1034
1035 private:
pbos@webrtc.orgcaba2d22014-05-14 13:57:12 +00001036 virtual DeliveryStatus DeliverPacket(const uint8_t* packet,
1037 size_t length) OVERRIDE {
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001038 if (RtpHeaderParser::IsRtcp(packet, length))
pbos@webrtc.orgcaba2d22014-05-14 13:57:12 +00001039 return DELIVERY_OK;
pbos@webrtc.org709e2972014-03-19 10:59:52 +00001040
1041 RTPHeader header;
pbos@webrtc.org62bafae2014-07-08 12:10:51 +00001042 if (!parser_->Parse(packet, length, &header))
pbos@webrtc.orgcaba2d22014-05-14 13:57:12 +00001043 return DELIVERY_PACKET_ERROR;
pbos@webrtc.org994d0b72014-06-27 08:47:52 +00001044 assert(stream_ != NULL);
1045 VideoSendStream::Stats stats = stream_->GetStats();
pbos@webrtc.org709e2972014-03-19 10:59:52 +00001046 if (!stats.substreams.empty()) {
1047 EXPECT_EQ(1u, stats.substreams.size());
1048 int bitrate_bps = stats.substreams.begin()->second.bitrate_bps;
1049 test::PrintResult(
1050 "bitrate_stats_",
1051 "min_transmit_bitrate_low_remb",
1052 "bitrate_bps",
1053 static_cast<size_t>(bitrate_bps),
1054 "bps",
1055 false);
1056 if (bitrate_bps > kHighBitrateBps) {
1057 rtp_rtcp_->SetREMBData(kRembBitrateBps, 1, &header.ssrc);
1058 rtp_rtcp_->Process();
1059 bitrate_capped_ = true;
1060 } else if (bitrate_capped_ &&
1061 bitrate_bps < kRembRespectedBitrateBps) {
1062 observation_complete_->Set();
1063 }
1064 }
pbos@webrtc.orgcaba2d22014-05-14 13:57:12 +00001065 return DELIVERY_OK;
pbos@webrtc.org709e2972014-03-19 10:59:52 +00001066 }
1067
pbos@webrtc.org994d0b72014-06-27 08:47:52 +00001068 virtual void SetReceivers(
1069 PacketReceiver* send_transport_receiver,
1070 PacketReceiver* receive_transport_receiver) OVERRIDE {
1071 RtpRtcpObserver::SetReceivers(this, send_transport_receiver);
1072 }
1073
1074 virtual void ModifyConfigs(
1075 VideoSendStream::Config* send_config,
pbos@webrtc.orgbe9d2a42014-06-30 13:19:09 +00001076 std::vector<VideoReceiveStream::Config>* receive_configs,
pbos@webrtc.orgbbe0a852014-09-19 12:30:25 +00001077 VideoEncoderConfig* encoder_config) OVERRIDE {
pbos@webrtc.org994d0b72014-06-27 08:47:52 +00001078 send_config->rtp.min_transmit_bitrate_bps = kMinTransmitBitrateBps;
1079 }
1080
1081 virtual void PerformTest() OVERRIDE {
1082 EXPECT_EQ(kEventSignaled, Wait())
1083 << "Timeout while waiting for low bitrate stats after REMB.";
1084 }
1085
pbos@webrtc.org709e2972014-03-19 10:59:52 +00001086 scoped_ptr<RtpRtcp> rtp_rtcp_;
1087 internal::TransportAdapter feedback_transport_;
pbos@webrtc.org994d0b72014-06-27 08:47:52 +00001088 VideoSendStream* stream_;
pbos@webrtc.org709e2972014-03-19 10:59:52 +00001089 bool bitrate_capped_;
pbos@webrtc.org994d0b72014-06-27 08:47:52 +00001090 } test;
pbos@webrtc.org709e2972014-03-19 10:59:52 +00001091
pbos@webrtc.org994d0b72014-06-27 08:47:52 +00001092 RunBaseTest(&test);
pbos@webrtc.org709e2972014-03-19 10:59:52 +00001093}
1094
wuchengli@chromium.orgf425b552014-06-20 12:04:05 +00001095TEST_F(VideoSendStreamTest, CapturesTextureAndI420VideoFrames) {
1096 class FrameObserver : public I420FrameCallback {
1097 public:
1098 FrameObserver() : output_frame_event_(EventWrapper::Create()) {}
1099
1100 void FrameCallback(I420VideoFrame* video_frame) OVERRIDE {
1101 // Clone the frame because the caller owns it.
1102 output_frames_.push_back(video_frame->CloneFrame());
1103 output_frame_event_->Set();
1104 }
1105
1106 void WaitOutputFrame() {
1107 const unsigned long kWaitFrameTimeoutMs = 3000;
1108 EXPECT_EQ(kEventSignaled, output_frame_event_->Wait(kWaitFrameTimeoutMs))
1109 << "Timeout while waiting for output frames.";
1110 }
1111
1112 const std::vector<I420VideoFrame*>& output_frames() const {
1113 return output_frames_.get();
1114 }
1115
1116 private:
1117 // Delivered output frames.
1118 ScopedVector<I420VideoFrame> output_frames_;
1119
1120 // Indicate an output frame has arrived.
1121 scoped_ptr<EventWrapper> output_frame_event_;
1122 };
1123
1124 // Initialize send stream.
1125 test::NullTransport transport;
pbos@webrtc.org994d0b72014-06-27 08:47:52 +00001126 CreateSenderCall(Call::Config(&transport));
1127
1128 CreateSendConfig(1);
wuchengli@chromium.orgf425b552014-06-20 12:04:05 +00001129 FrameObserver observer;
1130 send_config_.pre_encode_callback = &observer;
pbos@webrtc.org994d0b72014-06-27 08:47:52 +00001131 CreateStreams();
wuchengli@chromium.orgf425b552014-06-20 12:04:05 +00001132
1133 // Prepare five input frames. Send I420VideoFrame and TextureVideoFrame
1134 // alternatively.
1135 ScopedVector<I420VideoFrame> input_frames;
pbos@webrtc.orgbbe0a852014-09-19 12:30:25 +00001136 int width = static_cast<int>(encoder_config_.streams[0].width);
1137 int height = static_cast<int>(encoder_config_.streams[0].height);
wuchengli@chromium.orgf425b552014-06-20 12:04:05 +00001138 webrtc::RefCountImpl<FakeNativeHandle>* handle1 =
1139 new webrtc::RefCountImpl<FakeNativeHandle>();
1140 webrtc::RefCountImpl<FakeNativeHandle>* handle2 =
1141 new webrtc::RefCountImpl<FakeNativeHandle>();
1142 webrtc::RefCountImpl<FakeNativeHandle>* handle3 =
1143 new webrtc::RefCountImpl<FakeNativeHandle>();
1144 input_frames.push_back(new TextureVideoFrame(handle1, width, height, 1, 1));
1145 input_frames.push_back(new TextureVideoFrame(handle2, width, height, 2, 2));
1146 input_frames.push_back(CreateI420VideoFrame(width, height, 1));
1147 input_frames.push_back(CreateI420VideoFrame(width, height, 2));
1148 input_frames.push_back(new TextureVideoFrame(handle3, width, height, 3, 3));
1149
1150 send_stream_->Start();
1151 for (size_t i = 0; i < input_frames.size(); i++) {
1152 // Make a copy of the input frame because the buffer will be swapped.
1153 scoped_ptr<I420VideoFrame> frame(input_frames[i]->CloneFrame());
1154 send_stream_->Input()->SwapFrame(frame.get());
1155 // Do not send the next frame too fast, so the frame dropper won't drop it.
1156 if (i < input_frames.size() - 1)
pbos@webrtc.orgbbe0a852014-09-19 12:30:25 +00001157 SleepMs(1000 / encoder_config_.streams[0].max_framerate);
wuchengli@chromium.orgf425b552014-06-20 12:04:05 +00001158 // Wait until the output frame is received before sending the next input
1159 // frame. Or the previous input frame may be replaced without delivering.
1160 observer.WaitOutputFrame();
1161 }
1162 send_stream_->Stop();
1163
1164 // Test if the input and output frames are the same. render_time_ms and
1165 // timestamp are not compared because capturer sets those values.
1166 ExpectEqualFramesVector(input_frames.get(), observer.output_frames());
1167
pbos@webrtc.org994d0b72014-06-27 08:47:52 +00001168 DestroyStreams();
wuchengli@chromium.orgf425b552014-06-20 12:04:05 +00001169}
1170
1171void ExpectEqualFrames(const I420VideoFrame& frame1,
1172 const I420VideoFrame& frame2) {
1173 if (frame1.native_handle() != NULL || frame2.native_handle() != NULL)
1174 ExpectEqualTextureFrames(frame1, frame2);
1175 else
1176 ExpectEqualBufferFrames(frame1, frame2);
1177}
1178
1179void ExpectEqualTextureFrames(const I420VideoFrame& frame1,
1180 const I420VideoFrame& frame2) {
1181 EXPECT_EQ(frame1.native_handle(), frame2.native_handle());
1182 EXPECT_EQ(frame1.width(), frame2.width());
1183 EXPECT_EQ(frame1.height(), frame2.height());
1184}
1185
1186void ExpectEqualBufferFrames(const I420VideoFrame& frame1,
1187 const I420VideoFrame& frame2) {
1188 EXPECT_EQ(frame1.width(), frame2.width());
1189 EXPECT_EQ(frame1.height(), frame2.height());
1190 EXPECT_EQ(frame1.stride(kYPlane), frame2.stride(kYPlane));
1191 EXPECT_EQ(frame1.stride(kUPlane), frame2.stride(kUPlane));
1192 EXPECT_EQ(frame1.stride(kVPlane), frame2.stride(kVPlane));
1193 EXPECT_EQ(frame1.ntp_time_ms(), frame2.ntp_time_ms());
1194 ASSERT_EQ(frame1.allocated_size(kYPlane), frame2.allocated_size(kYPlane));
1195 EXPECT_EQ(0,
1196 memcmp(frame1.buffer(kYPlane),
1197 frame2.buffer(kYPlane),
1198 frame1.allocated_size(kYPlane)));
1199 ASSERT_EQ(frame1.allocated_size(kUPlane), frame2.allocated_size(kUPlane));
1200 EXPECT_EQ(0,
1201 memcmp(frame1.buffer(kUPlane),
1202 frame2.buffer(kUPlane),
1203 frame1.allocated_size(kUPlane)));
1204 ASSERT_EQ(frame1.allocated_size(kVPlane), frame2.allocated_size(kVPlane));
1205 EXPECT_EQ(0,
1206 memcmp(frame1.buffer(kVPlane),
1207 frame2.buffer(kVPlane),
1208 frame1.allocated_size(kVPlane)));
1209}
1210
1211void ExpectEqualFramesVector(const std::vector<I420VideoFrame*>& frames1,
1212 const std::vector<I420VideoFrame*>& frames2) {
1213 EXPECT_EQ(frames1.size(), frames2.size());
1214 for (size_t i = 0; i < std::min(frames1.size(), frames2.size()); ++i)
1215 ExpectEqualFrames(*frames1[i], *frames2[i]);
1216}
1217
1218I420VideoFrame* CreateI420VideoFrame(int width, int height, uint8_t data) {
1219 I420VideoFrame* frame = new I420VideoFrame();
1220 const int kSizeY = width * height * 2;
1221 const int kSizeUV = width * height;
1222 scoped_ptr<uint8_t[]> buffer(new uint8_t[kSizeY]);
1223 memset(buffer.get(), data, kSizeY);
1224 frame->CreateFrame(kSizeY,
1225 buffer.get(),
1226 kSizeUV,
1227 buffer.get(),
1228 kSizeUV,
1229 buffer.get(),
1230 width,
1231 height,
1232 width,
1233 width / 2,
1234 width / 2);
1235 frame->set_timestamp(data);
1236 frame->set_ntp_time_ms(data);
1237 frame->set_render_time_ms(data);
1238 return frame;
1239}
1240
pbos@webrtc.org161f8082014-07-07 14:22:35 +00001241TEST_F(VideoSendStreamTest, EncoderIsProperlyInitializedAndDestroyed) {
1242 class EncoderStateObserver : public test::SendTest, public VideoEncoder {
1243 public:
1244 EncoderStateObserver()
1245 : SendTest(kDefaultTimeoutMs),
1246 crit_(CriticalSectionWrapper::CreateCriticalSection()),
1247 initialized_(false),
1248 callback_registered_(false),
1249 num_releases_(0),
1250 released_(false) {}
1251
1252 bool IsReleased() {
1253 CriticalSectionScoped lock(crit_.get());
1254 return released_;
1255 }
1256
1257 bool IsReadyForEncode() {
1258 CriticalSectionScoped lock(crit_.get());
1259 return initialized_ && callback_registered_;
1260 }
1261
1262 size_t num_releases() {
1263 CriticalSectionScoped lock(crit_.get());
1264 return num_releases_;
1265 }
1266
1267 private:
1268 virtual int32_t InitEncode(const VideoCodec* codecSettings,
1269 int32_t numberOfCores,
1270 uint32_t maxPayloadSize) OVERRIDE {
1271 CriticalSectionScoped lock(crit_.get());
1272 EXPECT_FALSE(initialized_);
1273 initialized_ = true;
1274 released_ = false;
1275 return 0;
1276 }
1277
1278 virtual int32_t Encode(
1279 const I420VideoFrame& inputImage,
1280 const CodecSpecificInfo* codecSpecificInfo,
1281 const std::vector<VideoFrameType>* frame_types) OVERRIDE {
1282 EXPECT_TRUE(IsReadyForEncode());
1283
1284 observation_complete_->Set();
1285 return 0;
1286 }
1287
1288 virtual int32_t RegisterEncodeCompleteCallback(
1289 EncodedImageCallback* callback) OVERRIDE {
1290 CriticalSectionScoped lock(crit_.get());
1291 EXPECT_TRUE(initialized_);
1292 callback_registered_ = true;
1293 return 0;
1294 }
1295
1296 virtual int32_t Release() OVERRIDE {
1297 CriticalSectionScoped lock(crit_.get());
1298 EXPECT_TRUE(IsReadyForEncode());
1299 EXPECT_FALSE(released_);
1300 initialized_ = false;
1301 callback_registered_ = false;
1302 released_ = true;
1303 ++num_releases_;
1304 return 0;
1305 }
1306
1307 virtual int32_t SetChannelParameters(uint32_t packetLoss,
1308 int rtt) OVERRIDE {
1309 EXPECT_TRUE(IsReadyForEncode());
1310 return 0;
1311 }
1312
1313 virtual int32_t SetRates(uint32_t newBitRate, uint32_t frameRate) OVERRIDE {
1314 EXPECT_TRUE(IsReadyForEncode());
1315 return 0;
1316 }
1317
1318 virtual void OnStreamsCreated(
1319 VideoSendStream* send_stream,
1320 const std::vector<VideoReceiveStream*>& receive_streams) OVERRIDE {
1321 // Encoder initialization should be done in stream construction before
1322 // starting.
1323 EXPECT_TRUE(IsReadyForEncode());
1324 stream_ = send_stream;
1325 }
1326
1327 virtual void ModifyConfigs(
1328 VideoSendStream::Config* send_config,
1329 std::vector<VideoReceiveStream::Config>* receive_configs,
pbos@webrtc.orgbbe0a852014-09-19 12:30:25 +00001330 VideoEncoderConfig* encoder_config) OVERRIDE {
pbos@webrtc.org161f8082014-07-07 14:22:35 +00001331 send_config->encoder_settings.encoder = this;
pbos@webrtc.orgbbe0a852014-09-19 12:30:25 +00001332 encoder_config_ = *encoder_config;
pbos@webrtc.org161f8082014-07-07 14:22:35 +00001333 }
1334
1335 virtual void PerformTest() OVERRIDE {
1336 EXPECT_EQ(kEventSignaled, Wait())
1337 << "Timed out while waiting for Encode.";
1338 EXPECT_EQ(0u, num_releases());
pbos@webrtc.orgbbe0a852014-09-19 12:30:25 +00001339 stream_->ReconfigureVideoEncoder(encoder_config_);
pbos@webrtc.org161f8082014-07-07 14:22:35 +00001340 EXPECT_EQ(0u, num_releases());
1341 stream_->Stop();
1342 // Encoder should not be released before destroying the VideoSendStream.
1343 EXPECT_FALSE(IsReleased());
1344 EXPECT_TRUE(IsReadyForEncode());
1345 stream_->Start();
1346 // Sanity check, make sure we still encode frames with this encoder.
1347 EXPECT_EQ(kEventSignaled, Wait())
1348 << "Timed out while waiting for Encode.";
1349 }
1350
1351 scoped_ptr<CriticalSectionWrapper> crit_;
1352 VideoSendStream* stream_;
1353 bool initialized_ GUARDED_BY(crit_);
1354 bool callback_registered_ GUARDED_BY(crit_);
1355 size_t num_releases_ GUARDED_BY(crit_);
1356 bool released_ GUARDED_BY(crit_);
pbos@webrtc.orgbbe0a852014-09-19 12:30:25 +00001357 VideoEncoderConfig encoder_config_;
pbos@webrtc.org161f8082014-07-07 14:22:35 +00001358 } test_encoder;
1359
1360 RunBaseTest(&test_encoder);
1361
1362 EXPECT_TRUE(test_encoder.IsReleased());
1363 EXPECT_EQ(1u, test_encoder.num_releases());
1364}
1365
pbos@webrtc.orgbbe0a852014-09-19 12:30:25 +00001366TEST_F(VideoSendStreamTest, EncoderSetupPropagatesCommonEncoderConfigValues) {
1367 class VideoCodecConfigObserver : public test::SendTest,
1368 public test::FakeEncoder {
1369 public:
1370 VideoCodecConfigObserver()
1371 : SendTest(kDefaultTimeoutMs),
1372 FakeEncoder(Clock::GetRealTimeClock()),
1373 num_initializations_(0) {}
1374
1375 private:
1376 virtual void ModifyConfigs(
1377 VideoSendStream::Config* send_config,
1378 std::vector<VideoReceiveStream::Config>* receive_configs,
1379 VideoEncoderConfig* encoder_config) OVERRIDE {
1380 send_config->encoder_settings.encoder = this;
1381 encoder_config_ = *encoder_config;
1382 }
1383
1384 virtual void OnStreamsCreated(
1385 VideoSendStream* send_stream,
1386 const std::vector<VideoReceiveStream*>& receive_streams) OVERRIDE {
1387 stream_ = send_stream;
1388 }
1389
1390 virtual int32_t InitEncode(const VideoCodec* config,
1391 int32_t number_of_cores,
1392 uint32_t max_payload_size) OVERRIDE {
1393 if (num_initializations_ == 0) {
1394 // Verify default values.
1395 EXPECT_EQ(kRealtimeVideo, config->mode);
1396 } else {
1397 // Verify that changed values are propagated.
1398 EXPECT_EQ(kScreensharing, config->mode);
1399 }
1400 ++num_initializations_;
1401 return FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
1402 }
1403
1404 virtual void PerformTest() OVERRIDE {
1405 EXPECT_EQ(1u, num_initializations_) << "VideoEncoder not initialized.";
1406
1407 encoder_config_.content_type = VideoEncoderConfig::kScreenshare;
1408 stream_->ReconfigureVideoEncoder(encoder_config_);
1409 EXPECT_EQ(2u, num_initializations_)
1410 << "ReconfigureVideoEncoder did not reinitialize the encoder with "
1411 "new encoder settings.";
1412 }
1413
1414 size_t num_initializations_;
1415 VideoSendStream* stream_;
1416 VideoEncoderConfig encoder_config_;
1417 } test;
1418
1419 RunBaseTest(&test);
1420}
1421
pbos@webrtc.org91f17522014-07-10 10:13:37 +00001422TEST_F(VideoSendStreamTest, EncoderSetupPropagatesVp8Config) {
1423 class VideoCodecConfigObserver : public test::SendTest,
1424 public test::FakeEncoder {
1425 public:
1426 VideoCodecConfigObserver()
1427 : SendTest(kDefaultTimeoutMs),
1428 FakeEncoder(Clock::GetRealTimeClock()),
1429 num_initializations_(0) {
1430 memset(&vp8_settings_, 0, sizeof(vp8_settings_));
1431 }
1432
1433 private:
1434 virtual void ModifyConfigs(
1435 VideoSendStream::Config* send_config,
1436 std::vector<VideoReceiveStream::Config>* receive_configs,
pbos@webrtc.orgbbe0a852014-09-19 12:30:25 +00001437 VideoEncoderConfig* encoder_config) OVERRIDE {
pbos@webrtc.org91f17522014-07-10 10:13:37 +00001438 send_config->encoder_settings.encoder = this;
1439 send_config->encoder_settings.payload_name = "VP8";
1440
pbos@webrtc.orgbbe0a852014-09-19 12:30:25 +00001441 encoder_config->encoder_specific_settings = &vp8_settings_;
1442 encoder_config_ = *encoder_config;
pbos@webrtc.org91f17522014-07-10 10:13:37 +00001443 }
1444
1445 virtual void OnStreamsCreated(
1446 VideoSendStream* send_stream,
1447 const std::vector<VideoReceiveStream*>& receive_streams) OVERRIDE {
1448 stream_ = send_stream;
1449 }
1450
1451 virtual int32_t InitEncode(const VideoCodec* config,
1452 int32_t number_of_cores,
1453 uint32_t max_payload_size) OVERRIDE {
1454 EXPECT_EQ(kVideoCodecVP8, config->codecType);
1455 EXPECT_EQ(0,
1456 memcmp(&config->codecSpecific.VP8,
1457 &vp8_settings_,
1458 sizeof(vp8_settings_)));
1459 ++num_initializations_;
1460 return FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
1461 }
1462
1463 virtual void PerformTest() OVERRIDE {
1464 EXPECT_EQ(1u, num_initializations_) << "VideoEncoder not initialized.";
1465
1466 vp8_settings_.denoisingOn = true;
pbos@webrtc.orgbbe0a852014-09-19 12:30:25 +00001467 stream_->ReconfigureVideoEncoder(encoder_config_);
pbos@webrtc.org91f17522014-07-10 10:13:37 +00001468 EXPECT_EQ(2u, num_initializations_)
1469 << "ReconfigureVideoEncoder did not reinitialize the encoder with "
1470 "new encoder settings.";
1471 }
1472
pbos@webrtc.orgbbe0a852014-09-19 12:30:25 +00001473 int32_t Encode(const I420VideoFrame& input_image,
1474 const CodecSpecificInfo* codec_specific_info,
1475 const std::vector<VideoFrameType>* frame_types) OVERRIDE {
pbos@webrtc.orgbd9c0922014-07-10 13:21:40 +00001476 // Silently skip the encode, FakeEncoder::Encode doesn't produce VP8.
1477 return 0;
1478 }
1479
pbos@webrtc.org91f17522014-07-10 10:13:37 +00001480 VideoCodecVP8 vp8_settings_;
1481 size_t num_initializations_;
1482 VideoSendStream* stream_;
pbos@webrtc.orgbbe0a852014-09-19 12:30:25 +00001483 VideoEncoderConfig encoder_config_;
pbos@webrtc.org91f17522014-07-10 10:13:37 +00001484 } test;
1485
1486 RunBaseTest(&test);
1487}
1488
pbos@webrtc.org2f4b14e2014-07-15 15:25:39 +00001489TEST_F(VideoSendStreamTest, RtcpSenderReportContainsMediaBytesSent) {
1490 class RtcpByeTest : public test::SendTest {
1491 public:
1492 RtcpByeTest() : SendTest(kDefaultTimeoutMs), media_bytes_sent_(0) {}
1493
1494 private:
1495 virtual Action OnSendRtp(const uint8_t* packet, size_t length) OVERRIDE {
1496 RTPHeader header;
1497 EXPECT_TRUE(parser_->Parse(packet, length, &header));
1498 media_bytes_sent_ += length - header.headerLength - header.paddingLength;
1499 return SEND_PACKET;
1500 }
1501
1502 virtual Action OnSendRtcp(const uint8_t* packet, size_t length) OVERRIDE {
1503 RTCPUtility::RTCPParserV2 parser(packet, length, true);
1504 EXPECT_TRUE(parser.IsValid());
1505
1506 RTCPUtility::RTCPPacketTypes packet_type = parser.Begin();
1507 uint32_t sender_octet_count = 0;
1508 while (packet_type != RTCPUtility::kRtcpNotValidCode) {
1509 if (packet_type == RTCPUtility::kRtcpSrCode) {
1510 sender_octet_count = parser.Packet().SR.SenderOctetCount;
1511 EXPECT_EQ(sender_octet_count, media_bytes_sent_);
1512 if (sender_octet_count > 0)
1513 observation_complete_->Set();
1514 }
1515
1516 packet_type = parser.Iterate();
1517 }
1518
1519 return SEND_PACKET;
1520 }
1521
1522 virtual void PerformTest() OVERRIDE {
1523 EXPECT_EQ(kEventSignaled, Wait())
1524 << "Timed out while waiting for RTCP sender report.";
1525 }
1526
1527 size_t media_bytes_sent_;
1528 } test;
1529
1530 RunBaseTest(&test);
1531}
1532
pbos@webrtc.org119a1cc2013-08-20 13:14:07 +00001533} // namespace webrtc