Skip to content

Commit d819921

Browse files
henbosWebRTC LUCI CQ
authored andcommitted
[Stats] Update totalPacketSendDelay to only cover time in pacer queue.
This metric was always supposed to be the spec's answer to googBucketDelay, and is defined as "The total number of seconds that packets have spent buffered locally before being transmitted onto the network." But our implementation measured the time between capture and send, including encode time. This is incorrect and yields a much larger value than expected. This CL updated the metric to do what the spec says. Implementation-wise we measure the time between pushing and popping each packet from the queue (in modules/pacing/prioritized_packet_queue.cc). The spec says to increment the delay counter at the same time as we increment the packet counter in order for the app to be able to do "delta totalPacketSendDelay / delta packetSent". For this reason, `total_packet_delay` is added to RtpPacketCounter. (Previously, the two counters were incremented on different threads and observers.) Running Google Meet on a good network, I could observe a 2-3 ms average send delay per packet with this implementation compared to 20-30 ms with the old implementation. See b/137014977#comment170 for comparison with googBucketDelay which is a little bit different by design - totalPacketSendDelay is clearly better than googBucketDelay. Since none of this depend on the media kind, we can wire up this metric for audio as well in a follow-up: https://webrtc-review.googlesource.com/c/src/+/280523 Bug: webrtc:14593 Change-Id: If8fcd82fee74030d0923ee5df2c2aea2264600d4 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/280443 Reviewed-by: Erik Språng <[email protected]> Commit-Queue: Henrik Boström <[email protected]> Cr-Commit-Position: refs/heads/main@{#38480}
1 parent c34a8c1 commit d819921

18 files changed

+82
-57
lines changed

call/video_send_stream.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,10 @@ class VideoSendStream {
7777
// TODO(holmer): Move bitrate_bps out to the webrtc::Call layer.
7878
int total_bitrate_bps = 0;
7979
int retransmit_bitrate_bps = 0;
80+
// `avg_delay_ms` and `max_delay_ms` are only used in tests. Consider
81+
// deleting.
8082
int avg_delay_ms = 0;
8183
int max_delay_ms = 0;
82-
uint64_t total_packet_send_delay_ms = 0;
8384
StreamDataCounters rtp_stats;
8485
RtcpPacketTypeCounter rtcp_packet_type_counts;
8586
// A snapshot of the most recent Report Block with additional data of

media/base/media_channel.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -595,7 +595,8 @@ struct VideoSenderInfo : public MediaSenderInfo {
595595
uint64_t total_encode_time_ms = 0;
596596
// https://w3c.github.io/webrtc-stats/#dom-rtcoutboundrtpstreamstats-totalencodedbytestarget
597597
uint64_t total_encoded_bytes_target = 0;
598-
uint64_t total_packet_send_delay_ms = 0;
598+
// https://w3c.github.io/webrtc-stats/#dom-rtcoutboundrtpstreamstats-totalpacketsenddelay
599+
webrtc::TimeDelta total_packet_send_delay = webrtc::TimeDelta::Zero();
599600
bool has_entered_low_resolution = false;
600601
absl::optional<uint64_t> qp_sum;
601602
webrtc::VideoContentType content_type = webrtc::VideoContentType::UNSPECIFIED;

media/engine/webrtc_video_engine.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2674,7 +2674,8 @@ WebRtcVideoChannel::WebRtcVideoSendStream::GetPerLayerVideoSenderInfos(
26742674
stream_stats.rtp_stats.transmitted.header_bytes +
26752675
stream_stats.rtp_stats.transmitted.padding_bytes;
26762676
info.packets_sent = stream_stats.rtp_stats.transmitted.packets;
2677-
info.total_packet_send_delay_ms += stream_stats.total_packet_send_delay_ms;
2677+
info.total_packet_send_delay +=
2678+
stream_stats.rtp_stats.transmitted.total_packet_delay;
26782679
info.send_frame_width = stream_stats.width;
26792680
info.send_frame_height = stream_stats.height;
26802681
info.key_frames_encoded = stream_stats.frame_counts.key_frames;
@@ -2728,7 +2729,7 @@ WebRtcVideoChannel::WebRtcVideoSendStream::GetAggregatedVideoSenderInfo(
27282729
info.header_and_padding_bytes_sent +=
27292730
infos[i].header_and_padding_bytes_sent;
27302731
info.packets_sent += infos[i].packets_sent;
2731-
info.total_packet_send_delay_ms += infos[i].total_packet_send_delay_ms;
2732+
info.total_packet_send_delay += infos[i].total_packet_send_delay;
27322733
info.retransmitted_bytes_sent += infos[i].retransmitted_bytes_sent;
27332734
info.retransmitted_packets_sent += infos[i].retransmitted_packets_sent;
27342735
info.packets_lost += infos[i].packets_lost;

media/engine/webrtc_video_engine_unittest.cc

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5567,7 +5567,7 @@ TEST_F(WebRtcVideoChannelTest, GetAggregatedStatsReportWithoutSubStreams) {
55675567
EXPECT_EQ(sender.total_encoded_bytes_target,
55685568
stats.total_encoded_bytes_target);
55695569
// Comes from substream only.
5570-
EXPECT_EQ(sender.total_packet_send_delay_ms, 0u);
5570+
EXPECT_EQ(sender.total_packet_send_delay, webrtc::TimeDelta::Zero());
55715571
EXPECT_EQ(sender.qp_sum, absl::nullopt);
55725572

55735573
EXPECT_EQ(sender.has_entered_low_resolution,
@@ -5594,7 +5594,8 @@ TEST_F(WebRtcVideoChannelTest, GetAggregatedStatsReportForSubStreams) {
55945594
substream.retransmit_bitrate_bps = 6;
55955595
substream.avg_delay_ms = 7;
55965596
substream.max_delay_ms = 8;
5597-
substream.total_packet_send_delay_ms = 9;
5597+
substream.rtp_stats.transmitted.total_packet_delay =
5598+
webrtc::TimeDelta::Millis(9);
55985599
substream.rtp_stats.transmitted.header_bytes = 10;
55995600
substream.rtp_stats.transmitted.padding_bytes = 11;
56005601
substream.rtp_stats.retransmitted.payload_bytes = 12;
@@ -5640,6 +5641,8 @@ TEST_F(WebRtcVideoChannelTest, GetAggregatedStatsReportForSubStreams) {
56405641
static_cast<int>(2 * substream.rtp_stats.transmitted.packets));
56415642
EXPECT_EQ(sender.retransmitted_packets_sent,
56425643
2u * substream.rtp_stats.retransmitted.packets);
5644+
EXPECT_EQ(sender.total_packet_send_delay,
5645+
2 * substream.rtp_stats.transmitted.total_packet_delay);
56435646
EXPECT_EQ(sender.packets_lost,
56445647
2 * substream.report_block_data->report_block().packets_lost);
56455648
EXPECT_EQ(sender.fraction_lost,
@@ -5689,8 +5692,6 @@ TEST_F(WebRtcVideoChannelTest, GetAggregatedStatsReportForSubStreams) {
56895692
EXPECT_EQ(sender.total_encode_time_ms, 2u * substream.total_encode_time_ms);
56905693
EXPECT_EQ(sender.total_encoded_bytes_target,
56915694
2u * substream.total_encoded_bytes_target);
5692-
EXPECT_EQ(sender.total_packet_send_delay_ms,
5693-
2u * substream.total_packet_send_delay_ms);
56945695
EXPECT_EQ(sender.has_entered_low_resolution,
56955696
stats.has_entered_low_resolution);
56965697
EXPECT_EQ(sender.qp_sum, 2u * *substream.qp_sum);
@@ -5716,7 +5717,8 @@ TEST_F(WebRtcVideoChannelTest, GetPerLayerStatsReportForSubStreams) {
57165717
substream.retransmit_bitrate_bps = 6;
57175718
substream.avg_delay_ms = 7;
57185719
substream.max_delay_ms = 8;
5719-
substream.total_packet_send_delay_ms = 9;
5720+
substream.rtp_stats.transmitted.total_packet_delay =
5721+
webrtc::TimeDelta::Millis(9);
57205722
substream.rtp_stats.transmitted.header_bytes = 10;
57215723
substream.rtp_stats.transmitted.padding_bytes = 11;
57225724
substream.rtp_stats.retransmitted.payload_bytes = 12;
@@ -5760,6 +5762,8 @@ TEST_F(WebRtcVideoChannelTest, GetPerLayerStatsReportForSubStreams) {
57605762
substream.rtp_stats.retransmitted.payload_bytes);
57615763
EXPECT_EQ(sender.packets_sent,
57625764
static_cast<int>(substream.rtp_stats.transmitted.packets));
5765+
EXPECT_EQ(sender.total_packet_send_delay,
5766+
substream.rtp_stats.transmitted.total_packet_delay);
57635767
EXPECT_EQ(sender.retransmitted_packets_sent,
57645768
substream.rtp_stats.retransmitted.packets);
57655769
EXPECT_EQ(sender.packets_lost,
@@ -5810,8 +5814,6 @@ TEST_F(WebRtcVideoChannelTest, GetPerLayerStatsReportForSubStreams) {
58105814
EXPECT_EQ(sender.total_encode_time_ms, substream.total_encode_time_ms);
58115815
EXPECT_EQ(sender.total_encoded_bytes_target,
58125816
substream.total_encoded_bytes_target);
5813-
EXPECT_EQ(sender.total_packet_send_delay_ms,
5814-
substream.total_packet_send_delay_ms);
58155817
EXPECT_EQ(sender.has_entered_low_resolution,
58165818
stats.has_entered_low_resolution);
58175819
EXPECT_EQ(sender.qp_sum, *substream.qp_sum);

modules/pacing/prioritized_packet_queue.cc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,13 @@ std::unique_ptr<RtpPacketToSend> PrioritizedPacketQueue::Pop() {
180180
last_update_time_ - packet.enqueue_time - pause_time_sum_;
181181
queue_time_sum_ -= time_in_non_paused_state;
182182

183+
// Set the time spent in the send queue, which is the per-packet equivalent of
184+
// totalPacketSendDelay. The notion of being paused is an implementation
185+
// detail that we do not want to expose, so it makes sense to report the
186+
// metric excluding the pause time. This also avoids spikes in the metric.
187+
// https://w3c.github.io/webrtc-stats/#dom-rtcoutboundrtpstreamstats-totalpacketsenddelay
188+
packet.packet->set_time_in_send_queue(time_in_non_paused_state);
189+
183190
RTC_DCHECK(size_packets_ > 0 || queue_time_sum_ == TimeDelta::Zero());
184191

185192
RTC_CHECK(packet.enqueue_time_iterator != enqueue_times_.end());

modules/rtp_rtcp/include/rtp_rtcp_defines.cc

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "absl/algorithm/container.h"
1818
#include "api/array_view.h"
1919
#include "modules/rtp_rtcp/source/rtp_packet.h"
20+
#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
2021

2122
namespace webrtc {
2223

@@ -52,11 +53,23 @@ RtpPacketCounter::RtpPacketCounter(const RtpPacket& packet)
5253
padding_bytes(packet.padding_size()),
5354
packets(1) {}
5455

56+
RtpPacketCounter::RtpPacketCounter(const RtpPacketToSend& packet_to_send)
57+
: RtpPacketCounter(static_cast<const RtpPacket&>(packet_to_send)) {
58+
total_packet_delay =
59+
packet_to_send.time_in_send_queue().value_or(TimeDelta::Zero());
60+
}
61+
5562
void RtpPacketCounter::AddPacket(const RtpPacket& packet) {
5663
++packets;
5764
header_bytes += packet.headers_size();
5865
padding_bytes += packet.padding_size();
5966
payload_bytes += packet.payload_size();
6067
}
6168

69+
void RtpPacketCounter::AddPacket(const RtpPacketToSend& packet_to_send) {
70+
AddPacket(static_cast<const RtpPacket&>(packet_to_send));
71+
total_packet_delay +=
72+
packet_to_send.time_in_send_queue().value_or(TimeDelta::Zero());
73+
}
74+
6275
} // namespace webrtc

modules/rtp_rtcp/include/rtp_rtcp_defines.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -312,12 +312,14 @@ struct RtpPacketCounter {
312312
: header_bytes(0), payload_bytes(0), padding_bytes(0), packets(0) {}
313313

314314
explicit RtpPacketCounter(const RtpPacket& packet);
315+
explicit RtpPacketCounter(const RtpPacketToSend& packet_to_send);
315316

316317
void Add(const RtpPacketCounter& other) {
317318
header_bytes += other.header_bytes;
318319
payload_bytes += other.payload_bytes;
319320
padding_bytes += other.padding_bytes;
320321
packets += other.packets;
322+
total_packet_delay += other.total_packet_delay;
321323
}
322324

323325
void Subtract(const RtpPacketCounter& other) {
@@ -329,16 +331,20 @@ struct RtpPacketCounter {
329331
padding_bytes -= other.padding_bytes;
330332
RTC_DCHECK_GE(packets, other.packets);
331333
packets -= other.packets;
334+
RTC_DCHECK_GE(total_packet_delay, other.total_packet_delay);
335+
total_packet_delay -= other.total_packet_delay;
332336
}
333337

334338
bool operator==(const RtpPacketCounter& other) const {
335339
return header_bytes == other.header_bytes &&
336340
payload_bytes == other.payload_bytes &&
337-
padding_bytes == other.padding_bytes && packets == other.packets;
341+
padding_bytes == other.padding_bytes && packets == other.packets &&
342+
total_packet_delay == other.total_packet_delay;
338343
}
339344

340345
// Not inlined, since use of RtpPacket would result in circular includes.
341346
void AddPacket(const RtpPacket& packet);
347+
void AddPacket(const RtpPacketToSend& packet_to_send);
342348

343349
size_t TotalBytes() const {
344350
return header_bytes + payload_bytes + padding_bytes;
@@ -348,6 +354,9 @@ struct RtpPacketCounter {
348354
size_t payload_bytes; // Payload bytes, excluding RTP headers and padding.
349355
size_t padding_bytes; // Number of padding bytes.
350356
uint32_t packets; // Number of packets.
357+
// The total delay of all `packets`. For RtpPacketToSend packets, this is
358+
// `time_in_send_queue()`. For receive packets, this is zero.
359+
webrtc::TimeDelta total_packet_delay = webrtc::TimeDelta::Zero();
351360
};
352361

353362
// Data usage statistics for a (rtp) stream.
@@ -470,7 +479,6 @@ class SendSideDelayObserver {
470479
virtual ~SendSideDelayObserver() {}
471480
virtual void SendSideDelayUpdated(int avg_delay_ms,
472481
int max_delay_ms,
473-
uint64_t total_delay_ms,
474482
uint32_t ssrc) = 0;
475483
};
476484

modules/rtp_rtcp/source/deprecated/deprecated_rtp_sender_egress.cc

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,6 @@ DEPRECATED_RtpSenderEgress::DEPRECATED_RtpSenderEgress(
9090
timestamp_offset_(0),
9191
max_delay_it_(send_delays_.end()),
9292
sum_delays_ms_(0),
93-
total_packet_send_delay_ms_(0),
9493
send_rates_(kNumMediaTypes,
9594
{kBitrateStatisticsWindowMs, RateStatistics::kBpsScale}),
9695
rtp_sequence_number_map_(need_rtp_packet_infos_
@@ -341,7 +340,6 @@ void DEPRECATED_RtpSenderEgress::UpdateDelayStatistics(int64_t capture_time_ms,
341340

342341
int avg_delay_ms = 0;
343342
int max_delay_ms = 0;
344-
uint64_t total_packet_send_delay_ms = 0;
345343
{
346344
MutexLock lock(&lock_);
347345
// Compute the max and average of the recent capture-to-send delays.
@@ -392,8 +390,6 @@ void DEPRECATED_RtpSenderEgress::UpdateDelayStatistics(int64_t capture_time_ms,
392390
max_delay_it_ = it;
393391
}
394392
sum_delays_ms_ += new_send_delay;
395-
total_packet_send_delay_ms_ += new_send_delay;
396-
total_packet_send_delay_ms = total_packet_send_delay_ms_;
397393

398394
size_t num_delays = send_delays_.size();
399395
RTC_DCHECK(max_delay_it_ != send_delays_.end());
@@ -405,8 +401,8 @@ void DEPRECATED_RtpSenderEgress::UpdateDelayStatistics(int64_t capture_time_ms,
405401
avg_delay_ms =
406402
rtc::dchecked_cast<int>((sum_delays_ms_ + num_delays / 2) / num_delays);
407403
}
408-
send_side_delay_observer_->SendSideDelayUpdated(
409-
avg_delay_ms, max_delay_ms, total_packet_send_delay_ms, ssrc);
404+
send_side_delay_observer_->SendSideDelayUpdated(avg_delay_ms, max_delay_ms,
405+
ssrc);
410406
}
411407

412408
void DEPRECATED_RtpSenderEgress::RecomputeMaxSendDelay() {

modules/rtp_rtcp/source/deprecated/deprecated_rtp_sender_egress.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,6 @@ class DEPRECATED_RtpSenderEgress {
133133
SendDelayMap::const_iterator max_delay_it_ RTC_GUARDED_BY(lock_);
134134
// The sum of delays over a kSendSideDelayWindowMs sliding window.
135135
int64_t sum_delays_ms_ RTC_GUARDED_BY(lock_);
136-
uint64_t total_packet_send_delay_ms_ RTC_GUARDED_BY(lock_);
137136
StreamDataCounters rtp_stats_ RTC_GUARDED_BY(lock_);
138137
StreamDataCounters rtx_rtp_stats_ RTC_GUARDED_BY(lock_);
139138
// One element per value in RtpPacketMediaType, with index matching value.

modules/rtp_rtcp/source/rtp_packet_to_send.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "api/array_view.h"
2020
#include "api/ref_counted_base.h"
2121
#include "api/scoped_refptr.h"
22+
#include "api/units/time_delta.h"
2223
#include "api/units/timestamp.h"
2324
#include "api/video/video_timing.h"
2425
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
@@ -120,6 +121,15 @@ class RtpPacketToSend : public RtpPacket {
120121
void set_is_red(bool is_red) { is_red_ = is_red; }
121122
bool is_red() const { return is_red_; }
122123

124+
// The amount of time spent in the send queue, used for totalPacketSendDelay.
125+
// https://w3c.github.io/webrtc-stats/#dom-rtcoutboundrtpstreamstats-totalpacketsenddelay
126+
void set_time_in_send_queue(TimeDelta time_in_send_queue) {
127+
time_in_send_queue_ = time_in_send_queue;
128+
}
129+
absl::optional<TimeDelta> time_in_send_queue() const {
130+
return time_in_send_queue_;
131+
}
132+
123133
private:
124134
webrtc::Timestamp capture_time_ = webrtc::Timestamp::Zero();
125135
absl::optional<RtpPacketMediaType> packet_type_;
@@ -130,6 +140,7 @@ class RtpPacketToSend : public RtpPacket {
130140
bool is_key_frame_ = false;
131141
bool fec_protect_packet_ = false;
132142
bool is_red_ = false;
143+
absl::optional<TimeDelta> time_in_send_queue_;
133144
};
134145

135146
} // namespace webrtc

0 commit comments

Comments
 (0)