1 /*
2  *  Copyright (c) 2013 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/remote_bitrate_estimator/inter_arrival.h"
12 
13 #include <algorithm>
14 #include <cassert>
15 
16 #include "webrtc/base/logging.h"
17 #include "webrtc/modules/include/module_common_types.h"
18 
19 namespace webrtc {
20 
21 static const int kBurstDeltaThresholdMs  = 5;
22 
InterArrival(uint32_t timestamp_group_length_ticks,double timestamp_to_ms_coeff,bool enable_burst_grouping)23 InterArrival::InterArrival(uint32_t timestamp_group_length_ticks,
24                            double timestamp_to_ms_coeff,
25                            bool enable_burst_grouping)
26     : kTimestampGroupLengthTicks(timestamp_group_length_ticks),
27       current_timestamp_group_(),
28       prev_timestamp_group_(),
29       timestamp_to_ms_coeff_(timestamp_to_ms_coeff),
30       burst_grouping_(enable_burst_grouping) {}
31 
ComputeDeltas(uint32_t timestamp,int64_t arrival_time_ms,size_t packet_size,uint32_t * timestamp_delta,int64_t * arrival_time_delta_ms,int * packet_size_delta)32 bool InterArrival::ComputeDeltas(uint32_t timestamp,
33                                  int64_t arrival_time_ms,
34                                  size_t packet_size,
35                                  uint32_t* timestamp_delta,
36                                  int64_t* arrival_time_delta_ms,
37                                  int* packet_size_delta) {
38   assert(timestamp_delta != NULL);
39   assert(arrival_time_delta_ms != NULL);
40   assert(packet_size_delta != NULL);
41   bool calculated_deltas = false;
42   if (current_timestamp_group_.IsFirstPacket()) {
43     // We don't have enough data to update the filter, so we store it until we
44     // have two frames of data to process.
45     current_timestamp_group_.timestamp = timestamp;
46     current_timestamp_group_.first_timestamp = timestamp;
47   } else if (!PacketInOrder(timestamp)) {
48     return false;
49   } else if (NewTimestampGroup(arrival_time_ms, timestamp)) {
50     // First packet of a later frame, the previous frame sample is ready.
51     if (prev_timestamp_group_.complete_time_ms >= 0) {
52       *timestamp_delta = current_timestamp_group_.timestamp -
53                          prev_timestamp_group_.timestamp;
54       *arrival_time_delta_ms = current_timestamp_group_.complete_time_ms -
55                                prev_timestamp_group_.complete_time_ms;
56       if (*arrival_time_delta_ms < 0) {
57         // The group of packets has been reordered since receiving its local
58         // arrival timestamp.
59         LOG(LS_WARNING) << "Packets are being reordered on the path from the "
60                            "socket to the bandwidth estimator. Ignoring this "
61                            "packet for bandwidth estimation.";
62         return false;
63       }
64       assert(*arrival_time_delta_ms >= 0);
65       *packet_size_delta = static_cast<int>(current_timestamp_group_.size) -
66           static_cast<int>(prev_timestamp_group_.size);
67       calculated_deltas = true;
68     }
69     prev_timestamp_group_ = current_timestamp_group_;
70     // The new timestamp is now the current frame.
71     current_timestamp_group_.first_timestamp = timestamp;
72     current_timestamp_group_.timestamp = timestamp;
73     current_timestamp_group_.size = 0;
74   } else {
75     current_timestamp_group_.timestamp = LatestTimestamp(
76         current_timestamp_group_.timestamp, timestamp);
77   }
78   // Accumulate the frame size.
79   current_timestamp_group_.size += packet_size;
80   current_timestamp_group_.complete_time_ms = arrival_time_ms;
81 
82   return calculated_deltas;
83 }
84 
PacketInOrder(uint32_t timestamp)85 bool InterArrival::PacketInOrder(uint32_t timestamp) {
86   if (current_timestamp_group_.IsFirstPacket()) {
87     return true;
88   } else {
89     // Assume that a diff which is bigger than half the timestamp interval
90     // (32 bits) must be due to reordering. This code is almost identical to
91     // that in IsNewerTimestamp() in module_common_types.h.
92     uint32_t timestamp_diff = timestamp -
93         current_timestamp_group_.first_timestamp;
94     return timestamp_diff < 0x80000000;
95   }
96 }
97 
98 // Assumes that |timestamp| is not reordered compared to
99 // |current_timestamp_group_|.
NewTimestampGroup(int64_t arrival_time_ms,uint32_t timestamp) const100 bool InterArrival::NewTimestampGroup(int64_t arrival_time_ms,
101                                      uint32_t timestamp) const {
102   if (current_timestamp_group_.IsFirstPacket()) {
103     return false;
104   } else if (BelongsToBurst(arrival_time_ms, timestamp)) {
105     return false;
106   } else {
107     uint32_t timestamp_diff = timestamp -
108         current_timestamp_group_.first_timestamp;
109     return timestamp_diff > kTimestampGroupLengthTicks;
110   }
111 }
112 
BelongsToBurst(int64_t arrival_time_ms,uint32_t timestamp) const113 bool InterArrival::BelongsToBurst(int64_t arrival_time_ms,
114                                   uint32_t timestamp) const {
115   if (!burst_grouping_) {
116     return false;
117   }
118   assert(current_timestamp_group_.complete_time_ms >= 0);
119   int64_t arrival_time_delta_ms = arrival_time_ms -
120       current_timestamp_group_.complete_time_ms;
121   uint32_t timestamp_diff = timestamp - current_timestamp_group_.timestamp;
122   int64_t ts_delta_ms = timestamp_to_ms_coeff_ * timestamp_diff + 0.5;
123   if (ts_delta_ms == 0)
124     return true;
125   int propagation_delta_ms = arrival_time_delta_ms - ts_delta_ms;
126   return propagation_delta_ms < 0 &&
127       arrival_time_delta_ms <= kBurstDeltaThresholdMs;
128 }
129 }  // namespace webrtc
130