1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
3*d9f75844SAndroid Build Coastguard Worker *
4*d9f75844SAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker * that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker * tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker * in the file PATENTS. All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker * be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker */
10*d9f75844SAndroid Build Coastguard Worker
11*d9f75844SAndroid Build Coastguard Worker #include "call/receive_time_calculator.h"
12*d9f75844SAndroid Build Coastguard Worker
13*d9f75844SAndroid Build Coastguard Worker #include <memory>
14*d9f75844SAndroid Build Coastguard Worker #include <string>
15*d9f75844SAndroid Build Coastguard Worker #include <type_traits>
16*d9f75844SAndroid Build Coastguard Worker
17*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/experiments/field_trial_parser.h"
18*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/numerics/safe_minmax.h"
19*d9f75844SAndroid Build Coastguard Worker
20*d9f75844SAndroid Build Coastguard Worker namespace webrtc {
21*d9f75844SAndroid Build Coastguard Worker namespace {
22*d9f75844SAndroid Build Coastguard Worker
23*d9f75844SAndroid Build Coastguard Worker const char kBweReceiveTimeCorrection[] = "WebRTC-Bwe-ReceiveTimeFix";
24*d9f75844SAndroid Build Coastguard Worker } // namespace
25*d9f75844SAndroid Build Coastguard Worker
ReceiveTimeCalculatorConfig(const FieldTrialsView & field_trials)26*d9f75844SAndroid Build Coastguard Worker ReceiveTimeCalculatorConfig::ReceiveTimeCalculatorConfig(
27*d9f75844SAndroid Build Coastguard Worker const FieldTrialsView& field_trials)
28*d9f75844SAndroid Build Coastguard Worker : max_packet_time_repair("maxrep", TimeDelta::Millis(2000)),
29*d9f75844SAndroid Build Coastguard Worker stall_threshold("stall", TimeDelta::Millis(5)),
30*d9f75844SAndroid Build Coastguard Worker tolerance("tol", TimeDelta::Millis(1)),
31*d9f75844SAndroid Build Coastguard Worker max_stall("maxstall", TimeDelta::Seconds(5)) {
32*d9f75844SAndroid Build Coastguard Worker std::string trial_string = field_trials.Lookup(kBweReceiveTimeCorrection);
33*d9f75844SAndroid Build Coastguard Worker ParseFieldTrial(
34*d9f75844SAndroid Build Coastguard Worker {&max_packet_time_repair, &stall_threshold, &tolerance, &max_stall},
35*d9f75844SAndroid Build Coastguard Worker trial_string);
36*d9f75844SAndroid Build Coastguard Worker }
37*d9f75844SAndroid Build Coastguard Worker ReceiveTimeCalculatorConfig::ReceiveTimeCalculatorConfig(
38*d9f75844SAndroid Build Coastguard Worker const ReceiveTimeCalculatorConfig&) = default;
39*d9f75844SAndroid Build Coastguard Worker ReceiveTimeCalculatorConfig::~ReceiveTimeCalculatorConfig() = default;
40*d9f75844SAndroid Build Coastguard Worker
ReceiveTimeCalculator(const FieldTrialsView & field_trials)41*d9f75844SAndroid Build Coastguard Worker ReceiveTimeCalculator::ReceiveTimeCalculator(
42*d9f75844SAndroid Build Coastguard Worker const FieldTrialsView& field_trials)
43*d9f75844SAndroid Build Coastguard Worker : config_(field_trials) {}
44*d9f75844SAndroid Build Coastguard Worker
45*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<ReceiveTimeCalculator>
CreateFromFieldTrial(const FieldTrialsView & field_trials)46*d9f75844SAndroid Build Coastguard Worker ReceiveTimeCalculator::CreateFromFieldTrial(
47*d9f75844SAndroid Build Coastguard Worker const FieldTrialsView& field_trials) {
48*d9f75844SAndroid Build Coastguard Worker if (!field_trials.IsEnabled(kBweReceiveTimeCorrection))
49*d9f75844SAndroid Build Coastguard Worker return nullptr;
50*d9f75844SAndroid Build Coastguard Worker return std::make_unique<ReceiveTimeCalculator>(field_trials);
51*d9f75844SAndroid Build Coastguard Worker }
52*d9f75844SAndroid Build Coastguard Worker
ReconcileReceiveTimes(int64_t packet_time_us,int64_t system_time_us,int64_t safe_time_us)53*d9f75844SAndroid Build Coastguard Worker int64_t ReceiveTimeCalculator::ReconcileReceiveTimes(int64_t packet_time_us,
54*d9f75844SAndroid Build Coastguard Worker int64_t system_time_us,
55*d9f75844SAndroid Build Coastguard Worker int64_t safe_time_us) {
56*d9f75844SAndroid Build Coastguard Worker int64_t stall_time_us = system_time_us - packet_time_us;
57*d9f75844SAndroid Build Coastguard Worker if (total_system_time_passed_us_ < config_.stall_threshold->us()) {
58*d9f75844SAndroid Build Coastguard Worker stall_time_us = rtc::SafeMin(stall_time_us, config_.max_stall->us());
59*d9f75844SAndroid Build Coastguard Worker }
60*d9f75844SAndroid Build Coastguard Worker int64_t corrected_time_us = safe_time_us - stall_time_us;
61*d9f75844SAndroid Build Coastguard Worker
62*d9f75844SAndroid Build Coastguard Worker if (last_packet_time_us_ == -1 && stall_time_us < 0) {
63*d9f75844SAndroid Build Coastguard Worker static_clock_offset_us_ = stall_time_us;
64*d9f75844SAndroid Build Coastguard Worker corrected_time_us += static_clock_offset_us_;
65*d9f75844SAndroid Build Coastguard Worker } else if (last_packet_time_us_ > 0) {
66*d9f75844SAndroid Build Coastguard Worker // All repairs depend on variables being intialized
67*d9f75844SAndroid Build Coastguard Worker int64_t packet_time_delta_us = packet_time_us - last_packet_time_us_;
68*d9f75844SAndroid Build Coastguard Worker int64_t system_time_delta_us = system_time_us - last_system_time_us_;
69*d9f75844SAndroid Build Coastguard Worker int64_t safe_time_delta_us = safe_time_us - last_safe_time_us_;
70*d9f75844SAndroid Build Coastguard Worker
71*d9f75844SAndroid Build Coastguard Worker // Repair backwards clock resets during initial stall. In this case, the
72*d9f75844SAndroid Build Coastguard Worker // reset is observed only in packet time but never in system time.
73*d9f75844SAndroid Build Coastguard Worker if (system_time_delta_us < 0)
74*d9f75844SAndroid Build Coastguard Worker total_system_time_passed_us_ += config_.stall_threshold->us();
75*d9f75844SAndroid Build Coastguard Worker else
76*d9f75844SAndroid Build Coastguard Worker total_system_time_passed_us_ += system_time_delta_us;
77*d9f75844SAndroid Build Coastguard Worker if (packet_time_delta_us < 0 &&
78*d9f75844SAndroid Build Coastguard Worker total_system_time_passed_us_ < config_.stall_threshold->us()) {
79*d9f75844SAndroid Build Coastguard Worker static_clock_offset_us_ -= packet_time_delta_us;
80*d9f75844SAndroid Build Coastguard Worker }
81*d9f75844SAndroid Build Coastguard Worker corrected_time_us += static_clock_offset_us_;
82*d9f75844SAndroid Build Coastguard Worker
83*d9f75844SAndroid Build Coastguard Worker // Detect resets inbetween clock readings in socket and app.
84*d9f75844SAndroid Build Coastguard Worker bool forward_clock_reset =
85*d9f75844SAndroid Build Coastguard Worker corrected_time_us + config_.tolerance->us() < last_corrected_time_us_;
86*d9f75844SAndroid Build Coastguard Worker bool obvious_backward_clock_reset = system_time_us < packet_time_us;
87*d9f75844SAndroid Build Coastguard Worker
88*d9f75844SAndroid Build Coastguard Worker // Harder case with backward clock reset during stall, the reset being
89*d9f75844SAndroid Build Coastguard Worker // smaller than the stall. Compensate throughout the stall.
90*d9f75844SAndroid Build Coastguard Worker bool small_backward_clock_reset =
91*d9f75844SAndroid Build Coastguard Worker !obvious_backward_clock_reset &&
92*d9f75844SAndroid Build Coastguard Worker safe_time_delta_us > system_time_delta_us + config_.tolerance->us();
93*d9f75844SAndroid Build Coastguard Worker bool stall_start =
94*d9f75844SAndroid Build Coastguard Worker packet_time_delta_us >= 0 &&
95*d9f75844SAndroid Build Coastguard Worker system_time_delta_us > packet_time_delta_us + config_.tolerance->us();
96*d9f75844SAndroid Build Coastguard Worker bool stall_is_over = safe_time_delta_us > config_.stall_threshold->us();
97*d9f75844SAndroid Build Coastguard Worker bool packet_time_caught_up =
98*d9f75844SAndroid Build Coastguard Worker packet_time_delta_us < 0 && system_time_delta_us >= 0;
99*d9f75844SAndroid Build Coastguard Worker if (stall_start && small_backward_clock_reset)
100*d9f75844SAndroid Build Coastguard Worker small_reset_during_stall_ = true;
101*d9f75844SAndroid Build Coastguard Worker else if (stall_is_over || packet_time_caught_up)
102*d9f75844SAndroid Build Coastguard Worker small_reset_during_stall_ = false;
103*d9f75844SAndroid Build Coastguard Worker
104*d9f75844SAndroid Build Coastguard Worker // If resets are detected, advance time by (capped) packet time increase.
105*d9f75844SAndroid Build Coastguard Worker if (forward_clock_reset || obvious_backward_clock_reset ||
106*d9f75844SAndroid Build Coastguard Worker small_reset_during_stall_) {
107*d9f75844SAndroid Build Coastguard Worker corrected_time_us = last_corrected_time_us_ +
108*d9f75844SAndroid Build Coastguard Worker rtc::SafeClamp(packet_time_delta_us, 0,
109*d9f75844SAndroid Build Coastguard Worker config_.max_packet_time_repair->us());
110*d9f75844SAndroid Build Coastguard Worker }
111*d9f75844SAndroid Build Coastguard Worker }
112*d9f75844SAndroid Build Coastguard Worker
113*d9f75844SAndroid Build Coastguard Worker last_corrected_time_us_ = corrected_time_us;
114*d9f75844SAndroid Build Coastguard Worker last_packet_time_us_ = packet_time_us;
115*d9f75844SAndroid Build Coastguard Worker last_system_time_us_ = system_time_us;
116*d9f75844SAndroid Build Coastguard Worker last_safe_time_us_ = safe_time_us;
117*d9f75844SAndroid Build Coastguard Worker return corrected_time_us;
118*d9f75844SAndroid Build Coastguard Worker }
119*d9f75844SAndroid Build Coastguard Worker
120*d9f75844SAndroid Build Coastguard Worker } // namespace webrtc
121