summaryrefslogtreecommitdiff
path: root/chromium/media/cast/rtp_sender/packet_storage/packet_storage.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/media/cast/rtp_sender/packet_storage/packet_storage.cc')
-rw-r--r--chromium/media/cast/rtp_sender/packet_storage/packet_storage.cc141
1 files changed, 141 insertions, 0 deletions
diff --git a/chromium/media/cast/rtp_sender/packet_storage/packet_storage.cc b/chromium/media/cast/rtp_sender/packet_storage/packet_storage.cc
new file mode 100644
index 00000000000..9c2d7ff0884
--- /dev/null
+++ b/chromium/media/cast/rtp_sender/packet_storage/packet_storage.cc
@@ -0,0 +1,141 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/cast/rtp_sender/packet_storage/packet_storage.h"
+
+#include <string>
+
+#include "base/logging.h"
+#include "media/cast/cast_config.h"
+#include "media/cast/cast_defines.h"
+
+namespace media {
+namespace cast {
+
+// Limit the max time delay to avoid frame id wrap around; 256 / 60 fps.
+const int kMaxAllowedTimeStoredMs = 4000;
+
+typedef PacketMap::iterator PacketMapIterator;
+typedef TimeToPacketMap::iterator TimeToPacketIterator;
+
+class StoredPacket {
+ public:
+ StoredPacket() {
+ packet_.reserve(kIpPacketSize);
+ }
+
+ void Save(const std::vector<uint8>& packet) {
+ DCHECK_LT(packet.size(), kIpPacketSize) << "Invalid argument";
+ packet_.clear();
+ packet_.insert(packet_.begin(), packet.begin(), packet.end());
+ }
+
+ void GetCopy(std::vector<uint8>* packet) {
+ packet->insert(packet->begin(), packet_.begin(), packet_.end());
+ }
+
+ private:
+ std::vector<uint8> packet_;
+};
+
+
+PacketStorage::PacketStorage(int max_time_stored_ms)
+ : default_tick_clock_(new base::DefaultTickClock()),
+ clock_(default_tick_clock_.get()) {
+ max_time_stored_ = base::TimeDelta::FromMilliseconds(max_time_stored_ms);
+ DCHECK_LE(max_time_stored_ms, kMaxAllowedTimeStoredMs) << "Invalid argument";
+}
+
+PacketStorage::~PacketStorage() {
+ time_to_packet_map_.clear();
+
+ PacketMapIterator store_it = stored_packets_.begin();
+ for (; store_it != stored_packets_.end();
+ store_it = stored_packets_.begin()) {
+ stored_packets_.erase(store_it);
+ }
+ while (!free_packets_.empty()) {
+ free_packets_.pop_front();
+ }
+}
+
+void PacketStorage::CleanupOldPackets(base::TimeTicks now) {
+ TimeToPacketIterator time_it = time_to_packet_map_.begin();
+
+ // Check max size.
+ while (time_to_packet_map_.size() >= kMaxStoredPackets) {
+ PacketMapIterator store_it = stored_packets_.find(time_it->second);
+
+ // We should always find the packet.
+ DCHECK(store_it != stored_packets_.end()) << "Invalid state";
+ time_to_packet_map_.erase(time_it);
+ // Save the pointer.
+ linked_ptr<StoredPacket> storted_packet = store_it->second;
+ stored_packets_.erase(store_it);
+ // Add this packet to the free list for later re-use.
+ free_packets_.push_back(storted_packet);
+ time_it = time_to_packet_map_.begin();
+ }
+
+ // Time out old packets.
+ while (time_it != time_to_packet_map_.end()) {
+ if (now < time_it->first + max_time_stored_) {
+ break;
+ }
+ // Packet too old.
+ PacketMapIterator store_it = stored_packets_.find(time_it->second);
+
+ // We should always find the packet.
+ DCHECK(store_it != stored_packets_.end()) << "Invalid state";
+ time_to_packet_map_.erase(time_it);
+ // Save the pointer.
+ linked_ptr<StoredPacket> storted_packet = store_it->second;
+ stored_packets_.erase(store_it);
+ // Add this packet to the free list for later re-use.
+ free_packets_.push_back(storted_packet);
+ time_it = time_to_packet_map_.begin();
+ }
+}
+
+void PacketStorage::StorePacket(uint8 frame_id,
+ uint16 packet_id,
+ const std::vector<uint8>& packet) {
+ base::TimeTicks now = clock_->NowTicks();
+ CleanupOldPackets(now);
+
+ uint32 index = (static_cast<uint32>(frame_id) << 16) + packet_id;
+ PacketMapIterator it = stored_packets_.find(index);
+ if (it != stored_packets_.end()) {
+ // We have already saved this.
+ DCHECK(false) << "Invalid state";
+ return;
+ }
+ linked_ptr<StoredPacket> stored_packet;
+ if (free_packets_.empty()) {
+ // No previous allocated packets allocate one.
+ stored_packet.reset(new StoredPacket());
+ } else {
+ // Re-use previous allocated packet.
+ stored_packet = free_packets_.front();
+ free_packets_.pop_front();
+ }
+ stored_packet->Save(packet);
+ stored_packets_[index] = stored_packet;
+ time_to_packet_map_.insert(std::make_pair(now, index));
+}
+
+bool PacketStorage::GetPacket(uint8 frame_id,
+ uint16 packet_id,
+ std::vector<uint8>* packet) {
+ uint32 index = (static_cast<uint32>(frame_id) << 16) + packet_id;
+ PacketMapIterator it = stored_packets_.find(index);
+ if (it == stored_packets_.end()) {
+ return false;
+ }
+ it->second->GetCopy(packet);
+ return true;
+}
+
+} // namespace cast
+} // namespace media