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