Home | History | Annotate | Download | only in test
      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/video_coding/test/rtp_player.h"
     12 
     13 #include <stdio.h>
     14 
     15 #include <map>
     16 
     17 #include "webrtc/base/scoped_ptr.h"
     18 #include "webrtc/modules/rtp_rtcp/include/rtp_header_parser.h"
     19 #include "webrtc/modules/rtp_rtcp/include/rtp_payload_registry.h"
     20 #include "webrtc/modules/rtp_rtcp/include/rtp_receiver.h"
     21 #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp.h"
     22 #include "webrtc/modules/video_coding/internal_defines.h"
     23 #include "webrtc/modules/video_coding/test/test_util.h"
     24 #include "webrtc/system_wrappers/include/clock.h"
     25 #include "webrtc/system_wrappers/include/critical_section_wrapper.h"
     26 #include "webrtc/test/rtp_file_reader.h"
     27 
     28 #if 1
     29 #define DEBUG_LOG1(text, arg)
     30 #else
     31 #define DEBUG_LOG1(text, arg) (printf(text "\n", arg))
     32 #endif
     33 
     34 namespace webrtc {
     35 namespace rtpplayer {
     36 
     37 enum {
     38   kMaxPacketBufferSize = 4096,
     39   kDefaultTransmissionTimeOffsetExtensionId = 2
     40 };
     41 
     42 class RawRtpPacket {
     43  public:
     44   RawRtpPacket(const uint8_t* data,
     45                size_t length,
     46                uint32_t ssrc,
     47                uint16_t seq_num)
     48       : data_(new uint8_t[length]),
     49         length_(length),
     50         resend_time_ms_(-1),
     51         ssrc_(ssrc),
     52         seq_num_(seq_num) {
     53     assert(data);
     54     memcpy(data_.get(), data, length_);
     55   }
     56 
     57   const uint8_t* data() const { return data_.get(); }
     58   size_t length() const { return length_; }
     59   int64_t resend_time_ms() const { return resend_time_ms_; }
     60   void set_resend_time_ms(int64_t timeMs) { resend_time_ms_ = timeMs; }
     61   uint32_t ssrc() const { return ssrc_; }
     62   uint16_t seq_num() const { return seq_num_; }
     63 
     64  private:
     65   rtc::scoped_ptr<uint8_t[]> data_;
     66   size_t length_;
     67   int64_t resend_time_ms_;
     68   uint32_t ssrc_;
     69   uint16_t seq_num_;
     70 
     71   RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(RawRtpPacket);
     72 };
     73 
     74 class LostPackets {
     75  public:
     76   LostPackets(Clock* clock, int64_t rtt_ms)
     77       : crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
     78         debug_file_(fopen("PacketLossDebug.txt", "w")),
     79         loss_count_(0),
     80         packets_(),
     81         clock_(clock),
     82         rtt_ms_(rtt_ms) {
     83     assert(clock);
     84   }
     85 
     86   ~LostPackets() {
     87     if (debug_file_) {
     88       fclose(debug_file_);
     89       debug_file_ = NULL;
     90     }
     91     while (!packets_.empty()) {
     92       delete packets_.back();
     93       packets_.pop_back();
     94     }
     95   }
     96 
     97   void AddPacket(RawRtpPacket* packet) {
     98     assert(packet);
     99     printf("Throw:  %08x:%u\n", packet->ssrc(), packet->seq_num());
    100     CriticalSectionScoped cs(crit_sect_.get());
    101     if (debug_file_) {
    102       fprintf(debug_file_, "%u Lost packet: %u\n", loss_count_,
    103               packet->seq_num());
    104     }
    105     packets_.push_back(packet);
    106     loss_count_++;
    107   }
    108 
    109   void SetResendTime(uint32_t ssrc, int16_t resendSeqNum) {
    110     int64_t resend_time_ms = clock_->TimeInMilliseconds() + rtt_ms_;
    111     int64_t now_ms = clock_->TimeInMilliseconds();
    112     CriticalSectionScoped cs(crit_sect_.get());
    113     for (RtpPacketIterator it = packets_.begin(); it != packets_.end(); ++it) {
    114       RawRtpPacket* packet = *it;
    115       if (ssrc == packet->ssrc() && resendSeqNum == packet->seq_num() &&
    116           packet->resend_time_ms() + 10 < now_ms) {
    117         if (debug_file_) {
    118           fprintf(debug_file_, "Resend %u at %u\n", packet->seq_num(),
    119                   MaskWord64ToUWord32(resend_time_ms));
    120         }
    121         packet->set_resend_time_ms(resend_time_ms);
    122         return;
    123       }
    124     }
    125     // We may get here since the captured stream may itself be missing packets.
    126   }
    127 
    128   RawRtpPacket* NextPacketToResend(int64_t time_now) {
    129     CriticalSectionScoped cs(crit_sect_.get());
    130     for (RtpPacketIterator it = packets_.begin(); it != packets_.end(); ++it) {
    131       RawRtpPacket* packet = *it;
    132       if (time_now >= packet->resend_time_ms() &&
    133           packet->resend_time_ms() != -1) {
    134         packets_.erase(it);
    135         return packet;
    136       }
    137     }
    138     return NULL;
    139   }
    140 
    141   int NumberOfPacketsToResend() const {
    142     CriticalSectionScoped cs(crit_sect_.get());
    143     int count = 0;
    144     for (ConstRtpPacketIterator it = packets_.begin(); it != packets_.end();
    145          ++it) {
    146       if ((*it)->resend_time_ms() >= 0) {
    147         count++;
    148       }
    149     }
    150     return count;
    151   }
    152 
    153   void LogPacketResent(RawRtpPacket* packet) {
    154     int64_t now_ms = clock_->TimeInMilliseconds();
    155     CriticalSectionScoped cs(crit_sect_.get());
    156     if (debug_file_) {
    157       fprintf(debug_file_, "Resent %u at %u\n", packet->seq_num(),
    158               MaskWord64ToUWord32(now_ms));
    159     }
    160   }
    161 
    162   void Print() const {
    163     CriticalSectionScoped cs(crit_sect_.get());
    164     printf("Lost packets: %u\n", loss_count_);
    165     printf("Packets waiting to be resent: %d\n", NumberOfPacketsToResend());
    166     printf("Packets still lost: %zd\n", packets_.size());
    167     printf("Sequence numbers:\n");
    168     for (ConstRtpPacketIterator it = packets_.begin(); it != packets_.end();
    169          ++it) {
    170       printf("%u, ", (*it)->seq_num());
    171     }
    172     printf("\n");
    173   }
    174 
    175  private:
    176   typedef std::vector<RawRtpPacket*> RtpPacketList;
    177   typedef RtpPacketList::iterator RtpPacketIterator;
    178   typedef RtpPacketList::const_iterator ConstRtpPacketIterator;
    179 
    180   rtc::scoped_ptr<CriticalSectionWrapper> crit_sect_;
    181   FILE* debug_file_;
    182   int loss_count_;
    183   RtpPacketList packets_;
    184   Clock* clock_;
    185   int64_t rtt_ms_;
    186 
    187   RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(LostPackets);
    188 };
    189 
    190 class SsrcHandlers {
    191  public:
    192   SsrcHandlers(PayloadSinkFactoryInterface* payload_sink_factory,
    193                const PayloadTypes& payload_types)
    194       : payload_sink_factory_(payload_sink_factory),
    195         payload_types_(payload_types),
    196         handlers_() {
    197     assert(payload_sink_factory);
    198   }
    199 
    200   ~SsrcHandlers() {
    201     while (!handlers_.empty()) {
    202       delete handlers_.begin()->second;
    203       handlers_.erase(handlers_.begin());
    204     }
    205   }
    206 
    207   int RegisterSsrc(uint32_t ssrc, LostPackets* lost_packets, Clock* clock) {
    208     if (handlers_.count(ssrc) > 0) {
    209       return 0;
    210     }
    211     DEBUG_LOG1("Registering handler for ssrc=%08x", ssrc);
    212 
    213     rtc::scoped_ptr<Handler> handler(
    214         new Handler(ssrc, payload_types_, lost_packets));
    215     handler->payload_sink_.reset(payload_sink_factory_->Create(handler.get()));
    216     if (handler->payload_sink_.get() == NULL) {
    217       return -1;
    218     }
    219 
    220     RtpRtcp::Configuration configuration;
    221     configuration.clock = clock;
    222     configuration.audio = false;
    223     handler->rtp_module_.reset(RtpReceiver::CreateVideoReceiver(
    224         configuration.clock, handler->payload_sink_.get(), NULL,
    225         handler->rtp_payload_registry_.get()));
    226     if (handler->rtp_module_.get() == NULL) {
    227       return -1;
    228     }
    229 
    230     handler->rtp_module_->SetNACKStatus(kNackOff);
    231     handler->rtp_header_parser_->RegisterRtpHeaderExtension(
    232         kRtpExtensionTransmissionTimeOffset,
    233         kDefaultTransmissionTimeOffsetExtensionId);
    234 
    235     for (PayloadTypesIterator it = payload_types_.begin();
    236          it != payload_types_.end(); ++it) {
    237       VideoCodec codec;
    238       memset(&codec, 0, sizeof(codec));
    239       strncpy(codec.plName, it->name().c_str(), sizeof(codec.plName) - 1);
    240       codec.plType = it->payload_type();
    241       codec.codecType = it->codec_type();
    242       if (handler->rtp_module_->RegisterReceivePayload(
    243               codec.plName, codec.plType, 90000, 0, codec.maxBitrate) < 0) {
    244         return -1;
    245       }
    246     }
    247 
    248     handlers_[ssrc] = handler.release();
    249     return 0;
    250   }
    251 
    252   void IncomingPacket(const uint8_t* data, size_t length) {
    253     for (HandlerMapIt it = handlers_.begin(); it != handlers_.end(); ++it) {
    254       if (!it->second->rtp_header_parser_->IsRtcp(data, length)) {
    255         RTPHeader header;
    256         it->second->rtp_header_parser_->Parse(data, length, &header);
    257         PayloadUnion payload_specific;
    258         it->second->rtp_payload_registry_->GetPayloadSpecifics(
    259             header.payloadType, &payload_specific);
    260         it->second->rtp_module_->IncomingRtpPacket(header, data, length,
    261                                                    payload_specific, true);
    262       }
    263     }
    264   }
    265 
    266  private:
    267   class Handler : public RtpStreamInterface {
    268    public:
    269     Handler(uint32_t ssrc,
    270             const PayloadTypes& payload_types,
    271             LostPackets* lost_packets)
    272         : rtp_header_parser_(RtpHeaderParser::Create()),
    273           rtp_payload_registry_(new RTPPayloadRegistry(
    274               RTPPayloadStrategy::CreateStrategy(false))),
    275           rtp_module_(),
    276           payload_sink_(),
    277           ssrc_(ssrc),
    278           payload_types_(payload_types),
    279           lost_packets_(lost_packets) {
    280       assert(lost_packets);
    281     }
    282     virtual ~Handler() {}
    283 
    284     virtual void ResendPackets(const uint16_t* sequence_numbers,
    285                                uint16_t length) {
    286       assert(sequence_numbers);
    287       for (uint16_t i = 0; i < length; i++) {
    288         lost_packets_->SetResendTime(ssrc_, sequence_numbers[i]);
    289       }
    290     }
    291 
    292     virtual uint32_t ssrc() const { return ssrc_; }
    293     virtual const PayloadTypes& payload_types() const { return payload_types_; }
    294 
    295     rtc::scoped_ptr<RtpHeaderParser> rtp_header_parser_;
    296     rtc::scoped_ptr<RTPPayloadRegistry> rtp_payload_registry_;
    297     rtc::scoped_ptr<RtpReceiver> rtp_module_;
    298     rtc::scoped_ptr<PayloadSinkInterface> payload_sink_;
    299 
    300    private:
    301     uint32_t ssrc_;
    302     const PayloadTypes& payload_types_;
    303     LostPackets* lost_packets_;
    304 
    305     RTC_DISALLOW_COPY_AND_ASSIGN(Handler);
    306   };
    307 
    308   typedef std::map<uint32_t, Handler*> HandlerMap;
    309   typedef std::map<uint32_t, Handler*>::iterator HandlerMapIt;
    310 
    311   PayloadSinkFactoryInterface* payload_sink_factory_;
    312   PayloadTypes payload_types_;
    313   HandlerMap handlers_;
    314 
    315   RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(SsrcHandlers);
    316 };
    317 
    318 class RtpPlayerImpl : public RtpPlayerInterface {
    319  public:
    320   RtpPlayerImpl(PayloadSinkFactoryInterface* payload_sink_factory,
    321                 const PayloadTypes& payload_types,
    322                 Clock* clock,
    323                 rtc::scoped_ptr<test::RtpFileReader>* packet_source,
    324                 float loss_rate,
    325                 int64_t rtt_ms,
    326                 bool reordering)
    327       : ssrc_handlers_(payload_sink_factory, payload_types),
    328         clock_(clock),
    329         next_rtp_time_(0),
    330         first_packet_(true),
    331         first_packet_rtp_time_(0),
    332         first_packet_time_ms_(0),
    333         loss_rate_(loss_rate),
    334         lost_packets_(clock, rtt_ms),
    335         resend_packet_count_(0),
    336         no_loss_startup_(100),
    337         end_of_file_(false),
    338         reordering_(false),
    339         reorder_buffer_() {
    340     assert(clock);
    341     assert(packet_source);
    342     assert(packet_source->get());
    343     packet_source_.swap(*packet_source);
    344     srand(321);
    345   }
    346 
    347   virtual ~RtpPlayerImpl() {}
    348 
    349   virtual int NextPacket(int64_t time_now) {
    350     // Send any packets ready to be resent.
    351     for (RawRtpPacket* packet = lost_packets_.NextPacketToResend(time_now);
    352          packet != NULL; packet = lost_packets_.NextPacketToResend(time_now)) {
    353       int ret = SendPacket(packet->data(), packet->length());
    354       if (ret > 0) {
    355         printf("Resend: %08x:%u\n", packet->ssrc(), packet->seq_num());
    356         lost_packets_.LogPacketResent(packet);
    357         resend_packet_count_++;
    358       }
    359       delete packet;
    360       if (ret < 0) {
    361         return ret;
    362       }
    363     }
    364 
    365     // Send any packets from packet source.
    366     if (!end_of_file_ && (TimeUntilNextPacket() == 0 || first_packet_)) {
    367       if (first_packet_) {
    368         if (!packet_source_->NextPacket(&next_packet_))
    369           return 0;
    370         first_packet_rtp_time_ = next_packet_.time_ms;
    371         first_packet_time_ms_ = clock_->TimeInMilliseconds();
    372         first_packet_ = false;
    373       }
    374 
    375       if (reordering_ && reorder_buffer_.get() == NULL) {
    376         reorder_buffer_.reset(
    377             new RawRtpPacket(next_packet_.data, next_packet_.length, 0, 0));
    378         return 0;
    379       }
    380       int ret = SendPacket(next_packet_.data, next_packet_.length);
    381       if (reorder_buffer_.get()) {
    382         SendPacket(reorder_buffer_->data(), reorder_buffer_->length());
    383         reorder_buffer_.reset(NULL);
    384       }
    385       if (ret < 0) {
    386         return ret;
    387       }
    388 
    389       if (!packet_source_->NextPacket(&next_packet_)) {
    390         end_of_file_ = true;
    391         return 0;
    392       } else if (next_packet_.length == 0) {
    393         return 0;
    394       }
    395     }
    396 
    397     if (end_of_file_ && lost_packets_.NumberOfPacketsToResend() == 0) {
    398       return 1;
    399     }
    400     return 0;
    401   }
    402 
    403   virtual uint32_t TimeUntilNextPacket() const {
    404     int64_t time_left = (next_rtp_time_ - first_packet_rtp_time_) -
    405                         (clock_->TimeInMilliseconds() - first_packet_time_ms_);
    406     if (time_left < 0) {
    407       return 0;
    408     }
    409     return static_cast<uint32_t>(time_left);
    410   }
    411 
    412   virtual void Print() const {
    413     printf("Resent packets: %u\n", resend_packet_count_);
    414     lost_packets_.Print();
    415   }
    416 
    417  private:
    418   int SendPacket(const uint8_t* data, size_t length) {
    419     assert(data);
    420     assert(length > 0);
    421 
    422     rtc::scoped_ptr<RtpHeaderParser> rtp_header_parser(
    423         RtpHeaderParser::Create());
    424     if (!rtp_header_parser->IsRtcp(data, length)) {
    425       RTPHeader header;
    426       if (!rtp_header_parser->Parse(data, length, &header)) {
    427         return -1;
    428       }
    429       uint32_t ssrc = header.ssrc;
    430       if (ssrc_handlers_.RegisterSsrc(ssrc, &lost_packets_, clock_) < 0) {
    431         DEBUG_LOG1("Unable to register ssrc: %d", ssrc);
    432         return -1;
    433       }
    434 
    435       if (no_loss_startup_ > 0) {
    436         no_loss_startup_--;
    437       } else if ((rand() + 1.0) / (RAND_MAX + 1.0) < loss_rate_) {  // NOLINT
    438         uint16_t seq_num = header.sequenceNumber;
    439         lost_packets_.AddPacket(new RawRtpPacket(data, length, ssrc, seq_num));
    440         DEBUG_LOG1("Dropped packet: %d!", header.header.sequenceNumber);
    441         return 0;
    442       }
    443     }
    444 
    445     ssrc_handlers_.IncomingPacket(data, length);
    446     return 1;
    447   }
    448 
    449   SsrcHandlers ssrc_handlers_;
    450   Clock* clock_;
    451   rtc::scoped_ptr<test::RtpFileReader> packet_source_;
    452   test::RtpPacket next_packet_;
    453   uint32_t next_rtp_time_;
    454   bool first_packet_;
    455   int64_t first_packet_rtp_time_;
    456   int64_t first_packet_time_ms_;
    457   float loss_rate_;
    458   LostPackets lost_packets_;
    459   uint32_t resend_packet_count_;
    460   uint32_t no_loss_startup_;
    461   bool end_of_file_;
    462   bool reordering_;
    463   rtc::scoped_ptr<RawRtpPacket> reorder_buffer_;
    464 
    465   RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(RtpPlayerImpl);
    466 };
    467 
    468 RtpPlayerInterface* Create(const std::string& input_filename,
    469                            PayloadSinkFactoryInterface* payload_sink_factory,
    470                            Clock* clock,
    471                            const PayloadTypes& payload_types,
    472                            float loss_rate,
    473                            int64_t rtt_ms,
    474                            bool reordering) {
    475   rtc::scoped_ptr<test::RtpFileReader> packet_source(
    476       test::RtpFileReader::Create(test::RtpFileReader::kRtpDump,
    477                                   input_filename));
    478   if (packet_source.get() == NULL) {
    479     packet_source.reset(test::RtpFileReader::Create(test::RtpFileReader::kPcap,
    480                                                     input_filename));
    481     if (packet_source.get() == NULL) {
    482       return NULL;
    483     }
    484   }
    485 
    486   rtc::scoped_ptr<RtpPlayerImpl> impl(
    487       new RtpPlayerImpl(payload_sink_factory, payload_types, clock,
    488                         &packet_source, loss_rate, rtt_ms, reordering));
    489   return impl.release();
    490 }
    491 }  // namespace rtpplayer
    492 }  // namespace webrtc
    493