diff --git a/api/stats/rtcstats_objects.h b/api/stats/rtcstats_objects.h index 0b5d8d2954..4861f8ab84 100644 --- a/api/stats/rtcstats_objects.h +++ b/api/stats/rtcstats_objects.h @@ -256,6 +256,8 @@ class RTC_EXPORT RTCInboundRtpStreamStats final // possible to distinguish retransmissions. RTCStatsMember retransmitted_packets_received; RTCStatsMember retransmitted_bytes_received; + RTCStatsMember rtx_ssrc; + RTCStatsMember last_packet_received_timestamp; RTCStatsMember jitter_buffer_delay; RTCStatsMember jitter_buffer_target_delay; @@ -368,6 +370,9 @@ class RTC_EXPORT RTCOutboundRtpStreamStats final // In JavaScript, this is only exposed if HW exposure is allowed. RTCStatsMember power_efficient_encoder; RTCStatsMember scalability_mode; + + // RTX ssrc. Only present if RTX is negotiated. + RTCStatsMember rtx_ssrc; }; // https://w3c.github.io/webrtc-stats/#remoteinboundrtpstats-dict* diff --git a/pc/rtc_stats_collector.cc b/pc/rtc_stats_collector.cc index 07e8771f2f..0c4df20093 100644 --- a/pc/rtc_stats_collector.cc +++ b/pc/rtc_stats_collector.cc @@ -677,6 +677,12 @@ CreateInboundRTPStreamStatsFromVideoReceiverInfo( inbound_video->power_efficient_decoder = *video_receiver_info.power_efficient_decoder; } + for (const auto& ssrc_group : video_receiver_info.ssrc_groups) { + if (ssrc_group.semantics == cricket::kFidSsrcGroupSemantics && + ssrc_group.ssrcs.size() == 2) { + inbound_video->rtx_ssrc = ssrc_group.ssrcs[1]; + } + } return inbound_video; } @@ -826,6 +832,12 @@ CreateOutboundRTPStreamStatsFromVideoSenderInfo( outbound_video->scalability_mode = std::string( ScalabilityModeToString(*video_sender_info.scalability_mode)); } + for (const auto& ssrc_group : video_sender_info.ssrc_groups) { + if (ssrc_group.semantics == cricket::kFidSsrcGroupSemantics && + ssrc_group.ssrcs.size() == 2) { + outbound_video->rtx_ssrc = ssrc_group.ssrcs[1]; + } + } return outbound_video; } diff --git a/pc/rtc_stats_collector_unittest.cc b/pc/rtc_stats_collector_unittest.cc index 8781b323d6..788c884a54 100644 --- a/pc/rtc_stats_collector_unittest.cc +++ b/pc/rtc_stats_collector_unittest.cc @@ -2368,6 +2368,8 @@ TEST_F(RTCStatsCollectorTest, CollectRTCInboundRtpStreamStats_Video) { 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; + video_media_info.receivers[0].ssrc_groups.push_back( + {cricket::kFidSsrcGroupSemantics, {1, 4404}}); // Note: these two values intentionally differ, // only the decoded one should show up. @@ -2434,6 +2436,7 @@ TEST_F(RTCStatsCollectorTest, CollectRTCInboundRtpStreamStats_Video) { expected_video.retransmitted_bytes_received = 62; expected_video.fec_packets_received = 32; expected_video.fec_bytes_received = 54; + expected_video.rtx_ssrc = 4404; ASSERT_TRUE(report->Get(expected_video.id())); EXPECT_EQ( @@ -2629,6 +2632,8 @@ TEST_F(RTCStatsCollectorTest, CollectRTCOutboundRtpStreamStats_Video) { video_media_info.senders[0].huge_frames_sent = 2; video_media_info.senders[0].active = false; video_media_info.senders[0].scalability_mode = ScalabilityMode::kL3T3_KEY; + video_media_info.senders[0].ssrc_groups.push_back( + {cricket::kFidSsrcGroupSemantics, {1, 4404}}); video_media_info.aggregated_senders.push_back(video_media_info.senders[0]); RtpCodecParameters codec_parameters; codec_parameters.payload_type = 42; @@ -2684,6 +2689,7 @@ TEST_F(RTCStatsCollectorTest, CollectRTCOutboundRtpStreamStats_Video) { expected_video.active = false; expected_video.power_efficient_encoder = false; expected_video.scalability_mode = "L3T3_KEY"; + expected_video.rtx_ssrc = 4404; // `expected_video.content_type` should be undefined. // `expected_video.qp_sum` should be undefined. // `expected_video.encoder_implementation` should be undefined. diff --git a/pc/rtc_stats_integrationtest.cc b/pc/rtc_stats_integrationtest.cc index fd478655cc..3e767a77e3 100644 --- a/pc/rtc_stats_integrationtest.cc +++ b/pc/rtc_stats_integrationtest.cc @@ -693,11 +693,13 @@ class RTCStatsReportVerifier { inbound_stream.retransmitted_packets_received); verifier.TestMemberIsNonNegative( inbound_stream.retransmitted_bytes_received); + verifier.TestMemberIsNonNegative(inbound_stream.rtx_ssrc); } else { verifier.TestMemberIsUndefined( inbound_stream.retransmitted_packets_received); verifier.TestMemberIsUndefined( inbound_stream.retransmitted_bytes_received); + verifier.TestMemberIsUndefined(inbound_stream.rtx_ssrc); } // Test runtime too short to get an estimate (at least two RTCP sender @@ -849,6 +851,7 @@ class RTCStatsReportVerifier { outbound_stream.huge_frames_sent); verifier.MarkMemberTested(outbound_stream.rid, true); verifier.TestMemberIsDefined(outbound_stream.scalability_mode); + verifier.TestMemberIsNonNegative(outbound_stream.rtx_ssrc); } else { verifier.TestMemberIsUndefined(outbound_stream.frames_encoded); verifier.TestMemberIsUndefined(outbound_stream.key_frames_encoded); @@ -871,6 +874,7 @@ class RTCStatsReportVerifier { verifier.TestMemberIsUndefined(outbound_stream.frames_sent); verifier.TestMemberIsUndefined(outbound_stream.huge_frames_sent); verifier.TestMemberIsUndefined(outbound_stream.scalability_mode); + verifier.TestMemberIsUndefined(outbound_stream.rtx_ssrc); } return verifier.ExpectAllMembersSuccessfullyTested(); } diff --git a/stats/rtcstats_objects.cc b/stats/rtcstats_objects.cc index 97786f94bf..fbd597cf1a 100644 --- a/stats/rtcstats_objects.cc +++ b/stats/rtcstats_objects.cc @@ -313,6 +313,7 @@ WEBRTC_RTCSTATS_IMPL( &header_bytes_received, &retransmitted_packets_received, &retransmitted_bytes_received, + &rtx_ssrc, &last_packet_received_timestamp, &jitter_buffer_delay, &jitter_buffer_target_delay, @@ -378,6 +379,7 @@ RTCInboundRtpStreamStats::RTCInboundRtpStreamStats(std::string id, header_bytes_received("headerBytesReceived"), retransmitted_packets_received("retransmittedPacketsReceived"), retransmitted_bytes_received("retransmittedBytesReceived"), + rtx_ssrc("rtxSsrc"), last_packet_received_timestamp("lastPacketReceivedTimestamp"), jitter_buffer_delay("jitterBufferDelay"), jitter_buffer_target_delay("jitterBufferTargetDelay"), @@ -462,7 +464,8 @@ WEBRTC_RTCSTATS_IMPL( &qp_sum, &active, &power_efficient_encoder, - &scalability_mode) + &scalability_mode, + &rtx_ssrc) // clang-format on RTCOutboundRtpStreamStats::RTCOutboundRtpStreamStats(std::string id, @@ -498,7 +501,8 @@ RTCOutboundRtpStreamStats::RTCOutboundRtpStreamStats(std::string id, qp_sum("qpSum"), active("active"), power_efficient_encoder("powerEfficientEncoder"), - scalability_mode("scalabilityMode") {} + scalability_mode("scalabilityMode"), + rtx_ssrc("rtxSsrc") {} RTCOutboundRtpStreamStats::RTCOutboundRtpStreamStats( const RTCOutboundRtpStreamStats& other) = default;