Use environment monotonic timestamps (i.e. not UTC) in RTCStats.

Add media config for using environment monotonic timestamps (i.e. not UTC) in RTCStats constructor, and implemented the usage of the flag.

Bug: chromium:369369568
Change-Id: Ia93d048742c28af201164fe7b2152b791bb6d0b6
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/363946
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Reviewed-by: Henrik Boström <hbos@webrtc.org>
Commit-Queue: Olov Brändström <brandstrom@google.com>
Cr-Commit-Position: refs/heads/main@{#43156}
This commit is contained in:
Olov Brändström 2024-10-02 16:42:05 +02:00 committed by WebRTC LUCI CQ
parent 208491c8b9
commit 4baeed3b97
12 changed files with 110 additions and 33 deletions

View File

@ -351,6 +351,13 @@ class RTC_EXPORT PeerConnectionInterface : public webrtc::RefCountInterface {
bool dscp() const { return media_config.enable_dscp; }
void set_dscp(bool enable) { media_config.enable_dscp = enable; }
bool stats_timestamp_with_environment_clock() const {
return media_config.stats_timestamp_with_environment_clock;
}
void set_stats_timestamp_with_environment_clock(bool enable) {
media_config.stats_timestamp_with_environment_clock = enable;
}
bool cpu_adaptation() const {
return media_config.video.enable_cpu_adaptation;
}

View File

@ -22,6 +22,17 @@ struct MediaConfig {
// and delete this flag.
bool enable_dscp = true;
// If true, RTCStats timestamps are sourced from the monotonically increasing
// environment Clock, where the epoch is unspecified (i.e. up to the Clock
// implementation). If false, RTCStats timestamps are either sourced from
// system clock via rtc::TimeUTCMicros() which is relative to 1970 but not
// necessarily monotonically increasing, or from a monotonic clock that is
// set to rtc::TimeUTCMicros() at first call, and then procceeds to increase
// monotonically.
// TODO(webrtc:370535296): Change default value to true and delete this flag
// once downstream projects have migrated.
bool stats_timestamp_with_environment_clock = false;
// Video-specific config.
struct Video {
// Enable WebRTC CPU Overuse Detection. This flag comes from the

View File

@ -6035,7 +6035,8 @@ TEST_F(WebRtcVideoChannelTest, GetAggregatedStatsReportForSubStreams) {
report_block.SetCumulativeLost(17);
report_block.SetFractionLost(18);
webrtc::ReportBlockData report_block_data;
report_block_data.SetReportBlock(0, report_block, webrtc::Timestamp::Zero());
report_block_data.SetReportBlock(0, report_block, webrtc::Timestamp::Zero(),
webrtc::Timestamp::Zero());
report_block_data.AddRoundTripTimeSample(webrtc::TimeDelta::Millis(19));
substream.report_block_data = report_block_data;
substream.encode_frame_rate = 20.0;
@ -6159,7 +6160,8 @@ TEST_F(WebRtcVideoChannelTest, GetPerLayerStatsReportForSubStreams) {
report_block.SetCumulativeLost(17);
report_block.SetFractionLost(18);
webrtc::ReportBlockData report_block_data;
report_block_data.SetReportBlock(0, report_block, webrtc::Timestamp::Zero());
report_block_data.SetReportBlock(0, report_block, webrtc::Timestamp::Zero(),
webrtc::Timestamp::Zero());
report_block_data.AddRoundTripTimeSample(webrtc::TimeDelta::Millis(19));
substream.report_block_data = report_block_data;
substream.encode_frame_rate = 20.0;

View File

@ -21,9 +21,12 @@ TimeDelta ReportBlockData::jitter(int rtp_clock_rate_hz) const {
return TimeDelta::Seconds(jitter()) / rtp_clock_rate_hz;
}
// TODO(webrtc:370535296): When (webrtc:370535296) is fixed, we don't need the
// utc timestamp.
void ReportBlockData::SetReportBlock(uint32_t sender_ssrc,
const rtcp::ReportBlock& report_block,
Timestamp report_block_timestamp_utc) {
Timestamp report_block_timestamp_utc,
Timestamp report_block_timestamp) {
sender_ssrc_ = sender_ssrc;
source_ssrc_ = report_block.source_ssrc();
fraction_lost_raw_ = report_block.fraction_lost();
@ -31,6 +34,7 @@ void ReportBlockData::SetReportBlock(uint32_t sender_ssrc,
extended_highest_sequence_number_ = report_block.extended_high_seq_num();
jitter_ = report_block.jitter();
report_block_timestamp_utc_ = report_block_timestamp_utc;
report_block_timestamp_ = report_block_timestamp;
}
void ReportBlockData::AddRoundTripTimeSample(TimeDelta rtt) {

View File

@ -72,10 +72,15 @@ class ReportBlockData {
TimeDelta jitter(int rtp_clock_rate_hz) const;
// Time in utc epoch (Jan 1st, 1970) the report block was received.
// TODO(webrtc:370535296): When (webrtc:370535296) is fixed, we don't need the
// utc timestamp.
Timestamp report_block_timestamp_utc() const {
return report_block_timestamp_utc_;
}
// Monotonic time when the report block was received.
Timestamp report_block_timestamp() const { return report_block_timestamp_; }
// Round Trip Time measurments for given (sender_ssrc, source_ssrc) pair.
// Min, max, sum, number of measurements are since beginning of the call.
TimeDelta last_rtt() const { return last_rtt_; }
@ -91,13 +96,19 @@ class ReportBlockData {
extended_highest_sequence_number_ = sn;
}
void set_jitter(uint32_t jitter) { jitter_ = jitter; }
// TODO(webrtc:370535296): When (webrtc:370535296) is fixed, we don't need the
// utc timestamp.
void set_report_block_timestamp_utc(Timestamp arrival_time) {
report_block_timestamp_utc_ = arrival_time;
}
void set_report_block_timestamp(Timestamp arrival_time) {
report_block_timestamp_ = arrival_time;
}
void SetReportBlock(uint32_t sender_ssrc,
const rtcp::ReportBlock& report_block,
Timestamp report_block_timestamp_utc);
Timestamp report_block_timestamp_utc,
Timestamp report_block_timestamp);
void AddRoundTripTimeSample(TimeDelta rtt);
private:
@ -107,7 +118,10 @@ class ReportBlockData {
int32_t cumulative_lost_ = 0;
uint32_t extended_highest_sequence_number_ = 0;
uint32_t jitter_ = 0;
// TODO(webrtc:370535296): When (webrtc:370535296) is fixed, we don't need the
// utc timestamp.
Timestamp report_block_timestamp_utc_ = Timestamp::Zero();
Timestamp report_block_timestamp_ = Timestamp::Zero();
TimeDelta last_rtt_ = TimeDelta::Zero();
TimeDelta sum_rtt_ = TimeDelta::Zero();
size_t num_rtts_ = 0;

View File

@ -624,7 +624,7 @@ void RTCPReceiver::HandleReportBlock(const ReportBlock& report_block,
// https://tools.ietf.org/html/rfc868).
report_block_data->SetReportBlock(
remote_ssrc, report_block,
Timestamp::Millis(now_ntp.ToMs() - rtc::kNtpJan1970Millisecs));
Timestamp::Millis(now_ntp.ToMs() - rtc::kNtpJan1970Millisecs), now);
uint32_t send_time_ntp = report_block.last_sr();
// RFC3550, section 6.4.1, LSR field discription states:

View File

@ -375,7 +375,7 @@ void RtcpTransceiverImpl::HandleReportBlocks(
auto sender_it = local_senders_by_ssrc_.find(block.source_ssrc());
if (sender_it != local_senders_by_ssrc_.end()) {
LocalSenderState& state = *sender_it->second;
state.report_block.SetReportBlock(sender_ssrc, block, now_utc);
state.report_block.SetReportBlock(sender_ssrc, block, now_utc, now);
if (rtt.has_value()) {
state.report_block.AddRoundTripTimeSample(*rtt);
}
@ -385,7 +385,7 @@ void RtcpTransceiverImpl::HandleReportBlocks(
// No registered sender for this report block, still report it to the
// network link.
ReportBlockData report_block;
report_block.SetReportBlock(sender_ssrc, block, now_utc);
report_block.SetReportBlock(sender_ssrc, block, now_utc, now);
if (rtt.has_value()) {
report_block.AddRoundTripTimeSample(*rtt);
}

View File

@ -762,7 +762,7 @@ RTCError PeerConnection::Initialize(
configuration_ = configuration;
legacy_stats_ = std::make_unique<LegacyStatsCollector>(this);
stats_collector_ = RTCStatsCollector::Create(this);
stats_collector_ = RTCStatsCollector::Create(this, env_);
sdp_handler_ =
SdpOfferAnswerHandler::Create(this, configuration, dependencies,

View File

@ -843,14 +843,18 @@ ProduceRemoteInboundRtpStreamStatsFromReportBlockData(
const ReportBlockData& report_block,
cricket::MediaType media_type,
const std::map<std::string, RTCOutboundRtpStreamStats*>& outbound_rtps,
const RTCStatsReport& report) {
const RTCStatsReport& report,
const bool stats_timestamp_with_environment_clock) {
// RTCStats' timestamp generally refers to when the metric was sampled, but
// for "remote-[outbound/inbound]-rtp" it refers to the local time when the
// Report Block was received.
Timestamp arrival_timestamp = stats_timestamp_with_environment_clock
? report_block.report_block_timestamp()
: report_block.report_block_timestamp_utc();
auto remote_inbound = std::make_unique<RTCRemoteInboundRtpStreamStats>(
RTCRemoteInboundRtpStreamStatsIdFromSourceSsrc(
media_type, report_block.source_ssrc()),
report_block.report_block_timestamp_utc());
arrival_timestamp);
remote_inbound->ssrc = report_block.source_ssrc();
remote_inbound->kind =
media_type == cricket::MEDIA_TYPE_AUDIO ? "audio" : "video";
@ -1114,13 +1118,18 @@ RTCStatsCollector::RequestInfo::RequestInfo(
rtc::scoped_refptr<RTCStatsCollector> RTCStatsCollector::Create(
PeerConnectionInternal* pc,
const Environment& env,
int64_t cache_lifetime_us) {
return rtc::make_ref_counted<RTCStatsCollector>(pc, cache_lifetime_us);
return rtc::make_ref_counted<RTCStatsCollector>(pc, env, cache_lifetime_us);
}
RTCStatsCollector::RTCStatsCollector(PeerConnectionInternal* pc,
const Environment& env,
int64_t cache_lifetime_us)
: pc_(pc),
env_(env),
stats_timestamp_with_environment_clock_(
pc->GetConfiguration().stats_timestamp_with_environment_clock()),
signaling_thread_(pc->signaling_thread()),
worker_thread_(pc->worker_thread()),
network_thread_(pc->network_thread()),
@ -1179,10 +1188,16 @@ void RTCStatsCollector::GetStatsReportInternal(
// case of already gathering stats, `callback_` will be invoked when there
// are no more pending partial reports.
// "Now" using a system clock, relative to the UNIX epoch (Jan 1, 1970,
// UTC), in microseconds. The system clock could be modified and is not
// necessarily monotonically increasing.
Timestamp timestamp = Timestamp::Micros(rtc::TimeUTCMicros());
Timestamp timestamp =
stats_timestamp_with_environment_clock_
?
// "Now" using a monotonically increasing timer.
env_.clock().CurrentTime()
:
// "Now" using a system clock, relative to the UNIX epoch (Jan 1,
// 1970, UTC), in microseconds. The system clock could be modified
// and is not necessarily monotonically increasing.
Timestamp::Micros(rtc::TimeUTCMicros());
num_pending_partial_reports_ = 2;
partial_report_timestamp_us_ = cache_now_us;
@ -1767,7 +1782,8 @@ void RTCStatsCollector::ProduceAudioRTPStreamStats_n(
for (const auto& report_block_data : voice_sender_info.report_block_datas) {
report->AddStats(ProduceRemoteInboundRtpStreamStatsFromReportBlockData(
transport_id, report_block_data, cricket::MEDIA_TYPE_AUDIO,
audio_outbound_rtps, *report));
audio_outbound_rtps, *report,
stats_timestamp_with_environment_clock_));
}
}
}
@ -1861,7 +1877,8 @@ void RTCStatsCollector::ProduceVideoRTPStreamStats_n(
for (const auto& report_block_data : video_sender_info.report_block_datas) {
report->AddStats(ProduceRemoteInboundRtpStreamStatsFromReportBlockData(
transport_id, report_block_data, cricket::MEDIA_TYPE_VIDEO,
video_outbound_rtps, *report));
video_outbound_rtps, *report,
stats_timestamp_with_environment_clock_));
}
}
}

View File

@ -60,6 +60,7 @@ class RTCStatsCollector : public RefCountInterface {
public:
static rtc::scoped_refptr<RTCStatsCollector> Create(
PeerConnectionInternal* pc,
const Environment& env,
int64_t cache_lifetime_us = 50 * rtc::kNumMicrosecsPerMillisec);
// Gets a recent stats report. If there is a report cached that is still fresh
@ -95,7 +96,9 @@ class RTCStatsCollector : public RefCountInterface {
DataChannelInterface::DataState state);
protected:
RTCStatsCollector(PeerConnectionInternal* pc, int64_t cache_lifetime_us);
RTCStatsCollector(PeerConnectionInternal* pc,
const Environment& env,
int64_t cache_lifetime_us);
~RTCStatsCollector();
struct CertificateStatsPair {
@ -252,6 +255,8 @@ class RTCStatsCollector : public RefCountInterface {
rtc::scoped_refptr<RtpReceiverInternal> receiver_selector);
PeerConnectionInternal* const pc_;
const Environment env_;
const bool stats_timestamp_with_environment_clock_;
rtc::Thread* const signaling_thread_;
rtc::Thread* const worker_thread_;
rtc::Thread* const network_thread_;

View File

@ -427,10 +427,12 @@ rtc::scoped_refptr<MockRtpReceiverInternal> CreateMockReceiver(
class RTCStatsCollectorWrapper {
public:
explicit RTCStatsCollectorWrapper(
rtc::scoped_refptr<FakePeerConnectionForStats> pc)
rtc::scoped_refptr<FakePeerConnectionForStats> pc,
const Environment& env)
: pc_(pc),
stats_collector_(
RTCStatsCollector::Create(pc.get(),
env,
50 * rtc::kNumMicrosecsPerMillisec)) {}
rtc::scoped_refptr<RTCStatsCollector> stats_collector() {
@ -662,7 +664,7 @@ class RTCStatsCollectorTest : public ::testing::Test {
public:
RTCStatsCollectorTest()
: pc_(rtc::make_ref_counted<FakePeerConnectionForStats>()),
stats_(new RTCStatsCollectorWrapper(pc_)),
stats_(new RTCStatsCollectorWrapper(pc_, CreateEnvironment())),
data_channel_controller_(
new FakeDataChannelController(pc_->network_thread())) {}
@ -3294,6 +3296,7 @@ class RTCStatsCollectorTestWithParamKind
TEST_P(RTCStatsCollectorTestWithParamKind,
RTCRemoteInboundRtpStreamStatsCollectedFromReportBlock) {
const Timestamp kReportBlockTimestampUtc = Timestamp::Micros(123456789);
const Timestamp kReportBlockTimestamp = Timestamp::Micros(12345678);
const uint8_t kFractionLost = 12;
const TimeDelta kRoundTripTimeSample1 = TimeDelta::Millis(1'234);
const TimeDelta kRoundTripTimeSample2 = TimeDelta::Seconds(13);
@ -3311,7 +3314,8 @@ TEST_P(RTCStatsCollectorTestWithParamKind,
report_block.SetCumulativeLost(7);
report_block.SetFractionLost(kFractionLost);
ReportBlockData report_block_data;
report_block_data.SetReportBlock(0, report_block, kReportBlockTimestampUtc);
report_block_data.SetReportBlock(0, report_block, kReportBlockTimestampUtc,
kReportBlockTimestamp);
report_block_data.AddRoundTripTimeSample(kRoundTripTimeSample1);
// Only the last sample should be exposed as the
// `RTCRemoteInboundRtpStreamStats::round_trip_time`.
@ -3361,13 +3365,15 @@ TEST_P(RTCStatsCollectorTestWithParamKind,
TEST_P(RTCStatsCollectorTestWithParamKind,
RTCRemoteInboundRtpStreamStatsRttMissingBeforeMeasurement) {
constexpr Timestamp kReportBlockTimestampUtc = Timestamp::Micros(123456789);
const Timestamp kReportBlockTimestamp = Timestamp::Micros(12345678);
rtcp::ReportBlock report_block;
// The remote-inbound-rtp SSRC and the outbound-rtp SSRC is the same as the
// `source_ssrc`, "SSRC of the RTP packet sender".
report_block.SetMediaSsrc(12);
ReportBlockData report_block_data; // AddRoundTripTimeSample() not called.
report_block_data.SetReportBlock(0, report_block, kReportBlockTimestampUtc);
report_block_data.SetReportBlock(0, report_block, kReportBlockTimestampUtc,
kReportBlockTimestamp);
AddSenderInfoAndMediaChannel("TransportName", {report_block_data},
std::nullopt);
@ -3387,6 +3393,7 @@ TEST_P(RTCStatsCollectorTestWithParamKind,
TEST_P(RTCStatsCollectorTestWithParamKind,
RTCRemoteInboundRtpStreamStatsWithTimestampFromReportBlock) {
const Timestamp kReportBlockTimestampUtc = Timestamp::Micros(123456789);
const Timestamp kReportBlockTimestamp = Timestamp::Micros(12345678);
fake_clock_.SetTime(kReportBlockTimestampUtc);
rtcp::ReportBlock report_block;
@ -3394,7 +3401,8 @@ TEST_P(RTCStatsCollectorTestWithParamKind,
// `source_ssrc`, "SSRC of the RTP packet sender".
report_block.SetMediaSsrc(12);
ReportBlockData report_block_data;
report_block_data.SetReportBlock(0, report_block, kReportBlockTimestampUtc);
report_block_data.SetReportBlock(0, report_block, kReportBlockTimestampUtc,
kReportBlockTimestamp);
AddSenderInfoAndMediaChannel("TransportName", {report_block_data},
std::nullopt);
@ -3419,6 +3427,7 @@ TEST_P(RTCStatsCollectorTestWithParamKind,
TEST_P(RTCStatsCollectorTestWithParamKind,
RTCRemoteInboundRtpStreamStatsWithCodecBasedMembers) {
const Timestamp kReportBlockTimestampUtc = Timestamp::Micros(123456789);
const Timestamp kReportBlockTimestamp = Timestamp::Micros(12345678);
fake_clock_.SetTime(kReportBlockTimestampUtc);
rtcp::ReportBlock report_block;
@ -3427,7 +3436,8 @@ TEST_P(RTCStatsCollectorTestWithParamKind,
report_block.SetMediaSsrc(12);
report_block.SetJitter(5000);
ReportBlockData report_block_data;
report_block_data.SetReportBlock(0, report_block, kReportBlockTimestampUtc);
report_block_data.SetReportBlock(0, report_block, kReportBlockTimestampUtc,
kReportBlockTimestamp);
RtpCodecParameters codec;
codec.payload_type = 3;
@ -3455,6 +3465,7 @@ TEST_P(RTCStatsCollectorTestWithParamKind,
TEST_P(RTCStatsCollectorTestWithParamKind,
RTCRemoteInboundRtpStreamStatsWithRtcpTransport) {
const Timestamp kReportBlockTimestampUtc = Timestamp::Micros(123456789);
const Timestamp kReportBlockTimestamp = Timestamp::Micros(12345678);
fake_clock_.SetTime(kReportBlockTimestampUtc);
rtcp::ReportBlock report_block;
@ -3462,7 +3473,8 @@ TEST_P(RTCStatsCollectorTestWithParamKind,
// `source_ssrc`, "SSRC of the RTP packet sender".
report_block.SetMediaSsrc(12);
ReportBlockData report_block_data;
report_block_data.SetReportBlock(0, report_block, kReportBlockTimestampUtc);
report_block_data.SetReportBlock(0, report_block, kReportBlockTimestampUtc,
kReportBlockTimestamp);
cricket::TransportChannelStats rtp_transport_channel_stats;
rtp_transport_channel_stats.component = cricket::ICE_CANDIDATE_COMPONENT_RTP;
@ -3747,9 +3759,10 @@ class FakeRTCStatsCollector : public RTCStatsCollector,
public:
static rtc::scoped_refptr<FakeRTCStatsCollector> Create(
PeerConnectionInternal* pc,
const Environment& env,
int64_t cache_lifetime_us) {
return rtc::scoped_refptr<FakeRTCStatsCollector>(
new rtc::RefCountedObject<FakeRTCStatsCollector>(pc,
new rtc::RefCountedObject<FakeRTCStatsCollector>(pc, env,
cache_lifetime_us));
}
@ -3794,8 +3807,10 @@ class FakeRTCStatsCollector : public RTCStatsCollector,
}
protected:
FakeRTCStatsCollector(PeerConnectionInternal* pc, int64_t cache_lifetime)
: RTCStatsCollector(pc, cache_lifetime),
FakeRTCStatsCollector(PeerConnectionInternal* pc,
const Environment& env,
int64_t cache_lifetime)
: RTCStatsCollector(pc, env, cache_lifetime),
signaling_thread_(pc->signaling_thread()),
worker_thread_(pc->worker_thread()),
network_thread_(pc->network_thread()) {}
@ -3845,7 +3860,7 @@ TEST(RTCStatsCollectorTestWithFakeCollector, ThreadUsageAndResultsMerging) {
rtc::AutoThread main_thread_;
auto pc = rtc::make_ref_counted<FakePeerConnectionForStats>();
rtc::scoped_refptr<FakeRTCStatsCollector> stats_collector(
FakeRTCStatsCollector::Create(pc.get(),
FakeRTCStatsCollector::Create(pc.get(), CreateEnvironment(),
50 * rtc::kNumMicrosecsPerMillisec));
stats_collector->VerifyThreadUsageAndResultsMerging();
}

View File

@ -199,7 +199,8 @@ TEST_F(SendStatisticsProxyTest, ReportBlockDataObserver) {
report_block.SetFractionLost(offset + 2);
report_block.SetJitter(offset + 3);
ReportBlockData data;
data.SetReportBlock(/*sender_ssrc=*/0, report_block, Timestamp::Zero());
data.SetReportBlock(/*sender_ssrc=*/0, report_block, Timestamp::Zero(),
Timestamp::Zero());
expected_.substreams[ssrc].report_block_data = data;
callback->OnReportBlockDataUpdated(data);
@ -214,7 +215,8 @@ TEST_F(SendStatisticsProxyTest, ReportBlockDataObserver) {
report_block.SetFractionLost(offset + 2);
report_block.SetJitter(offset + 3);
ReportBlockData data;
data.SetReportBlock(/*sender_ssrc=*/0, report_block, Timestamp::Zero());
data.SetReportBlock(/*sender_ssrc=*/0, report_block, Timestamp::Zero(),
Timestamp::Zero());
expected_.substreams[ssrc].report_block_data = data;
callback->OnReportBlockDataUpdated(data);
@ -2319,7 +2321,7 @@ TEST_F(SendStatisticsProxyTest, NoSubstreams) {
rtcp::ReportBlock report_block;
report_block.SetMediaSsrc(excluded_ssrc);
ReportBlockData data;
data.SetReportBlock(0, report_block, Timestamp::Zero());
data.SetReportBlock(0, report_block, Timestamp::Zero(), Timestamp::Zero());
rtcp_callback->OnReportBlockDataUpdated(data);
// From BitrateStatisticsObserver.
@ -2372,7 +2374,7 @@ TEST_F(SendStatisticsProxyTest, EncodedResolutionTimesOut) {
rtcp::ReportBlock report_block;
report_block.SetMediaSsrc(config_.rtp.ssrcs[0]);
ReportBlockData data;
data.SetReportBlock(0, report_block, Timestamp::Zero());
data.SetReportBlock(0, report_block, Timestamp::Zero(), Timestamp::Zero());
rtcp_callback->OnReportBlockDataUpdated(data);
// Report stats for second SSRC to make sure it's not outdated along with the