diff --git a/call/call.cc b/call/call.cc index 0d58ed8ed9..b30b92f861 100644 --- a/call/call.cc +++ b/call/call.cc @@ -466,6 +466,10 @@ class Call final : public webrtc::Call, bool is_started_ RTC_GUARDED_BY(worker_thread_) = false; + RTC_NO_UNIQUE_ADDRESS SequenceChecker sent_packet_sequence_checker_; + absl::optional last_sent_packet_ + RTC_GUARDED_BY(sent_packet_sequence_checker_); + RTC_DISALLOW_COPY_AND_ASSIGN(Call); }; } // namespace internal @@ -814,6 +818,7 @@ Call::Call(Clock* clock, RTC_DCHECK(worker_thread_->IsCurrent()); send_transport_sequence_checker_.Detach(); + sent_packet_sequence_checker_.Detach(); // Do not remove this call; it is here to convince the compiler that the // WebRTC source timestamp string needs to be in the final binary. @@ -1382,6 +1387,20 @@ void Call::OnUpdateSyncGroup(webrtc::AudioReceiveStream& stream, } void Call::OnSentPacket(const rtc::SentPacket& sent_packet) { + RTC_DCHECK_RUN_ON(&sent_packet_sequence_checker_); + // When bundling is in effect, multiple senders may be sharing the same + // transport. It means every |sent_packet| will be multiply notified from + // different channels, WebRtcVoiceMediaChannel or WebRtcVideoChannel. Record + // |last_sent_packet_| to deduplicate redundant notifications to downstream. + // (https://crbug.com/webrtc/13437): Pass all packets without a |packet_id| to + // downstream. + if (last_sent_packet_.has_value() && last_sent_packet_->packet_id != -1 && + last_sent_packet_->packet_id == sent_packet.packet_id && + last_sent_packet_->send_time_ms == sent_packet.send_time_ms) { + return; + } + last_sent_packet_ = sent_packet; + // In production and with most tests, this method will be called on the // network thread. However some test classes such as DirectTransport don't // incorporate a network thread. This means that tests for RtpSenderEgress