Update StreamDataCounter with FEC bytes.
Add histograms stats for send/receive FEC bitrate:
- "WebRTC.Video.FecBitrateReceivedInKbps"
- "WebRTC.Video.FecBitrateSentInKbps"
Correct media payload bytes in StreamDataCounter to not include FEC bytes.
Fix stats for rtcp packets sent/received per minute (regression from r7910).
BUG=crbug/419657
R=holmer@google.com, mflodman@webrtc.org
Review URL: https://webrtc-codereview.appspot.com/34789004
git-svn-id: http://webrtc.googlecode.com/svn/trunk@8164 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/webrtc/common_types.h b/webrtc/common_types.h
index fe736cd..f347ec3 100644
--- a/webrtc/common_types.h
+++ b/webrtc/common_types.h
@@ -286,16 +286,16 @@
}
// Returns the number of bytes corresponding to the actual media payload (i.e.
- // RTP headers, padding and retransmissions are excluded). Note this function
- // does not have meaning for an RTX stream.
+ // RTP headers, padding, retransmissions and fec packets are excluded).
+ // Note this function does not have meaning for an RTX stream.
size_t MediaPayloadBytes() const {
- return transmitted.payload_bytes - retransmitted.payload_bytes;
+ return transmitted.payload_bytes - retransmitted.payload_bytes -
+ fec.payload_bytes;
}
int64_t first_packet_time_ms; // Time when first packet is sent/received.
RtpPacketCounter transmitted; // Number of transmitted packets/bytes.
RtpPacketCounter retransmitted; // Number of retransmitted packets/bytes.
- // TODO(asapersson): add FEC bytes.
RtpPacketCounter fec; // Number of redundancy packets/bytes.
};
diff --git a/webrtc/modules/rtp_rtcp/interface/receive_statistics.h b/webrtc/modules/rtp_rtcp/interface/receive_statistics.h
index 701d8dd..3bd953f 100644
--- a/webrtc/modules/rtp_rtcp/interface/receive_statistics.h
+++ b/webrtc/modules/rtp_rtcp/interface/receive_statistics.h
@@ -61,7 +61,8 @@
bool retransmitted) = 0;
// Increment counter for number of FEC packets received.
- virtual void FecPacketReceived(uint32_t ssrc) = 0;
+ virtual void FecPacketReceived(const RTPHeader& header,
+ size_t packet_length) = 0;
// Returns a map of all statisticians which have seen an incoming packet
// during the last two seconds.
@@ -87,7 +88,8 @@
virtual void IncomingPacket(const RTPHeader& rtp_header,
size_t packet_length,
bool retransmitted) OVERRIDE;
- virtual void FecPacketReceived(uint32_t ssrc) OVERRIDE;
+ virtual void FecPacketReceived(const RTPHeader& header,
+ size_t packet_length) OVERRIDE;
virtual StatisticianMap GetActiveStatisticians() const OVERRIDE;
virtual StreamStatistician* GetStatistician(uint32_t ssrc) const OVERRIDE;
virtual int64_t TimeUntilNextProcess() OVERRIDE;
diff --git a/webrtc/modules/rtp_rtcp/source/receive_statistics_impl.cc b/webrtc/modules/rtp_rtcp/source/receive_statistics_impl.cc
index aefab15..916ef54 100644
--- a/webrtc/modules/rtp_rtcp/source/receive_statistics_impl.cc
+++ b/webrtc/modules/rtp_rtcp/source/receive_statistics_impl.cc
@@ -200,10 +200,15 @@
rtcp_callback_->StatisticsUpdated(data, ssrc);
}
-void StreamStatisticianImpl::FecPacketReceived() {
+void StreamStatisticianImpl::FecPacketReceived(const RTPHeader& header,
+ size_t packet_length) {
{
CriticalSectionScoped cs(stream_lock_.get());
++receive_counters_.fec.packets;
+ receive_counters_.fec.payload_bytes +=
+ packet_length - (header.headerLength + header.paddingLength);
+ receive_counters_.fec.header_bytes += header.headerLength;
+ receive_counters_.fec.padding_bytes += header.paddingLength;
}
NotifyRtpCallback();
}
@@ -441,12 +446,13 @@
impl->IncomingPacket(header, packet_length, retransmitted);
}
-void ReceiveStatisticsImpl::FecPacketReceived(uint32_t ssrc) {
+void ReceiveStatisticsImpl::FecPacketReceived(const RTPHeader& header,
+ size_t packet_length) {
CriticalSectionScoped cs(receive_statistics_lock_.get());
- StatisticianImplMap::iterator it = statisticians_.find(ssrc);
+ StatisticianImplMap::iterator it = statisticians_.find(header.ssrc);
// Ignore FEC if it is the first packet.
if (it != statisticians_.end()) {
- it->second->FecPacketReceived();
+ it->second->FecPacketReceived(header, packet_length);
}
}
@@ -543,7 +549,8 @@
size_t packet_length,
bool retransmitted) {}
-void NullReceiveStatistics::FecPacketReceived(uint32_t ssrc) {}
+void NullReceiveStatistics::FecPacketReceived(const RTPHeader& header,
+ size_t packet_length) {}
StatisticianMap NullReceiveStatistics::GetActiveStatisticians() const {
return StatisticianMap();
diff --git a/webrtc/modules/rtp_rtcp/source/receive_statistics_impl.h b/webrtc/modules/rtp_rtcp/source/receive_statistics_impl.h
index 4b02f36..ab80a74 100644
--- a/webrtc/modules/rtp_rtcp/source/receive_statistics_impl.h
+++ b/webrtc/modules/rtp_rtcp/source/receive_statistics_impl.h
@@ -44,7 +44,7 @@
void IncomingPacket(const RTPHeader& rtp_header,
size_t packet_length,
bool retransmitted);
- void FecPacketReceived();
+ void FecPacketReceived(const RTPHeader& header, size_t packet_length);
void SetMaxReorderingThreshold(int max_reordering_threshold);
void ProcessBitrate();
virtual void LastReceiveTimeNtp(uint32_t* secs, uint32_t* frac) const;
@@ -110,7 +110,8 @@
virtual void IncomingPacket(const RTPHeader& header,
size_t packet_length,
bool retransmitted) OVERRIDE;
- virtual void FecPacketReceived(uint32_t ssrc) OVERRIDE;
+ virtual void FecPacketReceived(const RTPHeader& header,
+ size_t packet_length) OVERRIDE;
virtual StatisticianMap GetActiveStatisticians() const OVERRIDE;
virtual StreamStatistician* GetStatistician(uint32_t ssrc) const OVERRIDE;
virtual void SetMaxReorderingThreshold(int max_reordering_threshold) OVERRIDE;
diff --git a/webrtc/modules/rtp_rtcp/source/receive_statistics_unittest.cc b/webrtc/modules/rtp_rtcp/source/receive_statistics_unittest.cc
index c90e62e..7f3f564 100644
--- a/webrtc/modules/rtp_rtcp/source/receive_statistics_unittest.cc
+++ b/webrtc/modules/rtp_rtcp/source/receive_statistics_unittest.cc
@@ -276,6 +276,9 @@
EXPECT_EQ(expected.retransmitted.padding_bytes,
stats_.retransmitted.padding_bytes);
EXPECT_EQ(expected.retransmitted.packets, stats_.retransmitted.packets);
+ EXPECT_EQ(expected.fec.payload_bytes, stats_.fec.payload_bytes);
+ EXPECT_EQ(expected.fec.header_bytes, stats_.fec.header_bytes);
+ EXPECT_EQ(expected.fec.padding_bytes, stats_.fec.padding_bytes);
EXPECT_EQ(expected.fec.packets, stats_.fec.packets);
}
@@ -336,13 +339,16 @@
header1_.paddingLength = 0;
++header1_.sequenceNumber;
clock_.AdvanceTimeMilliseconds(5);
- // One recovered packet.
+ // One FEC packet.
receive_statistics_->IncomingPacket(
header1_, kPacketSize1 + kHeaderLength, false);
- receive_statistics_->FecPacketReceived(kSsrc1);
+ receive_statistics_->FecPacketReceived(header1_,
+ kPacketSize1 + kHeaderLength);
expected.transmitted.payload_bytes = kPacketSize1 * 4;
expected.transmitted.header_bytes = kHeaderLength * 4;
expected.transmitted.packets = 4;
+ expected.fec.payload_bytes = kPacketSize1;
+ expected.fec.header_bytes = kHeaderLength;
expected.fec.packets = 1;
callback.Matches(5, kSsrc1, expected);
@@ -361,12 +367,13 @@
receive_statistics_->RegisterRtpStatisticsCallback(&callback);
const uint32_t kHeaderLength = 20;
+ header1_.headerLength = kHeaderLength;
// If first packet is FEC, ignore it.
- receive_statistics_->FecPacketReceived(kSsrc1);
+ receive_statistics_->FecPacketReceived(header1_,
+ kPacketSize1 + kHeaderLength);
EXPECT_EQ(0u, callback.num_calls_);
- header1_.headerLength = kHeaderLength;
receive_statistics_->IncomingPacket(
header1_, kPacketSize1 + kHeaderLength, false);
StreamDataCounters expected;
@@ -377,7 +384,10 @@
expected.fec.packets = 0;
callback.Matches(1, kSsrc1, expected);
- receive_statistics_->FecPacketReceived(kSsrc1);
+ receive_statistics_->FecPacketReceived(header1_,
+ kPacketSize1 + kHeaderLength);
+ expected.fec.payload_bytes = kPacketSize1;
+ expected.fec.header_bytes = kHeaderLength;
expected.fec.packets = 1;
callback.Matches(2, kSsrc1, expected);
}
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender.cc b/webrtc/modules/rtp_rtcp/source/rtp_sender.cc
index 952e770..d7cc0bc 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_sender.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtp_sender.cc
@@ -900,6 +900,10 @@
}
if (IsFecPacket(buffer, header)) {
++counters->fec.packets;
+ counters->fec.payload_bytes +=
+ packet_length - (header.headerLength + header.paddingLength);
+ counters->fec.header_bytes += header.headerLength;
+ counters->fec.padding_bytes += header.paddingLength;
}
if (is_retransmit) {
diff --git a/webrtc/video_engine/vie_channel.cc b/webrtc/video_engine/vie_channel.cc
index 1e0a056..1ec8a10 100644
--- a/webrtc/video_engine/vie_channel.cc
+++ b/webrtc/video_engine/vie_channel.cc
@@ -202,11 +202,11 @@
int64_t elapsed_sec = rtcp_received.TimeSinceFirstPacketInMs(now) / 1000;
if (elapsed_sec > metrics::kMinRunTimeInSeconds) {
RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.NackPacketsReceivedPerMinute",
- rtcp_received.nack_packets / elapsed_sec / 60);
+ rtcp_received.nack_packets * 60 / elapsed_sec);
RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.FirPacketsReceivedPerMinute",
- rtcp_received.fir_packets / elapsed_sec / 60);
+ rtcp_received.fir_packets * 60 / elapsed_sec);
RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.PliPacketsReceivedPerMinute",
- rtcp_received.pli_packets / elapsed_sec / 60);
+ rtcp_received.pli_packets * 60 / elapsed_sec);
if (rtcp_received.nack_requests > 0) {
RTC_HISTOGRAM_PERCENTAGE(
"WebRTC.Video.UniqueNackRequestsReceivedInPercent",
@@ -224,11 +224,11 @@
int64_t elapsed_sec = rtcp_sent.TimeSinceFirstPacketInMs(now) / 1000;
if (elapsed_sec > metrics::kMinRunTimeInSeconds) {
RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.NackPacketsSentPerMinute",
- rtcp_sent.nack_packets / elapsed_sec / 60);
+ rtcp_sent.nack_packets * 60 / elapsed_sec);
RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.FirPacketsSentPerMinute",
- rtcp_sent.fir_packets / elapsed_sec / 60);
+ rtcp_sent.fir_packets * 60 / elapsed_sec);
RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.PliPacketsSentPerMinute",
- rtcp_sent.pli_packets / elapsed_sec / 60);
+ rtcp_sent.pli_packets * 60 / elapsed_sec);
if (rtcp_sent.nack_requests > 0) {
RTC_HISTOGRAM_PERCENTAGE("WebRTC.Video.UniqueNackRequestsSentInPercent",
rtcp_sent.UniqueNackRequestsInPercent());
@@ -261,6 +261,10 @@
RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.RtxBitrateReceivedInKbps",
rtx.transmitted.TotalBytes() * 8 / elapsed_sec / 1000);
}
+ if (vie_receiver_.IsFecEnabled()) {
+ RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.FecBitrateReceivedInKbps",
+ rtp_rtx.fec.TotalBytes() * 8 / elapsed_sec / 1000);
+ }
}
}
}
@@ -290,6 +294,14 @@
RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.RtxBitrateSentInKbps",
rtx.transmitted.TotalBytes() * 8 / elapsed_sec / 1000);
}
+ bool fec_enabled = false;
+ uint8_t pltype_red;
+ uint8_t pltype_fec;
+ rtp_rtcp_->GenericFECStatus(fec_enabled, pltype_red, pltype_fec);
+ if (fec_enabled) {
+ RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.FecBitrateSentInKbps",
+ rtp_rtx.fec.TotalBytes() * 8 / elapsed_sec / 1000);
+ }
}
int32_t ViEChannel::SetSendCodec(const VideoCodec& video_codec,
diff --git a/webrtc/video_engine/vie_receiver.cc b/webrtc/video_engine/vie_receiver.cc
index 7e1034f..cdff860 100644
--- a/webrtc/video_engine/vie_receiver.cc
+++ b/webrtc/video_engine/vie_receiver.cc
@@ -129,6 +129,10 @@
return rtp_payload_registry_->GetRtxSsrc(ssrc);
}
+bool ViEReceiver::IsFecEnabled() const {
+ return rtp_payload_registry_->ulpfec_payload_type() > -1;
+}
+
uint32_t ViEReceiver::GetRemoteSsrc() const {
return rtp_receiver_->SSRC();
}
@@ -319,7 +323,7 @@
if (rtp_payload_registry_->IsRed(header)) {
int8_t ulpfec_pt = rtp_payload_registry_->ulpfec_payload_type();
if (packet[header.headerLength] == ulpfec_pt)
- rtp_receive_statistics_->FecPacketReceived(header.ssrc);
+ rtp_receive_statistics_->FecPacketReceived(header, packet_length);
if (fec_receiver_->AddReceivedRedPacket(
header, packet, packet_length, ulpfec_pt) != 0) {
return false;
diff --git a/webrtc/video_engine/vie_receiver.h b/webrtc/video_engine/vie_receiver.h
index 6354d68..b8e6569 100644
--- a/webrtc/video_engine/vie_receiver.h
+++ b/webrtc/video_engine/vie_receiver.h
@@ -51,6 +51,8 @@
void SetRtxSsrc(uint32_t ssrc);
bool GetRtxSsrc(uint32_t* ssrc) const;
+ bool IsFecEnabled() const;
+
uint32_t GetRemoteSsrc() const;
int GetCsrcs(uint32_t* csrcs) const;