| Index: media/cast/transport/pacing/paced_sender.cc | 
| diff --git a/media/cast/transport/pacing/paced_sender.cc b/media/cast/transport/pacing/paced_sender.cc | 
| index 10b42240759a3fd2c2580f802a7ed3b1e8b473ea..5f926449c2ac9b9214f9daf61962d53957a580d5 100644 | 
| --- a/media/cast/transport/pacing/paced_sender.cc | 
| +++ b/media/cast/transport/pacing/paced_sender.cc | 
| @@ -73,11 +73,21 @@ bool PacedSender::SendPackets(const SendPacketVector& packets) { | 
| return true; | 
| } | 
|  | 
| -bool PacedSender::ResendPackets(const SendPacketVector& packets) { | 
| +bool PacedSender::ResendPackets(const SendPacketVector& packets, | 
| +                                base::TimeDelta dedupe_window) { | 
| if (packets.empty()) { | 
| return true; | 
| } | 
| +  base::TimeTicks now = clock_->NowTicks(); | 
| for (size_t i = 0; i < packets.size(); i++) { | 
| +    std::map<PacketKey, base::TimeTicks>::const_iterator j = | 
| +        sent_time_.find(packets[i].first); | 
| + | 
| +    if (j != sent_time_.end() && now - j->second < dedupe_window) { | 
| +      LogPacketEvent(packets[i].second->data, PACKET_RTX_REJECTED); | 
| +      continue; | 
| +    } | 
| + | 
| packet_list_[packets[i].first] = | 
| make_pair(PacketType_Resend, packets[i].second); | 
| } | 
| @@ -108,11 +118,13 @@ void PacedSender::CancelSendingPacket(const PacketKey& packet_key) { | 
| packet_list_.erase(packet_key); | 
| } | 
|  | 
| -PacketRef PacedSender::GetNextPacket(PacketType* packet_type) { | 
| +PacketRef PacedSender::GetNextPacket(PacketType* packet_type, | 
| +                                     PacketKey* packet_key) { | 
| std::map<PacketKey, std::pair<PacketType, PacketRef> >::iterator i; | 
| i = packet_list_.begin(); | 
| DCHECK(i != packet_list_.end()); | 
| *packet_type = i->second.first; | 
| +  *packet_key = i->first; | 
| PacketRef ret = i->second.second; | 
| packet_list_.erase(i); | 
| return ret; | 
| @@ -185,14 +197,17 @@ void PacedSender::SendStoredPackets() { | 
| return; | 
| } | 
| PacketType packet_type; | 
| -    PacketRef packet = GetNextPacket(&packet_type); | 
| +    PacketKey packet_key; | 
| +    PacketRef packet = GetNextPacket(&packet_type, &packet_key); | 
| +    sent_time_[packet_key] = now; | 
| +    sent_time_buffer_[packet_key] = now; | 
|  | 
| switch (packet_type) { | 
| case PacketType_Resend: | 
| -        LogPacketEvent(packet->data, true); | 
| +        LogPacketEvent(packet->data, PACKET_RETRANSMITTED); | 
| break; | 
| case PacketType_Normal: | 
| -        LogPacketEvent(packet->data, false); | 
| +        LogPacketEvent(packet->data, PACKET_SENT_TO_NETWORK); | 
| break; | 
| case PacketType_RTCP: | 
| break; | 
| @@ -203,10 +218,17 @@ void PacedSender::SendStoredPackets() { | 
| } | 
| current_burst_size_++; | 
| } | 
| +  // Keep ~1 second of data (1000 packets) | 
| +  if (sent_time_buffer_.size() > kMaxBurstSize * 1000 / kPacingIntervalMs) { | 
| +    sent_time_.swap(sent_time_buffer_); | 
| +    sent_time_buffer_.clear(); | 
| +  } | 
| +  DCHECK_LE(sent_time_buffer_.size(), kMaxBurstSize * 1000 / kPacingIntervalMs); | 
| +  DCHECK_LE(sent_time_.size(), 2 * kMaxBurstSize * 1000 / kPacingIntervalMs); | 
| state_ = State_Unblocked; | 
| } | 
|  | 
| -void PacedSender::LogPacketEvent(const Packet& packet, bool retransmit) { | 
| +void PacedSender::LogPacketEvent(const Packet& packet, CastLoggingEvent event) { | 
| // Get SSRC from packet and compare with the audio_ssrc / video_ssrc to see | 
| // if the packet is audio or video. | 
| DCHECK_GE(packet.size(), 12u); | 
| @@ -224,8 +246,6 @@ void PacedSender::LogPacketEvent(const Packet& packet, bool retransmit) { | 
| return; | 
| } | 
|  | 
| -  CastLoggingEvent event = retransmit ? | 
| -      PACKET_RETRANSMITTED : PACKET_SENT_TO_NETWORK; | 
| EventMediaType media_type = is_audio ? AUDIO_EVENT : VIDEO_EVENT; | 
| logging_->InsertSinglePacketEvent(clock_->NowTicks(), event, media_type, | 
| packet); | 
|  |