• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "media/cast/net/rtp_sender/packet_storage/packet_storage.h"
6 
7 #include <string>
8 
9 #include "base/logging.h"
10 #include "media/cast/cast_defines.h"
11 
12 namespace media {
13 namespace cast {
14 
15 // Limit the max time delay to avoid frame id wrap around; 256 / 60 fps.
16 const int kMaxAllowedTimeStoredMs = 4000;
17 
18 typedef PacketMap::iterator PacketMapIterator;
19 typedef TimeToPacketMap::iterator TimeToPacketIterator;
20 
21 class StoredPacket {
22  public:
StoredPacket()23   StoredPacket() {
24     packet_.reserve(kIpPacketSize);
25   }
26 
Save(const Packet * packet)27   void Save(const Packet* packet) {
28     DCHECK_LT(packet->size(), kIpPacketSize) << "Invalid argument";
29     packet_.clear();
30     packet_.insert(packet_.begin(), packet->begin(), packet->end());
31   }
32 
GetCopy(PacketList * packets)33   void GetCopy(PacketList* packets) {
34     packets->push_back(Packet(packet_.begin(), packet_.end()));
35   }
36 
37  private:
38   Packet packet_;
39 };
40 
PacketStorage(base::TickClock * clock,int max_time_stored_ms)41 PacketStorage::PacketStorage(base::TickClock* clock,
42                              int max_time_stored_ms)
43     : clock_(clock) {
44   max_time_stored_ = base::TimeDelta::FromMilliseconds(max_time_stored_ms);
45   DCHECK_LE(max_time_stored_ms, kMaxAllowedTimeStoredMs) << "Invalid argument";
46 }
47 
~PacketStorage()48 PacketStorage::~PacketStorage() {
49   time_to_packet_map_.clear();
50 
51   PacketMapIterator store_it = stored_packets_.begin();
52   for (; store_it != stored_packets_.end();
53       store_it = stored_packets_.begin()) {
54     stored_packets_.erase(store_it);
55   }
56   while (!free_packets_.empty()) {
57     free_packets_.pop_front();
58   }
59 }
60 
CleanupOldPackets(base::TimeTicks now)61 void PacketStorage::CleanupOldPackets(base::TimeTicks now) {
62   TimeToPacketIterator time_it = time_to_packet_map_.begin();
63 
64   // Check max size.
65   while (time_to_packet_map_.size() >= kMaxStoredPackets) {
66     PacketMapIterator store_it = stored_packets_.find(time_it->second);
67 
68     // We should always find the packet.
69     DCHECK(store_it != stored_packets_.end()) << "Invalid state";
70     time_to_packet_map_.erase(time_it);
71     // Save the pointer.
72     linked_ptr<StoredPacket> storted_packet = store_it->second;
73     stored_packets_.erase(store_it);
74     // Add this packet to the free list for later re-use.
75     free_packets_.push_back(storted_packet);
76     time_it = time_to_packet_map_.begin();
77   }
78 
79   // Time out old packets.
80   while (time_it != time_to_packet_map_.end()) {
81     if (now < time_it->first + max_time_stored_) {
82       break;
83     }
84     // Packet too old.
85     PacketMapIterator store_it = stored_packets_.find(time_it->second);
86 
87     // We should always find the packet.
88     DCHECK(store_it != stored_packets_.end()) << "Invalid state";
89     time_to_packet_map_.erase(time_it);
90     // Save the pointer.
91     linked_ptr<StoredPacket> storted_packet = store_it->second;
92     stored_packets_.erase(store_it);
93     // Add this packet to the free list for later re-use.
94     free_packets_.push_back(storted_packet);
95     time_it = time_to_packet_map_.begin();
96   }
97 }
98 
StorePacket(uint32 frame_id,uint16 packet_id,const Packet * packet)99 void PacketStorage::StorePacket(uint32 frame_id, uint16 packet_id,
100                                 const Packet* packet) {
101   base::TimeTicks now = clock_->NowTicks();
102   CleanupOldPackets(now);
103 
104   // Internally we only use the 8 LSB of the frame id.
105   uint32 index = ((0xff & frame_id) << 16) + packet_id;
106   PacketMapIterator it = stored_packets_.find(index);
107   if (it != stored_packets_.end()) {
108     // We have already saved this.
109     DCHECK(false) << "Invalid state";
110     return;
111   }
112   linked_ptr<StoredPacket> stored_packet;
113   if (free_packets_.empty()) {
114     // No previous allocated packets allocate one.
115     stored_packet.reset(new StoredPacket());
116   } else {
117     // Re-use previous allocated packet.
118     stored_packet = free_packets_.front();
119     free_packets_.pop_front();
120   }
121   stored_packet->Save(packet);
122   stored_packets_[index] = stored_packet;
123   time_to_packet_map_.insert(std::make_pair(now, index));
124 }
125 
GetPackets(const MissingFramesAndPacketsMap & missing_frames_and_packets)126 PacketList PacketStorage::GetPackets(
127     const MissingFramesAndPacketsMap& missing_frames_and_packets) {
128   PacketList packets_to_resend;
129 
130   // Iterate over all frames in the list.
131   for (MissingFramesAndPacketsMap::const_iterator it =
132        missing_frames_and_packets.begin();
133        it != missing_frames_and_packets.end(); ++it) {
134     uint8 frame_id = it->first;
135     const PacketIdSet& packets_set = it->second;
136     bool success = false;
137 
138     if (packets_set.empty()) {
139       VLOG(1) << "Missing all packets in frame " << static_cast<int>(frame_id);
140 
141       uint16 packet_id = 0;
142       do {
143         // Get packet from storage.
144         success = GetPacket(frame_id, packet_id, &packets_to_resend);
145         ++packet_id;
146       } while (success);
147     } else {
148       // Iterate over all of the packets in the frame.
149       for (PacketIdSet::const_iterator set_it = packets_set.begin();
150           set_it != packets_set.end(); ++set_it) {
151         GetPacket(frame_id, *set_it, &packets_to_resend);
152       }
153     }
154   }
155   return packets_to_resend;
156 }
157 
GetPacket(uint8 frame_id,uint16 packet_id,PacketList * packets)158 bool PacketStorage::GetPacket(uint8 frame_id,
159                               uint16 packet_id,
160                               PacketList* packets) {
161   // Internally we only use the 8 LSB of the frame id.
162   uint32 index = (static_cast<uint32>(frame_id) << 16) + packet_id;
163   PacketMapIterator it = stored_packets_.find(index);
164   if (it == stored_packets_.end()) {
165     return false;
166   }
167   it->second->GetCopy(packets);
168   VLOG(1) << "Resend " << static_cast<int>(frame_id)
169           << ":" << packet_id;
170   return true;
171 }
172 
173 }  // namespace cast
174 }  // namespace media
175