diff --git a/api/stats/rtcstats_objects.h b/api/stats/rtcstats_objects.h index 36013928ec..0b5d8d2954 100644 --- a/api/stats/rtcstats_objects.h +++ b/api/stats/rtcstats_objects.h @@ -248,6 +248,7 @@ class RTC_EXPORT RTCInboundRtpStreamStats final RTCStatsMember packets_received; RTCStatsMember packets_discarded; RTCStatsMember fec_packets_received; + RTCStatsMember fec_bytes_received; RTCStatsMember fec_packets_discarded; RTCStatsMember bytes_received; RTCStatsMember header_bytes_received; diff --git a/call/BUILD.gn b/call/BUILD.gn index c40cfcf28e..39cbc0a9c1 100644 --- a/call/BUILD.gn +++ b/call/BUILD.gn @@ -67,6 +67,7 @@ rtc_library("call_interfaces") { "../modules/audio_processing", "../modules/audio_processing:api", "../modules/audio_processing:audio_processing_statistics", + "../modules/rtp_rtcp", "../modules/rtp_rtcp:rtp_rtcp_format", "../rtc_base:audio_format_to_string", "../rtc_base:checks", diff --git a/call/flexfec_receive_stream.h b/call/flexfec_receive_stream.h index 4f6fe44afa..c5ac0f9fb6 100644 --- a/call/flexfec_receive_stream.h +++ b/call/flexfec_receive_stream.h @@ -21,6 +21,7 @@ #include "api/rtp_parameters.h" #include "call/receive_stream.h" #include "call/rtp_packet_sink_interface.h" +#include "modules/rtp_rtcp/include/receive_statistics.h" namespace webrtc { @@ -69,6 +70,8 @@ class FlexfecReceiveStream : public RtpPacketSinkInterface, // Called to change the payload type after initialization. virtual void SetPayloadType(int payload_type) = 0; virtual int payload_type() const = 0; + + virtual const ReceiveStatistics* GetStats() const = 0; }; } // namespace webrtc diff --git a/call/flexfec_receive_stream_impl.cc b/call/flexfec_receive_stream_impl.cc index cbfbe55297..e20f1b6ac5 100644 --- a/call/flexfec_receive_stream_impl.cc +++ b/call/flexfec_receive_stream_impl.cc @@ -21,7 +21,6 @@ #include "api/rtp_parameters.h" #include "call/rtp_stream_receiver_controller_interface.h" #include "modules/rtp_rtcp/include/flexfec_receiver.h" -#include "modules/rtp_rtcp/include/receive_statistics.h" #include "modules/rtp_rtcp/source/rtp_packet_received.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" diff --git a/call/flexfec_receive_stream_impl.h b/call/flexfec_receive_stream_impl.h index 73cdff8b73..5ce2cb6f0e 100644 --- a/call/flexfec_receive_stream_impl.h +++ b/call/flexfec_receive_stream_impl.h @@ -70,6 +70,10 @@ class FlexfecReceiveStreamImpl : public FlexfecReceiveStream { rtp_rtcp_->SetRTCPStatus(mode); } + const ReceiveStatistics* GetStats() const override { + return rtp_receive_statistics_.get(); + } + private: RTC_NO_UNIQUE_ADDRESS SequenceChecker packet_sequence_checker_; diff --git a/media/BUILD.gn b/media/BUILD.gn index c0aba7aac1..6a271da117 100644 --- a/media/BUILD.gn +++ b/media/BUILD.gn @@ -538,6 +538,7 @@ rtc_library("rtc_audio_video") { "../modules/audio_processing:audio_processing_statistics", "../modules/audio_processing/aec_dump", "../modules/audio_processing/agc:gain_control_interface", + "../modules/rtp_rtcp", "../modules/rtp_rtcp:rtp_rtcp_format", "../modules/video_coding", "../modules/video_coding:video_codec_interface", diff --git a/media/base/media_channel.h b/media/base/media_channel.h index 99197020cb..dee53bb5ca 100644 --- a/media/base/media_channel.h +++ b/media/base/media_channel.h @@ -462,6 +462,12 @@ struct MediaReceiverInfo { absl::optional codec_payload_type; std::vector local_stats; std::vector remote_stats; + // https://w3c.github.io/webrtc-stats/#dom-rtcinboundrtpstreamstats-fecpacketsreceived + absl::optional fec_packets_received; + // https://w3c.github.io/webrtc-stats/#dom-rtcinboundrtpstreamstats-fecpacketsdiscarded + absl::optional fec_packets_discarded; + // https://w3c.github.io/webrtc-stats/#dom-rtcinboundrtpstreamstats-fecbytesreceived + absl::optional fec_bytes_received; }; struct VoiceSenderInfo : public MediaSenderInfo { @@ -496,8 +502,6 @@ struct VoiceReceiverInfo : public MediaReceiverInfo { uint64_t concealment_events = 0; uint64_t inserted_samples_for_deceleration = 0; uint64_t removed_samples_for_acceleration = 0; - uint64_t fec_packets_received = 0; - uint64_t fec_packets_discarded = 0; // Stats below correspond to similarly-named fields in the WebRTC stats spec. // https://w3c.github.io/webrtc-stats/#dom-rtcreceivedrtpstreamstats uint64_t packets_discarded = 0; diff --git a/media/engine/fake_webrtc_call.h b/media/engine/fake_webrtc_call.h index 7c8b93dde6..92ff1b84d7 100644 --- a/media/engine/fake_webrtc_call.h +++ b/media/engine/fake_webrtc_call.h @@ -348,6 +348,8 @@ class FakeFlexfecReceiveStream final : public webrtc::FlexfecReceiveStream { uint32_t remote_ssrc() const { return config_.rtp.remote_ssrc; } + const webrtc::ReceiveStatistics* GetStats() const override { return nullptr; } + private: void OnRtpPacket(const webrtc::RtpPacketReceived& packet) override; diff --git a/media/engine/webrtc_video_engine.cc b/media/engine/webrtc_video_engine.cc index 68df906b54..3b929eda33 100644 --- a/media/engine/webrtc_video_engine.cc +++ b/media/engine/webrtc_video_engine.cc @@ -51,6 +51,7 @@ #include "media/base/rid_description.h" #include "media/base/rtp_utils.h" #include "media/engine/webrtc_media_engine.h" +#include "modules/rtp_rtcp/include/receive_statistics.h" #include "modules/rtp_rtcp/include/report_block_data.h" #include "modules/rtp_rtcp/include/rtcp_statistics.h" #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" @@ -3652,6 +3653,29 @@ WebRtcVideoReceiveChannel::WebRtcVideoReceiveStream::GetVideoReceiverInfo( info.packets_received += stats.rtx_rtp_stats->packet_counter.packets; } + if (flexfec_stream_) { + const webrtc::ReceiveStatistics* fec_stats = flexfec_stream_->GetStats(); + if (fec_stats) { + const webrtc::StreamStatistician* statistican = + fec_stats->GetStatistician(flexfec_config_.rtp.remote_ssrc); + if (statistican) { + const webrtc::RtpReceiveStats fec_rtp_stats = statistican->GetStats(); + info.fec_packets_received = fec_rtp_stats.packet_counter.packets; + // TODO(bugs.webrtc.org/15250): implement fecPacketsDiscarded. + info.fec_bytes_received = fec_rtp_stats.packet_counter.payload_bytes; + // FEC information gets added to primary counters. + info.payload_bytes_received += + fec_rtp_stats.packet_counter.payload_bytes; + info.header_and_padding_bytes_received += + fec_rtp_stats.packet_counter.header_bytes + + fec_rtp_stats.packet_counter.padding_bytes; + info.packets_received += fec_rtp_stats.packet_counter.packets; + } else { + info.fec_packets_received = 0; + } + } + } + if (log_stats) RTC_LOG(LS_INFO) << stats.ToString(rtc::TimeMillis()); diff --git a/pc/rtc_stats_collector.cc b/pc/rtc_stats_collector.cc index 8cba02b5ce..33b4a6e787 100644 --- a/pc/rtc_stats_collector.cc +++ b/pc/rtc_stats_collector.cc @@ -425,6 +425,17 @@ void SetInboundRTPStreamStatsFromMediaReceiverInfo( if (media_receiver_info.nacks_sent.has_value()) { inbound_stats->nack_count = *media_receiver_info.nacks_sent; } + if (media_receiver_info.fec_packets_received.has_value()) { + inbound_stats->fec_packets_received = + *media_receiver_info.fec_packets_received; + } + if (media_receiver_info.fec_packets_discarded.has_value()) { + inbound_stats->fec_packets_discarded = + *media_receiver_info.fec_packets_discarded; + } + if (media_receiver_info.fec_bytes_received.has_value()) { + inbound_stats->fec_bytes_received = *media_receiver_info.fec_bytes_received; + } } std::unique_ptr CreateInboundAudioStreamStats( @@ -483,10 +494,6 @@ std::unique_ptr CreateInboundAudioStreamStats( inbound_audio->estimated_playout_timestamp = static_cast( *voice_receiver_info.estimated_playout_ntp_timestamp_ms); } - inbound_audio->fec_packets_received = - voice_receiver_info.fec_packets_received; - inbound_audio->fec_packets_discarded = - voice_receiver_info.fec_packets_discarded; inbound_audio->packets_discarded = voice_receiver_info.packets_discarded; inbound_audio->jitter_buffer_flushes = voice_receiver_info.jitter_buffer_flushes; @@ -670,6 +677,7 @@ CreateInboundRTPStreamStatsFromVideoReceiverInfo( inbound_video->power_efficient_decoder = *video_receiver_info.power_efficient_decoder; } + return inbound_video; } diff --git a/pc/rtc_stats_collector_unittest.cc b/pc/rtc_stats_collector_unittest.cc index a9f326f96a..7be06725ee 100644 --- a/pc/rtc_stats_collector_unittest.cc +++ b/pc/rtc_stats_collector_unittest.cc @@ -2348,6 +2348,8 @@ TEST_F(RTCStatsCollectorTest, CollectRTCInboundRtpStreamStats_Video) { video_media_info.receivers[0].power_efficient_decoder = false; video_media_info.receivers[0].retransmitted_packets_received = 17; video_media_info.receivers[0].retransmitted_bytes_received = 62; + video_media_info.receivers[0].fec_packets_received = 32; + video_media_info.receivers[0].fec_bytes_received = 54; // Note: these two values intentionally differ, // only the decoded one should show up. @@ -2412,6 +2414,8 @@ TEST_F(RTCStatsCollectorTest, CollectRTCInboundRtpStreamStats_Video) { expected_video.power_efficient_decoder = false; expected_video.retransmitted_packets_received = 17; expected_video.retransmitted_bytes_received = 62; + expected_video.fec_packets_received = 32; + expected_video.fec_bytes_received = 54; ASSERT_TRUE(report->Get(expected_video.id())); EXPECT_EQ( diff --git a/pc/rtc_stats_integrationtest.cc b/pc/rtc_stats_integrationtest.cc index 12a0063940..fd478655cc 100644 --- a/pc/rtc_stats_integrationtest.cc +++ b/pc/rtc_stats_integrationtest.cc @@ -608,8 +608,13 @@ class RTCStatsReportVerifier { inbound_stream.fec_packets_received); verifier.TestMemberIsNonNegative( inbound_stream.fec_packets_discarded); + verifier.TestMemberIsUndefined(inbound_stream.fec_bytes_received); } else { verifier.TestMemberIsUndefined(inbound_stream.packets_discarded); + // FEC stats are only present when FlexFEC was negotiated which is guarded + // by the WebRTC-FlexFEC-03-Advertised/Enabled/ field trial and off by + // default. + verifier.TestMemberIsUndefined(inbound_stream.fec_bytes_received); verifier.TestMemberIsUndefined(inbound_stream.fec_packets_received); verifier.TestMemberIsUndefined(inbound_stream.fec_packets_discarded); } diff --git a/stats/rtcstats_objects.cc b/stats/rtcstats_objects.cc index 31720ad33f..97786f94bf 100644 --- a/stats/rtcstats_objects.cc +++ b/stats/rtcstats_objects.cc @@ -307,6 +307,7 @@ WEBRTC_RTCSTATS_IMPL( &packets_received, &packets_discarded, &fec_packets_received, + &fec_bytes_received, &fec_packets_discarded, &bytes_received, &header_bytes_received, @@ -371,6 +372,7 @@ RTCInboundRtpStreamStats::RTCInboundRtpStreamStats(std::string id, packets_received("packetsReceived"), packets_discarded("packetsDiscarded"), fec_packets_received("fecPacketsReceived"), + fec_bytes_received("fecBytesReceived"), fec_packets_discarded("fecPacketsDiscarded"), bytes_received("bytesReceived"), header_bytes_received("headerBytesReceived"),