Home | History | Annotate | Download | only in source
      1 /*
      2  *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
      3  *
      4  *  Use of this source code is governed by a BSD-style license
      5  *  that can be found in the LICENSE file in the root of the source
      6  *  tree. An additional intellectual property rights grant can be found
      7  *  in the file PATENTS.  All contributing project authors may
      8  *  be found in the AUTHORS file in the root of the source tree.
      9  */
     10 
     11 #include "webrtc/modules/rtp_rtcp/source/rtp_packet_history.h"
     12 
     13 #include <assert.h>
     14 #include <stdlib.h>
     15 #include <string.h>   // memset
     16 #include <limits>
     17 #include <set>
     18 
     19 #include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
     20 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
     21 #include "webrtc/system_wrappers/interface/logging.h"
     22 
     23 namespace webrtc {
     24 
     25 enum { kMinPacketRequestBytes = 50 };
     26 
     27 RTPPacketHistory::RTPPacketHistory(Clock* clock)
     28   : clock_(clock),
     29     critsect_(CriticalSectionWrapper::CreateCriticalSection()),
     30     store_(false),
     31     prev_index_(0),
     32     max_packet_length_(0) {
     33 }
     34 
     35 RTPPacketHistory::~RTPPacketHistory() {
     36   {
     37     CriticalSectionScoped cs(critsect_);
     38     Free();
     39   }
     40   delete critsect_;
     41 }
     42 
     43 void RTPPacketHistory::SetStorePacketsStatus(bool enable,
     44                                              uint16_t number_to_store) {
     45   CriticalSectionScoped cs(critsect_);
     46   if (enable) {
     47     if (store_) {
     48       LOG(LS_WARNING) << "Purging packet history in order to re-set status.";
     49       Free();
     50     }
     51     Allocate(number_to_store);
     52   } else {
     53     Free();
     54   }
     55 }
     56 
     57 void RTPPacketHistory::Allocate(uint16_t number_to_store) {
     58   assert(number_to_store > 0);
     59   assert(!store_);
     60   store_ = true;
     61   stored_packets_.resize(number_to_store);
     62   stored_seq_nums_.resize(number_to_store);
     63   stored_lengths_.resize(number_to_store);
     64   stored_times_.resize(number_to_store);
     65   stored_send_times_.resize(number_to_store);
     66   stored_types_.resize(number_to_store);
     67 }
     68 
     69 void RTPPacketHistory::Free() {
     70   if (!store_) {
     71     return;
     72   }
     73 
     74   std::vector<std::vector<uint8_t> >::iterator it;
     75   for (it = stored_packets_.begin(); it != stored_packets_.end(); ++it) {
     76     it->clear();
     77   }
     78 
     79   stored_packets_.clear();
     80   stored_seq_nums_.clear();
     81   stored_lengths_.clear();
     82   stored_times_.clear();
     83   stored_send_times_.clear();
     84   stored_types_.clear();
     85 
     86   store_ = false;
     87   prev_index_ = 0;
     88   max_packet_length_ = 0;
     89 }
     90 
     91 bool RTPPacketHistory::StorePackets() const {
     92   CriticalSectionScoped cs(critsect_);
     93   return store_;
     94 }
     95 
     96 // private, lock should already be taken
     97 void RTPPacketHistory::VerifyAndAllocatePacketLength(uint16_t packet_length) {
     98   assert(packet_length > 0);
     99   if (!store_) {
    100     return;
    101   }
    102 
    103   if (packet_length <= max_packet_length_) {
    104     return;
    105   }
    106 
    107   std::vector<std::vector<uint8_t> >::iterator it;
    108   for (it = stored_packets_.begin(); it != stored_packets_.end(); ++it) {
    109     it->resize(packet_length);
    110   }
    111   max_packet_length_ = packet_length;
    112 }
    113 
    114 int32_t RTPPacketHistory::PutRTPPacket(const uint8_t* packet,
    115                                        uint16_t packet_length,
    116                                        uint16_t max_packet_length,
    117                                        int64_t capture_time_ms,
    118                                        StorageType type) {
    119   if (type == kDontStore) {
    120     return 0;
    121   }
    122 
    123   CriticalSectionScoped cs(critsect_);
    124   if (!store_) {
    125     return 0;
    126   }
    127 
    128   assert(packet);
    129   assert(packet_length > 3);
    130 
    131   VerifyAndAllocatePacketLength(max_packet_length);
    132 
    133   if (packet_length > max_packet_length_) {
    134     LOG(LS_WARNING) << "Failed to store RTP packet with length: "
    135                     << packet_length;
    136     return -1;
    137   }
    138 
    139   const uint16_t seq_num = (packet[2] << 8) + packet[3];
    140 
    141   // Store packet
    142   std::vector<std::vector<uint8_t> >::iterator it =
    143       stored_packets_.begin() + prev_index_;
    144   std::copy(packet, packet + packet_length, it->begin());
    145 
    146   stored_seq_nums_[prev_index_] = seq_num;
    147   stored_lengths_[prev_index_] = packet_length;
    148   stored_times_[prev_index_] = (capture_time_ms > 0) ? capture_time_ms :
    149       clock_->TimeInMilliseconds();
    150   stored_send_times_[prev_index_] = 0;  // Packet not sent.
    151   stored_types_[prev_index_] = type;
    152 
    153   ++prev_index_;
    154   if (prev_index_ >= stored_seq_nums_.size()) {
    155     prev_index_ = 0;
    156   }
    157   return 0;
    158 }
    159 
    160 bool RTPPacketHistory::HasRTPPacket(uint16_t sequence_number) const {
    161   CriticalSectionScoped cs(critsect_);
    162   if (!store_) {
    163     return false;
    164   }
    165 
    166   int32_t index = 0;
    167   bool found = FindSeqNum(sequence_number, &index);
    168   if (!found) {
    169     return false;
    170   }
    171 
    172   uint16_t length = stored_lengths_.at(index);
    173   if (length == 0 || length > max_packet_length_) {
    174     // Invalid length.
    175     return false;
    176   }
    177   return true;
    178 }
    179 
    180 bool RTPPacketHistory::GetPacketAndSetSendTime(uint16_t sequence_number,
    181                                                uint32_t min_elapsed_time_ms,
    182                                                bool retransmit,
    183                                                uint8_t* packet,
    184                                                uint16_t* packet_length,
    185                                                int64_t* stored_time_ms) {
    186   assert(*packet_length >= max_packet_length_);
    187   CriticalSectionScoped cs(critsect_);
    188   if (!store_) {
    189     return false;
    190   }
    191 
    192   int32_t index = 0;
    193   bool found = FindSeqNum(sequence_number, &index);
    194   if (!found) {
    195     LOG(LS_WARNING) << "No match for getting seqNum " << sequence_number;
    196     return false;
    197   }
    198 
    199   uint16_t length = stored_lengths_.at(index);
    200   assert(length <= max_packet_length_);
    201   if (length == 0) {
    202     LOG(LS_WARNING) << "No match for getting seqNum " << sequence_number
    203                     << ", len " << length;
    204     return false;
    205   }
    206 
    207   // Verify elapsed time since last retrieve.
    208   int64_t now = clock_->TimeInMilliseconds();
    209   if (min_elapsed_time_ms > 0 &&
    210       ((now - stored_send_times_.at(index)) < min_elapsed_time_ms)) {
    211     return false;
    212   }
    213 
    214   if (retransmit && stored_types_.at(index) == kDontRetransmit) {
    215     // No bytes copied since this packet shouldn't be retransmitted or is
    216     // of zero size.
    217     return false;
    218   }
    219   stored_send_times_[index] = clock_->TimeInMilliseconds();
    220   GetPacket(index, packet, packet_length, stored_time_ms);
    221   return true;
    222 }
    223 
    224 void RTPPacketHistory::GetPacket(int index,
    225                                  uint8_t* packet,
    226                                  uint16_t* packet_length,
    227                                  int64_t* stored_time_ms) const {
    228   // Get packet.
    229   uint16_t length = stored_lengths_.at(index);
    230   std::vector<std::vector<uint8_t> >::const_iterator it_found_packet =
    231       stored_packets_.begin() + index;
    232   std::copy(it_found_packet->begin(), it_found_packet->begin() + length,
    233             packet);
    234   *packet_length = length;
    235   *stored_time_ms = stored_times_.at(index);
    236 }
    237 
    238 bool RTPPacketHistory::GetBestFittingPacket(uint8_t* packet,
    239                                             uint16_t* packet_length,
    240                                             int64_t* stored_time_ms) {
    241   CriticalSectionScoped cs(critsect_);
    242   if (!store_)
    243     return false;
    244   int index = FindBestFittingPacket(*packet_length);
    245   if (index < 0)
    246     return false;
    247   GetPacket(index, packet, packet_length, stored_time_ms);
    248   return true;
    249 }
    250 
    251 // private, lock should already be taken
    252 bool RTPPacketHistory::FindSeqNum(uint16_t sequence_number,
    253                                   int32_t* index) const {
    254   uint16_t temp_sequence_number = 0;
    255   if (prev_index_ > 0) {
    256     *index = prev_index_ - 1;
    257     temp_sequence_number = stored_seq_nums_[*index];
    258   } else {
    259     *index = stored_seq_nums_.size() - 1;
    260     temp_sequence_number = stored_seq_nums_[*index];  // wrap
    261   }
    262 
    263   int32_t idx = (prev_index_ - 1) - (temp_sequence_number - sequence_number);
    264   if (idx >= 0 && idx < static_cast<int>(stored_seq_nums_.size())) {
    265     *index = idx;
    266     temp_sequence_number = stored_seq_nums_[*index];
    267   }
    268 
    269   if (temp_sequence_number != sequence_number) {
    270     // We did not found a match, search all.
    271     for (uint16_t m = 0; m < stored_seq_nums_.size(); m++) {
    272       if (stored_seq_nums_[m] == sequence_number) {
    273         *index = m;
    274         temp_sequence_number = stored_seq_nums_[*index];
    275         break;
    276       }
    277     }
    278   }
    279   if (temp_sequence_number == sequence_number) {
    280     // We found a match.
    281     return true;
    282   }
    283   return false;
    284 }
    285 
    286 int RTPPacketHistory::FindBestFittingPacket(uint16_t size) const {
    287   if (size < kMinPacketRequestBytes || stored_lengths_.empty())
    288     return -1;
    289   int min_diff = -1;
    290   size_t best_index = 0;
    291   for (size_t i = 0; i < stored_lengths_.size(); ++i) {
    292     if (stored_lengths_[i] == 0)
    293       continue;
    294     int diff = abs(stored_lengths_[i] - size);
    295     if (min_diff < 0 || diff < min_diff) {
    296       min_diff = diff;
    297       best_index = i;
    298     }
    299   }
    300   if (min_diff < 0)
    301     return -1;
    302   return best_index;
    303 }
    304 }  // namespace webrtc
    305