mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-12 21:30:45 +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();
|
||||
// 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 @@ class VideoReceiveStreamInterface : public MediaReceiveStreamInterface {
|
|||
// 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 {
|
||||
|
|
|
@ -476,6 +476,19 @@ struct MediaReceiverInfo {
|
|||
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 @@ struct VoiceReceiverInfo : public MediaReceiverInfo {
|
|||
// 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 {
|
||||
|
|
|
@ -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)
|
||||
RTC_LOG(LS_INFO) << stats.ToString(rtc::TimeMillis());
|
||||
|
||||
|
|
|
@ -514,53 +514,54 @@ std::unique_ptr<RTCAudioPlayoutStats> CreateAudioPlayoutStats(
|
|||
}
|
||||
|
||||
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 @@ void RTCStatsCollector::ProduceAudioRTPStreamStats_n(
|
|||
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 @@ void RTCStatsCollector::ProduceVideoRTPStreamStats_n(
|
|||
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 @@ void RTCStatsCollector::ProduceVideoRTPStreamStats_n(
|
|||
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
|
||||
|
|
|
@ -939,10 +939,16 @@ class RTCStatsReportVerifier {
|
|||
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();
|
||||
}
|
||||
|
||||
|
|
|
@ -1048,6 +1048,12 @@ absl::optional<int64_t> RtpVideoStreamReceiver2::LastReceivedKeyframePacketMs()
|
|||
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_);
|
||||
|
|
|
@ -209,6 +209,9 @@ class RtpVideoStreamReceiver2 : public LossNotificationSender,
|
|||
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;
|
||||
|
|
|
@ -568,6 +568,18 @@ VideoReceiveStreamInterface::Stats VideoReceiveStream2::GetStats() const {
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue