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/codecs/test/packet_manipulator.h"
     12 
     13 #include <assert.h>
     14 #include <stdio.h>
     15 
     16 #include "webrtc/base/format_macros.h"
     17 
     18 namespace webrtc {
     19 namespace test {
     20 
     21 PacketManipulatorImpl::PacketManipulatorImpl(PacketReader* packet_reader,
     22                                              const NetworkingConfig& config,
     23                                              bool verbose)
     24     : packet_reader_(packet_reader),
     25       config_(config),
     26       active_burst_packets_(0),
     27       critsect_(CriticalSectionWrapper::CreateCriticalSection()),
     28       random_seed_(1),
     29       verbose_(verbose) {
     30   assert(packet_reader);
     31 }
     32 
     33 PacketManipulatorImpl::~PacketManipulatorImpl() {
     34   delete critsect_;
     35 }
     36 
     37 int PacketManipulatorImpl::ManipulatePackets(
     38     webrtc::EncodedImage* encoded_image) {
     39   int nbr_packets_dropped = 0;
     40   // There's no need to build a copy of the image data since viewing an
     41   // EncodedImage object, setting the length to a new lower value represents
     42   // that everything is dropped after that position in the byte array.
     43   // EncodedImage._size is the allocated bytes.
     44   // EncodedImage._length is how many that are filled with data.
     45   int new_length = 0;
     46   packet_reader_->InitializeReading(encoded_image->_buffer,
     47                                     encoded_image->_length,
     48                                     config_.packet_size_in_bytes);
     49   uint8_t* packet = NULL;
     50   int nbr_bytes_to_read;
     51   // keep track of if we've lost any packets, since then we shall loose
     52   // the remains of the current frame:
     53   bool packet_loss_has_occurred = false;
     54   while ((nbr_bytes_to_read = packet_reader_->NextPacket(&packet)) > 0) {
     55     // Check if we're currently in a packet loss burst that is not completed:
     56     if (active_burst_packets_ > 0) {
     57       active_burst_packets_--;
     58       nbr_packets_dropped++;
     59     } else if (RandomUniform() < config_.packet_loss_probability ||
     60                packet_loss_has_occurred) {
     61       packet_loss_has_occurred = true;
     62       nbr_packets_dropped++;
     63       if (config_.packet_loss_mode == kBurst) {
     64         // Initiate a new burst
     65         active_burst_packets_ = config_.packet_loss_burst_length - 1;
     66       }
     67     } else {
     68       new_length += nbr_bytes_to_read;
     69     }
     70   }
     71   encoded_image->_length = new_length;
     72   if (nbr_packets_dropped > 0) {
     73     // Must set completeFrame to false to inform the decoder about this:
     74     encoded_image->_completeFrame = false;
     75     if (verbose_) {
     76       printf("Dropped %d packets for frame %d (frame length: %" PRIuS ")\n",
     77              nbr_packets_dropped, encoded_image->_timeStamp,
     78              encoded_image->_length);
     79     }
     80   }
     81   return nbr_packets_dropped;
     82 }
     83 
     84 void PacketManipulatorImpl::InitializeRandomSeed(unsigned int seed) {
     85   random_seed_ = seed;
     86 }
     87 
     88 inline double PacketManipulatorImpl::RandomUniform() {
     89   // Use the previous result as new seed before each rand() call. Doing this
     90   // it doesn't matter if other threads are calling rand() since we'll always
     91   // get the same behavior as long as we're using a fixed initial seed.
     92   critsect_->Enter();
     93   srand(random_seed_);
     94   random_seed_ = rand();  // NOLINT (rand_r instead of rand)
     95   critsect_->Leave();
     96   return (random_seed_ + 1.0) / (RAND_MAX + 1.0);
     97 }
     98 
     99 const char* PacketLossModeToStr(PacketLossMode e) {
    100   switch (e) {
    101     case kUniform:
    102       return "Uniform";
    103     case kBurst:
    104       return "Burst";
    105     default:
    106       assert(false);
    107       return "Unknown";
    108   }
    109 }
    110 
    111 }  // namespace test
    112 }  // namespace webrtc
    113