|  | /* | 
|  | *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. | 
|  | * | 
|  | *  Use of this source code is governed by a BSD-style license | 
|  | *  that can be found in the LICENSE file in the root of the source | 
|  | *  tree. An additional intellectual property rights grant can be found | 
|  | *  in the file PATENTS.  All contributing project authors may | 
|  | *  be found in the AUTHORS file in the root of the source tree. | 
|  | */ | 
|  |  | 
|  | #include "webrtc/modules/remote_bitrate_estimator/inter_arrival.h" | 
|  |  | 
|  | #include <algorithm> | 
|  | #include <cassert> | 
|  |  | 
|  | #include "webrtc/base/logging.h" | 
|  | #include "webrtc/modules/include/module_common_types.h" | 
|  |  | 
|  | namespace webrtc { | 
|  |  | 
|  | static const int kBurstDeltaThresholdMs = 5; | 
|  |  | 
|  | InterArrival::InterArrival(uint32_t timestamp_group_length_ticks, | 
|  | double timestamp_to_ms_coeff, | 
|  | bool enable_burst_grouping) | 
|  | : kTimestampGroupLengthTicks(timestamp_group_length_ticks), | 
|  | current_timestamp_group_(), | 
|  | prev_timestamp_group_(), | 
|  | timestamp_to_ms_coeff_(timestamp_to_ms_coeff), | 
|  | burst_grouping_(enable_burst_grouping) {} | 
|  |  | 
|  | bool InterArrival::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) { | 
|  | assert(timestamp_delta != NULL); | 
|  | assert(arrival_time_delta_ms != NULL); | 
|  | assert(packet_size_delta != NULL); | 
|  | bool calculated_deltas = false; | 
|  | if (current_timestamp_group_.IsFirstPacket()) { | 
|  | // We don't have enough data to update the filter, so we store it until we | 
|  | // have two frames of data to process. | 
|  | current_timestamp_group_.timestamp = timestamp; | 
|  | current_timestamp_group_.first_timestamp = timestamp; | 
|  | } else if (!PacketInOrder(timestamp)) { | 
|  | return false; | 
|  | } else if (NewTimestampGroup(arrival_time_ms, timestamp)) { | 
|  | // First packet of a later frame, the previous frame sample is ready. | 
|  | if (prev_timestamp_group_.complete_time_ms >= 0) { | 
|  | *timestamp_delta = current_timestamp_group_.timestamp - | 
|  | prev_timestamp_group_.timestamp; | 
|  | *arrival_time_delta_ms = current_timestamp_group_.complete_time_ms - | 
|  | prev_timestamp_group_.complete_time_ms; | 
|  | if (*arrival_time_delta_ms < 0) { | 
|  | // The group of packets has been reordered since receiving its local | 
|  | // arrival timestamp. | 
|  | LOG(LS_WARNING) << "Packets are being reordered on the path from the " | 
|  | "socket to the bandwidth estimator. Ignoring this " | 
|  | "packet for bandwidth estimation."; | 
|  | return false; | 
|  | } | 
|  | assert(*arrival_time_delta_ms >= 0); | 
|  | *packet_size_delta = static_cast<int>(current_timestamp_group_.size) - | 
|  | static_cast<int>(prev_timestamp_group_.size); | 
|  | calculated_deltas = true; | 
|  | } | 
|  | prev_timestamp_group_ = current_timestamp_group_; | 
|  | // The new timestamp is now the current frame. | 
|  | current_timestamp_group_.first_timestamp = timestamp; | 
|  | current_timestamp_group_.timestamp = timestamp; | 
|  | current_timestamp_group_.size = 0; | 
|  | } else { | 
|  | current_timestamp_group_.timestamp = LatestTimestamp( | 
|  | current_timestamp_group_.timestamp, timestamp); | 
|  | } | 
|  | // Accumulate the frame size. | 
|  | current_timestamp_group_.size += packet_size; | 
|  | current_timestamp_group_.complete_time_ms = arrival_time_ms; | 
|  |  | 
|  | return calculated_deltas; | 
|  | } | 
|  |  | 
|  | bool InterArrival::PacketInOrder(uint32_t timestamp) { | 
|  | if (current_timestamp_group_.IsFirstPacket()) { | 
|  | return true; | 
|  | } else { | 
|  | // Assume that a diff which is bigger than half the timestamp interval | 
|  | // (32 bits) must be due to reordering. This code is almost identical to | 
|  | // that in IsNewerTimestamp() in module_common_types.h. | 
|  | uint32_t timestamp_diff = timestamp - | 
|  | current_timestamp_group_.first_timestamp; | 
|  | return timestamp_diff < 0x80000000; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Assumes that |timestamp| is not reordered compared to | 
|  | // |current_timestamp_group_|. | 
|  | bool InterArrival::NewTimestampGroup(int64_t arrival_time_ms, | 
|  | uint32_t timestamp) const { | 
|  | if (current_timestamp_group_.IsFirstPacket()) { | 
|  | return false; | 
|  | } else if (BelongsToBurst(arrival_time_ms, timestamp)) { | 
|  | return false; | 
|  | } else { | 
|  | uint32_t timestamp_diff = timestamp - | 
|  | current_timestamp_group_.first_timestamp; | 
|  | return timestamp_diff > kTimestampGroupLengthTicks; | 
|  | } | 
|  | } | 
|  |  | 
|  | bool InterArrival::BelongsToBurst(int64_t arrival_time_ms, | 
|  | uint32_t timestamp) const { | 
|  | if (!burst_grouping_) { | 
|  | return false; | 
|  | } | 
|  | assert(current_timestamp_group_.complete_time_ms >= 0); | 
|  | int64_t arrival_time_delta_ms = arrival_time_ms - | 
|  | current_timestamp_group_.complete_time_ms; | 
|  | uint32_t timestamp_diff = timestamp - current_timestamp_group_.timestamp; | 
|  | int64_t ts_delta_ms = timestamp_to_ms_coeff_ * timestamp_diff + 0.5; | 
|  | if (ts_delta_ms == 0) | 
|  | return true; | 
|  | int propagation_delta_ms = arrival_time_delta_ms - ts_delta_ms; | 
|  | return propagation_delta_ms < 0 && | 
|  | arrival_time_delta_ms <= kBurstDeltaThresholdMs; | 
|  | } | 
|  | }  // namespace webrtc |