blob: 918b9c5b0e11aa914a345f0af94270d1ef38b8ab [file] [log] [blame]
sprang5e023eb2015-09-14 06:42:43 -07001/*
2 * Copyright (c) 2015 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
Stefan Holmer280de9e2016-09-30 10:06:51 +020011#include "webrtc/modules/congestion_controller/transport_feedback_adapter.h"
mflodman0e7e2592015-11-12 21:02:42 -080012
stefan9e117c5e12017-08-16 08:16:25 -070013#include <algorithm>
14
Stefan Holmer280de9e2016-09-30 10:06:51 +020015#include "webrtc/modules/congestion_controller/delay_based_bwe.h"
sprang5e023eb2015-09-14 06:42:43 -070016#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
Edward Lemurc20978e2017-07-06 19:44:34 +020017#include "webrtc/rtc_base/checks.h"
18#include "webrtc/rtc_base/logging.h"
19#include "webrtc/rtc_base/mod_ops.h"
nisse284542b2017-01-10 08:58:32 -080020#include "webrtc/system_wrappers/include/field_trial.h"
sprang5e023eb2015-09-14 06:42:43 -070021
22namespace webrtc {
23
24const int64_t kNoTimestamp = -1;
stefane9ad2712017-02-10 06:09:28 -080025const int64_t kSendTimeHistoryWindowMs = 60000;
sprang5e023eb2015-09-14 06:42:43 -070026const int64_t kBaseTimestampScaleFactor =
27 rtcp::TransportFeedback::kDeltaScaleFactor * (1 << 8);
28const int64_t kBaseTimestampRangeSizeUs = kBaseTimestampScaleFactor * (1 << 24);
29
elad.alon61ce37e2017-03-09 07:09:31 -080030TransportFeedbackAdapter::TransportFeedbackAdapter(const Clock* clock)
sprangc1b57a12017-02-28 08:50:47 -080031 : send_side_bwe_with_overhead_(
32 webrtc::field_trial::IsEnabled("WebRTC-SendSideBwe-WithOverhead")),
elad.alon0fe12162017-01-31 05:48:37 -080033 transport_overhead_bytes_per_packet_(0),
michaeltf4caaab2017-01-16 23:55:07 -080034 send_time_history_(clock, kSendTimeHistoryWindowMs),
sprang5e023eb2015-09-14 06:42:43 -070035 clock_(clock),
36 current_offset_ms_(kNoTimestamp),
Stefan Holmer9ea46b52017-03-15 12:40:25 +010037 last_timestamp_us_(kNoTimestamp),
38 local_net_id_(0),
39 remote_net_id_(0) {}
sprang5e023eb2015-09-14 06:42:43 -070040
elad.alond12a8e12017-03-23 11:04:48 -070041TransportFeedbackAdapter::~TransportFeedbackAdapter() {
42 RTC_DCHECK(observers_.empty());
43}
sprang5e023eb2015-09-14 06:42:43 -070044
elad.alond12a8e12017-03-23 11:04:48 -070045void TransportFeedbackAdapter::RegisterPacketFeedbackObserver(
46 PacketFeedbackObserver* observer) {
47 rtc::CritScope cs(&observers_lock_);
48 RTC_DCHECK(observer);
49 RTC_DCHECK(std::find(observers_.begin(), observers_.end(), observer) ==
50 observers_.end());
51 observers_.push_back(observer);
52}
53
54void TransportFeedbackAdapter::DeRegisterPacketFeedbackObserver(
55 PacketFeedbackObserver* observer) {
56 rtc::CritScope cs(&observers_lock_);
57 RTC_DCHECK(observer);
58 const auto it = std::find(observers_.begin(), observers_.end(), observer);
59 RTC_DCHECK(it != observers_.end());
60 observers_.erase(it);
61}
62
63void TransportFeedbackAdapter::AddPacket(uint32_t ssrc,
64 uint16_t sequence_number,
stefanbbe876f2015-10-23 02:05:40 -070065 size_t length,
philipel8aadd502017-02-23 02:56:13 -080066 const PacedPacketInfo& pacing_info) {
elad.alond12a8e12017-03-23 11:04:48 -070067 {
68 rtc::CritScope cs(&lock_);
69 if (send_side_bwe_with_overhead_) {
70 length += transport_overhead_bytes_per_packet_;
71 }
72 const int64_t creation_time_ms = clock_->TimeInMilliseconds();
73 send_time_history_.AddAndRemoveOld(
74 PacketFeedback(creation_time_ms, sequence_number, length, local_net_id_,
75 remote_net_id_, pacing_info));
nisse284542b2017-01-10 08:58:32 -080076 }
elad.alond12a8e12017-03-23 11:04:48 -070077
78 {
79 rtc::CritScope cs(&observers_lock_);
80 for (auto observer : observers_) {
81 observer->OnPacketAdded(ssrc, sequence_number);
82 }
83 }
sprang5e023eb2015-09-14 06:42:43 -070084}
85
stefanbbe876f2015-10-23 02:05:40 -070086void TransportFeedbackAdapter::OnSentPacket(uint16_t sequence_number,
87 int64_t send_time_ms) {
stefanc1aeaf02015-10-15 07:26:07 -070088 rtc::CritScope cs(&lock_);
stefanbbe876f2015-10-23 02:05:40 -070089 send_time_history_.OnSentPacket(sequence_number, send_time_ms);
stefanc1aeaf02015-10-15 07:26:07 -070090}
91
nisse284542b2017-01-10 08:58:32 -080092void TransportFeedbackAdapter::SetTransportOverhead(
93 int transport_overhead_bytes_per_packet) {
94 rtc::CritScope cs(&lock_);
95 transport_overhead_bytes_per_packet_ = transport_overhead_bytes_per_packet;
96}
97
Stefan Holmer9ea46b52017-03-15 12:40:25 +010098void TransportFeedbackAdapter::SetNetworkIds(uint16_t local_id,
99 uint16_t remote_id) {
philipelcb9ba302017-03-07 06:30:59 -0800100 rtc::CritScope cs(&lock_);
Stefan Holmer9ea46b52017-03-15 12:40:25 +0100101 local_net_id_ = local_id;
102 remote_net_id_ = remote_id;
philipelcb9ba302017-03-07 06:30:59 -0800103}
104
elad.alonf9490002017-03-06 05:32:21 -0800105std::vector<PacketFeedback> TransportFeedbackAdapter::GetPacketFeedbackVector(
sprang5e023eb2015-09-14 06:42:43 -0700106 const rtcp::TransportFeedback& feedback) {
107 int64_t timestamp_us = feedback.GetBaseTimeUs();
stefan9e117c5e12017-08-16 08:16:25 -0700108 int64_t now_ms = clock_->TimeInMilliseconds();
sprang5e023eb2015-09-14 06:42:43 -0700109 // Add timestamp deltas to a local time base selected on first packet arrival.
110 // This won't be the true time base, but makes it easier to manually inspect
111 // time stamps.
112 if (last_timestamp_us_ == kNoTimestamp) {
stefan9e117c5e12017-08-16 08:16:25 -0700113 current_offset_ms_ = now_ms;
sprang5e023eb2015-09-14 06:42:43 -0700114 } else {
115 int64_t delta = timestamp_us - last_timestamp_us_;
116
117 // Detect and compensate for wrap-arounds in base time.
118 if (std::abs(delta - kBaseTimestampRangeSizeUs) < std::abs(delta)) {
119 delta -= kBaseTimestampRangeSizeUs; // Wrap backwards.
120 } else if (std::abs(delta + kBaseTimestampRangeSizeUs) < std::abs(delta)) {
121 delta += kBaseTimestampRangeSizeUs; // Wrap forwards.
122 }
123
124 current_offset_ms_ += delta / 1000;
125 }
126 last_timestamp_us_ = timestamp_us;
127
elad.alonf9490002017-03-06 05:32:21 -0800128 std::vector<PacketFeedback> packet_feedback_vector;
danilchapc1b693c2017-04-20 08:23:41 -0700129 if (feedback.GetPacketStatusCount() == 0) {
stefane3a55672017-02-13 09:08:22 -0800130 LOG(LS_INFO) << "Empty transport feedback packet received.";
131 return packet_feedback_vector;
132 }
danilchapc1b693c2017-04-20 08:23:41 -0700133 packet_feedback_vector.reserve(feedback.GetPacketStatusCount());
stefan9e117c5e12017-08-16 08:16:25 -0700134 int64_t feedback_rtt = -1;
sprang5e023eb2015-09-14 06:42:43 -0700135 {
136 rtc::CritScope cs(&lock_);
137 size_t failed_lookups = 0;
138 int64_t offset_us = 0;
stefane3a55672017-02-13 09:08:22 -0800139 int64_t timestamp_ms = 0;
elad.alonec304f92017-03-08 05:03:53 -0800140 uint16_t seq_num = feedback.GetBaseSequence();
danilchapc1b693c2017-04-20 08:23:41 -0700141 for (const auto& packet : feedback.GetReceivedPackets()) {
elad.alonec304f92017-03-08 05:03:53 -0800142 // Insert into the vector those unreceived packets which precede this
143 // iteration's received packet.
144 for (; seq_num != packet.sequence_number(); ++seq_num) {
145 PacketFeedback packet_feedback(PacketFeedback::kNotReceived, seq_num);
146 // Note: Element not removed from history because it might be reported
147 // as received by another feedback.
148 if (!send_time_history_.GetFeedback(&packet_feedback, false))
149 ++failed_lookups;
Stefan Holmer9ea46b52017-03-15 12:40:25 +0100150 if (packet_feedback.local_net_id == local_net_id_ &&
151 packet_feedback.remote_net_id == remote_net_id_) {
152 packet_feedback_vector.push_back(packet_feedback);
153 }
elad.alonec304f92017-03-08 05:03:53 -0800154 }
155
156 // Handle this iteration's received packet.
danilchap4a0c7642017-01-18 02:40:30 -0800157 offset_us += packet.delta_us();
stefane3a55672017-02-13 09:08:22 -0800158 timestamp_ms = current_offset_ms_ + (offset_us / 1000);
elad.alonf9490002017-03-06 05:32:21 -0800159 PacketFeedback packet_feedback(timestamp_ms, packet.sequence_number());
160 if (!send_time_history_.GetFeedback(&packet_feedback, true))
danilchap4a0c7642017-01-18 02:40:30 -0800161 ++failed_lookups;
Stefan Holmer9ea46b52017-03-15 12:40:25 +0100162 if (packet_feedback.local_net_id == local_net_id_ &&
163 packet_feedback.remote_net_id == remote_net_id_) {
stefan9e117c5e12017-08-16 08:16:25 -0700164 if (packet_feedback.send_time_ms >= 0) {
165 int64_t rtt = now_ms - packet_feedback.send_time_ms;
166 // max() is used to account for feedback being delayed by the
167 // receiver.
168 feedback_rtt = std::max(rtt, feedback_rtt);
169 }
Stefan Holmer9ea46b52017-03-15 12:40:25 +0100170 packet_feedback_vector.push_back(packet_feedback);
171 }
elad.alonec304f92017-03-08 05:03:53 -0800172
173 ++seq_num;
sprang5e023eb2015-09-14 06:42:43 -0700174 }
elad.alonec304f92017-03-08 05:03:53 -0800175
sprang5e023eb2015-09-14 06:42:43 -0700176 if (failed_lookups > 0) {
177 LOG(LS_WARNING) << "Failed to lookup send time for " << failed_lookups
178 << " packet" << (failed_lookups > 1 ? "s" : "")
179 << ". Send time history too small?";
180 }
stefan9e117c5e12017-08-16 08:16:25 -0700181 if (feedback_rtt > -1) {
182 feedback_rtts_.push_back(feedback_rtt);
183 const size_t kFeedbackRttWindow = 32;
184 if (feedback_rtts_.size() > kFeedbackRttWindow)
185 feedback_rtts_.pop_front();
186 min_feedback_rtt_.emplace(
187 *std::min_element(feedback_rtts_.begin(), feedback_rtts_.end()));
188 }
sprang5e023eb2015-09-14 06:42:43 -0700189 }
stefanc3de0332016-08-02 07:22:17 -0700190 return packet_feedback_vector;
191}
Erik Språng6b8d3552015-09-24 15:06:57 +0200192
stefanc3de0332016-08-02 07:22:17 -0700193void TransportFeedbackAdapter::OnTransportFeedback(
194 const rtcp::TransportFeedback& feedback) {
Stefan Holmer60e43462016-09-07 09:58:20 +0200195 last_packet_feedback_vector_ = GetPacketFeedbackVector(feedback);
elad.alond12a8e12017-03-23 11:04:48 -0700196 {
197 rtc::CritScope cs(&observers_lock_);
198 for (auto observer : observers_) {
199 observer->OnPacketFeedbackVector(last_packet_feedback_vector_);
200 }
201 }
Stefan Holmer60e43462016-09-07 09:58:20 +0200202}
203
elad.alonf9490002017-03-06 05:32:21 -0800204std::vector<PacketFeedback>
205TransportFeedbackAdapter::GetTransportFeedbackVector() const {
Stefan Holmer60e43462016-09-07 09:58:20 +0200206 return last_packet_feedback_vector_;
sprang5e023eb2015-09-14 06:42:43 -0700207}
stefan9e117c5e12017-08-16 08:16:25 -0700208
209rtc::Optional<int64_t> TransportFeedbackAdapter::GetMinFeedbackLoopRtt() const {
210 rtc::CritScope cs(&lock_);
211 return min_feedback_rtt_;
212}
213
214size_t TransportFeedbackAdapter::GetOutstandingBytes() const {
215 rtc::CritScope cs(&lock_);
216 return send_time_history_.GetOutstandingBytes(local_net_id_, remote_net_id_);
217}
sprang5e023eb2015-09-14 06:42:43 -0700218} // namespace webrtc