blob: 3c7fb6f83c243a65d621d5feed702ed8fd89bb68 [file] [log] [blame]
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +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 */
10
kwiberg84be5112016-04-27 01:19:58 -070011#include <memory>
Danil Chapovalovd1996b72018-01-16 11:07:18 +010012#include <vector>
kwiberg84be5112016-04-27 01:19:58 -070013
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020014#include "modules/rtp_rtcp/include/receive_statistics.h"
15#include "system_wrappers/include/clock.h"
16#include "test/gmock.h"
17#include "test/gtest.h"
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +000018
19namespace webrtc {
Danil Chapovalovd1996b72018-01-16 11:07:18 +010020namespace {
21
Taylor Brandstetter84916932018-06-25 15:50:26 -070022using ::testing::_;
23using ::testing::SaveArg;
Danil Chapovalovd1996b72018-01-16 11:07:18 +010024using ::testing::SizeIs;
25using ::testing::UnorderedElementsAre;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +000026
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000027const size_t kPacketSize1 = 100;
28const size_t kPacketSize2 = 300;
Danil Chapovalovd1996b72018-01-16 11:07:18 +010029const uint32_t kSsrc1 = 101;
30const uint32_t kSsrc2 = 202;
31const uint32_t kSsrc3 = 203;
32const uint32_t kSsrc4 = 304;
33
34RTPHeader CreateRtpHeader(uint32_t ssrc) {
35 RTPHeader header;
36 memset(&header, 0, sizeof(header));
37 header.ssrc = ssrc;
38 header.sequenceNumber = 100;
39 return header;
40}
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +000041
42class ReceiveStatisticsTest : public ::testing::Test {
43 public:
Yves Gerey665174f2018-06-19 15:03:05 +020044 ReceiveStatisticsTest()
45 : clock_(0), receive_statistics_(ReceiveStatistics::Create(&clock_)) {
Danil Chapovalovd1996b72018-01-16 11:07:18 +010046 header1_ = CreateRtpHeader(kSsrc1);
47 header2_ = CreateRtpHeader(kSsrc2);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +000048 }
49
50 protected:
51 SimulatedClock clock_;
kwiberg84be5112016-04-27 01:19:58 -070052 std::unique_ptr<ReceiveStatistics> receive_statistics_;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +000053 RTPHeader header1_;
54 RTPHeader header2_;
55};
56
57TEST_F(ReceiveStatisticsTest, TwoIncomingSsrcs) {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +000058 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +000059 ++header1_.sequenceNumber;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +000060 receive_statistics_->IncomingPacket(header2_, kPacketSize2, false);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +000061 ++header2_.sequenceNumber;
62 clock_.AdvanceTimeMilliseconds(100);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +000063 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +000064 ++header1_.sequenceNumber;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +000065 receive_statistics_->IncomingPacket(header2_, kPacketSize2, false);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +000066 ++header2_.sequenceNumber;
67
68 StreamStatistician* statistician =
69 receive_statistics_->GetStatistician(kSsrc1);
70 ASSERT_TRUE(statistician != NULL);
71 EXPECT_GT(statistician->BitrateReceived(), 0u);
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000072 size_t bytes_received = 0;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +000073 uint32_t packets_received = 0;
74 statistician->GetDataCounters(&bytes_received, &packets_received);
75 EXPECT_EQ(200u, bytes_received);
76 EXPECT_EQ(2u, packets_received);
77
Yves Gerey665174f2018-06-19 15:03:05 +020078 statistician = receive_statistics_->GetStatistician(kSsrc2);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +000079 ASSERT_TRUE(statistician != NULL);
80 EXPECT_GT(statistician->BitrateReceived(), 0u);
81 statistician->GetDataCounters(&bytes_received, &packets_received);
82 EXPECT_EQ(600u, bytes_received);
83 EXPECT_EQ(2u, packets_received);
84
Danil Chapovalovc5267d22017-09-18 13:57:19 +020085 EXPECT_EQ(2u, receive_statistics_->RtcpReportBlocks(3).size());
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +000086 // Add more incoming packets and verify that they are registered in both
87 // access methods.
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +000088 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +000089 ++header1_.sequenceNumber;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +000090 receive_statistics_->IncomingPacket(header2_, kPacketSize2, false);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +000091 ++header2_.sequenceNumber;
92
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +000093 receive_statistics_->GetStatistician(kSsrc1)->GetDataCounters(
94 &bytes_received, &packets_received);
95 EXPECT_EQ(300u, bytes_received);
96 EXPECT_EQ(3u, packets_received);
97 receive_statistics_->GetStatistician(kSsrc2)->GetDataCounters(
98 &bytes_received, &packets_received);
99 EXPECT_EQ(900u, bytes_received);
100 EXPECT_EQ(3u, packets_received);
101}
102
Danil Chapovalovd1996b72018-01-16 11:07:18 +0100103TEST_F(ReceiveStatisticsTest,
104 RtcpReportBlocksReturnsMaxBlocksWhenThereAreMoreStatisticians) {
105 RTPHeader header1 = CreateRtpHeader(kSsrc1);
106 RTPHeader header2 = CreateRtpHeader(kSsrc2);
107 RTPHeader header3 = CreateRtpHeader(kSsrc3);
108 receive_statistics_->IncomingPacket(header1, kPacketSize1, false);
109 receive_statistics_->IncomingPacket(header2, kPacketSize1, false);
110 receive_statistics_->IncomingPacket(header3, kPacketSize1, false);
111
112 EXPECT_THAT(receive_statistics_->RtcpReportBlocks(2), SizeIs(2));
113 EXPECT_THAT(receive_statistics_->RtcpReportBlocks(2), SizeIs(2));
114 EXPECT_THAT(receive_statistics_->RtcpReportBlocks(2), SizeIs(2));
115}
116
117TEST_F(ReceiveStatisticsTest,
118 RtcpReportBlocksReturnsAllObservedSsrcsWithMultipleCalls) {
119 RTPHeader header1 = CreateRtpHeader(kSsrc1);
120 RTPHeader header2 = CreateRtpHeader(kSsrc2);
121 RTPHeader header3 = CreateRtpHeader(kSsrc3);
122 RTPHeader header4 = CreateRtpHeader(kSsrc4);
123 receive_statistics_->IncomingPacket(header1, kPacketSize1, false);
124 receive_statistics_->IncomingPacket(header2, kPacketSize1, false);
125 receive_statistics_->IncomingPacket(header3, kPacketSize1, false);
126 receive_statistics_->IncomingPacket(header4, kPacketSize1, false);
127
128 std::vector<uint32_t> observed_ssrcs;
129 std::vector<rtcp::ReportBlock> report_blocks =
130 receive_statistics_->RtcpReportBlocks(2);
131 ASSERT_THAT(report_blocks, SizeIs(2));
132 observed_ssrcs.push_back(report_blocks[0].source_ssrc());
133 observed_ssrcs.push_back(report_blocks[1].source_ssrc());
134
135 report_blocks = receive_statistics_->RtcpReportBlocks(2);
136 ASSERT_THAT(report_blocks, SizeIs(2));
137 observed_ssrcs.push_back(report_blocks[0].source_ssrc());
138 observed_ssrcs.push_back(report_blocks[1].source_ssrc());
139
140 EXPECT_THAT(observed_ssrcs,
141 UnorderedElementsAre(kSsrc1, kSsrc2, kSsrc3, kSsrc4));
142}
143
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000144TEST_F(ReceiveStatisticsTest, ActiveStatisticians) {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000145 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000146 ++header1_.sequenceNumber;
147 clock_.AdvanceTimeMilliseconds(1000);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000148 receive_statistics_->IncomingPacket(header2_, kPacketSize2, false);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000149 ++header2_.sequenceNumber;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000150 // Nothing should time out since only 1000 ms has passed since the first
151 // packet came in.
Danil Chapovalovc5267d22017-09-18 13:57:19 +0200152 EXPECT_EQ(2u, receive_statistics_->RtcpReportBlocks(3).size());
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000153
154 clock_.AdvanceTimeMilliseconds(7000);
155 // kSsrc1 should have timed out.
Danil Chapovalovc5267d22017-09-18 13:57:19 +0200156 EXPECT_EQ(1u, receive_statistics_->RtcpReportBlocks(3).size());
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000157
158 clock_.AdvanceTimeMilliseconds(1000);
159 // kSsrc2 should have timed out.
Danil Chapovalovc5267d22017-09-18 13:57:19 +0200160 EXPECT_EQ(0u, receive_statistics_->RtcpReportBlocks(3).size());
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000161
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000162 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000163 ++header1_.sequenceNumber;
164 // kSsrc1 should be active again and the data counters should have survived.
Danil Chapovalovc5267d22017-09-18 13:57:19 +0200165 EXPECT_EQ(1u, receive_statistics_->RtcpReportBlocks(3).size());
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000166 StreamStatistician* statistician =
167 receive_statistics_->GetStatistician(kSsrc1);
168 ASSERT_TRUE(statistician != NULL);
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000169 size_t bytes_received = 0;
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000170 uint32_t packets_received = 0;
171 statistician->GetDataCounters(&bytes_received, &packets_received);
172 EXPECT_EQ(200u, bytes_received);
173 EXPECT_EQ(2u, packets_received);
174}
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000175
asapersson@webrtc.org97d04892014-12-09 09:47:53 +0000176TEST_F(ReceiveStatisticsTest, GetReceiveStreamDataCounters) {
177 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
178 StreamStatistician* statistician =
179 receive_statistics_->GetStatistician(kSsrc1);
180 ASSERT_TRUE(statistician != NULL);
181
182 StreamDataCounters counters;
183 statistician->GetReceiveStreamDataCounters(&counters);
asapersson@webrtc.orgd08d3892014-12-16 12:03:11 +0000184 EXPECT_GT(counters.first_packet_time_ms, -1);
asapersson@webrtc.orgcfd82df2015-01-22 09:39:59 +0000185 EXPECT_EQ(1u, counters.transmitted.packets);
asapersson@webrtc.org97d04892014-12-09 09:47:53 +0000186
asapersson@webrtc.org97d04892014-12-09 09:47:53 +0000187 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
188 statistician->GetReceiveStreamDataCounters(&counters);
asapersson@webrtc.orgd08d3892014-12-16 12:03:11 +0000189 EXPECT_GT(counters.first_packet_time_ms, -1);
asapersson@webrtc.orgcfd82df2015-01-22 09:39:59 +0000190 EXPECT_EQ(2u, counters.transmitted.packets);
asapersson@webrtc.org97d04892014-12-09 09:47:53 +0000191}
192
Taylor Brandstetter84916932018-06-25 15:50:26 -0700193class MockRtcpCallback : public RtcpStatisticsCallback {
194 public:
195 MOCK_METHOD2(StatisticsUpdated,
196 void(const RtcpStatistics& statistics, uint32_t ssrc));
197 MOCK_METHOD2(CNameChanged, void(const char* cname, uint32_t ssrc));
198};
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000199
Taylor Brandstetter84916932018-06-25 15:50:26 -0700200// Test that the RTCP statistics callback is invoked every time a packet is
201// received (so that at the application level, GetStats will return up-to-date
202// stats, not just stats from the last generated RTCP SR or RR).
203TEST_F(ReceiveStatisticsTest,
204 RtcpStatisticsCallbackInvokedForEveryPacketReceived) {
205 MockRtcpCallback callback;
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000206 receive_statistics_->RegisterRtcpStatisticsCallback(&callback);
207
Taylor Brandstetter84916932018-06-25 15:50:26 -0700208 // Just receive the same packet multiple times; doesn't really matter for the
209 // purposes of this test.
210 EXPECT_CALL(callback, StatisticsUpdated(_, _)).Times(3);
211 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
212 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
213 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
214}
215
216// The callback should also be invoked when |fraction_lost| is updated due to
217// GetStatistics being called.
218TEST_F(ReceiveStatisticsTest,
219 RtcpStatisticsCallbackInvokedWhenFractionLostUpdated) {
220 MockRtcpCallback callback;
221 receive_statistics_->RegisterRtcpStatisticsCallback(&callback);
222
223 EXPECT_CALL(callback, StatisticsUpdated(_, _)).Times(2);
224 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
225 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
226
227 // This just returns the current statistics without updating anything, so no
228 // need to invoke the callback.
229 RtcpStatistics statistics;
230 receive_statistics_->GetStatistician(kSsrc1)->GetStatistics(
231 &statistics, /*update_fraction_lost=*/false);
232
233 // Update fraction lost, expecting a new callback.
234 EXPECT_CALL(callback, StatisticsUpdated(_, _)).Times(1);
235 receive_statistics_->GetStatistician(kSsrc1)->GetStatistics(
236 &statistics, /*update_fraction_lost=*/true);
237}
238
239TEST_F(ReceiveStatisticsTest,
240 RtcpStatisticsCallbackNotInvokedAfterDeregistered) {
241 // Register the callback and receive a couple packets.
242 MockRtcpCallback callback;
243 receive_statistics_->RegisterRtcpStatisticsCallback(&callback);
244 EXPECT_CALL(callback, StatisticsUpdated(_, _)).Times(2);
245 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
246 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
247
248 // Dereigster the callback. Neither receiving a packet nor generating a
249 // report (calling GetStatistics) should result in another callback.
250 receive_statistics_->RegisterRtcpStatisticsCallback(nullptr);
251 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
252 RtcpStatistics statistics;
253 receive_statistics_->GetStatistician(kSsrc1)->GetStatistics(
254 &statistics, /*update_fraction_lost=*/true);
255}
256
257// Test that the RtcpStatisticsCallback sees the exact same values as returned
258// from GetStatistics.
259TEST_F(ReceiveStatisticsTest,
260 RtcpStatisticsFromCallbackMatchThoseFromGetStatistics) {
261 MockRtcpCallback callback;
262 RtcpStatistics stats_from_callback;
263 EXPECT_CALL(callback, StatisticsUpdated(_, _))
264 .WillRepeatedly(SaveArg<0>(&stats_from_callback));
265 receive_statistics_->RegisterRtcpStatisticsCallback(&callback);
266
267 // Using units of milliseconds.
268 header1_.payload_type_frequency = 1000;
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000269 // Add some arbitrary data, with loss and jitter.
270 header1_.sequenceNumber = 1;
271 clock_.AdvanceTimeMilliseconds(7);
272 header1_.timestamp += 3;
273 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
274 header1_.sequenceNumber += 2;
275 clock_.AdvanceTimeMilliseconds(9);
276 header1_.timestamp += 9;
277 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
278 --header1_.sequenceNumber;
279 clock_.AdvanceTimeMilliseconds(13);
280 header1_.timestamp += 47;
281 receive_statistics_->IncomingPacket(header1_, kPacketSize1, true);
282 header1_.sequenceNumber += 3;
283 clock_.AdvanceTimeMilliseconds(11);
284 header1_.timestamp += 17;
285 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000286
Taylor Brandstetter84916932018-06-25 15:50:26 -0700287 // The stats from the last callback due to IncomingPacket should match
288 // those returned by GetStatistics afterwards.
289 RtcpStatistics stats_from_getstatistics;
290 receive_statistics_->GetStatistician(kSsrc1)->GetStatistics(
291 &stats_from_getstatistics, /*update_fraction_lost=*/false);
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000292
Taylor Brandstetter84916932018-06-25 15:50:26 -0700293 EXPECT_EQ(stats_from_getstatistics.packets_lost,
294 stats_from_callback.packets_lost);
295 EXPECT_EQ(stats_from_getstatistics.extended_highest_sequence_number,
296 stats_from_callback.extended_highest_sequence_number);
297 EXPECT_EQ(stats_from_getstatistics.fraction_lost,
298 stats_from_callback.fraction_lost);
299 EXPECT_EQ(stats_from_getstatistics.jitter, stats_from_callback.jitter);
300
301 // Now update fraction lost, and check that we got matching values from the
302 // new callback.
303 receive_statistics_->GetStatistician(kSsrc1)->GetStatistics(
304 &stats_from_getstatistics, /*update_fraction_lost=*/true);
305 EXPECT_EQ(stats_from_getstatistics.packets_lost,
306 stats_from_callback.packets_lost);
307 EXPECT_EQ(stats_from_getstatistics.extended_highest_sequence_number,
308 stats_from_callback.extended_highest_sequence_number);
309 EXPECT_EQ(stats_from_getstatistics.fraction_lost,
310 stats_from_callback.fraction_lost);
311 EXPECT_EQ(stats_from_getstatistics.jitter, stats_from_callback.jitter);
312}
313
314// Test that |fraction_lost| is only updated when a report is generated (when
315// GetStatistics is called with |update_fraction_lost| set to true). Meaning
316// that it will always represent a value computed between two RTCP SR or RRs.
317TEST_F(ReceiveStatisticsTest, FractionLostOnlyUpdatedWhenReportGenerated) {
318 MockRtcpCallback callback;
319 RtcpStatistics stats_from_callback;
320 EXPECT_CALL(callback, StatisticsUpdated(_, _))
321 .WillRepeatedly(SaveArg<0>(&stats_from_callback));
322 receive_statistics_->RegisterRtcpStatisticsCallback(&callback);
323
324 // Simulate losing one packet.
325 header1_.sequenceNumber = 1;
326 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
327 header1_.sequenceNumber = 2;
328 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
329 header1_.sequenceNumber = 4;
330 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
331 // Haven't generated a report yet, so |fraction_lost| should still be 0.
332 EXPECT_EQ(0u, stats_from_callback.fraction_lost);
333
334 // Call GetStatistics with |update_fraction_lost| set to false; should be a
335 // no-op.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000336 RtcpStatistics statistics;
Taylor Brandstetter84916932018-06-25 15:50:26 -0700337 receive_statistics_->GetStatistician(kSsrc1)->GetStatistics(
338 &statistics, /*update_fraction_lost=*/false);
339 EXPECT_EQ(0u, stats_from_callback.fraction_lost);
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000340
Taylor Brandstetter84916932018-06-25 15:50:26 -0700341 // Call GetStatistics with |update_fraction_lost| set to true, simulating a
342 // report being generated.
343 receive_statistics_->GetStatistician(kSsrc1)->GetStatistics(
344 &statistics, /*update_fraction_lost=*/true);
345 // 25% = 63/255.
346 EXPECT_EQ(63u, stats_from_callback.fraction_lost);
347
348 // Lose another packet.
349 header1_.sequenceNumber = 6;
350 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
351 // Should return same value as before since we haven't generated a new report
352 // yet.
353 EXPECT_EQ(63u, stats_from_callback.fraction_lost);
354
355 // Simulate another report being generated.
356 receive_statistics_->GetStatistician(kSsrc1)->GetStatistics(
357 &statistics, /*update_fraction_lost=*/true);
358 // 50% = 127/255.
359 EXPECT_EQ(127, stats_from_callback.fraction_lost);
360}
361
362// Simple test for fraction/cumulative loss computation, with only loss, no
363// duplicates or reordering.
364TEST_F(ReceiveStatisticsTest, SimpleLossComputation) {
365 header1_.sequenceNumber = 1;
366 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
367 header1_.sequenceNumber = 3;
368 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
369 header1_.sequenceNumber = 4;
370 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
371 header1_.sequenceNumber = 5;
372 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
373
374 RtcpStatistics statistics;
375 receive_statistics_->GetStatistician(kSsrc1)->GetStatistics(
376 &statistics, /*update_fraction_lost=*/true);
377 // 20% = 51/255.
378 EXPECT_EQ(51u, statistics.fraction_lost);
Harald Alvestrandc7c41912017-12-08 09:59:34 +0100379 EXPECT_EQ(1, statistics.packets_lost);
Taylor Brandstetter84916932018-06-25 15:50:26 -0700380}
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000381
Taylor Brandstetter84916932018-06-25 15:50:26 -0700382// Test that fraction/cumulative loss is computed correctly when there's some
383// reordering.
384TEST_F(ReceiveStatisticsTest, LossComputationWithReordering) {
385 header1_.sequenceNumber = 1;
386 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
387 header1_.sequenceNumber = 3;
388 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
389 header1_.sequenceNumber = 2;
390 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
391 header1_.sequenceNumber = 5;
392 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000393
Taylor Brandstetter84916932018-06-25 15:50:26 -0700394 RtcpStatistics statistics;
395 receive_statistics_->GetStatistician(kSsrc1)->GetStatistics(
396 &statistics, /*update_fraction_lost=*/true);
397 // 20% = 51/255.
398 EXPECT_EQ(51u, statistics.fraction_lost);
399}
400
401// Somewhat unintuitively, duplicate packets count against lost packets
402// according to RFC3550.
403TEST_F(ReceiveStatisticsTest, LossComputationWithDuplicates) {
404 // Lose 2 packets, but also receive 1 duplicate. Should actually count as
405 // only 1 packet being lost.
406 header1_.sequenceNumber = 1;
407 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
408 header1_.sequenceNumber = 4;
409 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
410 header1_.sequenceNumber = 4;
411 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
412 header1_.sequenceNumber = 5;
413 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
414
415 RtcpStatistics statistics;
416 receive_statistics_->GetStatistician(kSsrc1)->GetStatistics(
417 &statistics, /*update_fraction_lost=*/true);
418 // 20% = 51/255.
419 EXPECT_EQ(51u, statistics.fraction_lost);
420 EXPECT_EQ(1, statistics.packets_lost);
421}
422
423// Test that sequence numbers wrapping around doesn't screw up loss
424// computations.
425TEST_F(ReceiveStatisticsTest, LossComputationWithSequenceNumberWrapping) {
426 // First, test loss computation over a period that included a sequence number
427 // rollover.
428 header1_.sequenceNumber = 65533;
429 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
430 header1_.sequenceNumber = 0;
431 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
432 header1_.sequenceNumber = 65534;
433 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
434 header1_.sequenceNumber = 1;
435 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
436
437 // Only one packet was actually lost, 65535.
438 RtcpStatistics statistics;
439 receive_statistics_->GetStatistician(kSsrc1)->GetStatistics(
440 &statistics, /*update_fraction_lost=*/true);
441 // 20% = 51/255.
442 EXPECT_EQ(51u, statistics.fraction_lost);
443 EXPECT_EQ(1, statistics.packets_lost);
444
445 // Now test losing one packet *after* the rollover.
446 header1_.sequenceNumber = 3;
447 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
448 receive_statistics_->GetStatistician(kSsrc1)->GetStatistics(
449 &statistics, /*update_fraction_lost=*/true);
450 // 50% = 127/255.
451 EXPECT_EQ(127u, statistics.fraction_lost);
452 EXPECT_EQ(2, statistics.packets_lost);
453}
454
455// Somewhat unintuitively, since duplicate packets count against loss, you can
456// actually end up with negative loss. |fraction_lost| should be clamped to
457// zero in this case, since it's signed, while |packets_lost| is signed so it
458// should be negative.
459TEST_F(ReceiveStatisticsTest, NegativeLoss) {
460 // Receive one packet and simulate a report being generated by calling
461 // GetStatistics, to establish a baseline for |fraction_lost|.
462 header1_.sequenceNumber = 1;
463 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
464 RtcpStatistics statistics;
465 receive_statistics_->GetStatistician(kSsrc1)->GetStatistics(
466 &statistics, /*update_fraction_lost=*/true);
467
468 // Receive some duplicate packets. Results in "negative" loss, since
469 // "expected packets since last report" is 3 and "received" is 4, and 3 minus
470 // 4 is -1. See RFC3550 Appendix A.3.
471 header1_.sequenceNumber = 4;
472 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
473 header1_.sequenceNumber = 2;
474 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
475 header1_.sequenceNumber = 2;
476 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
477 header1_.sequenceNumber = 2;
478 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
479 receive_statistics_->GetStatistician(kSsrc1)->GetStatistics(
480 &statistics, /*update_fraction_lost=*/true);
481 EXPECT_EQ(0u, statistics.fraction_lost);
482 EXPECT_EQ(-1, statistics.packets_lost);
483
484 // Lose 2 packets; now cumulative loss should become positive again.
485 header1_.sequenceNumber = 7;
486 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
487 receive_statistics_->GetStatistician(kSsrc1)->GetStatistics(
488 &statistics, /*update_fraction_lost=*/true);
489 // 66% = 170/255.
490 EXPECT_EQ(170u, statistics.fraction_lost);
491 EXPECT_EQ(1, statistics.packets_lost);
492}
493
494// Since cumulative loss is carried in a signed 24-bit field, it should be
495// clamped to 0x7fffff in the positive direction, 0x800000 in the negative
496// direction.
497TEST_F(ReceiveStatisticsTest, PositiveCumulativeLossClamped) {
498 header1_.sequenceNumber = 1;
499 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
500
501 // Lose 2^23 packets, expecting loss to be clamped to 2^23-1.
502 for (int i = 0; i < 0x800000; ++i) {
503 header1_.sequenceNumber = (header1_.sequenceNumber + 2 % 65536);
504 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
505 }
506 RtcpStatistics statistics;
507 receive_statistics_->GetStatistician(kSsrc1)->GetStatistics(
508 &statistics, /*update_fraction_lost=*/false);
509 EXPECT_EQ(0x7fffff, statistics.packets_lost);
510}
511
512TEST_F(ReceiveStatisticsTest, NegativeCumulativeLossClamped) {
513 header1_.sequenceNumber = 1;
514 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
515
516 // Receive 2^23+1 duplicate packets (counted as negative loss), expecting
517 // loss to be clamped to -2^23.
518 for (int i = 0; i < 0x800001; ++i) {
519 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
520 }
521 RtcpStatistics statistics;
522 receive_statistics_->GetStatistician(kSsrc1)->GetStatistics(
523 &statistics, /*update_fraction_lost=*/false);
524 EXPECT_EQ(-0x800000, statistics.packets_lost);
525}
526
527// Test that the extended highest sequence number is computed correctly when
528// sequence numbers wrap around or packets are received out of order.
529TEST_F(ReceiveStatisticsTest, ExtendedHighestSequenceNumberComputation) {
530 MockRtcpCallback callback;
531 RtcpStatistics stats_from_callback;
532 EXPECT_CALL(callback, StatisticsUpdated(_, _))
533 .WillRepeatedly(SaveArg<0>(&stats_from_callback));
534 receive_statistics_->RegisterRtcpStatisticsCallback(&callback);
535
536 header1_.sequenceNumber = 65535;
537 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
538 EXPECT_EQ(65535u, stats_from_callback.extended_highest_sequence_number);
539
540 // Wrap around.
541 header1_.sequenceNumber = 1;
542 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
543 EXPECT_EQ(65536u + 1u, stats_from_callback.extended_highest_sequence_number);
544
545 // Should be treated as out of order; shouldn't increment highest extended
546 // sequence number.
547 header1_.sequenceNumber = 65530;
548 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
549 EXPECT_EQ(65536u + 1u, stats_from_callback.extended_highest_sequence_number);
550
551 // Receive a couple packets then wrap around again.
552 // TODO(bugs.webrtc.org/9445): With large jumps like this, RFC3550 suggests
553 // for the receiver to assume the other side restarted, and reset all its
554 // sequence number counters. Why aren't we doing this?
555 header1_.sequenceNumber = 30000;
556 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
557 EXPECT_EQ(65536u + 30000u,
558 stats_from_callback.extended_highest_sequence_number);
559
560 header1_.sequenceNumber = 50000;
561 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
562 EXPECT_EQ(65536u + 50000u,
563 stats_from_callback.extended_highest_sequence_number);
564
565 header1_.sequenceNumber = 10000;
566 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
567 EXPECT_EQ(2 * 65536u + 10000u,
568 stats_from_callback.extended_highest_sequence_number);
569
570 // If a packet is received more than "MaxReorderingThreshold" packets out of
571 // order (defaults to 50), it's assumed to be in order.
572 // TODO(bugs.webrtc.org/9445): RFC3550 would recommend treating this as a
573 // restart as mentioned above.
574 header1_.sequenceNumber = 9900;
575 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
576 EXPECT_EQ(3 * 65536u + 9900u,
577 stats_from_callback.extended_highest_sequence_number);
578}
579
580// Test jitter computation with no loss/reordering/etc.
581TEST_F(ReceiveStatisticsTest, SimpleJitterComputation) {
582 MockRtcpCallback callback;
583 RtcpStatistics stats_from_callback;
584 EXPECT_CALL(callback, StatisticsUpdated(_, _))
585 .WillRepeatedly(SaveArg<0>(&stats_from_callback));
586 receive_statistics_->RegisterRtcpStatisticsCallback(&callback);
587
588 // Using units of milliseconds.
589 header1_.payload_type_frequency = 1000;
590
591 // Regardless of initial timestamps, jitter should start at 0.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000592 header1_.sequenceNumber = 1;
593 clock_.AdvanceTimeMilliseconds(7);
594 header1_.timestamp += 3;
595 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
Taylor Brandstetter84916932018-06-25 15:50:26 -0700596 EXPECT_EQ(0u, stats_from_callback.jitter);
597
598 // Incrementing timestamps by the same amount shouldn't increase jitter.
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000599 ++header1_.sequenceNumber;
Taylor Brandstetter84916932018-06-25 15:50:26 -0700600 clock_.AdvanceTimeMilliseconds(50);
601 header1_.timestamp += 50;
602 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
603 EXPECT_EQ(0u, stats_from_callback.jitter);
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000604
Taylor Brandstetter84916932018-06-25 15:50:26 -0700605 // Difference of 16ms, divided by 16 yields exactly 1.
606 ++header1_.sequenceNumber;
607 clock_.AdvanceTimeMilliseconds(32);
608 header1_.timestamp += 16;
609 receive_statistics_->IncomingPacket(header1_, kPacketSize1, true);
610 EXPECT_EQ(1u, stats_from_callback.jitter);
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000611
Taylor Brandstetter84916932018-06-25 15:50:26 -0700612 // (90 + 1 * 15) / 16 = 6.5625; should round down to 6.
613 // TODO(deadbeef): Why don't we round to the nearest integer?
614 ++header1_.sequenceNumber;
615 clock_.AdvanceTimeMilliseconds(10);
616 header1_.timestamp += 100;
617 receive_statistics_->IncomingPacket(header1_, kPacketSize1, true);
618 EXPECT_EQ(6u, stats_from_callback.jitter);
619
620 // (30 + 6.5625 * 15) / 16 = 8.0273; should round down to 8.
621 ++header1_.sequenceNumber;
622 clock_.AdvanceTimeMilliseconds(50);
623 header1_.timestamp += 20;
624 receive_statistics_->IncomingPacket(header1_, kPacketSize1, true);
625 EXPECT_EQ(8u, stats_from_callback.jitter);
626}
627
628// TODO(deadbeef): Why do we do this? It goes against RFC3550, which explicitly
629// says the calculation should be based on order of arrival and packets may not
630// necessarily arrive in sequence.
631TEST_F(ReceiveStatisticsTest, JitterComputationIgnoresReorderedPackets) {
632 MockRtcpCallback callback;
633 RtcpStatistics stats_from_callback;
634 EXPECT_CALL(callback, StatisticsUpdated(_, _))
635 .WillRepeatedly(SaveArg<0>(&stats_from_callback));
636 receive_statistics_->RegisterRtcpStatisticsCallback(&callback);
637
638 // Using units of milliseconds.
639 header1_.payload_type_frequency = 1000;
640
641 // Regardless of initial timestamps, jitter should start at 0.
642 header1_.sequenceNumber = 1;
643 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
644 EXPECT_EQ(0u, stats_from_callback.jitter);
645
646 // This should be ignored, even though there's a difference of 70 here.
647 header1_.sequenceNumber = 0;
648 clock_.AdvanceTimeMilliseconds(50);
649 header1_.timestamp -= 20;
650 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
651 EXPECT_EQ(0u, stats_from_callback.jitter);
652
653 // Relative to the first packet there's a difference of 181ms in arrival
654 // time, 20ms in timestamp, so jitter should be 161/16 = 10.
655 header1_.sequenceNumber = 2;
656 clock_.AdvanceTimeMilliseconds(131);
657 header1_.timestamp += 40;
658 receive_statistics_->IncomingPacket(header1_, kPacketSize1, false);
659 EXPECT_EQ(10u, stats_from_callback.jitter);
sprang@webrtc.org54ae4ff2013-12-19 13:26:02 +0000660}
sprang@webrtc.org0e932572014-01-23 10:00:39 +0000661
sprang@webrtc.orgc30e9e22014-09-08 08:20:18 +0000662class RtpTestCallback : public StreamDataCountersCallback {
663 public:
664 RtpTestCallback()
665 : StreamDataCountersCallback(), num_calls_(0), ssrc_(0), stats_() {}
Danil Chapovalovdd7e2842018-03-09 15:37:03 +0000666 ~RtpTestCallback() override = default;
sprang@webrtc.orgc30e9e22014-09-08 08:20:18 +0000667
Danil Chapovalovdd7e2842018-03-09 15:37:03 +0000668 void DataCountersUpdated(const StreamDataCounters& counters,
669 uint32_t ssrc) override {
sprang@webrtc.orgc30e9e22014-09-08 08:20:18 +0000670 ssrc_ = ssrc;
671 stats_ = counters;
672 ++num_calls_;
673 }
674
asapersson@webrtc.org44149392015-02-04 08:34:47 +0000675 void MatchPacketCounter(const RtpPacketCounter& expected,
676 const RtpPacketCounter& actual) {
677 EXPECT_EQ(expected.payload_bytes, actual.payload_bytes);
678 EXPECT_EQ(expected.header_bytes, actual.header_bytes);
679 EXPECT_EQ(expected.padding_bytes, actual.padding_bytes);
680 EXPECT_EQ(expected.packets, actual.packets);
681 }
682
asapersson@webrtc.org97d04892014-12-09 09:47:53 +0000683 void Matches(uint32_t num_calls,
684 uint32_t ssrc,
685 const StreamDataCounters& expected) {
sprang@webrtc.orgc30e9e22014-09-08 08:20:18 +0000686 EXPECT_EQ(num_calls, num_calls_);
687 EXPECT_EQ(ssrc, ssrc_);
asapersson@webrtc.org44149392015-02-04 08:34:47 +0000688 MatchPacketCounter(expected.transmitted, stats_.transmitted);
689 MatchPacketCounter(expected.retransmitted, stats_.retransmitted);
690 MatchPacketCounter(expected.fec, stats_.fec);
sprang@webrtc.orgc30e9e22014-09-08 08:20:18 +0000691 }
692
693 uint32_t num_calls_;
694 uint32_t ssrc_;
695 StreamDataCounters stats_;
696};
697
sprang@webrtc.org0e932572014-01-23 10:00:39 +0000698TEST_F(ReceiveStatisticsTest, RtpCallbacks) {
sprang@webrtc.orgc30e9e22014-09-08 08:20:18 +0000699 RtpTestCallback callback;
sprang@webrtc.org0e932572014-01-23 10:00:39 +0000700 receive_statistics_->RegisterRtpStatisticsCallback(&callback);
701
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000702 const size_t kHeaderLength = 20;
703 const size_t kPaddingLength = 9;
sprang@webrtc.org0e932572014-01-23 10:00:39 +0000704
705 // One packet of size kPacketSize1.
706 header1_.headerLength = kHeaderLength;
Yves Gerey665174f2018-06-19 15:03:05 +0200707 receive_statistics_->IncomingPacket(header1_, kPacketSize1 + kHeaderLength,
708 false);
asapersson@webrtc.org97d04892014-12-09 09:47:53 +0000709 StreamDataCounters expected;
asapersson@webrtc.orgcfd82df2015-01-22 09:39:59 +0000710 expected.transmitted.payload_bytes = kPacketSize1;
711 expected.transmitted.header_bytes = kHeaderLength;
712 expected.transmitted.padding_bytes = 0;
713 expected.transmitted.packets = 1;
714 expected.retransmitted.payload_bytes = 0;
715 expected.retransmitted.header_bytes = 0;
716 expected.retransmitted.padding_bytes = 0;
717 expected.retransmitted.packets = 0;
718 expected.fec.packets = 0;
asapersson@webrtc.org97d04892014-12-09 09:47:53 +0000719 callback.Matches(1, kSsrc1, expected);
sprang@webrtc.org0e932572014-01-23 10:00:39 +0000720
721 ++header1_.sequenceNumber;
722 clock_.AdvanceTimeMilliseconds(5);
723 header1_.paddingLength = 9;
724 // Another packet of size kPacketSize1 with 9 bytes padding.
725 receive_statistics_->IncomingPacket(
726 header1_, kPacketSize1 + kHeaderLength + kPaddingLength, false);
asapersson@webrtc.orgcfd82df2015-01-22 09:39:59 +0000727 expected.transmitted.payload_bytes = kPacketSize1 * 2;
728 expected.transmitted.header_bytes = kHeaderLength * 2;
729 expected.transmitted.padding_bytes = kPaddingLength;
730 expected.transmitted.packets = 2;
asapersson@webrtc.org97d04892014-12-09 09:47:53 +0000731 callback.Matches(2, kSsrc1, expected);
sprang@webrtc.org0e932572014-01-23 10:00:39 +0000732
733 clock_.AdvanceTimeMilliseconds(5);
734 // Retransmit last packet.
735 receive_statistics_->IncomingPacket(
736 header1_, kPacketSize1 + kHeaderLength + kPaddingLength, true);
asapersson@webrtc.orgcfd82df2015-01-22 09:39:59 +0000737 expected.transmitted.payload_bytes = kPacketSize1 * 3;
738 expected.transmitted.header_bytes = kHeaderLength * 3;
739 expected.transmitted.padding_bytes = kPaddingLength * 2;
740 expected.transmitted.packets = 3;
741 expected.retransmitted.payload_bytes = kPacketSize1;
742 expected.retransmitted.header_bytes = kHeaderLength;
743 expected.retransmitted.padding_bytes = kPaddingLength;
744 expected.retransmitted.packets = 1;
asapersson@webrtc.org97d04892014-12-09 09:47:53 +0000745 callback.Matches(3, kSsrc1, expected);
sprang@webrtc.org0e932572014-01-23 10:00:39 +0000746
747 header1_.paddingLength = 0;
748 ++header1_.sequenceNumber;
749 clock_.AdvanceTimeMilliseconds(5);
asapersson@webrtc.org273fbbb2015-01-27 12:17:29 +0000750 // One FEC packet.
Yves Gerey665174f2018-06-19 15:03:05 +0200751 receive_statistics_->IncomingPacket(header1_, kPacketSize1 + kHeaderLength,
752 false);
asapersson@webrtc.org273fbbb2015-01-27 12:17:29 +0000753 receive_statistics_->FecPacketReceived(header1_,
754 kPacketSize1 + kHeaderLength);
asapersson@webrtc.orgcfd82df2015-01-22 09:39:59 +0000755 expected.transmitted.payload_bytes = kPacketSize1 * 4;
756 expected.transmitted.header_bytes = kHeaderLength * 4;
757 expected.transmitted.packets = 4;
asapersson@webrtc.org273fbbb2015-01-27 12:17:29 +0000758 expected.fec.payload_bytes = kPacketSize1;
759 expected.fec.header_bytes = kHeaderLength;
asapersson@webrtc.orgcfd82df2015-01-22 09:39:59 +0000760 expected.fec.packets = 1;
asapersson@webrtc.org97d04892014-12-09 09:47:53 +0000761 callback.Matches(5, kSsrc1, expected);
sprang@webrtc.org0e932572014-01-23 10:00:39 +0000762
763 receive_statistics_->RegisterRtpStatisticsCallback(NULL);
764
765 // New stats, but callback should not be called.
766 ++header1_.sequenceNumber;
767 clock_.AdvanceTimeMilliseconds(5);
Yves Gerey665174f2018-06-19 15:03:05 +0200768 receive_statistics_->IncomingPacket(header1_, kPacketSize1 + kHeaderLength,
769 true);
asapersson@webrtc.org97d04892014-12-09 09:47:53 +0000770 callback.Matches(5, kSsrc1, expected);
sprang@webrtc.org0e932572014-01-23 10:00:39 +0000771}
sprang@webrtc.orgc30e9e22014-09-08 08:20:18 +0000772
773TEST_F(ReceiveStatisticsTest, RtpCallbacksFecFirst) {
774 RtpTestCallback callback;
775 receive_statistics_->RegisterRtpStatisticsCallback(&callback);
776
777 const uint32_t kHeaderLength = 20;
asapersson@webrtc.org273fbbb2015-01-27 12:17:29 +0000778 header1_.headerLength = kHeaderLength;
sprang@webrtc.orgc30e9e22014-09-08 08:20:18 +0000779
780 // If first packet is FEC, ignore it.
asapersson@webrtc.org273fbbb2015-01-27 12:17:29 +0000781 receive_statistics_->FecPacketReceived(header1_,
782 kPacketSize1 + kHeaderLength);
sprang@webrtc.orgc30e9e22014-09-08 08:20:18 +0000783 EXPECT_EQ(0u, callback.num_calls_);
784
Yves Gerey665174f2018-06-19 15:03:05 +0200785 receive_statistics_->IncomingPacket(header1_, kPacketSize1 + kHeaderLength,
786 false);
asapersson@webrtc.org97d04892014-12-09 09:47:53 +0000787 StreamDataCounters expected;
asapersson@webrtc.orgcfd82df2015-01-22 09:39:59 +0000788 expected.transmitted.payload_bytes = kPacketSize1;
789 expected.transmitted.header_bytes = kHeaderLength;
790 expected.transmitted.padding_bytes = 0;
791 expected.transmitted.packets = 1;
792 expected.fec.packets = 0;
asapersson@webrtc.org97d04892014-12-09 09:47:53 +0000793 callback.Matches(1, kSsrc1, expected);
sprang@webrtc.orgc30e9e22014-09-08 08:20:18 +0000794
asapersson@webrtc.org273fbbb2015-01-27 12:17:29 +0000795 receive_statistics_->FecPacketReceived(header1_,
796 kPacketSize1 + kHeaderLength);
797 expected.fec.payload_bytes = kPacketSize1;
798 expected.fec.header_bytes = kHeaderLength;
asapersson@webrtc.orgcfd82df2015-01-22 09:39:59 +0000799 expected.fec.packets = 1;
asapersson@webrtc.org97d04892014-12-09 09:47:53 +0000800 callback.Matches(2, kSsrc1, expected);
sprang@webrtc.orgc30e9e22014-09-08 08:20:18 +0000801}
Danil Chapovalovd1996b72018-01-16 11:07:18 +0100802
803} // namespace
stefan@webrtc.org286fe0b2013-08-21 20:58:21 +0000804} // namespace webrtc