Add statistics gathering for packet loss.
Adds a class used to classify whether packet loss events are a single packet or multiple packets as well as how many packets have been lost. Also exposes a new function in the RtpRtcp interface to retrieve these statistics.
BUG=
Review URL: https://codereview.webrtc.org/1198853004
Cr-Commit-Position: refs/heads/master@{#9568}
diff --git a/webrtc/modules/modules.gyp b/webrtc/modules/modules.gyp
index af4c97b..7f3a1e8 100644
--- a/webrtc/modules/modules.gyp
+++ b/webrtc/modules/modules.gyp
@@ -230,6 +230,7 @@
'rtp_rtcp/source/fec_test_helper.h',
'rtp_rtcp/source/h264_sps_parser_unittest.cc',
'rtp_rtcp/source/nack_rtx_unittest.cc',
+ 'rtp_rtcp/source/packet_loss_stats_unittest.cc',
'rtp_rtcp/source/producer_fec_unittest.cc',
'rtp_rtcp/source/receive_statistics_unittest.cc',
'rtp_rtcp/source/remote_ntp_time_estimator_unittest.cc',
diff --git a/webrtc/modules/rtp_rtcp/BUILD.gn b/webrtc/modules/rtp_rtcp/BUILD.gn
index 0eda287..ca4b812 100644
--- a/webrtc/modules/rtp_rtcp/BUILD.gn
+++ b/webrtc/modules/rtp_rtcp/BUILD.gn
@@ -35,6 +35,8 @@
"source/h264_sps_parser.cc",
"source/h264_sps_parser.h",
"source/mock/mock_rtp_payload_strategy.h",
+ "source/packet_loss_stats.cc",
+ "source/packet_loss_stats.h",
"source/producer_fec.cc",
"source/producer_fec.h",
"source/receive_statistics_impl.cc",
diff --git a/webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h b/webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h
index 98f7c26..7a96088 100644
--- a/webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h
+++ b/webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h
@@ -431,6 +431,14 @@
StreamDataCounters* rtx_counters) const = 0;
/*
+ * Get packet loss statistics for the RTP stream.
+ */
+ virtual void GetRtpPacketLossStats(
+ bool outgoing,
+ uint32_t ssrc,
+ struct RtpPacketLossStats* loss_stats) const = 0;
+
+ /*
* Get received RTCP sender info
*
* return -1 on failure else 0
diff --git a/webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h b/webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h
index ed7dfe0..ea36687 100644
--- a/webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h
+++ b/webrtc/modules/rtp_rtcp/interface/rtp_rtcp_defines.h
@@ -350,5 +350,18 @@
const uint8_t volume) override {}
};
+// Statistics about packet loss for a single directional connection. All values
+// are totals since the connection initiated.
+struct RtpPacketLossStats {
+ // The number of packets lost in events where no adjacent packets were also
+ // lost.
+ uint64_t single_packet_loss_count;
+ // The number of events in which more than one adjacent packet was lost.
+ uint64_t multiple_packet_loss_event_count;
+ // The number of packets lost in events where more than one adjacent packet
+ // was lost.
+ uint64_t multiple_packet_loss_packet_count;
+};
+
} // namespace webrtc
#endif // WEBRTC_MODULES_RTP_RTCP_INTERFACE_RTP_RTCP_DEFINES_H_
diff --git a/webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h b/webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
index 99e5b1c..127a795 100644
--- a/webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
+++ b/webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h
@@ -165,6 +165,8 @@
int32_t(size_t *bytesSent, uint32_t *packetsSent));
MOCK_CONST_METHOD2(GetSendStreamDataCounters,
void(StreamDataCounters*, StreamDataCounters*));
+ MOCK_CONST_METHOD3(GetRtpPacketLossStats,
+ void(bool, uint32_t, struct RtpPacketLossStats*));
MOCK_METHOD1(RemoteRTCPStat,
int32_t(RTCPSenderInfo* senderInfo));
MOCK_CONST_METHOD1(RemoteRTCPStat,
diff --git a/webrtc/modules/rtp_rtcp/rtp_rtcp.gypi b/webrtc/modules/rtp_rtcp/rtp_rtcp.gypi
index e73b43a..dcd47df 100644
--- a/webrtc/modules/rtp_rtcp/rtp_rtcp.gypi
+++ b/webrtc/modules/rtp_rtcp/rtp_rtcp.gypi
@@ -31,6 +31,8 @@
'source/byte_io.h',
'source/fec_receiver_impl.cc',
'source/fec_receiver_impl.h',
+ 'source/packet_loss_stats.cc',
+ 'source/packet_loss_stats.h',
'source/receive_statistics_impl.cc',
'source/receive_statistics_impl.h',
'source/remote_ntp_time_estimator.cc',
diff --git a/webrtc/modules/rtp_rtcp/source/packet_loss_stats.cc b/webrtc/modules/rtp_rtcp/source/packet_loss_stats.cc
new file mode 100644
index 0000000..4ab3864
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/packet_loss_stats.cc
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/modules/rtp_rtcp/source/packet_loss_stats.h"
+
+#include <vector>
+
+#include "webrtc/base/checks.h"
+
+// After this many packets are added, adding additional packets will cause the
+// oldest packets to be pruned from the buffer.
+static const int kBufferSize = 100;
+
+namespace webrtc {
+
+PacketLossStats::PacketLossStats()
+ : single_loss_historic_count_(0),
+ multiple_loss_historic_event_count_(0),
+ multiple_loss_historic_packet_count_(0) {
+}
+
+void PacketLossStats::AddLostPacket(uint16_t sequence_number) {
+ // Detect sequence number wrap around.
+ if (!lost_packets_buffer_.empty() &&
+ static_cast<int>(*(lost_packets_buffer_.rbegin())) - sequence_number
+ > 0x8000) {
+ // The buffer contains large numbers and this is a small number.
+ lost_packets_wrapped_buffer_.insert(sequence_number);
+ } else {
+ lost_packets_buffer_.insert(sequence_number);
+ }
+ if (lost_packets_wrapped_buffer_.size() + lost_packets_buffer_.size()
+ > kBufferSize || (!lost_packets_wrapped_buffer_.empty() &&
+ *(lost_packets_wrapped_buffer_.rbegin()) > 0x4000)) {
+ PruneBuffer();
+ }
+}
+
+int PacketLossStats::GetSingleLossCount() const {
+ int single_loss_count, unused1, unused2;
+ ComputeLossCounts(&single_loss_count, &unused1, &unused2);
+ return single_loss_count;
+}
+
+int PacketLossStats::GetMultipleLossEventCount() const {
+ int event_count, unused1, unused2;
+ ComputeLossCounts(&unused1, &event_count, &unused2);
+ return event_count;
+}
+
+int PacketLossStats::GetMultipleLossPacketCount() const {
+ int packet_count, unused1, unused2;
+ ComputeLossCounts(&unused1, &unused2, &packet_count);
+ return packet_count;
+}
+
+void PacketLossStats::ComputeLossCounts(
+ int* out_single_loss_count,
+ int* out_multiple_loss_event_count,
+ int* out_multiple_loss_packet_count) const {
+ *out_single_loss_count = single_loss_historic_count_;
+ *out_multiple_loss_event_count = multiple_loss_historic_event_count_;
+ *out_multiple_loss_packet_count = multiple_loss_historic_packet_count_;
+ if (lost_packets_buffer_.empty()) {
+ DCHECK(lost_packets_wrapped_buffer_.empty());
+ return;
+ }
+ uint16_t last_num = 0;
+ int sequential_count = 0;
+ std::vector<const std::set<uint16_t>*> buffers;
+ buffers.push_back(&lost_packets_buffer_);
+ buffers.push_back(&lost_packets_wrapped_buffer_);
+ for (auto buffer : buffers) {
+ for (auto it = buffer->begin(); it != buffer->end(); ++it) {
+ uint16_t current_num = *it;
+ if (sequential_count > 0 && current_num != ((last_num + 1) & 0xFFFF)) {
+ if (sequential_count == 1) {
+ (*out_single_loss_count)++;
+ } else {
+ (*out_multiple_loss_event_count)++;
+ *out_multiple_loss_packet_count += sequential_count;
+ }
+ sequential_count = 0;
+ }
+ sequential_count++;
+ last_num = current_num;
+ }
+ }
+ if (sequential_count == 1) {
+ (*out_single_loss_count)++;
+ } else if (sequential_count > 1) {
+ (*out_multiple_loss_event_count)++;
+ *out_multiple_loss_packet_count += sequential_count;
+ }
+}
+
+void PacketLossStats::PruneBuffer() {
+ // Remove the oldest lost packet and any contiguous packets and move them
+ // into the historic counts.
+ auto it = lost_packets_buffer_.begin();
+ uint16_t last_removed = 0;
+ int remove_count = 0;
+ // Count adjacent packets and continue counting if it is wrap around by
+ // swapping in the wrapped buffer and letting our value wrap as well.
+ while (remove_count == 0 || (!lost_packets_buffer_.empty() &&
+ *it == ((last_removed + 1) & 0xFFFF))) {
+ last_removed = *it;
+ remove_count++;
+ auto to_erase = it++;
+ lost_packets_buffer_.erase(to_erase);
+ if (lost_packets_buffer_.empty()) {
+ lost_packets_buffer_.swap(lost_packets_wrapped_buffer_);
+ it = lost_packets_buffer_.begin();
+ }
+ }
+ if (remove_count > 1) {
+ multiple_loss_historic_event_count_++;
+ multiple_loss_historic_packet_count_ += remove_count;
+ } else {
+ single_loss_historic_count_++;
+ }
+ // Continue pruning if the wrapped buffer is beyond a threshold and there are
+ // things left in the pre-wrapped buffer.
+ if (!lost_packets_wrapped_buffer_.empty() &&
+ *(lost_packets_wrapped_buffer_.rbegin()) > 0x4000) {
+ PruneBuffer();
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/packet_loss_stats.h b/webrtc/modules/rtp_rtcp/source/packet_loss_stats.h
new file mode 100644
index 0000000..2eab043
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/packet_loss_stats.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_RTP_RTCP_SOURCE_PACKET_LOSS_STATS_H_
+#define WEBRTC_MODULES_RTP_RTCP_SOURCE_PACKET_LOSS_STATS_H_
+
+#include <stdint.h>
+#include <set>
+
+namespace webrtc {
+
+// Keeps track of statistics of packet loss including whether losses are a
+// single packet or multiple packets in a row.
+class PacketLossStats {
+ public:
+ PacketLossStats();
+ ~PacketLossStats() {}
+
+ // Adds a lost packet to the stats by sequence number.
+ void AddLostPacket(uint16_t sequence_number);
+
+ // Queries the number of packets that were lost by themselves, no neighboring
+ // packets were lost.
+ int GetSingleLossCount() const;
+
+ // Queries the number of times that multiple packets with sequential numbers
+ // were lost. This is the number of events with more than one packet lost,
+ // regardless of the size of the event;
+ int GetMultipleLossEventCount() const;
+
+ // Queries the number of packets lost in multiple packet loss events. Combined
+ // with the event count, this can be used to determine the average event size.
+ int GetMultipleLossPacketCount() const;
+
+ private:
+ std::set<uint16_t> lost_packets_buffer_;
+ std::set<uint16_t> lost_packets_wrapped_buffer_;
+ int single_loss_historic_count_;
+ int multiple_loss_historic_event_count_;
+ int multiple_loss_historic_packet_count_;
+
+ void ComputeLossCounts(int* out_single_loss_count,
+ int* out_multiple_loss_event_count,
+ int* out_multiple_loss_packet_count) const;
+ void PruneBuffer();
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_RTP_RTCP_SOURCE_PACKET_LOSS_STATS_H_
diff --git a/webrtc/modules/rtp_rtcp/source/packet_loss_stats_unittest.cc b/webrtc/modules/rtp_rtcp/source/packet_loss_stats_unittest.cc
new file mode 100644
index 0000000..6606282
--- /dev/null
+++ b/webrtc/modules/rtp_rtcp/source/packet_loss_stats_unittest.cc
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/modules/rtp_rtcp/source/packet_loss_stats.h"
+
+namespace webrtc {
+
+class PacketLossStatsTest : public ::testing::Test {
+ protected:
+ PacketLossStats stats_;
+};
+
+// Add a lost packet as every other packet, they should all count as single
+// losses.
+TEST_F(PacketLossStatsTest, EveryOtherPacket) {
+ for (int i = 0; i < 1000; i += 2) {
+ stats_.AddLostPacket(i);
+ }
+ EXPECT_EQ(500, stats_.GetSingleLossCount());
+ EXPECT_EQ(0, stats_.GetMultipleLossEventCount());
+ EXPECT_EQ(0, stats_.GetMultipleLossPacketCount());
+}
+
+// Add a lost packet as every other packet, but such that the sequence numbers
+// will wrap around while they are being added.
+TEST_F(PacketLossStatsTest, EveryOtherPacketWrapped) {
+ for (int i = 65500; i < 66500; i += 2) {
+ stats_.AddLostPacket(i & 0xFFFF);
+ }
+ EXPECT_EQ(500, stats_.GetSingleLossCount());
+ EXPECT_EQ(0, stats_.GetMultipleLossEventCount());
+ EXPECT_EQ(0, stats_.GetMultipleLossPacketCount());
+}
+
+// Add a lost packet as every other packet, but such that the sequence numbers
+// will wrap around close to the very end, such that the buffer contains packets
+// on either side of the wrapping.
+TEST_F(PacketLossStatsTest, EveryOtherPacketWrappedAtEnd) {
+ for (int i = 64600; i < 65600; i += 2) {
+ stats_.AddLostPacket(i & 0xFFFF);
+ }
+ EXPECT_EQ(500, stats_.GetSingleLossCount());
+ EXPECT_EQ(0, stats_.GetMultipleLossEventCount());
+ EXPECT_EQ(0, stats_.GetMultipleLossPacketCount());
+}
+
+// Add a lost packet as the first three of every eight packets. Each set of
+// three should count as a multiple loss event and three multiple loss packets.
+TEST_F(PacketLossStatsTest, FirstThreeOfEight) {
+ for (int i = 0; i < 1000; ++i) {
+ if ((i & 7) < 3) {
+ stats_.AddLostPacket(i);
+ }
+ }
+ EXPECT_EQ(0, stats_.GetSingleLossCount());
+ EXPECT_EQ(125, stats_.GetMultipleLossEventCount());
+ EXPECT_EQ(375, stats_.GetMultipleLossPacketCount());
+}
+
+// Add a lost packet as the first three of every eight packets such that the
+// sequence numbers wrap in the middle of adding them.
+TEST_F(PacketLossStatsTest, FirstThreeOfEightWrapped) {
+ for (int i = 65500; i < 66500; ++i) {
+ if ((i & 7) < 3) {
+ stats_.AddLostPacket(i & 0xFFFF);
+ }
+ }
+ EXPECT_EQ(0, stats_.GetSingleLossCount());
+ EXPECT_EQ(125, stats_.GetMultipleLossEventCount());
+ EXPECT_EQ(375, stats_.GetMultipleLossPacketCount());
+}
+
+// Add a lost packet as the first three of every eight packets such that the
+// sequence numbers wrap near the end of adding them and there are still numbers
+// in the buffer from before the wrapping.
+TEST_F(PacketLossStatsTest, FirstThreeOfEightWrappedAtEnd) {
+ for (int i = 64600; i < 65600; ++i) {
+ if ((i & 7) < 3) {
+ stats_.AddLostPacket(i & 0xFFFF);
+ }
+ }
+ EXPECT_EQ(0, stats_.GetSingleLossCount());
+ EXPECT_EQ(125, stats_.GetMultipleLossEventCount());
+ EXPECT_EQ(375, stats_.GetMultipleLossPacketCount());
+}
+
+// Add loss packets as the first three and the fifth of every eight packets. The
+// set of three should be multiple loss and the fifth should be single loss.
+TEST_F(PacketLossStatsTest, FirstThreeAndFifthOfEight) {
+ for (int i = 0; i < 1000; ++i) {
+ if ((i & 7) < 3 || (i & 7) == 4) {
+ stats_.AddLostPacket(i);
+ }
+ }
+ EXPECT_EQ(125, stats_.GetSingleLossCount());
+ EXPECT_EQ(125, stats_.GetMultipleLossEventCount());
+ EXPECT_EQ(375, stats_.GetMultipleLossPacketCount());
+}
+
+// Add loss packets as the first three and the fifth of every eight packets such
+// that the sequence numbers wrap in the middle of adding them.
+TEST_F(PacketLossStatsTest, FirstThreeAndFifthOfEightWrapped) {
+ for (int i = 65500; i < 66500; ++i) {
+ if ((i & 7) < 3 || (i & 7) == 4) {
+ stats_.AddLostPacket(i & 0xFFFF);
+ }
+ }
+ EXPECT_EQ(125, stats_.GetSingleLossCount());
+ EXPECT_EQ(125, stats_.GetMultipleLossEventCount());
+ EXPECT_EQ(375, stats_.GetMultipleLossPacketCount());
+}
+
+// Add loss packets as the first three and the fifth of every eight packets such
+// that the sequence numbers wrap near the end of adding them and there are
+// packets from before the wrapping still in the buffer.
+TEST_F(PacketLossStatsTest, FirstThreeAndFifthOfEightWrappedAtEnd) {
+ for (int i = 64600; i < 65600; ++i) {
+ if ((i & 7) < 3 || (i & 7) == 4) {
+ stats_.AddLostPacket(i & 0xFFFF);
+ }
+ }
+ EXPECT_EQ(125, stats_.GetSingleLossCount());
+ EXPECT_EQ(125, stats_.GetMultipleLossEventCount());
+ EXPECT_EQ(375, stats_.GetMultipleLossPacketCount());
+}
+
+// Add loss packets such that there is a multiple loss event that continues
+// around the wrapping of sequence numbers.
+TEST_F(PacketLossStatsTest, MultipleLossEventWrapped) {
+ for (int i = 60000; i < 60500; i += 2) {
+ stats_.AddLostPacket(i);
+ }
+ for (int i = 65530; i < 65540; ++i) {
+ stats_.AddLostPacket(i & 0xFFFF);
+ }
+ EXPECT_EQ(250, stats_.GetSingleLossCount());
+ EXPECT_EQ(1, stats_.GetMultipleLossEventCount());
+ EXPECT_EQ(10, stats_.GetMultipleLossPacketCount());
+}
+
+// Add loss packets such that there is a multiple loss event that continues
+// around the wrapping of sequence numbers and then is pushed out of the buffer.
+TEST_F(PacketLossStatsTest, MultipleLossEventWrappedPushedOut) {
+ for (int i = 60000; i < 60500; i += 2) {
+ stats_.AddLostPacket(i);
+ }
+ for (int i = 65530; i < 65540; ++i) {
+ stats_.AddLostPacket(i & 0xFFFF);
+ }
+ for (int i = 1000; i < 1500; i += 2) {
+ stats_.AddLostPacket(i);
+ }
+ EXPECT_EQ(500, stats_.GetSingleLossCount());
+ EXPECT_EQ(1, stats_.GetMultipleLossEventCount());
+ EXPECT_EQ(10, stats_.GetMultipleLossPacketCount());
+}
+
+// Add loss packets out of order and ensure that they still get counted
+// correctly as single or multiple loss events.
+TEST_F(PacketLossStatsTest, OutOfOrder) {
+ for (int i = 0; i < 1000; i += 10) {
+ stats_.AddLostPacket(i + 5);
+ stats_.AddLostPacket(i + 7);
+ stats_.AddLostPacket(i + 4);
+ stats_.AddLostPacket(i + 1);
+ stats_.AddLostPacket(i + 2);
+ }
+ EXPECT_EQ(100, stats_.GetSingleLossCount());
+ EXPECT_EQ(200, stats_.GetMultipleLossEventCount());
+ EXPECT_EQ(400, stats_.GetMultipleLossPacketCount());
+}
+
+// Add loss packets out of order and ensure that they still get counted
+// correctly as single or multiple loss events, and wrap in the middle of
+// adding.
+TEST_F(PacketLossStatsTest, OutOfOrderWrapped) {
+ for (int i = 65000; i < 66000; i += 10) {
+ stats_.AddLostPacket((i + 5) & 0xFFFF);
+ stats_.AddLostPacket((i + 7) & 0xFFFF);
+ stats_.AddLostPacket((i + 4) & 0xFFFF);
+ stats_.AddLostPacket((i + 1) & 0xFFFF);
+ stats_.AddLostPacket((i + 2) & 0xFFFF);
+ }
+ EXPECT_EQ(100, stats_.GetSingleLossCount());
+ EXPECT_EQ(200, stats_.GetMultipleLossEventCount());
+ EXPECT_EQ(400, stats_.GetMultipleLossPacketCount());
+}
+
+} // namespace webrtc
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
index d2e224d..c46664f 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc
@@ -604,6 +604,31 @@
rtp_sender_.GetDataCounters(rtp_counters, rtx_counters);
}
+void ModuleRtpRtcpImpl::GetRtpPacketLossStats(
+ bool outgoing,
+ uint32_t ssrc,
+ struct RtpPacketLossStats* loss_stats) const {
+ if (!loss_stats) return;
+ const PacketLossStats* stats_source = NULL;
+ if (outgoing) {
+ if (SSRC() == ssrc) {
+ stats_source = &send_loss_stats_;
+ }
+ } else {
+ if (rtcp_receiver_.RemoteSSRC() == ssrc) {
+ stats_source = &receive_loss_stats_;
+ }
+ }
+ if (stats_source) {
+ loss_stats->single_packet_loss_count =
+ stats_source->GetSingleLossCount();
+ loss_stats->multiple_packet_loss_event_count =
+ stats_source->GetMultipleLossEventCount();
+ loss_stats->multiple_packet_loss_packet_count =
+ stats_source->GetMultipleLossPacketCount();
+ }
+}
+
int32_t ModuleRtpRtcpImpl::RemoteRTCPStat(RTCPSenderInfo* sender_info) {
return rtcp_receiver_.SenderInfoReceived(sender_info);
}
@@ -677,6 +702,9 @@
// Send a Negative acknowledgment packet.
int32_t ModuleRtpRtcpImpl::SendNACK(const uint16_t* nack_list,
const uint16_t size) {
+ for (int i = 0; i < size; ++i) {
+ receive_loss_stats_.AddLostPacket(nack_list[i]);
+ }
uint16_t nack_length = size;
uint16_t start_id = 0;
int64_t now = clock_->TimeInMilliseconds();
@@ -892,6 +920,9 @@
void ModuleRtpRtcpImpl::OnReceivedNACK(
const std::list<uint16_t>& nack_sequence_numbers) {
+ for (uint16_t nack_sequence_number : nack_sequence_numbers) {
+ send_loss_stats_.AddLostPacket(nack_sequence_number);
+ }
if (!rtp_sender_.StorePackets() ||
nack_sequence_numbers.size() == 0) {
return;
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h
index 9cd7e70..791495a 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h
+++ b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h
@@ -16,6 +16,7 @@
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h"
+#include "webrtc/modules/rtp_rtcp/source/packet_loss_stats.h"
#include "webrtc/modules/rtp_rtcp/source/rtcp_receiver.h"
#include "webrtc/modules/rtp_rtcp/source/rtcp_sender.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_sender.h"
@@ -170,6 +171,11 @@
StreamDataCounters* rtp_counters,
StreamDataCounters* rtx_counters) const override;
+ void GetRtpPacketLossStats(
+ bool outgoing,
+ uint32_t ssrc,
+ struct RtpPacketLossStats* loss_stats) const override;
+
// Get received RTCP report, sender info.
int32_t RemoteRTCPStat(RTCPSenderInfo* sender_info) override;
@@ -374,6 +380,9 @@
RtcpRttStats* rtt_stats_;
+ PacketLossStats send_loss_stats_;
+ PacketLossStats receive_loss_stats_;
+
// The processed RTT from RtcpRttStats.
rtc::scoped_ptr<CriticalSectionWrapper> critical_section_rtt_;
int64_t rtt_ms_;