blob: ec37c8805058a839e7fb0069f8834fafe123b813 [file] [log] [blame]
sprang233bd872015-09-08 20:25:161/*
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
11#include "webrtc/modules/remote_bitrate_estimator/remote_estimator_proxy.h"
12
sprang9eb3d5d2016-08-02 09:00:2513#include <limits>
14
sprang233bd872015-09-08 20:25:1615#include "webrtc/base/checks.h"
16#include "webrtc/base/logging.h"
Henrik Kjellander98f53512015-10-28 17:17:4017#include "webrtc/system_wrappers/include/clock.h"
Henrik Kjellander0b9e29c2015-11-16 10:12:2418#include "webrtc/modules/pacing/packet_router.h"
sprang233bd872015-09-08 20:25:1619#include "webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
Henrik Kjellanderff761fb2015-11-04 07:31:5220#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp.h"
sprang233bd872015-09-08 20:25:1621
22namespace webrtc {
23
24// TODO(sprang): Tune these!
stefan13f6b8f2015-11-21 02:14:1425const int RemoteEstimatorProxy::kDefaultProcessIntervalMs = 50;
sprang233bd872015-09-08 20:25:1626const int RemoteEstimatorProxy::kBackWindowMs = 500;
27
sprang9eb3d5d2016-08-02 09:00:2528// The maximum allowed value for a timestamp in milliseconds. This is lower
29// than the numerical limit since we often convert to microseconds.
30static constexpr int64_t kMaxTimeMs =
31 std::numeric_limits<int64_t>::max() / 1000;
32
sprang233bd872015-09-08 20:25:1633RemoteEstimatorProxy::RemoteEstimatorProxy(Clock* clock,
34 PacketRouter* packet_router)
35 : clock_(clock),
36 packet_router_(packet_router),
37 last_process_time_ms_(-1),
38 media_ssrc_(0),
39 feedback_sequence_(0),
40 window_start_seq_(-1) {}
41
42RemoteEstimatorProxy::~RemoteEstimatorProxy() {}
43
44void RemoteEstimatorProxy::IncomingPacketFeedbackVector(
45 const std::vector<PacketInfo>& packet_feedback_vector) {
46 rtc::CritScope cs(&lock_);
47 for (PacketInfo info : packet_feedback_vector)
48 OnPacketArrival(info.sequence_number, info.arrival_time_ms);
49}
50
51void RemoteEstimatorProxy::IncomingPacket(int64_t arrival_time_ms,
52 size_t payload_size,
pbos2169d8b2016-06-20 18:53:0253 const RTPHeader& header) {
stefanbbe876f2015-10-23 09:05:4054 if (!header.extension.hasTransportSequenceNumber) {
55 LOG(LS_WARNING) << "RemoteEstimatorProxy: Incoming packet "
56 "is missing the transport sequence number extension!";
57 return;
58 }
sprang233bd872015-09-08 20:25:1659 rtc::CritScope cs(&lock_);
60 media_ssrc_ = header.ssrc;
Stefan Holmer62a5ccd2016-02-16 16:07:2161
sprang233bd872015-09-08 20:25:1662 OnPacketArrival(header.extension.transportSequenceNumber, arrival_time_ms);
63}
64
sprang233bd872015-09-08 20:25:1665bool RemoteEstimatorProxy::LatestEstimate(std::vector<unsigned int>* ssrcs,
66 unsigned int* bitrate_bps) const {
67 return false;
68}
69
sprang233bd872015-09-08 20:25:1670int64_t RemoteEstimatorProxy::TimeUntilNextProcess() {
71 int64_t now = clock_->TimeInMilliseconds();
72 int64_t time_until_next = 0;
73 if (last_process_time_ms_ != -1 &&
74 now - last_process_time_ms_ < kDefaultProcessIntervalMs) {
75 time_until_next = (last_process_time_ms_ + kDefaultProcessIntervalMs - now);
76 }
77 return time_until_next;
78}
79
pbosa26ac922016-02-25 12:50:0180void RemoteEstimatorProxy::Process() {
sprang233bd872015-09-08 20:25:1681 last_process_time_ms_ = clock_->TimeInMilliseconds();
82
83 bool more_to_build = true;
84 while (more_to_build) {
85 rtcp::TransportFeedback feedback_packet;
86 if (BuildFeedbackPacket(&feedback_packet)) {
henrikg91d6ede2015-09-17 07:24:3487 RTC_DCHECK(packet_router_ != nullptr);
sprang233bd872015-09-08 20:25:1688 packet_router_->SendFeedback(&feedback_packet);
89 } else {
90 more_to_build = false;
91 }
92 }
sprang233bd872015-09-08 20:25:1693}
94
95void RemoteEstimatorProxy::OnPacketArrival(uint16_t sequence_number,
96 int64_t arrival_time) {
sprang9eb3d5d2016-08-02 09:00:2597 if (arrival_time < 0 || arrival_time > kMaxTimeMs) {
98 LOG(LS_WARNING) << "Arrival time out of bounds: " << arrival_time;
99 return;
100 }
101
stefan159a2fe2016-07-18 11:14:11102 // TODO(holmer): We should handle a backwards wrap here if the first
103 // sequence number was small and the new sequence number is large. The
104 // SequenceNumberUnwrapper doesn't do this, so we should replace this with
105 // calls to IsNewerSequenceNumber instead.
sprang233bd872015-09-08 20:25:16106 int64_t seq = unwrapper_.Unwrap(sequence_number);
stefan159a2fe2016-07-18 11:14:11107 if (seq > window_start_seq_ + 0xFFFF / 2) {
108 LOG(LS_WARNING) << "Skipping this sequence number (" << sequence_number
109 << ") since it likely is reordered, but the unwrapper"
110 "failed to handle it. Feedback window starts at "
111 << window_start_seq_ << ".";
112 return;
113 }
sprang233bd872015-09-08 20:25:16114
Erik Språng956ed712016-07-05 10:00:56115 if (packet_arrival_times_.lower_bound(window_start_seq_) ==
116 packet_arrival_times_.end()) {
sprang233bd872015-09-08 20:25:16117 // Start new feedback packet, cull old packets.
118 for (auto it = packet_arrival_times_.begin();
119 it != packet_arrival_times_.end() && it->first < seq &&
120 arrival_time - it->second >= kBackWindowMs;) {
121 auto delete_it = it;
122 ++it;
123 packet_arrival_times_.erase(delete_it);
124 }
Erik Språng956ed712016-07-05 10:00:56125 }
126
127 if (window_start_seq_ == -1) {
128 window_start_seq_ = sequence_number;
sprang233bd872015-09-08 20:25:16129 } else if (seq < window_start_seq_) {
130 window_start_seq_ = seq;
131 }
132
Stefan Holmer91c5b562016-02-25 11:35:15133 // We are only interested in the first time a packet is received.
134 if (packet_arrival_times_.find(seq) != packet_arrival_times_.end())
135 return;
Stefan Holmer62a5ccd2016-02-16 16:07:21136
sprang233bd872015-09-08 20:25:16137 packet_arrival_times_[seq] = arrival_time;
138}
139
140bool RemoteEstimatorProxy::BuildFeedbackPacket(
141 rtcp::TransportFeedback* feedback_packet) {
sprang233bd872015-09-08 20:25:16142 // window_start_seq_ is the first sequence number to include in the current
143 // feedback packet. Some older may still be in the map, in case a reordering
144 // happens and we need to retransmit them.
Erik Språng956ed712016-07-05 10:00:56145 rtc::CritScope cs(&lock_);
146 auto it = packet_arrival_times_.lower_bound(window_start_seq_);
147 if (it == packet_arrival_times_.end()) {
148 // Feedback for all packets already sent.
149 return false;
150 }
sprang233bd872015-09-08 20:25:16151
152 // TODO(sprang): Measure receive times in microseconds and remove the
153 // conversions below.
Erik Språng956ed712016-07-05 10:00:56154 const int64_t first_sequence = it->first;
sprang233bd872015-09-08 20:25:16155 feedback_packet->WithMediaSourceSsrc(media_ssrc_);
Erik Språng956ed712016-07-05 10:00:56156 // Base sequence is the expected next (window_start_seq_). This is known, but
157 // we might not have actually received it, so the base time shall be the time
158 // of the first received packet in the feedback.
159 feedback_packet->WithBase(static_cast<uint16_t>(window_start_seq_ & 0xFFFF),
sprang233bd872015-09-08 20:25:16160 it->second * 1000);
161 feedback_packet->WithFeedbackSequenceNumber(feedback_sequence_++);
162 for (; it != packet_arrival_times_.end(); ++it) {
163 if (!feedback_packet->WithReceivedPacket(
164 static_cast<uint16_t>(it->first & 0xFFFF), it->second * 1000)) {
165 // If we can't even add the first seq to the feedback packet, we won't be
166 // able to build it at all.
Erik Språng956ed712016-07-05 10:00:56167 RTC_CHECK_NE(first_sequence, it->first);
sprang233bd872015-09-08 20:25:16168
169 // Could not add timestamp, feedback packet might be full. Return and
170 // try again with a fresh packet.
sprang233bd872015-09-08 20:25:16171 break;
172 }
Erik Språng956ed712016-07-05 10:00:56173
sprang233bd872015-09-08 20:25:16174 // Note: Don't erase items from packet_arrival_times_ after sending, in case
175 // they need to be re-sent after a reordering. Removal will be handled
176 // by OnPacketArrival once packets are too old.
Erik Språng956ed712016-07-05 10:00:56177 window_start_seq_ = it->first + 1;
sprang233bd872015-09-08 20:25:16178 }
sprang233bd872015-09-08 20:25:16179
180 return true;
181}
182
183} // namespace webrtc