From b34556e5986800edf16c8ab5fe9132c05f74a3b0 Mon Sep 17 00:00:00 2001 From: Sebastian Jansson Date: Wed, 21 Mar 2018 14:38:32 +0100 Subject: [PATCH] Added receive time calculator under field trial. The receive time calculator combines the packet time stamps received from the socket interface with the system clock used in WebRTC. This means that the packet timestamps are set in the WebRTC clock timebase and that large jumps in the time stamps from the socket will not affect the reported receive time stamps. Bug: None Change-Id: I293925c41919829524a115bb9377027bf0a797fb Reviewed-on: https://webrtc-review.googlesource.com/61862 Reviewed-by: Niels Moller Reviewed-by: Christoffer Rodbro Commit-Queue: Sebastian Jansson Cr-Commit-Position: refs/heads/master@{#22540} --- call/BUILD.gn | 3 + call/call.cc | 12 +++- call/receive_time_calculator.cc | 67 +++++++++++++++++++++ call/receive_time_calculator.h | 47 +++++++++++++++ call/receive_time_calculator_unittest.cc | 74 ++++++++++++++++++++++++ 5 files changed, 202 insertions(+), 1 deletion(-) create mode 100644 call/receive_time_calculator.cc create mode 100644 call/receive_time_calculator.h create mode 100644 call/receive_time_calculator_unittest.cc diff --git a/call/BUILD.gn b/call/BUILD.gn index eeb82e85f6..f43acd3e31 100644 --- a/call/BUILD.gn +++ b/call/BUILD.gn @@ -147,6 +147,8 @@ rtc_static_library("call") { "degraded_call.h", "flexfec_receive_stream_impl.cc", "flexfec_receive_stream_impl.h", + "receive_time_calculator.cc", + "receive_time_calculator.h", ] if (!build_with_chromium && is_clang) { @@ -249,6 +251,7 @@ if (rtc_include_tests) { "bitrate_estimator_tests.cc", "call_unittest.cc", "flexfec_receive_stream_unittest.cc", + "receive_time_calculator_unittest.cc", "rtcp_demuxer_unittest.cc", "rtp_bitrate_configurator_unittest.cc", "rtp_demuxer_unittest.cc", diff --git a/call/call.cc b/call/call.cc index b7f54e554f..3cd9864d1a 100644 --- a/call/call.cc +++ b/call/call.cc @@ -24,6 +24,7 @@ #include "call/bitrate_allocator.h" #include "call/call.h" #include "call/flexfec_receive_stream_impl.h" +#include "call/receive_time_calculator.h" #include "call/rtp_stream_receiver_controller.h" #include "call/rtp_transport_controller_send.h" #include "logging/rtc_event_log/events/rtc_event_audio_receive_stream_config.h" @@ -362,6 +363,9 @@ class Call : public webrtc::Call, RateLimiter retransmission_rate_limiter_; std::unique_ptr transport_send_; ReceiveSideCongestionController receive_side_cc_; + + const std::unique_ptr receive_time_calculator_; + const std::unique_ptr video_send_delay_stats_; const int64_t start_ms_; // TODO(perkj): |worker_queue_| is supposed to replace @@ -436,6 +440,7 @@ Call::Call(const Call::Config& config, pacer_bitrate_kbps_counter_(clock_, nullptr, true), retransmission_rate_limiter_(clock_, kRetransmitWindowSizeMs), receive_side_cc_(clock_, transport_send->packet_router()), + receive_time_calculator_(ReceiveTimeCalculator::CreateFromFieldTrial()), video_send_delay_stats_(new SendDelayStats(clock_)), start_ms_(clock_->TimeInMilliseconds()), worker_queue_("call_worker_queue") { @@ -1227,7 +1232,12 @@ PacketReceiver::DeliveryStatus Call::DeliverRtp(MediaType media_type, return DELIVERY_PACKET_ERROR; if (packet_time.timestamp != -1) { - parsed_packet.set_arrival_time_ms((packet_time.timestamp + 500) / 1000); + int64_t timestamp_us = packet_time.timestamp; + if (receive_time_calculator_) { + timestamp_us = receive_time_calculator_->ReconcileReceiveTimes( + packet_time.timestamp, clock_->TimeInMicroseconds()); + } + parsed_packet.set_arrival_time_ms((timestamp_us + 500) / 1000); } else { parsed_packet.set_arrival_time_ms(clock_->TimeInMilliseconds()); } diff --git a/call/receive_time_calculator.cc b/call/receive_time_calculator.cc new file mode 100644 index 0000000000..ecc0272f99 --- /dev/null +++ b/call/receive_time_calculator.cc @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2018 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 "call/receive_time_calculator.h" +#include "rtc_base/logging.h" +#include "rtc_base/ptr_util.h" +#include "system_wrappers/include/field_trial.h" + +namespace webrtc { +namespace { +using ::webrtc::field_trial::FindFullName; +using ::webrtc::field_trial::IsEnabled; + +const char kBweReceiveTimeCorrection[] = "WebRTC-BweReceiveTimeCorrection"; +} // namespace + +ReceiveTimeCalculator::ReceiveTimeCalculator(int64_t min_delta_ms, + int64_t max_delta_diff_ms) + : min_delta_us_(min_delta_ms * 1000), + max_delta_diff_us_(max_delta_diff_ms * 1000) {} + +std::unique_ptr +ReceiveTimeCalculator::CreateFromFieldTrial() { + if (!IsEnabled(kBweReceiveTimeCorrection)) + return nullptr; + int min, max; + if (sscanf(FindFullName(kBweReceiveTimeCorrection).c_str(), "Enabled/%d,%d", + &min, &max) != 2) { + RTC_LOG(LS_WARNING) << "Invalid number of parameters provided."; + return nullptr; + } + return rtc::MakeUnique(min, max); +} + +int64_t ReceiveTimeCalculator::ReconcileReceiveTimes(int64_t packet_time_us_, + int64_t safe_time_us_) { + if (!receive_time_offset_us_) { + receive_time_offset_us_ = safe_time_us_ - packet_time_us_; + } else { + int64_t safe_delta_us = safe_time_us_ - last_safe_time_us_; + int64_t packet_delta_us_ = packet_time_us_ - last_packet_time_us_; + int64_t delta_diff = packet_delta_us_ - safe_delta_us; + // Packet time should not decrease significantly, a large decrease indicates + // a reset of the packet time clock and we should reset the offest + // parameter. The safe reference time can increase in large jumps if the + // thread measuring it is backgrounded for longer periods. But if the packet + // time increases significantly more than the safe time, it indicates a + // clock reset and we should reset the offset. + + if (packet_delta_us_ < min_delta_us_ || delta_diff > max_delta_diff_us_) { + RTC_LOG(LS_WARNING) << "Received a clock jump of " << delta_diff + << " resetting offset"; + receive_time_offset_us_ = safe_time_us_ - packet_time_us_; + } + } + last_packet_time_us_ = packet_time_us_; + last_safe_time_us_ = safe_time_us_; + return packet_time_us_ + *receive_time_offset_us_; +} +} // namespace webrtc diff --git a/call/receive_time_calculator.h b/call/receive_time_calculator.h new file mode 100644 index 0000000000..b2dc00375d --- /dev/null +++ b/call/receive_time_calculator.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2018 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. + */ +#ifndef CALL_RECEIVE_TIME_CALCULATOR_H_ +#define CALL_RECEIVE_TIME_CALCULATOR_H_ + +#include +#include + +#include "api/optional.h" + +namespace webrtc { + +// The receive time calculator serves the purpose of combining packet time +// stamps with a safely incremental clock. This assumes that the packet time +// stamps are based on lower layer timestamps that have more accurate time +// increments since they are based on the exact receive time. They might +// however, have large jumps due to clock resets in the system. To compensate +// this they are combined with a safe clock source that is guaranteed to be +// consistent, but it will not be able to measure the exact time when a packet +// is received. +class ReceiveTimeCalculator { + public: + static std::unique_ptr CreateFromFieldTrial(); + // The min delta is used to correct for jumps backwards in time, to allow some + // packet reordering a small negative value is appropriate to use. The max + // delta difference is used as margin when detecting when packet time + // increases more than the safe clock. This should be larger than the largest + // expected sysmtem induced delay in the safe clock timestamp. + ReceiveTimeCalculator(int64_t min_delta_ms, int64_t max_delta_diff_ms); + int64_t ReconcileReceiveTimes(int64_t packet_time_us_, int64_t safe_time_us_); + + private: + const int64_t min_delta_us_; + const int64_t max_delta_diff_us_; + rtc::Optional receive_time_offset_us_; + int64_t last_packet_time_us_ = 0; + int64_t last_safe_time_us_ = 0; +}; +} // namespace webrtc +#endif // CALL_RECEIVE_TIME_CALCULATOR_H_ diff --git a/call/receive_time_calculator_unittest.cc b/call/receive_time_calculator_unittest.cc new file mode 100644 index 0000000000..92d5a279ea --- /dev/null +++ b/call/receive_time_calculator_unittest.cc @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2018 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 "call/receive_time_calculator.h" + +#include "test/gtest.h" + +namespace webrtc { +namespace test { +namespace { + +int64_t ReconcileMs(ReceiveTimeCalculator* calc, + int64_t packet_time_ms, + int64_t safe_time_ms) { + return calc->ReconcileReceiveTimes(packet_time_ms * 1000, + safe_time_ms * 1000) / + 1000; +} +} // namespace + +TEST(ReceiveTimeCalculatorTest, UsesSmallerIncrements) { + int64_t kMinDeltaMs = -20; + int64_t kMaxDeltaDiffMs = 100; + ReceiveTimeCalculator calc(kMinDeltaMs, kMaxDeltaDiffMs); + // Initialize offset. + ReconcileMs(&calc, 10000, 20000); + + EXPECT_EQ(ReconcileMs(&calc, 10010, 20100), 20010); + EXPECT_EQ(ReconcileMs(&calc, 10020, 20100), 20020); + EXPECT_EQ(ReconcileMs(&calc, 10030, 20100), 20030); + + EXPECT_EQ(ReconcileMs(&calc, 10110, 20200), 20110); + EXPECT_EQ(ReconcileMs(&calc, 10120, 20200), 20120); + EXPECT_EQ(ReconcileMs(&calc, 10130, 20200), 20130); + + // Small jumps backwards are let trough, they might be due to reordering. + EXPECT_EQ(ReconcileMs(&calc, 10120, 20200), 20120); + // The safe clock might be smaller than the packet clock. + EXPECT_EQ(ReconcileMs(&calc, 10210, 20200), 20210); + EXPECT_EQ(ReconcileMs(&calc, 10240, 20200), 20240); +} + +TEST(ReceiveTimeCalculatorTest, CorrectsJumps) { + int64_t kMinDeltaMs = -20; + int64_t kMaxDeltaDiffMs = 100; + ReceiveTimeCalculator calc(kMinDeltaMs, kMaxDeltaDiffMs); + // Initialize offset. + ReconcileMs(&calc, 10000, 20000); + + EXPECT_EQ(ReconcileMs(&calc, 10010, 20100), 20010); + EXPECT_EQ(ReconcileMs(&calc, 10020, 20100), 20020); + EXPECT_EQ(ReconcileMs(&calc, 10030, 20100), 20030); + + // Jump forward in time. + EXPECT_EQ(ReconcileMs(&calc, 10240, 20200), 20200); + EXPECT_EQ(ReconcileMs(&calc, 10250, 20200), 20210); + EXPECT_EQ(ReconcileMs(&calc, 10260, 20200), 20220); + + // Jump backward in time. + EXPECT_EQ(ReconcileMs(&calc, 10230, 20300), 20300); + EXPECT_EQ(ReconcileMs(&calc, 10240, 20300), 20310); + EXPECT_EQ(ReconcileMs(&calc, 10250, 20300), 20320); +} + +} // namespace test + +} // namespace webrtc