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}
This commit is contained in:
@ -230,6 +230,7 @@
|
|||||||
'rtp_rtcp/source/fec_test_helper.h',
|
'rtp_rtcp/source/fec_test_helper.h',
|
||||||
'rtp_rtcp/source/h264_sps_parser_unittest.cc',
|
'rtp_rtcp/source/h264_sps_parser_unittest.cc',
|
||||||
'rtp_rtcp/source/nack_rtx_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/producer_fec_unittest.cc',
|
||||||
'rtp_rtcp/source/receive_statistics_unittest.cc',
|
'rtp_rtcp/source/receive_statistics_unittest.cc',
|
||||||
'rtp_rtcp/source/remote_ntp_time_estimator_unittest.cc',
|
'rtp_rtcp/source/remote_ntp_time_estimator_unittest.cc',
|
||||||
|
@ -35,6 +35,8 @@ source_set("rtp_rtcp") {
|
|||||||
"source/h264_sps_parser.cc",
|
"source/h264_sps_parser.cc",
|
||||||
"source/h264_sps_parser.h",
|
"source/h264_sps_parser.h",
|
||||||
"source/mock/mock_rtp_payload_strategy.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.cc",
|
||||||
"source/producer_fec.h",
|
"source/producer_fec.h",
|
||||||
"source/receive_statistics_impl.cc",
|
"source/receive_statistics_impl.cc",
|
||||||
|
@ -430,6 +430,14 @@ class RtpRtcp : public Module {
|
|||||||
StreamDataCounters* rtp_counters,
|
StreamDataCounters* rtp_counters,
|
||||||
StreamDataCounters* rtx_counters) const = 0;
|
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
|
* Get received RTCP sender info
|
||||||
*
|
*
|
||||||
|
@ -350,5 +350,18 @@ class NullRtpAudioFeedback : public RtpAudioFeedback {
|
|||||||
const uint8_t volume) override {}
|
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
|
} // namespace webrtc
|
||||||
#endif // WEBRTC_MODULES_RTP_RTCP_INTERFACE_RTP_RTCP_DEFINES_H_
|
#endif // WEBRTC_MODULES_RTP_RTCP_INTERFACE_RTP_RTCP_DEFINES_H_
|
||||||
|
@ -165,6 +165,8 @@ class MockRtpRtcp : public RtpRtcp {
|
|||||||
int32_t(size_t *bytesSent, uint32_t *packetsSent));
|
int32_t(size_t *bytesSent, uint32_t *packetsSent));
|
||||||
MOCK_CONST_METHOD2(GetSendStreamDataCounters,
|
MOCK_CONST_METHOD2(GetSendStreamDataCounters,
|
||||||
void(StreamDataCounters*, StreamDataCounters*));
|
void(StreamDataCounters*, StreamDataCounters*));
|
||||||
|
MOCK_CONST_METHOD3(GetRtpPacketLossStats,
|
||||||
|
void(bool, uint32_t, struct RtpPacketLossStats*));
|
||||||
MOCK_METHOD1(RemoteRTCPStat,
|
MOCK_METHOD1(RemoteRTCPStat,
|
||||||
int32_t(RTCPSenderInfo* senderInfo));
|
int32_t(RTCPSenderInfo* senderInfo));
|
||||||
MOCK_CONST_METHOD1(RemoteRTCPStat,
|
MOCK_CONST_METHOD1(RemoteRTCPStat,
|
||||||
|
@ -31,6 +31,8 @@
|
|||||||
'source/byte_io.h',
|
'source/byte_io.h',
|
||||||
'source/fec_receiver_impl.cc',
|
'source/fec_receiver_impl.cc',
|
||||||
'source/fec_receiver_impl.h',
|
'source/fec_receiver_impl.h',
|
||||||
|
'source/packet_loss_stats.cc',
|
||||||
|
'source/packet_loss_stats.h',
|
||||||
'source/receive_statistics_impl.cc',
|
'source/receive_statistics_impl.cc',
|
||||||
'source/receive_statistics_impl.h',
|
'source/receive_statistics_impl.h',
|
||||||
'source/remote_ntp_time_estimator.cc',
|
'source/remote_ntp_time_estimator.cc',
|
||||||
|
137
webrtc/modules/rtp_rtcp/source/packet_loss_stats.cc
Normal file
137
webrtc/modules/rtp_rtcp/source/packet_loss_stats.cc
Normal file
@ -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
|
57
webrtc/modules/rtp_rtcp/source/packet_loss_stats.h
Normal file
57
webrtc/modules/rtp_rtcp/source/packet_loss_stats.h
Normal file
@ -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_
|
197
webrtc/modules/rtp_rtcp/source/packet_loss_stats_unittest.cc
Normal file
197
webrtc/modules/rtp_rtcp/source/packet_loss_stats_unittest.cc
Normal file
@ -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
|
@ -604,6 +604,31 @@ void ModuleRtpRtcpImpl::GetSendStreamDataCounters(
|
|||||||
rtp_sender_.GetDataCounters(rtp_counters, rtx_counters);
|
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) {
|
int32_t ModuleRtpRtcpImpl::RemoteRTCPStat(RTCPSenderInfo* sender_info) {
|
||||||
return rtcp_receiver_.SenderInfoReceived(sender_info);
|
return rtcp_receiver_.SenderInfoReceived(sender_info);
|
||||||
}
|
}
|
||||||
@ -677,6 +702,9 @@ int ModuleRtpRtcpImpl::SetSelectiveRetransmissions(uint8_t settings) {
|
|||||||
// Send a Negative acknowledgment packet.
|
// Send a Negative acknowledgment packet.
|
||||||
int32_t ModuleRtpRtcpImpl::SendNACK(const uint16_t* nack_list,
|
int32_t ModuleRtpRtcpImpl::SendNACK(const uint16_t* nack_list,
|
||||||
const uint16_t size) {
|
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 nack_length = size;
|
||||||
uint16_t start_id = 0;
|
uint16_t start_id = 0;
|
||||||
int64_t now = clock_->TimeInMilliseconds();
|
int64_t now = clock_->TimeInMilliseconds();
|
||||||
@ -892,6 +920,9 @@ bool ModuleRtpRtcpImpl::SendTimeOfXrRrReport(
|
|||||||
|
|
||||||
void ModuleRtpRtcpImpl::OnReceivedNACK(
|
void ModuleRtpRtcpImpl::OnReceivedNACK(
|
||||||
const std::list<uint16_t>& nack_sequence_numbers) {
|
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() ||
|
if (!rtp_sender_.StorePackets() ||
|
||||||
nack_sequence_numbers.size() == 0) {
|
nack_sequence_numbers.size() == 0) {
|
||||||
return;
|
return;
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
#include "webrtc/base/scoped_ptr.h"
|
#include "webrtc/base/scoped_ptr.h"
|
||||||
#include "webrtc/modules/rtp_rtcp/interface/rtp_rtcp.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_receiver.h"
|
||||||
#include "webrtc/modules/rtp_rtcp/source/rtcp_sender.h"
|
#include "webrtc/modules/rtp_rtcp/source/rtcp_sender.h"
|
||||||
#include "webrtc/modules/rtp_rtcp/source/rtp_sender.h"
|
#include "webrtc/modules/rtp_rtcp/source/rtp_sender.h"
|
||||||
@ -170,6 +171,11 @@ class ModuleRtpRtcpImpl : public RtpRtcp {
|
|||||||
StreamDataCounters* rtp_counters,
|
StreamDataCounters* rtp_counters,
|
||||||
StreamDataCounters* rtx_counters) const override;
|
StreamDataCounters* rtx_counters) const override;
|
||||||
|
|
||||||
|
void GetRtpPacketLossStats(
|
||||||
|
bool outgoing,
|
||||||
|
uint32_t ssrc,
|
||||||
|
struct RtpPacketLossStats* loss_stats) const override;
|
||||||
|
|
||||||
// Get received RTCP report, sender info.
|
// Get received RTCP report, sender info.
|
||||||
int32_t RemoteRTCPStat(RTCPSenderInfo* sender_info) override;
|
int32_t RemoteRTCPStat(RTCPSenderInfo* sender_info) override;
|
||||||
|
|
||||||
@ -374,6 +380,9 @@ class ModuleRtpRtcpImpl : public RtpRtcp {
|
|||||||
|
|
||||||
RtcpRttStats* rtt_stats_;
|
RtcpRttStats* rtt_stats_;
|
||||||
|
|
||||||
|
PacketLossStats send_loss_stats_;
|
||||||
|
PacketLossStats receive_loss_stats_;
|
||||||
|
|
||||||
// The processed RTT from RtcpRttStats.
|
// The processed RTT from RtcpRttStats.
|
||||||
rtc::scoped_ptr<CriticalSectionWrapper> critical_section_rtt_;
|
rtc::scoped_ptr<CriticalSectionWrapper> critical_section_rtt_;
|
||||||
int64_t rtt_ms_;
|
int64_t rtt_ms_;
|
||||||
|
Reference in New Issue
Block a user