blob: a9d0f8860d26256b917cb03fa2f92254f981f450 [file] [log] [blame]
/*
* 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,
uint32_t* timestamp_delta,
int64_t* arrival_time_delta_ms) {
assert(timestamp_delta != NULL);
assert(arrival_time_delta_ms != 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);
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;
}
else {
current_timestamp_group_.timestamp = LatestTimestamp(
current_timestamp_group_.timestamp, timestamp);
}
current_timestamp_group_.complete_time_ms =
std::max(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