stats: implement remote-outbound-rtp for video
following the audio changes. Note that RTT-related fields require
DLRR and are not implemented yet.
BUG=webrtc:12529
Change-Id: I3f9449fbe876a1b282a32f2bcebe1cf3e10989bf
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/346580
Reviewed-by: Florent Castelli <orphis@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Philipp Hancke <phancke@meta.com>
Cr-Commit-Position: refs/heads/main@{#42069}
diff --git a/call/video_receive_stream.h b/call/video_receive_stream.h
index 12f6bf6..20e9245 100644
--- a/call/video_receive_stream.h
+++ b/call/video_receive_stream.h
@@ -115,9 +115,11 @@
TimeDelta total_decode_time = TimeDelta::Zero();
// https://w3c.github.io/webrtc-stats/#dom-rtcinboundrtpstreamstats-totalprocessingdelay
TimeDelta total_processing_delay = TimeDelta::Zero();
- // TODO(bugs.webrtc.org/13986): standardize
+
+ // https://w3c.github.io/webrtc-stats/#dom-rtcinboundrtpstreamstats-totalassemblytime
TimeDelta total_assembly_time = TimeDelta::Zero();
uint32_t frames_assembled_from_multiple_packets = 0;
+
// Total inter frame delay in seconds.
// https://w3c.github.io/webrtc-stats/#dom-rtcinboundrtpstreamstats-totalinterframedelay
double total_inter_frame_delay = 0;
@@ -154,6 +156,14 @@
// Timing frame info: all important timestamps for a full lifetime of a
// single 'timing frame'.
absl::optional<webrtc::TimingFrameInfo> timing_frame_info;
+
+ // Remote outbound stats derived by the received RTCP sender reports.
+ // https://w3c.github.io/webrtc-stats/#remoteoutboundrtpstats-dict*
+ absl::optional<int64_t> last_sender_report_timestamp_ms;
+ absl::optional<int64_t> last_sender_report_remote_timestamp_ms;
+ uint32_t sender_reports_packets_sent = 0;
+ uint64_t sender_reports_bytes_sent = 0;
+ uint64_t sender_reports_reports_count = 0;
};
struct Config {
diff --git a/media/base/media_channel.h b/media/base/media_channel.h
index f941823..124f68c 100644
--- a/media/base/media_channel.h
+++ b/media/base/media_channel.h
@@ -476,6 +476,19 @@
absl::optional<uint64_t> fec_packets_discarded;
// https://w3c.github.io/webrtc-stats/#dom-rtcinboundrtpstreamstats-fecbytesreceived
absl::optional<uint64_t> fec_bytes_received;
+
+ // Remote outbound stats derived by the received RTCP sender reports.
+ // https://w3c.github.io/webrtc-stats/#remoteoutboundrtpstats-dict*
+ absl::optional<int64_t> last_sender_report_timestamp_ms;
+ absl::optional<int64_t> last_sender_report_remote_timestamp_ms;
+ uint64_t sender_reports_packets_sent = 0;
+ uint64_t sender_reports_bytes_sent = 0;
+ uint64_t sender_reports_reports_count = 0;
+ // These require a DLRR block, see
+ // https://w3c.github.io/webrtc-stats/#dom-rtcremoteoutboundrtpstreamstats-roundtriptime
+ absl::optional<webrtc::TimeDelta> round_trip_time;
+ webrtc::TimeDelta total_round_trip_time = webrtc::TimeDelta::Zero();
+ int round_trip_time_measurements = 0;
};
struct VoiceSenderInfo : public MediaSenderInfo {
@@ -551,16 +564,6 @@
// longer than 150 ms).
int32_t interruption_count = 0;
int32_t total_interruption_duration_ms = 0;
- // Remote outbound stats derived by the received RTCP sender reports.
- // https://w3c.github.io/webrtc-stats/#remoteoutboundrtpstats-dict*
- absl::optional<int64_t> last_sender_report_timestamp_ms;
- absl::optional<int64_t> last_sender_report_remote_timestamp_ms;
- uint64_t sender_reports_packets_sent = 0;
- uint64_t sender_reports_bytes_sent = 0;
- uint64_t sender_reports_reports_count = 0;
- absl::optional<webrtc::TimeDelta> round_trip_time;
- webrtc::TimeDelta total_round_trip_time = webrtc::TimeDelta::Zero();
- int round_trip_time_measurements = 0;
};
struct VideoSenderInfo : public MediaSenderInfo {
diff --git a/media/engine/webrtc_video_engine.cc b/media/engine/webrtc_video_engine.cc
index 24709dd..d4dccdf 100644
--- a/media/engine/webrtc_video_engine.cc
+++ b/media/engine/webrtc_video_engine.cc
@@ -3737,6 +3737,16 @@
}
}
+ // remote-outbound-rtp stats.
+ info.last_sender_report_timestamp_ms = stats.last_sender_report_timestamp_ms;
+ info.last_sender_report_remote_timestamp_ms =
+ stats.last_sender_report_remote_timestamp_ms;
+ info.sender_reports_packets_sent = stats.sender_reports_packets_sent;
+ info.sender_reports_bytes_sent = stats.sender_reports_bytes_sent;
+ info.sender_reports_reports_count = stats.sender_reports_reports_count;
+ // TODO(bugs.webrtc.org/12529): RTT-related fields are missing and can only be
+ // present if DLRR is enabled.
+
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 a49e8ef..1f94b0e 100644
--- a/pc/rtc_stats_collector.cc
+++ b/pc/rtc_stats_collector.cc
@@ -514,53 +514,54 @@
}
std::unique_ptr<RTCRemoteOutboundRtpStreamStats>
-CreateRemoteOutboundAudioStreamStats(
- const cricket::VoiceReceiverInfo& voice_receiver_info,
+CreateRemoteOutboundMediaStreamStats(
+ const cricket::MediaReceiverInfo& media_receiver_info,
const std::string& mid,
+ const std::string& kind,
const RTCInboundRtpStreamStats& inbound_audio_stats,
const std::string& transport_id) {
- if (!voice_receiver_info.last_sender_report_timestamp_ms.has_value()) {
+ if (!media_receiver_info.last_sender_report_timestamp_ms.has_value()) {
// Cannot create `RTCRemoteOutboundRtpStreamStats` when the RTCP SR arrival
// timestamp is not available - i.e., until the first sender report is
// received.
return nullptr;
}
- RTC_DCHECK_GT(voice_receiver_info.sender_reports_reports_count, 0);
+ RTC_DCHECK_GT(media_receiver_info.sender_reports_reports_count, 0);
// Create.
auto stats = std::make_unique<RTCRemoteOutboundRtpStreamStats>(
/*id=*/RTCRemoteOutboundRTPStreamStatsIDFromSSRC(
- cricket::MEDIA_TYPE_AUDIO, voice_receiver_info.ssrc()),
- Timestamp::Millis(*voice_receiver_info.last_sender_report_timestamp_ms));
+ cricket::MEDIA_TYPE_AUDIO, media_receiver_info.ssrc()),
+ Timestamp::Millis(*media_receiver_info.last_sender_report_timestamp_ms));
// Populate.
// - RTCRtpStreamStats.
- stats->ssrc = voice_receiver_info.ssrc();
- stats->kind = "audio";
+ stats->ssrc = media_receiver_info.ssrc();
+ stats->kind = kind;
stats->transport_id = transport_id;
if (inbound_audio_stats.codec_id.has_value()) {
stats->codec_id = *inbound_audio_stats.codec_id;
}
// - RTCSentRtpStreamStats.
- stats->packets_sent = voice_receiver_info.sender_reports_packets_sent;
- stats->bytes_sent = voice_receiver_info.sender_reports_bytes_sent;
+ stats->packets_sent = media_receiver_info.sender_reports_packets_sent;
+ stats->bytes_sent = media_receiver_info.sender_reports_bytes_sent;
// - RTCRemoteOutboundRtpStreamStats.
stats->local_id = inbound_audio_stats.id();
// last_sender_report_remote_timestamp_ms is set together with
// last_sender_report_timestamp_ms.
RTC_DCHECK(
- voice_receiver_info.last_sender_report_remote_timestamp_ms.has_value());
+ media_receiver_info.last_sender_report_remote_timestamp_ms.has_value());
stats->remote_timestamp = static_cast<double>(
- *voice_receiver_info.last_sender_report_remote_timestamp_ms);
- stats->reports_sent = voice_receiver_info.sender_reports_reports_count;
- if (voice_receiver_info.round_trip_time.has_value()) {
+ *media_receiver_info.last_sender_report_remote_timestamp_ms);
+ stats->reports_sent = media_receiver_info.sender_reports_reports_count;
+ if (media_receiver_info.round_trip_time.has_value()) {
stats->round_trip_time =
- voice_receiver_info.round_trip_time->seconds<double>();
+ media_receiver_info.round_trip_time->seconds<double>();
}
stats->round_trip_time_measurements =
- voice_receiver_info.round_trip_time_measurements;
+ media_receiver_info.round_trip_time_measurements;
stats->total_round_trip_time =
- voice_receiver_info.total_round_trip_time.seconds<double>();
+ media_receiver_info.total_round_trip_time.seconds<double>();
return stats;
}
@@ -1709,8 +1710,8 @@
continue;
}
// Remote-outbound.
- auto remote_outbound_audio = CreateRemoteOutboundAudioStreamStats(
- voice_receiver_info, mid, *inbound_audio_ptr, transport_id);
+ auto remote_outbound_audio = CreateRemoteOutboundMediaStreamStats(
+ voice_receiver_info, mid, "audio", *inbound_audio_ptr, transport_id);
// Add stats.
if (remote_outbound_audio) {
// When the remote outbound stats are available, the remote ID for the
@@ -1782,7 +1783,7 @@
std::string mid = *stats.mid;
std::string transport_id = RTCTransportStatsIDFromTransportChannel(
*stats.transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
- // Inbound
+ // Inbound and remote-outbound.
for (const cricket::VideoReceiverInfo& video_receiver_info :
stats.track_media_info_map.video_media_info()->receivers) {
if (!video_receiver_info.connected())
@@ -1795,9 +1796,27 @@
if (video_track) {
inbound_video->track_identifier = video_track->id();
}
- if (!report->TryAddStats(std::move(inbound_video))) {
+ auto* inbound_video_ptr = report->TryAddStats(std::move(inbound_video));
+ if (!inbound_video_ptr) {
RTC_LOG(LS_ERROR)
<< "Unable to add video 'inbound-rtp' to report, ID is not unique.";
+ continue;
+ }
+ // Remote-outbound.
+ auto remote_outbound_video = CreateRemoteOutboundMediaStreamStats(
+ video_receiver_info, mid, "video", *inbound_video_ptr, transport_id);
+ // Add stats.
+ if (remote_outbound_video) {
+ // When the remote outbound stats are available, the remote ID for the
+ // local inbound stats is set.
+ auto* remote_outbound_video_ptr =
+ report->TryAddStats(std::move(remote_outbound_video));
+ if (remote_outbound_video_ptr) {
+ inbound_video_ptr->remote_id = remote_outbound_video_ptr->id();
+ } else {
+ RTC_LOG(LS_ERROR) << "Unable to add video 'remote-outbound-rtp' to "
+ << "report, ID is not unique.";
+ }
}
}
// Outbound
diff --git a/pc/rtc_stats_integrationtest.cc b/pc/rtc_stats_integrationtest.cc
index de8e6e3..1ff060c 100644
--- a/pc/rtc_stats_integrationtest.cc
+++ b/pc/rtc_stats_integrationtest.cc
@@ -939,10 +939,16 @@
VerifyRTCRtpStreamStats(remote_outbound_stream, verifier);
VerifyRTCSentRtpStreamStats(remote_outbound_stream, verifier);
verifier.TestAttributeIsIDReference(remote_outbound_stream.local_id,
- RTCOutboundRtpStreamStats::kType);
+ RTCInboundRtpStreamStats::kType);
verifier.TestAttributeIsNonNegative<double>(
remote_outbound_stream.remote_timestamp);
verifier.TestAttributeIsDefined(remote_outbound_stream.reports_sent);
+ // RTT-related attributes need DLRR.
+ verifier.MarkAttributeTested(remote_outbound_stream.round_trip_time, true);
+ verifier.MarkAttributeTested(
+ remote_outbound_stream.round_trip_time_measurements, true);
+ verifier.MarkAttributeTested(remote_outbound_stream.total_round_trip_time,
+ true);
return verifier.ExpectAllAttributesSuccessfullyTested();
}
diff --git a/video/rtp_video_stream_receiver2.cc b/video/rtp_video_stream_receiver2.cc
index 8fef92c..ae9cb19 100644
--- a/video/rtp_video_stream_receiver2.cc
+++ b/video/rtp_video_stream_receiver2.cc
@@ -1048,6 +1048,12 @@
return absl::nullopt;
}
+absl::optional<RtpRtcpInterface::SenderReportStats>
+RtpVideoStreamReceiver2::GetSenderReportStats() const {
+ RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
+ return rtp_rtcp_->GetSenderReportStats();
+}
+
void RtpVideoStreamReceiver2::ManageFrame(
std::unique_ptr<RtpFrameObject> frame) {
RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
diff --git a/video/rtp_video_stream_receiver2.h b/video/rtp_video_stream_receiver2.h
index 1621283..8ea3ffd 100644
--- a/video/rtp_video_stream_receiver2.h
+++ b/video/rtp_video_stream_receiver2.h
@@ -209,6 +209,9 @@
absl::optional<uint32_t> LastReceivedFrameRtpTimestamp() const;
absl::optional<int64_t> LastReceivedKeyframePacketMs() const;
+ absl::optional<RtpRtcpInterface::SenderReportStats> GetSenderReportStats()
+ const;
+
private:
// Implements RtpVideoFrameReceiver.
void ManageFrame(std::unique_ptr<RtpFrameObject> frame) override;
diff --git a/video/video_receive_stream2.cc b/video/video_receive_stream2.cc
index 7d307c6..6f63f76 100644
--- a/video/video_receive_stream2.cc
+++ b/video/video_receive_stream2.cc
@@ -568,6 +568,18 @@
stats.rtx_rtp_stats = rtx_statistician->GetStats();
}
}
+
+ absl::optional<RtpRtcpInterface::SenderReportStats> rtcp_sr_stats =
+ rtp_video_stream_receiver_.GetSenderReportStats();
+ if (rtcp_sr_stats) {
+ stats.last_sender_report_timestamp_ms =
+ rtcp_sr_stats->last_arrival_timestamp.ToMs();
+ stats.last_sender_report_remote_timestamp_ms =
+ rtcp_sr_stats->last_remote_timestamp.ToMs();
+ stats.sender_reports_packets_sent = rtcp_sr_stats->packets_sent;
+ stats.sender_reports_bytes_sent = rtcp_sr_stats->bytes_sent;
+ stats.sender_reports_reports_count = rtcp_sr_stats->reports_count;
+ }
return stats;
}