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
18namespace webrtc {
19namespace test {
20
21PacketManipulatorImpl::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
33PacketManipulatorImpl::~PacketManipulatorImpl() {
34  delete critsect_;
35}
36
37int 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
84void PacketManipulatorImpl::InitializeRandomSeed(unsigned int seed) {
85  random_seed_ = seed;
86}
87
88inline 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
99const 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