diff --git a/webrtc/modules/pacing/paced_sender.cc b/webrtc/modules/pacing/paced_sender.cc index 121f860c7d..25ca2cf4c5 100644 --- a/webrtc/modules/pacing/paced_sender.cc +++ b/webrtc/modules/pacing/paced_sender.cc @@ -35,6 +35,15 @@ const int64_t kMaxIntervalTimeMs = 30; // TODO(sprang): Move at least PacketQueue and MediaBudget out to separate // files, so that we can more easily test them. +// Note about the -1 enqueue times below: +// This is a temporary hack to avoid crashes when the real-time clock is +// adjusted backwards, which can happen on Android when the phone syncs the +// clock to the network. See this bug: +// https://bugs.chromium.org/p/webrtc/issues/detail?id=5452 +// We can't just comment out the DCHECK either, as that would lead to the sum +// being wrong. Instead we just ignore packets from the past when we calculate +// the average queue time. + namespace webrtc { namespace paced_sender { struct Packet { @@ -50,7 +59,8 @@ struct Packet { ssrc(ssrc), sequence_number(seq_number), capture_time_ms(capture_time_ms), - enqueue_time_ms(enqueue_time_ms), + // TODO(sprang): Remove -1 option once we can guarantee monotonic clock. + enqueue_time_ms(enqueue_time_ms), // -1 = not valid; don't count. bytes(length_in_bytes), retransmission(retransmission), enqueue_order(enqueue_order) {} @@ -99,13 +109,16 @@ class PacketQueue { if (!AddToDupeSet(packet)) return; - UpdateQueueTime(packet.enqueue_time_ms); + if (packet.enqueue_time_ms >= time_last_updated_) + UpdateQueueTime(packet.enqueue_time_ms); // Store packet in list, use pointers in priority queue for cheaper moves. // Packets have a handle to its own iterator in the list, for easy removal // when popping from queue. packet_list_.push_front(packet); std::list::iterator it = packet_list_.begin(); + if (packet.enqueue_time_ms < time_last_updated_) + it->enqueue_time_ms = -1; it->this_it = it; // Handle for direct removal from list. prio_queue_.push(&(*it)); // Pointer into list. bytes_ += packet.bytes; @@ -122,7 +135,8 @@ class PacketQueue { void FinalizePop(const Packet& packet) { RemoveFromDupeSet(packet); bytes_ -= packet.bytes; - queue_time_sum_ -= (time_last_updated_ - packet.enqueue_time_ms); + if (packet.enqueue_time_ms != -1) + queue_time_sum_ -= (time_last_updated_ - packet.enqueue_time_ms); packet_list_.erase(packet.this_it); RTC_DCHECK_EQ(packet_list_.size(), prio_queue_.size()); if (packet_list_.empty()) @@ -136,14 +150,18 @@ class PacketQueue { uint64_t SizeInBytes() const { return bytes_; } int64_t OldestEnqueueTimeMs() const { - auto it = packet_list_.rbegin(); - if (it == packet_list_.rend()) - return 0; - return it->enqueue_time_ms; + for (auto it = packet_list_.rbegin(); it != packet_list_.rend(); ++it) { + if (it->enqueue_time_ms != -1) + return it->enqueue_time_ms; + } + return 0; } void UpdateQueueTime(int64_t timestamp_ms) { - RTC_DCHECK_GE(timestamp_ms, time_last_updated_); + // TODO(sprang): Remove this condition and reinstate a DCHECK once we have + // made sure all clocks are monotonic. + if (timestamp_ms < time_last_updated_) + return; int64_t delta = timestamp_ms - time_last_updated_; // Use packet packet_list_.size() not prio_queue_.size() here, as there // might be an outstanding element popped from prio_queue_ currently in the