diff --git a/webrtc/common_types.h b/webrtc/common_types.h index 9cb56af82f..43d1bd7060 100644 --- a/webrtc/common_types.h +++ b/webrtc/common_types.h @@ -229,13 +229,16 @@ struct RtcpPacketTypeCounter { uint32_t unique_nack_requests; // Number of unique NACKed RTP packets. }; -// Data usage statistics for a (rtp) stream +// Data usage statistics for a (rtp) stream. struct StreamDataCounters { StreamDataCounters() : bytes(0), header_bytes(0), padding_bytes(0), packets(0), + retransmitted_bytes(0), + retransmitted_header_bytes(0), + retransmitted_padding_bytes(0), retransmitted_packets(0), fec_packets(0) {} @@ -244,15 +247,34 @@ struct StreamDataCounters { header_bytes += other.header_bytes; padding_bytes += other.padding_bytes; packets += other.packets; + retransmitted_bytes += other.retransmitted_bytes; + retransmitted_header_bytes += other.retransmitted_header_bytes; + retransmitted_padding_bytes += other.retransmitted_padding_bytes; retransmitted_packets += other.retransmitted_packets; fec_packets += other.fec_packets; } + size_t TotalBytes() const { + return bytes + header_bytes + padding_bytes; + } + + size_t RetransmittedBytes() const { + return retransmitted_bytes + retransmitted_header_bytes + + retransmitted_padding_bytes; + } + + size_t MediaPayloadBytes() const { + return bytes - retransmitted_bytes; + } + // TODO(pbos): Rename bytes -> media_bytes. size_t bytes; // Payload bytes, excluding RTP headers and padding. size_t header_bytes; // Number of bytes used by RTP headers. size_t padding_bytes; // Number of padding bytes. uint32_t packets; // Number of packets. + size_t retransmitted_bytes; // Number of retransmitted payload bytes. + size_t retransmitted_header_bytes; // Retransmitted bytes used by RTP header. + size_t retransmitted_padding_bytes; // Retransmitted padding bytes. uint32_t retransmitted_packets; // Number of retransmitted packets. uint32_t fec_packets; // Number of redundancy packets. }; diff --git a/webrtc/modules/rtp_rtcp/interface/receive_statistics.h b/webrtc/modules/rtp_rtcp/interface/receive_statistics.h index 8cbed804ac..cf6b9751c2 100644 --- a/webrtc/modules/rtp_rtcp/interface/receive_statistics.h +++ b/webrtc/modules/rtp_rtcp/interface/receive_statistics.h @@ -57,7 +57,7 @@ class ReceiveStatistics : public Module { // Updates the receive statistics with this packet. virtual void IncomingPacket(const RTPHeader& rtp_header, - size_t bytes, + size_t packet_length, bool retransmitted) = 0; // Increment counter for number of FEC packets received. @@ -85,7 +85,7 @@ class ReceiveStatistics : public Module { class NullReceiveStatistics : public ReceiveStatistics { public: virtual void IncomingPacket(const RTPHeader& rtp_header, - size_t bytes, + size_t packet_length, bool retransmitted) OVERRIDE; virtual void FecPacketReceived(uint32_t ssrc) OVERRIDE; virtual StatisticianMap GetActiveStatisticians() const OVERRIDE; diff --git a/webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h b/webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h index d49c8e3ef9..bff099d7a3 100644 --- a/webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h +++ b/webrtc/modules/rtp_rtcp/interface/rtp_rtcp.h @@ -434,13 +434,21 @@ class RtpRtcp : public Module { virtual int32_t ResetSendDataCountersRTP() = 0; /* - * statistics of the amount of data sent and received + * Statistics of the amount of data sent * * return -1 on failure else 0 */ virtual int32_t DataCountersRTP( size_t* bytesSent, uint32_t* packetsSent) const = 0; + + /* + * Get send statistics for the RTP and RTX stream. + */ + virtual void GetSendStreamDataCounters( + StreamDataCounters* rtp_counters, + StreamDataCounters* rtx_counters) const = 0; + /* * Get received RTCP sender info * @@ -455,6 +463,7 @@ class RtpRtcp : public Module { */ virtual int32_t RemoteRTCPStat( std::vector* receiveBlocks) const = 0; + /* * Set received RTCP report block * diff --git a/webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h b/webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h index c76347f091..0edcf45ee8 100644 --- a/webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h +++ b/webrtc/modules/rtp_rtcp/mocks/mock_rtp_rtcp.h @@ -172,6 +172,8 @@ class MockRtpRtcp : public RtpRtcp { int32_t()); MOCK_CONST_METHOD2(DataCountersRTP, int32_t(size_t *bytesSent, uint32_t *packetsSent)); + MOCK_CONST_METHOD2(GetSendStreamDataCounters, + void(StreamDataCounters*, StreamDataCounters*)); MOCK_METHOD1(RemoteRTCPStat, int32_t(RTCPSenderInfo* senderInfo)); MOCK_CONST_METHOD1(RemoteRTCPStat, diff --git a/webrtc/modules/rtp_rtcp/source/receive_statistics_impl.cc b/webrtc/modules/rtp_rtcp/source/receive_statistics_impl.cc index 8585e16af6..fd4b82e331 100644 --- a/webrtc/modules/rtp_rtcp/source/receive_statistics_impl.cc +++ b/webrtc/modules/rtp_rtcp/source/receive_statistics_impl.cc @@ -68,26 +68,30 @@ void StreamStatisticianImpl::ResetStatistics() { } void StreamStatisticianImpl::IncomingPacket(const RTPHeader& header, - size_t bytes, + size_t packet_length, bool retransmitted) { - UpdateCounters(header, bytes, retransmitted); + UpdateCounters(header, packet_length, retransmitted); NotifyRtpCallback(); } void StreamStatisticianImpl::UpdateCounters(const RTPHeader& header, - size_t bytes, + size_t packet_length, bool retransmitted) { CriticalSectionScoped cs(stream_lock_.get()); bool in_order = InOrderPacketInternal(header.sequenceNumber); ssrc_ = header.ssrc; - incoming_bitrate_.Update(bytes); + incoming_bitrate_.Update(packet_length); receive_counters_.bytes += - bytes - (header.paddingLength + header.headerLength); + packet_length - (header.paddingLength + header.headerLength); receive_counters_.header_bytes += header.headerLength; receive_counters_.padding_bytes += header.paddingLength; ++receive_counters_.packets; if (!in_order && retransmitted) { ++receive_counters_.retransmitted_packets; + receive_counters_.retransmitted_bytes += + packet_length - (header.paddingLength + header.headerLength); + receive_counters_.retransmitted_header_bytes += header.headerLength; + receive_counters_.retransmitted_padding_bytes += header.paddingLength; } if (receive_counters_.packets == 1) { @@ -414,7 +418,7 @@ ReceiveStatisticsImpl::~ReceiveStatisticsImpl() { } void ReceiveStatisticsImpl::IncomingPacket(const RTPHeader& header, - size_t bytes, + size_t packet_length, bool retransmitted) { StreamStatisticianImpl* impl; { @@ -431,7 +435,7 @@ void ReceiveStatisticsImpl::IncomingPacket(const RTPHeader& header, // this whole ReceiveStatisticsImpl is destroyed. StreamStatisticianImpl has // it's own locking so don't hold receive_statistics_lock_ (potential // deadlock). - impl->IncomingPacket(header, bytes, retransmitted); + impl->IncomingPacket(header, packet_length, retransmitted); } void ReceiveStatisticsImpl::FecPacketReceived(uint32_t ssrc) { @@ -527,7 +531,7 @@ void ReceiveStatisticsImpl::DataCountersUpdated(const StreamDataCounters& stats, } void NullReceiveStatistics::IncomingPacket(const RTPHeader& rtp_header, - size_t bytes, + size_t packet_length, bool retransmitted) {} void NullReceiveStatistics::FecPacketReceived(uint32_t ssrc) {} diff --git a/webrtc/modules/rtp_rtcp/source/receive_statistics_impl.h b/webrtc/modules/rtp_rtcp/source/receive_statistics_impl.h index f3eaa580f1..87eea01e85 100644 --- a/webrtc/modules/rtp_rtcp/source/receive_statistics_impl.h +++ b/webrtc/modules/rtp_rtcp/source/receive_statistics_impl.h @@ -42,7 +42,7 @@ class StreamStatisticianImpl : public StreamStatistician { virtual bool IsPacketInOrder(uint16_t sequence_number) const OVERRIDE; void IncomingPacket(const RTPHeader& rtp_header, - size_t bytes, + size_t packet_length, bool retransmitted); void FecPacketReceived(); void SetMaxReorderingThreshold(int max_reordering_threshold); @@ -56,7 +56,7 @@ class StreamStatisticianImpl : public StreamStatistician { uint32_t receive_time_secs, uint32_t receive_time_frac); void UpdateCounters(const RTPHeader& rtp_header, - size_t bytes, + size_t packet_length, bool retransmitted); void NotifyRtpCallback() LOCKS_EXCLUDED(stream_lock_.get()); void NotifyRtcpCallback() LOCKS_EXCLUDED(stream_lock_.get()); @@ -108,7 +108,7 @@ class ReceiveStatisticsImpl : public ReceiveStatistics, // Implement ReceiveStatistics. virtual void IncomingPacket(const RTPHeader& header, - size_t bytes, + size_t packet_length, bool retransmitted) OVERRIDE; virtual void FecPacketReceived(uint32_t ssrc) OVERRIDE; virtual StatisticianMap GetActiveStatisticians() const OVERRIDE; diff --git a/webrtc/modules/rtp_rtcp/source/receive_statistics_unittest.cc b/webrtc/modules/rtp_rtcp/source/receive_statistics_unittest.cc index 808a88028b..6cc60089fb 100644 --- a/webrtc/modules/rtp_rtcp/source/receive_statistics_unittest.cc +++ b/webrtc/modules/rtp_rtcp/source/receive_statistics_unittest.cc @@ -132,6 +132,23 @@ TEST_F(ReceiveStatisticsTest, ActiveStatisticians) { EXPECT_EQ(2u, packets_received); } +TEST_F(ReceiveStatisticsTest, GetReceiveStreamDataCounters) { + receive_statistics_->IncomingPacket(header1_, kPacketSize1, false); + StreamStatistician* statistician = + receive_statistics_->GetStatistician(kSsrc1); + ASSERT_TRUE(statistician != NULL); + + StreamDataCounters counters; + statistician->GetReceiveStreamDataCounters(&counters); + EXPECT_EQ(1u, counters.packets); + + // GetReceiveStreamDataCounters includes reset counter values. + statistician->ResetStatistics(); + receive_statistics_->IncomingPacket(header1_, kPacketSize1, false); + statistician->GetReceiveStreamDataCounters(&counters); + EXPECT_EQ(2u, counters.packets); +} + TEST_F(ReceiveStatisticsTest, RtcpCallbacks) { class TestCallback : public RtcpStatisticsCallback { public: @@ -232,20 +249,22 @@ class RtpTestCallback : public StreamDataCountersCallback { ++num_calls_; } - void ExpectMatches(uint32_t num_calls, - uint32_t ssrc, - size_t bytes, - size_t padding, - uint32_t packets, - uint32_t retransmits, - uint32_t fec) { + void Matches(uint32_t num_calls, + uint32_t ssrc, + const StreamDataCounters& expected) { EXPECT_EQ(num_calls, num_calls_); EXPECT_EQ(ssrc, ssrc_); - EXPECT_EQ(bytes, stats_.bytes); - EXPECT_EQ(padding, stats_.padding_bytes); - EXPECT_EQ(packets, stats_.packets); - EXPECT_EQ(retransmits, stats_.retransmitted_packets); - EXPECT_EQ(fec, stats_.fec_packets); + EXPECT_EQ(expected.bytes, stats_.bytes); + EXPECT_EQ(expected.header_bytes, stats_.header_bytes); + EXPECT_EQ(expected.padding_bytes, stats_.padding_bytes); + EXPECT_EQ(expected.packets, stats_.packets); + EXPECT_EQ(expected.retransmitted_bytes, stats_.retransmitted_bytes); + EXPECT_EQ(expected.retransmitted_header_bytes, + stats_.retransmitted_header_bytes); + EXPECT_EQ(expected.retransmitted_padding_bytes, + stats_.retransmitted_padding_bytes); + EXPECT_EQ(expected.retransmitted_packets, stats_.retransmitted_packets); + EXPECT_EQ(expected.fec_packets, stats_.fec_packets); } uint32_t num_calls_; @@ -264,7 +283,17 @@ TEST_F(ReceiveStatisticsTest, RtpCallbacks) { header1_.headerLength = kHeaderLength; receive_statistics_->IncomingPacket( header1_, kPacketSize1 + kHeaderLength, false); - callback.ExpectMatches(1, kSsrc1, kPacketSize1, 0, 1, 0, 0); + StreamDataCounters expected; + expected.bytes = kPacketSize1; + expected.header_bytes = kHeaderLength; + expected.padding_bytes = 0; + expected.packets = 1; + expected.retransmitted_bytes = 0; + expected.retransmitted_header_bytes = 0; + expected.retransmitted_padding_bytes = 0; + expected.retransmitted_packets = 0; + expected.fec_packets = 0; + callback.Matches(1, kSsrc1, expected); ++header1_.sequenceNumber; clock_.AdvanceTimeMilliseconds(5); @@ -272,14 +301,25 @@ TEST_F(ReceiveStatisticsTest, RtpCallbacks) { // Another packet of size kPacketSize1 with 9 bytes padding. receive_statistics_->IncomingPacket( header1_, kPacketSize1 + kHeaderLength + kPaddingLength, false); - callback.ExpectMatches(2, kSsrc1, 2 * kPacketSize1, kPaddingLength, 2, 0, 0); + expected.bytes = kPacketSize1 * 2; + expected.header_bytes = kHeaderLength * 2; + expected.padding_bytes = kPaddingLength; + expected.packets = 2; + callback.Matches(2, kSsrc1, expected); clock_.AdvanceTimeMilliseconds(5); // Retransmit last packet. receive_statistics_->IncomingPacket( header1_, kPacketSize1 + kHeaderLength + kPaddingLength, true); - callback.ExpectMatches( - 3, kSsrc1, 3 * kPacketSize1, kPaddingLength * 2, 3, 1, 0); + expected.bytes = kPacketSize1 * 3; + expected.header_bytes = kHeaderLength * 3; + expected.padding_bytes = kPaddingLength * 2; + expected.packets = 3; + expected.retransmitted_bytes = kPacketSize1; + expected.retransmitted_header_bytes = kHeaderLength; + expected.retransmitted_padding_bytes = kPaddingLength; + expected.retransmitted_packets = 1; + callback.Matches(3, kSsrc1, expected); header1_.paddingLength = 0; ++header1_.sequenceNumber; @@ -288,8 +328,11 @@ TEST_F(ReceiveStatisticsTest, RtpCallbacks) { receive_statistics_->IncomingPacket( header1_, kPacketSize1 + kHeaderLength, false); receive_statistics_->FecPacketReceived(kSsrc1); - callback.ExpectMatches( - 5, kSsrc1, 4 * kPacketSize1, kPaddingLength * 2, 4, 1, 1); + expected.bytes = kPacketSize1 * 4; + expected.header_bytes = kHeaderLength * 4; + expected.packets = 4; + expected.fec_packets = 1; + callback.Matches(5, kSsrc1, expected); receive_statistics_->RegisterRtpStatisticsCallback(NULL); @@ -298,8 +341,7 @@ TEST_F(ReceiveStatisticsTest, RtpCallbacks) { clock_.AdvanceTimeMilliseconds(5); receive_statistics_->IncomingPacket( header1_, kPacketSize1 + kHeaderLength, true); - callback.ExpectMatches( - 5, kSsrc1, 4 * kPacketSize1, kPaddingLength * 2, 4, 1, 1); + callback.Matches(5, kSsrc1, expected); } TEST_F(ReceiveStatisticsTest, RtpCallbacksFecFirst) { @@ -315,9 +357,16 @@ TEST_F(ReceiveStatisticsTest, RtpCallbacksFecFirst) { header1_.headerLength = kHeaderLength; receive_statistics_->IncomingPacket( header1_, kPacketSize1 + kHeaderLength, false); - callback.ExpectMatches(1, kSsrc1, kPacketSize1, 0, 1, 0, 0); + StreamDataCounters expected; + expected.bytes = kPacketSize1; + expected.header_bytes = kHeaderLength; + expected.padding_bytes = 0; + expected.packets = 1; + expected.fec_packets = 0; + callback.Matches(1, kSsrc1, expected); receive_statistics_->FecPacketReceived(kSsrc1); - callback.ExpectMatches(2, kSsrc1, kPacketSize1, 0, 1, 0, 1); + expected.fec_packets = 1; + callback.Matches(2, kSsrc1, expected); } } // 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 44f7231016..f1f1dd6a16 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.cc @@ -803,6 +803,7 @@ bool ModuleRtpRtcpImpl::RtcpXrRrtrStatus() const { return rtcp_sender_.RtcpXrReceiverReferenceTime(); } +// TODO(asapersson): Replace this method with the one below. int32_t ModuleRtpRtcpImpl::DataCountersRTP( size_t* bytes_sent, uint32_t* packets_sent) const { @@ -821,6 +822,12 @@ int32_t ModuleRtpRtcpImpl::DataCountersRTP( return 0; } +void ModuleRtpRtcpImpl::GetSendStreamDataCounters( + StreamDataCounters* rtp_counters, + StreamDataCounters* rtx_counters) const { + rtp_sender_.GetDataCounters(rtp_counters, rtx_counters); +} + int32_t ModuleRtpRtcpImpl::RemoteRTCPStat(RTCPSenderInfo* sender_info) { return rtcp_receiver_.SenderInfoReceived(sender_info); } diff --git a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h index dd99a9d869..0b6de8ecfb 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h +++ b/webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h @@ -177,6 +177,10 @@ class ModuleRtpRtcpImpl : public RtpRtcp { virtual int32_t DataCountersRTP(size_t* bytes_sent, uint32_t* packets_sent) const OVERRIDE; + virtual void GetSendStreamDataCounters( + StreamDataCounters* rtp_counters, + StreamDataCounters* rtx_counters) const OVERRIDE; + // Get received RTCP report, sender info. virtual int32_t RemoteRTCPStat(RTCPSenderInfo* sender_info) OVERRIDE; diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender.cc b/webrtc/modules/rtp_rtcp/source/rtp_sender.cc index f1327ac170..7c4307f01a 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_sender.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_sender.cc @@ -890,7 +890,7 @@ bool RTPSender::PrepareAndSendPacket(uint8_t* buffer, } void RTPSender::UpdateRtpStats(const uint8_t* buffer, - size_t size, + size_t packet_length, const RTPHeader& header, bool is_rtx, bool is_retransmit) { @@ -905,7 +905,7 @@ void RTPSender::UpdateRtpStats(const uint8_t* buffer, counters = &rtp_stats_; } - total_bitrate_sent_.Update(size); + total_bitrate_sent_.Update(packet_length); ++counters->packets; if (IsFecPacket(buffer, header)) { ++counters->fec_packets; @@ -913,11 +913,15 @@ void RTPSender::UpdateRtpStats(const uint8_t* buffer, if (is_retransmit) { ++counters->retransmitted_packets; - } else { - counters->bytes += size - (header.headerLength + header.paddingLength); - counters->header_bytes += header.headerLength; - counters->padding_bytes += header.paddingLength; + counters->retransmitted_bytes += + packet_length - (header.headerLength + header.paddingLength); + counters->retransmitted_header_bytes += header.headerLength; + counters->retransmitted_padding_bytes += header.paddingLength; } + counters->bytes += + packet_length - (header.headerLength + header.paddingLength); + counters->header_bytes += header.headerLength; + counters->padding_bytes += header.paddingLength; if (rtp_stats_callback_) { rtp_stats_callback_->DataCountersUpdated(*counters, ssrc); diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender.h b/webrtc/modules/rtp_rtcp/source/rtp_sender.h index 0558c19165..795331a60b 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_sender.h +++ b/webrtc/modules/rtp_rtcp/source/rtp_sender.h @@ -327,7 +327,7 @@ class RTPSender : public RTPSenderInterface { const int64_t now_ms) const; void UpdateRtpStats(const uint8_t* buffer, - size_t size, + size_t packet_length, const RTPHeader& header, bool is_rtx, bool is_retransmit); diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc b/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc index 905b55907f..866258be7e 100644 --- a/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc +++ b/webrtc/modules/rtp_rtcp/source/rtp_sender_unittest.cc @@ -927,16 +927,20 @@ TEST_F(RtpSenderTest, StreamDataCountersCallbacks) { uint32_t ssrc_; StreamDataCounters counters_; - bool Matches(uint32_t ssrc, size_t bytes, size_t header_bytes, - size_t padding, uint32_t packets, uint32_t retransmits, - uint32_t fec) { - return ssrc_ == ssrc && - counters_.bytes == bytes && - counters_.header_bytes == header_bytes && - counters_.padding_bytes == padding && - counters_.packets == packets && - counters_.retransmitted_packets == retransmits && - counters_.fec_packets == fec; + void Matches(uint32_t ssrc, const StreamDataCounters& counters) { + EXPECT_EQ(ssrc, ssrc_); + EXPECT_EQ(counters.bytes, counters_.bytes); + EXPECT_EQ(counters.header_bytes, counters_.header_bytes); + EXPECT_EQ(counters.padding_bytes, counters_.padding_bytes); + EXPECT_EQ(counters.packets, counters_.packets); + EXPECT_EQ(counters.retransmitted_bytes, counters_.retransmitted_bytes); + EXPECT_EQ(counters.retransmitted_header_bytes, + counters_.retransmitted_header_bytes); + EXPECT_EQ(counters.retransmitted_padding_bytes, + counters_.retransmitted_padding_bytes); + EXPECT_EQ(counters.retransmitted_packets, + counters_.retransmitted_packets); + EXPECT_EQ(counters.fec_packets, counters_.fec_packets); } } callback; @@ -957,21 +961,37 @@ TEST_F(RtpSenderTest, StreamDataCountersCallbacks) { ASSERT_EQ(0, rtp_sender_->SendOutgoingData(kVideoFrameKey, payload_type, 1234, 4321, payload, sizeof(payload), NULL)); - - // {bytes = 6, header = 12, padding = 0, packets = 1, retrans = 0, fec = 0} - EXPECT_TRUE(callback.Matches(ssrc, 6, 12, 0, 1, 0, 0)); + StreamDataCounters expected; + expected.bytes = 6; + expected.header_bytes = 12; + expected.padding_bytes = 0; + expected.packets = 1; + expected.retransmitted_bytes = 0; + expected.retransmitted_header_bytes = 0; + expected.retransmitted_padding_bytes = 0; + expected.retransmitted_packets = 0; + expected.fec_packets = 0; + callback.Matches(ssrc, expected); // Retransmit a frame. uint16_t seqno = rtp_sender_->SequenceNumber() - 1; rtp_sender_->ReSendPacket(seqno, 0); - - // bytes = 6, header = 12, padding = 0, packets = 2, retrans = 1, fec = 0} - EXPECT_TRUE(callback.Matches(ssrc, 6, 12, 0, 2, 1, 0)); + expected.bytes = 12; + expected.header_bytes = 24; + expected.packets = 2; + expected.retransmitted_bytes = 6; + expected.retransmitted_header_bytes = 12; + expected.retransmitted_padding_bytes = 0; + expected.retransmitted_packets = 1; + callback.Matches(ssrc, expected); // Send padding. rtp_sender_->TimeToSendPadding(kMaxPaddingSize); - // {bytes = 6, header = 24, padding = 224, packets = 3, retrans = 1, fec = 0} - EXPECT_TRUE(callback.Matches(ssrc, 6, 24, kMaxPaddingSize, 3, 1, 0)); + expected.bytes = 12; + expected.header_bytes = 36; + expected.padding_bytes = kMaxPaddingSize; + expected.packets = 3; + callback.Matches(ssrc, expected); // Send FEC. rtp_sender_->SetGenericFECStatus(true, kRedPayloadType, kUlpfecPayloadType); @@ -984,9 +1004,11 @@ TEST_F(RtpSenderTest, StreamDataCountersCallbacks) { ASSERT_EQ(0, rtp_sender_->SendOutgoingData(kVideoFrameDelta, payload_type, 1234, 4321, payload, sizeof(payload), NULL)); - - // {bytes = 34, header = 48, padding = 224, packets = 5, retrans = 1, fec = 1} - EXPECT_TRUE(callback.Matches(ssrc, 34, 48, kMaxPaddingSize, 5, 1, 1)); + expected.bytes = 40; + expected.header_bytes = 60; + expected.packets = 5; + expected.fec_packets = 1; + callback.Matches(ssrc, expected); rtp_sender_->RegisterRtpStatisticsCallback(NULL); } @@ -1147,9 +1169,12 @@ TEST_F(RtpSenderTest, BytesReportedCorrectly) { EXPECT_EQ(rtx_stats.header_bytes, 24u); EXPECT_EQ(rtx_stats.padding_bytes, 2 * kMaxPaddingSize); + EXPECT_EQ(rtp_stats.TotalBytes(), + rtp_stats.bytes + rtp_stats.header_bytes + rtp_stats.padding_bytes); + EXPECT_EQ(rtx_stats.TotalBytes(), + rtx_stats.bytes + rtx_stats.header_bytes + rtx_stats.padding_bytes); + EXPECT_EQ(transport_.total_bytes_sent_, - rtp_stats.bytes + rtp_stats.header_bytes + rtp_stats.padding_bytes + - rtx_stats.bytes + rtx_stats.header_bytes + - rtx_stats.padding_bytes); + rtp_stats.TotalBytes() + rtx_stats.TotalBytes()); } } // namespace webrtc diff --git a/webrtc/system_wrappers/interface/metrics.h b/webrtc/system_wrappers/interface/metrics.h index 36da4cdc53..1b9426eb24 100644 --- a/webrtc/system_wrappers/interface/metrics.h +++ b/webrtc/system_wrappers/interface/metrics.h @@ -78,6 +78,9 @@ #define RTC_HISTOGRAM_COUNTS_10000(name, sample) RTC_HISTOGRAM_COUNTS( \ name, sample, 1, 10000, 50) +#define RTC_HISTOGRAM_COUNTS_100000(name, sample) RTC_HISTOGRAM_COUNTS( \ + name, sample, 1, 100000, 50) + #define RTC_HISTOGRAM_COUNTS(name, sample, min, max, bucket_count) \ RTC_HISTOGRAM_COMMON_BLOCK(name, sample, \ webrtc::metrics::HistogramFactoryGetCounts( \ diff --git a/webrtc/video_engine/vie_channel.cc b/webrtc/video_engine/vie_channel.cc index e6fbf3ce66..7b65c762c8 100644 --- a/webrtc/video_engine/vie_channel.cc +++ b/webrtc/video_engine/vie_channel.cc @@ -148,7 +148,8 @@ ViEChannel::ViEChannel(int32_t channel_id, nack_history_size_sender_(kSendSidePacketHistorySize), max_nack_reordering_threshold_(kMaxPacketAgeToNack), pre_render_callback_(NULL), - start_ms_(Clock::GetRealTimeClock()->TimeInMilliseconds()) { + start_ms_(Clock::GetRealTimeClock()->TimeInMilliseconds()), + start_send_ms_(0) { RtpRtcp::Configuration configuration = CreateRtpRtcpConfiguration(); configuration.remote_bitrate_estimator = remote_bitrate_estimator; configuration.receive_statistics = vie_receiver_.GetReceiveStatistics(); @@ -236,6 +237,7 @@ ViEChannel::~ViEChannel() { } void ViEChannel::UpdateHistograms() { + // TODO(asapersson): Use time from first sent/received packet. float elapsed_minutes = (Clock::GetRealTimeClock()->TimeInMilliseconds() - start_ms_) / 60000.0f; if (elapsed_minutes < metrics::kMinRunTimeInSeconds / 60.0f) { @@ -271,29 +273,55 @@ void ViEChannel::UpdateHistograms() { RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.PliPacketsSentPerMinute", rtcp_sent.pli_packets / elapsed_minutes); - StreamDataCounters data; - StreamDataCounters rtx_data; - GetReceiveStreamDataCounters(&data, &rtx_data); - uint32_t media_bytes = data.bytes; - uint32_t rtx_bytes = - rtx_data.bytes + rtx_data.header_bytes + rtx_data.padding_bytes; - uint32_t total_bytes = data.bytes + data.header_bytes + data.padding_bytes; - total_bytes += rtx_bytes; - uint32_t padding_bytes = data.padding_bytes + rtx_data.padding_bytes; + StreamDataCounters rtp; + StreamDataCounters rtx; + GetReceiveStreamDataCounters(&rtp, &rtx); + StreamDataCounters rtp_rtx = rtp; + rtp_rtx.Add(rtx); RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.BitrateReceivedInKbps", - total_bytes * 8 / (elapsed_minutes * 60) / 1000); + rtp_rtx.TotalBytes() * 8 / (elapsed_minutes * 60) / 1000); RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.MediaBitrateReceivedInKbps", - media_bytes * 8 / (elapsed_minutes * 60) / 1000); + rtp.MediaPayloadBytes() * 8 / (elapsed_minutes * 60) / 1000); RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.PaddingBitrateReceivedInKbps", - padding_bytes * 8 / (elapsed_minutes * 60) / 1000); + rtp_rtx.padding_bytes * 8 / (elapsed_minutes * 60) / 1000); + RTC_HISTOGRAM_COUNTS_10000( + "WebRTC.Video.RetransmittedBitrateReceivedInKbps", + rtp_rtx.RetransmittedBytes() * 8 / (elapsed_minutes * 60) / 1000); uint32_t ssrc = 0; if (vie_receiver_.GetRtxSsrc(&ssrc)) { RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.RtxBitrateReceivedInKbps", - rtx_bytes * 8 / (elapsed_minutes * 60) / 1000); + rtx.TotalBytes() * 8 / (elapsed_minutes * 60) / 1000); } } } +void ViEChannel::UpdateHistogramsAtStopSend() { + // TODO(asapersson): Use time from first sent packet. + int64_t elapsed_sec = + (Clock::GetRealTimeClock()->TimeInMilliseconds() - start_send_ms_) / 1000; + if (elapsed_sec < metrics::kMinRunTimeInSeconds) { + return; + } + StreamDataCounters rtp; + StreamDataCounters rtx; + GetSendStreamDataCounters(&rtp, &rtx); + StreamDataCounters rtp_rtx = rtp; + rtp_rtx.Add(rtx); + RTC_HISTOGRAM_COUNTS_100000("WebRTC.Video.BitrateSentInKbps", + rtp_rtx.TotalBytes() * 8 / elapsed_sec / 1000); + RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.MediaBitrateSentInKbps", + rtp.MediaPayloadBytes() * 8 / elapsed_sec / 1000); + RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.PaddingBitrateSentInKbps", + rtp_rtx.padding_bytes * 8 / elapsed_sec / 1000); + RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.RetransmittedBitrateSentInKbps", + rtp_rtx.RetransmittedBytes() * 8 / elapsed_sec / 1000); + uint32_t ssrc = 0; + if (vie_receiver_.GetRtxSsrc(&ssrc)) { + RTC_HISTOGRAM_COUNTS_10000("WebRTC.Video.RtxBitrateSentInKbps", + rtx.TotalBytes() * 8 / elapsed_sec / 1000); + } +} + int32_t ViEChannel::SetSendCodec(const VideoCodec& video_codec, bool new_stream) { if (!sender_) { @@ -1174,20 +1202,44 @@ int32_t ViEChannel::GetRtpStatistics(size_t* bytes_sent, return 0; } +void ViEChannel::GetSendStreamDataCounters( + StreamDataCounters* rtp_counters, + StreamDataCounters* rtx_counters) const { + rtp_rtcp_->GetSendStreamDataCounters(rtp_counters, rtx_counters); + CriticalSectionScoped cs(rtp_rtcp_cs_.get()); + for (std::list::const_iterator it = simulcast_rtp_rtcp_.begin(); + it != simulcast_rtp_rtcp_.end(); + it++) { + StreamDataCounters rtp_data; + StreamDataCounters rtx_data; + (*it)->GetSendStreamDataCounters(&rtp_data, &rtx_data); + rtp_counters->Add(rtp_data); + rtx_counters->Add(rtx_data); + } + for (std::list::const_iterator it = removed_rtp_rtcp_.begin(); + it != removed_rtp_rtcp_.end(); ++it) { + StreamDataCounters rtp_data; + StreamDataCounters rtx_data; + (*it)->GetSendStreamDataCounters(&rtp_data, &rtx_data); + rtp_counters->Add(rtp_data); + rtx_counters->Add(rtx_data); + } +} + void ViEChannel::GetReceiveStreamDataCounters( - StreamDataCounters* data, - StreamDataCounters* rtx_data) const { + StreamDataCounters* rtp_counters, + StreamDataCounters* rtx_counters) const { StreamStatistician* statistician = vie_receiver_.GetReceiveStatistics()-> GetStatistician(vie_receiver_.GetRemoteSsrc()); if (statistician) { - statistician->GetReceiveStreamDataCounters(data); + statistician->GetReceiveStreamDataCounters(rtp_counters); } uint32_t rtx_ssrc = 0; if (vie_receiver_.GetRtxSsrc(&rtx_ssrc)) { StreamStatistician* statistician = vie_receiver_.GetReceiveStatistics()->GetStatistician(rtx_ssrc); if (statistician) { - statistician->GetReceiveStreamDataCounters(rtx_data); + statistician->GetReceiveStreamDataCounters(rtx_counters); } } } @@ -1341,10 +1393,12 @@ int32_t ViEChannel::StartSend() { rtp_rtcp->SetSendingMediaStatus(true); rtp_rtcp->SetSendingStatus(true); } + start_send_ms_ = Clock::GetRealTimeClock()->TimeInMilliseconds(); return 0; } int32_t ViEChannel::StopSend() { + UpdateHistogramsAtStopSend(); CriticalSectionScoped cs(rtp_rtcp_cs_.get()); rtp_rtcp_->SetSendingMediaStatus(false); for (std::list::iterator it = simulcast_rtp_rtcp_.begin(); diff --git a/webrtc/video_engine/vie_channel.h b/webrtc/video_engine/vie_channel.h index ffb754c376..88d4a94867 100644 --- a/webrtc/video_engine/vie_channel.h +++ b/webrtc/video_engine/vie_channel.h @@ -194,9 +194,13 @@ class ViEChannel size_t* bytes_received, uint32_t* packets_received) const; + // Gets send statistics for the rtp and rtx stream. + void GetSendStreamDataCounters(StreamDataCounters* rtp_counters, + StreamDataCounters* rtx_counters) const; + // Gets received stream data counters. - void GetReceiveStreamDataCounters(StreamDataCounters* data, - StreamDataCounters* rtx_data) const; + void GetReceiveStreamDataCounters(StreamDataCounters* rtp_counters, + StreamDataCounters* rtx_counters) const; // Called on update of RTP statistics. void RegisterSendChannelRtpStatisticsCallback( @@ -379,6 +383,7 @@ class ViEChannel void SetRtxSendStatus(bool enable); void UpdateHistograms(); + void UpdateHistogramsAtStopSend(); // ViEChannel exposes methods that allow to modify observers and callbacks // to be modified. Such an API-style is cumbersome to implement and maintain @@ -498,6 +503,7 @@ class ViEChannel int max_nack_reordering_threshold_; I420FrameCallback* pre_render_callback_; const int64_t start_ms_; + int64_t start_send_ms_; std::map prev_report_blocks_; };