mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-13 05:40:42 +01:00
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}
This commit is contained in:
parent
7167c6fec9
commit
8f16289e10
8 changed files with 102 additions and 33 deletions
|
@ -115,9 +115,11 @@ class VideoReceiveStreamInterface : public MediaReceiveStreamInterface {
|
||||||
TimeDelta total_decode_time = TimeDelta::Zero();
|
TimeDelta total_decode_time = TimeDelta::Zero();
|
||||||
// https://w3c.github.io/webrtc-stats/#dom-rtcinboundrtpstreamstats-totalprocessingdelay
|
// https://w3c.github.io/webrtc-stats/#dom-rtcinboundrtpstreamstats-totalprocessingdelay
|
||||||
TimeDelta total_processing_delay = TimeDelta::Zero();
|
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();
|
TimeDelta total_assembly_time = TimeDelta::Zero();
|
||||||
uint32_t frames_assembled_from_multiple_packets = 0;
|
uint32_t frames_assembled_from_multiple_packets = 0;
|
||||||
|
|
||||||
// Total inter frame delay in seconds.
|
// Total inter frame delay in seconds.
|
||||||
// https://w3c.github.io/webrtc-stats/#dom-rtcinboundrtpstreamstats-totalinterframedelay
|
// https://w3c.github.io/webrtc-stats/#dom-rtcinboundrtpstreamstats-totalinterframedelay
|
||||||
double total_inter_frame_delay = 0;
|
double total_inter_frame_delay = 0;
|
||||||
|
@ -154,6 +156,14 @@ class VideoReceiveStreamInterface : public MediaReceiveStreamInterface {
|
||||||
// Timing frame info: all important timestamps for a full lifetime of a
|
// Timing frame info: all important timestamps for a full lifetime of a
|
||||||
// single 'timing frame'.
|
// single 'timing frame'.
|
||||||
absl::optional<webrtc::TimingFrameInfo> timing_frame_info;
|
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 {
|
struct Config {
|
||||||
|
|
|
@ -476,6 +476,19 @@ struct MediaReceiverInfo {
|
||||||
absl::optional<uint64_t> fec_packets_discarded;
|
absl::optional<uint64_t> fec_packets_discarded;
|
||||||
// https://w3c.github.io/webrtc-stats/#dom-rtcinboundrtpstreamstats-fecbytesreceived
|
// https://w3c.github.io/webrtc-stats/#dom-rtcinboundrtpstreamstats-fecbytesreceived
|
||||||
absl::optional<uint64_t> fec_bytes_received;
|
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 {
|
struct VoiceSenderInfo : public MediaSenderInfo {
|
||||||
|
@ -551,16 +564,6 @@ struct VoiceReceiverInfo : public MediaReceiverInfo {
|
||||||
// longer than 150 ms).
|
// longer than 150 ms).
|
||||||
int32_t interruption_count = 0;
|
int32_t interruption_count = 0;
|
||||||
int32_t total_interruption_duration_ms = 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 {
|
struct VideoSenderInfo : public MediaSenderInfo {
|
||||||
|
|
|
@ -3737,6 +3737,16 @@ WebRtcVideoReceiveChannel::WebRtcVideoReceiveStream::GetVideoReceiverInfo(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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)
|
if (log_stats)
|
||||||
RTC_LOG(LS_INFO) << stats.ToString(rtc::TimeMillis());
|
RTC_LOG(LS_INFO) << stats.ToString(rtc::TimeMillis());
|
||||||
|
|
||||||
|
|
|
@ -514,53 +514,54 @@ std::unique_ptr<RTCAudioPlayoutStats> CreateAudioPlayoutStats(
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<RTCRemoteOutboundRtpStreamStats>
|
std::unique_ptr<RTCRemoteOutboundRtpStreamStats>
|
||||||
CreateRemoteOutboundAudioStreamStats(
|
CreateRemoteOutboundMediaStreamStats(
|
||||||
const cricket::VoiceReceiverInfo& voice_receiver_info,
|
const cricket::MediaReceiverInfo& media_receiver_info,
|
||||||
const std::string& mid,
|
const std::string& mid,
|
||||||
|
const std::string& kind,
|
||||||
const RTCInboundRtpStreamStats& inbound_audio_stats,
|
const RTCInboundRtpStreamStats& inbound_audio_stats,
|
||||||
const std::string& transport_id) {
|
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
|
// Cannot create `RTCRemoteOutboundRtpStreamStats` when the RTCP SR arrival
|
||||||
// timestamp is not available - i.e., until the first sender report is
|
// timestamp is not available - i.e., until the first sender report is
|
||||||
// received.
|
// received.
|
||||||
return nullptr;
|
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.
|
// Create.
|
||||||
auto stats = std::make_unique<RTCRemoteOutboundRtpStreamStats>(
|
auto stats = std::make_unique<RTCRemoteOutboundRtpStreamStats>(
|
||||||
/*id=*/RTCRemoteOutboundRTPStreamStatsIDFromSSRC(
|
/*id=*/RTCRemoteOutboundRTPStreamStatsIDFromSSRC(
|
||||||
cricket::MEDIA_TYPE_AUDIO, voice_receiver_info.ssrc()),
|
cricket::MEDIA_TYPE_AUDIO, media_receiver_info.ssrc()),
|
||||||
Timestamp::Millis(*voice_receiver_info.last_sender_report_timestamp_ms));
|
Timestamp::Millis(*media_receiver_info.last_sender_report_timestamp_ms));
|
||||||
|
|
||||||
// Populate.
|
// Populate.
|
||||||
// - RTCRtpStreamStats.
|
// - RTCRtpStreamStats.
|
||||||
stats->ssrc = voice_receiver_info.ssrc();
|
stats->ssrc = media_receiver_info.ssrc();
|
||||||
stats->kind = "audio";
|
stats->kind = kind;
|
||||||
stats->transport_id = transport_id;
|
stats->transport_id = transport_id;
|
||||||
if (inbound_audio_stats.codec_id.has_value()) {
|
if (inbound_audio_stats.codec_id.has_value()) {
|
||||||
stats->codec_id = *inbound_audio_stats.codec_id;
|
stats->codec_id = *inbound_audio_stats.codec_id;
|
||||||
}
|
}
|
||||||
// - RTCSentRtpStreamStats.
|
// - RTCSentRtpStreamStats.
|
||||||
stats->packets_sent = voice_receiver_info.sender_reports_packets_sent;
|
stats->packets_sent = media_receiver_info.sender_reports_packets_sent;
|
||||||
stats->bytes_sent = voice_receiver_info.sender_reports_bytes_sent;
|
stats->bytes_sent = media_receiver_info.sender_reports_bytes_sent;
|
||||||
// - RTCRemoteOutboundRtpStreamStats.
|
// - RTCRemoteOutboundRtpStreamStats.
|
||||||
stats->local_id = inbound_audio_stats.id();
|
stats->local_id = inbound_audio_stats.id();
|
||||||
// last_sender_report_remote_timestamp_ms is set together with
|
// last_sender_report_remote_timestamp_ms is set together with
|
||||||
// last_sender_report_timestamp_ms.
|
// last_sender_report_timestamp_ms.
|
||||||
RTC_DCHECK(
|
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>(
|
stats->remote_timestamp = static_cast<double>(
|
||||||
*voice_receiver_info.last_sender_report_remote_timestamp_ms);
|
*media_receiver_info.last_sender_report_remote_timestamp_ms);
|
||||||
stats->reports_sent = voice_receiver_info.sender_reports_reports_count;
|
stats->reports_sent = media_receiver_info.sender_reports_reports_count;
|
||||||
if (voice_receiver_info.round_trip_time.has_value()) {
|
if (media_receiver_info.round_trip_time.has_value()) {
|
||||||
stats->round_trip_time =
|
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 =
|
stats->round_trip_time_measurements =
|
||||||
voice_receiver_info.round_trip_time_measurements;
|
media_receiver_info.round_trip_time_measurements;
|
||||||
stats->total_round_trip_time =
|
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;
|
return stats;
|
||||||
}
|
}
|
||||||
|
@ -1709,8 +1710,8 @@ void RTCStatsCollector::ProduceAudioRTPStreamStats_n(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Remote-outbound.
|
// Remote-outbound.
|
||||||
auto remote_outbound_audio = CreateRemoteOutboundAudioStreamStats(
|
auto remote_outbound_audio = CreateRemoteOutboundMediaStreamStats(
|
||||||
voice_receiver_info, mid, *inbound_audio_ptr, transport_id);
|
voice_receiver_info, mid, "audio", *inbound_audio_ptr, transport_id);
|
||||||
// Add stats.
|
// Add stats.
|
||||||
if (remote_outbound_audio) {
|
if (remote_outbound_audio) {
|
||||||
// When the remote outbound stats are available, the remote ID for the
|
// When the remote outbound stats are available, the remote ID for the
|
||||||
|
@ -1782,7 +1783,7 @@ void RTCStatsCollector::ProduceVideoRTPStreamStats_n(
|
||||||
std::string mid = *stats.mid;
|
std::string mid = *stats.mid;
|
||||||
std::string transport_id = RTCTransportStatsIDFromTransportChannel(
|
std::string transport_id = RTCTransportStatsIDFromTransportChannel(
|
||||||
*stats.transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
|
*stats.transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
|
||||||
// Inbound
|
// Inbound and remote-outbound.
|
||||||
for (const cricket::VideoReceiverInfo& video_receiver_info :
|
for (const cricket::VideoReceiverInfo& video_receiver_info :
|
||||||
stats.track_media_info_map.video_media_info()->receivers) {
|
stats.track_media_info_map.video_media_info()->receivers) {
|
||||||
if (!video_receiver_info.connected())
|
if (!video_receiver_info.connected())
|
||||||
|
@ -1795,9 +1796,27 @@ void RTCStatsCollector::ProduceVideoRTPStreamStats_n(
|
||||||
if (video_track) {
|
if (video_track) {
|
||||||
inbound_video->track_identifier = video_track->id();
|
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)
|
RTC_LOG(LS_ERROR)
|
||||||
<< "Unable to add video 'inbound-rtp' to report, ID is not unique.";
|
<< "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
|
// Outbound
|
||||||
|
|
|
@ -939,10 +939,16 @@ class RTCStatsReportVerifier {
|
||||||
VerifyRTCRtpStreamStats(remote_outbound_stream, verifier);
|
VerifyRTCRtpStreamStats(remote_outbound_stream, verifier);
|
||||||
VerifyRTCSentRtpStreamStats(remote_outbound_stream, verifier);
|
VerifyRTCSentRtpStreamStats(remote_outbound_stream, verifier);
|
||||||
verifier.TestAttributeIsIDReference(remote_outbound_stream.local_id,
|
verifier.TestAttributeIsIDReference(remote_outbound_stream.local_id,
|
||||||
RTCOutboundRtpStreamStats::kType);
|
RTCInboundRtpStreamStats::kType);
|
||||||
verifier.TestAttributeIsNonNegative<double>(
|
verifier.TestAttributeIsNonNegative<double>(
|
||||||
remote_outbound_stream.remote_timestamp);
|
remote_outbound_stream.remote_timestamp);
|
||||||
verifier.TestAttributeIsDefined(remote_outbound_stream.reports_sent);
|
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();
|
return verifier.ExpectAllAttributesSuccessfullyTested();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1048,6 +1048,12 @@ absl::optional<int64_t> RtpVideoStreamReceiver2::LastReceivedKeyframePacketMs()
|
||||||
return absl::nullopt;
|
return absl::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
absl::optional<RtpRtcpInterface::SenderReportStats>
|
||||||
|
RtpVideoStreamReceiver2::GetSenderReportStats() const {
|
||||||
|
RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
|
||||||
|
return rtp_rtcp_->GetSenderReportStats();
|
||||||
|
}
|
||||||
|
|
||||||
void RtpVideoStreamReceiver2::ManageFrame(
|
void RtpVideoStreamReceiver2::ManageFrame(
|
||||||
std::unique_ptr<RtpFrameObject> frame) {
|
std::unique_ptr<RtpFrameObject> frame) {
|
||||||
RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
|
RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
|
||||||
|
|
|
@ -209,6 +209,9 @@ class RtpVideoStreamReceiver2 : public LossNotificationSender,
|
||||||
absl::optional<uint32_t> LastReceivedFrameRtpTimestamp() const;
|
absl::optional<uint32_t> LastReceivedFrameRtpTimestamp() const;
|
||||||
absl::optional<int64_t> LastReceivedKeyframePacketMs() const;
|
absl::optional<int64_t> LastReceivedKeyframePacketMs() const;
|
||||||
|
|
||||||
|
absl::optional<RtpRtcpInterface::SenderReportStats> GetSenderReportStats()
|
||||||
|
const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Implements RtpVideoFrameReceiver.
|
// Implements RtpVideoFrameReceiver.
|
||||||
void ManageFrame(std::unique_ptr<RtpFrameObject> frame) override;
|
void ManageFrame(std::unique_ptr<RtpFrameObject> frame) override;
|
||||||
|
|
|
@ -568,6 +568,18 @@ VideoReceiveStreamInterface::Stats VideoReceiveStream2::GetStats() const {
|
||||||
stats.rtx_rtp_stats = rtx_statistician->GetStats();
|
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;
|
return stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue