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
This commit is contained in:
@ -286,16 +286,16 @@ struct StreamDataCounters {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns the number of bytes corresponding to the actual media payload (i.e.
|
// Returns the number of bytes corresponding to the actual media payload (i.e.
|
||||||
// RTP headers, padding and retransmissions are excluded). Note this function
|
// RTP headers, padding, retransmissions and fec packets are excluded).
|
||||||
// does not have meaning for an RTX stream.
|
// Note this function does not have meaning for an RTX stream.
|
||||||
size_t MediaPayloadBytes() const {
|
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.
|
int64_t first_packet_time_ms; // Time when first packet is sent/received.
|
||||||
RtpPacketCounter transmitted; // Number of transmitted packets/bytes.
|
RtpPacketCounter transmitted; // Number of transmitted packets/bytes.
|
||||||
RtpPacketCounter retransmitted; // Number of retransmitted packets/bytes.
|
RtpPacketCounter retransmitted; // Number of retransmitted packets/bytes.
|
||||||
// TODO(asapersson): add FEC bytes.
|
|
||||||
RtpPacketCounter fec; // Number of redundancy packets/bytes.
|
RtpPacketCounter fec; // Number of redundancy packets/bytes.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -61,7 +61,8 @@ class ReceiveStatistics : public Module {
|
|||||||
bool retransmitted) = 0;
|
bool retransmitted) = 0;
|
||||||
|
|
||||||
// Increment counter for number of FEC packets received.
|
// 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
|
// Returns a map of all statisticians which have seen an incoming packet
|
||||||
// during the last two seconds.
|
// during the last two seconds.
|
||||||
@ -87,7 +88,8 @@ class NullReceiveStatistics : public ReceiveStatistics {
|
|||||||
virtual void IncomingPacket(const RTPHeader& rtp_header,
|
virtual void IncomingPacket(const RTPHeader& rtp_header,
|
||||||
size_t packet_length,
|
size_t packet_length,
|
||||||
bool retransmitted) OVERRIDE;
|
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 StatisticianMap GetActiveStatisticians() const OVERRIDE;
|
||||||
virtual StreamStatistician* GetStatistician(uint32_t ssrc) const OVERRIDE;
|
virtual StreamStatistician* GetStatistician(uint32_t ssrc) const OVERRIDE;
|
||||||
virtual int64_t TimeUntilNextProcess() OVERRIDE;
|
virtual int64_t TimeUntilNextProcess() OVERRIDE;
|
||||||
|
@ -200,10 +200,15 @@ void StreamStatisticianImpl::NotifyRtcpCallback() {
|
|||||||
rtcp_callback_->StatisticsUpdated(data, ssrc);
|
rtcp_callback_->StatisticsUpdated(data, ssrc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StreamStatisticianImpl::FecPacketReceived() {
|
void StreamStatisticianImpl::FecPacketReceived(const RTPHeader& header,
|
||||||
|
size_t packet_length) {
|
||||||
{
|
{
|
||||||
CriticalSectionScoped cs(stream_lock_.get());
|
CriticalSectionScoped cs(stream_lock_.get());
|
||||||
++receive_counters_.fec.packets;
|
++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();
|
NotifyRtpCallback();
|
||||||
}
|
}
|
||||||
@ -441,12 +446,13 @@ void ReceiveStatisticsImpl::IncomingPacket(const RTPHeader& header,
|
|||||||
impl->IncomingPacket(header, packet_length, retransmitted);
|
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());
|
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.
|
// Ignore FEC if it is the first packet.
|
||||||
if (it != statisticians_.end()) {
|
if (it != statisticians_.end()) {
|
||||||
it->second->FecPacketReceived();
|
it->second->FecPacketReceived(header, packet_length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -543,7 +549,8 @@ void NullReceiveStatistics::IncomingPacket(const RTPHeader& rtp_header,
|
|||||||
size_t packet_length,
|
size_t packet_length,
|
||||||
bool retransmitted) {}
|
bool retransmitted) {}
|
||||||
|
|
||||||
void NullReceiveStatistics::FecPacketReceived(uint32_t ssrc) {}
|
void NullReceiveStatistics::FecPacketReceived(const RTPHeader& header,
|
||||||
|
size_t packet_length) {}
|
||||||
|
|
||||||
StatisticianMap NullReceiveStatistics::GetActiveStatisticians() const {
|
StatisticianMap NullReceiveStatistics::GetActiveStatisticians() const {
|
||||||
return StatisticianMap();
|
return StatisticianMap();
|
||||||
|
@ -44,7 +44,7 @@ class StreamStatisticianImpl : public StreamStatistician {
|
|||||||
void IncomingPacket(const RTPHeader& rtp_header,
|
void IncomingPacket(const RTPHeader& rtp_header,
|
||||||
size_t packet_length,
|
size_t packet_length,
|
||||||
bool retransmitted);
|
bool retransmitted);
|
||||||
void FecPacketReceived();
|
void FecPacketReceived(const RTPHeader& header, size_t packet_length);
|
||||||
void SetMaxReorderingThreshold(int max_reordering_threshold);
|
void SetMaxReorderingThreshold(int max_reordering_threshold);
|
||||||
void ProcessBitrate();
|
void ProcessBitrate();
|
||||||
virtual void LastReceiveTimeNtp(uint32_t* secs, uint32_t* frac) const;
|
virtual void LastReceiveTimeNtp(uint32_t* secs, uint32_t* frac) const;
|
||||||
@ -110,7 +110,8 @@ class ReceiveStatisticsImpl : public ReceiveStatistics,
|
|||||||
virtual void IncomingPacket(const RTPHeader& header,
|
virtual void IncomingPacket(const RTPHeader& header,
|
||||||
size_t packet_length,
|
size_t packet_length,
|
||||||
bool retransmitted) OVERRIDE;
|
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 StatisticianMap GetActiveStatisticians() const OVERRIDE;
|
||||||
virtual StreamStatistician* GetStatistician(uint32_t ssrc) const OVERRIDE;
|
virtual StreamStatistician* GetStatistician(uint32_t ssrc) const OVERRIDE;
|
||||||
virtual void SetMaxReorderingThreshold(int max_reordering_threshold) OVERRIDE;
|
virtual void SetMaxReorderingThreshold(int max_reordering_threshold) OVERRIDE;
|
||||||
|
@ -276,6 +276,9 @@ class RtpTestCallback : public StreamDataCountersCallback {
|
|||||||
EXPECT_EQ(expected.retransmitted.padding_bytes,
|
EXPECT_EQ(expected.retransmitted.padding_bytes,
|
||||||
stats_.retransmitted.padding_bytes);
|
stats_.retransmitted.padding_bytes);
|
||||||
EXPECT_EQ(expected.retransmitted.packets, stats_.retransmitted.packets);
|
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);
|
EXPECT_EQ(expected.fec.packets, stats_.fec.packets);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -336,13 +339,16 @@ TEST_F(ReceiveStatisticsTest, RtpCallbacks) {
|
|||||||
header1_.paddingLength = 0;
|
header1_.paddingLength = 0;
|
||||||
++header1_.sequenceNumber;
|
++header1_.sequenceNumber;
|
||||||
clock_.AdvanceTimeMilliseconds(5);
|
clock_.AdvanceTimeMilliseconds(5);
|
||||||
// One recovered packet.
|
// One FEC packet.
|
||||||
receive_statistics_->IncomingPacket(
|
receive_statistics_->IncomingPacket(
|
||||||
header1_, kPacketSize1 + kHeaderLength, false);
|
header1_, kPacketSize1 + kHeaderLength, false);
|
||||||
receive_statistics_->FecPacketReceived(kSsrc1);
|
receive_statistics_->FecPacketReceived(header1_,
|
||||||
|
kPacketSize1 + kHeaderLength);
|
||||||
expected.transmitted.payload_bytes = kPacketSize1 * 4;
|
expected.transmitted.payload_bytes = kPacketSize1 * 4;
|
||||||
expected.transmitted.header_bytes = kHeaderLength * 4;
|
expected.transmitted.header_bytes = kHeaderLength * 4;
|
||||||
expected.transmitted.packets = 4;
|
expected.transmitted.packets = 4;
|
||||||
|
expected.fec.payload_bytes = kPacketSize1;
|
||||||
|
expected.fec.header_bytes = kHeaderLength;
|
||||||
expected.fec.packets = 1;
|
expected.fec.packets = 1;
|
||||||
callback.Matches(5, kSsrc1, expected);
|
callback.Matches(5, kSsrc1, expected);
|
||||||
|
|
||||||
@ -361,12 +367,13 @@ TEST_F(ReceiveStatisticsTest, RtpCallbacksFecFirst) {
|
|||||||
receive_statistics_->RegisterRtpStatisticsCallback(&callback);
|
receive_statistics_->RegisterRtpStatisticsCallback(&callback);
|
||||||
|
|
||||||
const uint32_t kHeaderLength = 20;
|
const uint32_t kHeaderLength = 20;
|
||||||
|
header1_.headerLength = kHeaderLength;
|
||||||
|
|
||||||
// If first packet is FEC, ignore it.
|
// If first packet is FEC, ignore it.
|
||||||
receive_statistics_->FecPacketReceived(kSsrc1);
|
receive_statistics_->FecPacketReceived(header1_,
|
||||||
|
kPacketSize1 + kHeaderLength);
|
||||||
EXPECT_EQ(0u, callback.num_calls_);
|
EXPECT_EQ(0u, callback.num_calls_);
|
||||||
|
|
||||||
header1_.headerLength = kHeaderLength;
|
|
||||||
receive_statistics_->IncomingPacket(
|
receive_statistics_->IncomingPacket(
|
||||||
header1_, kPacketSize1 + kHeaderLength, false);
|
header1_, kPacketSize1 + kHeaderLength, false);
|
||||||
StreamDataCounters expected;
|
StreamDataCounters expected;
|
||||||
@ -377,7 +384,10 @@ TEST_F(ReceiveStatisticsTest, RtpCallbacksFecFirst) {
|
|||||||
expected.fec.packets = 0;
|
expected.fec.packets = 0;
|
||||||
callback.Matches(1, kSsrc1, expected);
|
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;
|
expected.fec.packets = 1;
|
||||||
callback.Matches(2, kSsrc1, expected);
|
callback.Matches(2, kSsrc1, expected);
|
||||||
}
|
}
|
||||||
|
@ -900,6 +900,10 @@ void RTPSender::UpdateRtpStats(const uint8_t* buffer,
|
|||||||
}
|
}
|
||||||
if (IsFecPacket(buffer, header)) {
|
if (IsFecPacket(buffer, header)) {
|
||||||
++counters->fec.packets;
|
++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) {
|
if (is_retransmit) {
|
||||||
|
@ -202,11 +202,11 @@ void ViEChannel::UpdateHistograms() {
|
|||||||
int64_t elapsed_sec = rtcp_received.TimeSinceFirstPacketInMs(now) / 1000;
|
int64_t elapsed_sec = rtcp_received.TimeSinceFirstPacketInMs(now) / 1000;
|
||||||
if (elapsed_sec > metrics::kMinRunTimeInSeconds) {
|
if (elapsed_sec > metrics::kMinRunTimeInSeconds) {
|
||||||
RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.NackPacketsReceivedPerMinute",
|
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",
|
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",
|
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) {
|
if (rtcp_received.nack_requests > 0) {
|
||||||
RTC_HISTOGRAM_PERCENTAGE(
|
RTC_HISTOGRAM_PERCENTAGE(
|
||||||
"WebRTC.Video.UniqueNackRequestsReceivedInPercent",
|
"WebRTC.Video.UniqueNackRequestsReceivedInPercent",
|
||||||
@ -224,11 +224,11 @@ void ViEChannel::UpdateHistograms() {
|
|||||||
int64_t elapsed_sec = rtcp_sent.TimeSinceFirstPacketInMs(now) / 1000;
|
int64_t elapsed_sec = rtcp_sent.TimeSinceFirstPacketInMs(now) / 1000;
|
||||||
if (elapsed_sec > metrics::kMinRunTimeInSeconds) {
|
if (elapsed_sec > metrics::kMinRunTimeInSeconds) {
|
||||||
RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.NackPacketsSentPerMinute",
|
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",
|
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",
|
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) {
|
if (rtcp_sent.nack_requests > 0) {
|
||||||
RTC_HISTOGRAM_PERCENTAGE("WebRTC.Video.UniqueNackRequestsSentInPercent",
|
RTC_HISTOGRAM_PERCENTAGE("WebRTC.Video.UniqueNackRequestsSentInPercent",
|
||||||
rtcp_sent.UniqueNackRequestsInPercent());
|
rtcp_sent.UniqueNackRequestsInPercent());
|
||||||
@ -261,6 +261,10 @@ void ViEChannel::UpdateHistograms() {
|
|||||||
RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.RtxBitrateReceivedInKbps",
|
RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.RtxBitrateReceivedInKbps",
|
||||||
rtx.transmitted.TotalBytes() * 8 / elapsed_sec / 1000);
|
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 @@ void ViEChannel::UpdateHistogramsAtStopSend() {
|
|||||||
RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.RtxBitrateSentInKbps",
|
RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.RtxBitrateSentInKbps",
|
||||||
rtx.transmitted.TotalBytes() * 8 / elapsed_sec / 1000);
|
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,
|
int32_t ViEChannel::SetSendCodec(const VideoCodec& video_codec,
|
||||||
|
@ -129,6 +129,10 @@ bool ViEReceiver::GetRtxSsrc(uint32_t* ssrc) const {
|
|||||||
return rtp_payload_registry_->GetRtxSsrc(ssrc);
|
return rtp_payload_registry_->GetRtxSsrc(ssrc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ViEReceiver::IsFecEnabled() const {
|
||||||
|
return rtp_payload_registry_->ulpfec_payload_type() > -1;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t ViEReceiver::GetRemoteSsrc() const {
|
uint32_t ViEReceiver::GetRemoteSsrc() const {
|
||||||
return rtp_receiver_->SSRC();
|
return rtp_receiver_->SSRC();
|
||||||
}
|
}
|
||||||
@ -319,7 +323,7 @@ bool ViEReceiver::ParseAndHandleEncapsulatingHeader(const uint8_t* packet,
|
|||||||
if (rtp_payload_registry_->IsRed(header)) {
|
if (rtp_payload_registry_->IsRed(header)) {
|
||||||
int8_t ulpfec_pt = rtp_payload_registry_->ulpfec_payload_type();
|
int8_t ulpfec_pt = rtp_payload_registry_->ulpfec_payload_type();
|
||||||
if (packet[header.headerLength] == ulpfec_pt)
|
if (packet[header.headerLength] == ulpfec_pt)
|
||||||
rtp_receive_statistics_->FecPacketReceived(header.ssrc);
|
rtp_receive_statistics_->FecPacketReceived(header, packet_length);
|
||||||
if (fec_receiver_->AddReceivedRedPacket(
|
if (fec_receiver_->AddReceivedRedPacket(
|
||||||
header, packet, packet_length, ulpfec_pt) != 0) {
|
header, packet, packet_length, ulpfec_pt) != 0) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -51,6 +51,8 @@ class ViEReceiver : public RtpData {
|
|||||||
void SetRtxSsrc(uint32_t ssrc);
|
void SetRtxSsrc(uint32_t ssrc);
|
||||||
bool GetRtxSsrc(uint32_t* ssrc) const;
|
bool GetRtxSsrc(uint32_t* ssrc) const;
|
||||||
|
|
||||||
|
bool IsFecEnabled() const;
|
||||||
|
|
||||||
uint32_t GetRemoteSsrc() const;
|
uint32_t GetRemoteSsrc() const;
|
||||||
int GetCsrcs(uint32_t* csrcs) const;
|
int GetCsrcs(uint32_t* csrcs) const;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user