sprang | 233bd87 | 2015-09-08 20:25:16 | [diff] [blame] | 1 | /* |
| 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 | |
sprang | 9eb3d5d | 2016-08-02 09:00:25 | [diff] [blame] | 13 | #include <limits> |
| 14 | |
sprang | 233bd87 | 2015-09-08 20:25:16 | [diff] [blame] | 15 | #include "webrtc/base/checks.h" |
| 16 | #include "webrtc/base/logging.h" |
Henrik Kjellander | 98f5351 | 2015-10-28 17:17:40 | [diff] [blame] | 17 | #include "webrtc/system_wrappers/include/clock.h" |
Henrik Kjellander | 0b9e29c | 2015-11-16 10:12:24 | [diff] [blame] | 18 | #include "webrtc/modules/pacing/packet_router.h" |
sprang | 233bd87 | 2015-09-08 20:25:16 | [diff] [blame] | 19 | #include "webrtc/modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h" |
Henrik Kjellander | ff761fb | 2015-11-04 07:31:52 | [diff] [blame] | 20 | #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp.h" |
sprang | 233bd87 | 2015-09-08 20:25:16 | [diff] [blame] | 21 | |
| 22 | namespace webrtc { |
| 23 | |
| 24 | // TODO(sprang): Tune these! |
stefan | 13f6b8f | 2015-11-21 02:14:14 | [diff] [blame] | 25 | const int RemoteEstimatorProxy::kDefaultProcessIntervalMs = 50; |
sprang | 233bd87 | 2015-09-08 20:25:16 | [diff] [blame] | 26 | const int RemoteEstimatorProxy::kBackWindowMs = 500; |
| 27 | |
sprang | 9eb3d5d | 2016-08-02 09:00:25 | [diff] [blame] | 28 | // The maximum allowed value for a timestamp in milliseconds. This is lower |
| 29 | // than the numerical limit since we often convert to microseconds. |
| 30 | static constexpr int64_t kMaxTimeMs = |
| 31 | std::numeric_limits<int64_t>::max() / 1000; |
| 32 | |
sprang | 233bd87 | 2015-09-08 20:25:16 | [diff] [blame] | 33 | RemoteEstimatorProxy::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 | |
| 42 | RemoteEstimatorProxy::~RemoteEstimatorProxy() {} |
| 43 | |
| 44 | void 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 | |
| 51 | void RemoteEstimatorProxy::IncomingPacket(int64_t arrival_time_ms, |
| 52 | size_t payload_size, |
pbos | 2169d8b | 2016-06-20 18:53:02 | [diff] [blame] | 53 | const RTPHeader& header) { |
stefan | bbe876f | 2015-10-23 09:05:40 | [diff] [blame] | 54 | if (!header.extension.hasTransportSequenceNumber) { |
| 55 | LOG(LS_WARNING) << "RemoteEstimatorProxy: Incoming packet " |
| 56 | "is missing the transport sequence number extension!"; |
| 57 | return; |
| 58 | } |
sprang | 233bd87 | 2015-09-08 20:25:16 | [diff] [blame] | 59 | rtc::CritScope cs(&lock_); |
| 60 | media_ssrc_ = header.ssrc; |
Stefan Holmer | 62a5ccd | 2016-02-16 16:07:21 | [diff] [blame] | 61 | |
sprang | 233bd87 | 2015-09-08 20:25:16 | [diff] [blame] | 62 | OnPacketArrival(header.extension.transportSequenceNumber, arrival_time_ms); |
| 63 | } |
| 64 | |
sprang | 233bd87 | 2015-09-08 20:25:16 | [diff] [blame] | 65 | bool RemoteEstimatorProxy::LatestEstimate(std::vector<unsigned int>* ssrcs, |
| 66 | unsigned int* bitrate_bps) const { |
| 67 | return false; |
| 68 | } |
| 69 | |
sprang | 233bd87 | 2015-09-08 20:25:16 | [diff] [blame] | 70 | int64_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 | |
pbos | a26ac92 | 2016-02-25 12:50:01 | [diff] [blame] | 80 | void RemoteEstimatorProxy::Process() { |
sprang | 233bd87 | 2015-09-08 20:25:16 | [diff] [blame] | 81 | 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)) { |
henrikg | 91d6ede | 2015-09-17 07:24:34 | [diff] [blame] | 87 | RTC_DCHECK(packet_router_ != nullptr); |
sprang | 233bd87 | 2015-09-08 20:25:16 | [diff] [blame] | 88 | packet_router_->SendFeedback(&feedback_packet); |
| 89 | } else { |
| 90 | more_to_build = false; |
| 91 | } |
| 92 | } |
sprang | 233bd87 | 2015-09-08 20:25:16 | [diff] [blame] | 93 | } |
| 94 | |
| 95 | void RemoteEstimatorProxy::OnPacketArrival(uint16_t sequence_number, |
| 96 | int64_t arrival_time) { |
sprang | 9eb3d5d | 2016-08-02 09:00:25 | [diff] [blame] | 97 | if (arrival_time < 0 || arrival_time > kMaxTimeMs) { |
| 98 | LOG(LS_WARNING) << "Arrival time out of bounds: " << arrival_time; |
| 99 | return; |
| 100 | } |
| 101 | |
stefan | 159a2fe | 2016-07-18 11:14:11 | [diff] [blame] | 102 | // 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. |
sprang | 233bd87 | 2015-09-08 20:25:16 | [diff] [blame] | 106 | int64_t seq = unwrapper_.Unwrap(sequence_number); |
stefan | 159a2fe | 2016-07-18 11:14:11 | [diff] [blame] | 107 | 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 | } |
sprang | 233bd87 | 2015-09-08 20:25:16 | [diff] [blame] | 114 | |
Erik Språng | 956ed71 | 2016-07-05 10:00:56 | [diff] [blame] | 115 | if (packet_arrival_times_.lower_bound(window_start_seq_) == |
| 116 | packet_arrival_times_.end()) { |
sprang | 233bd87 | 2015-09-08 20:25:16 | [diff] [blame] | 117 | // 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ång | 956ed71 | 2016-07-05 10:00:56 | [diff] [blame] | 125 | } |
| 126 | |
| 127 | if (window_start_seq_ == -1) { |
| 128 | window_start_seq_ = sequence_number; |
sprang | 233bd87 | 2015-09-08 20:25:16 | [diff] [blame] | 129 | } else if (seq < window_start_seq_) { |
| 130 | window_start_seq_ = seq; |
| 131 | } |
| 132 | |
Stefan Holmer | 91c5b56 | 2016-02-25 11:35:15 | [diff] [blame] | 133 | // 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 Holmer | 62a5ccd | 2016-02-16 16:07:21 | [diff] [blame] | 136 | |
sprang | 233bd87 | 2015-09-08 20:25:16 | [diff] [blame] | 137 | packet_arrival_times_[seq] = arrival_time; |
| 138 | } |
| 139 | |
| 140 | bool RemoteEstimatorProxy::BuildFeedbackPacket( |
| 141 | rtcp::TransportFeedback* feedback_packet) { |
sprang | 233bd87 | 2015-09-08 20:25:16 | [diff] [blame] | 142 | // 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ång | 956ed71 | 2016-07-05 10:00:56 | [diff] [blame] | 145 | 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 | } |
sprang | 233bd87 | 2015-09-08 20:25:16 | [diff] [blame] | 151 | |
| 152 | // TODO(sprang): Measure receive times in microseconds and remove the |
| 153 | // conversions below. |
Erik Språng | 956ed71 | 2016-07-05 10:00:56 | [diff] [blame] | 154 | const int64_t first_sequence = it->first; |
sprang | 233bd87 | 2015-09-08 20:25:16 | [diff] [blame] | 155 | feedback_packet->WithMediaSourceSsrc(media_ssrc_); |
Erik Språng | 956ed71 | 2016-07-05 10:00:56 | [diff] [blame] | 156 | // 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), |
sprang | 233bd87 | 2015-09-08 20:25:16 | [diff] [blame] | 160 | 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ång | 956ed71 | 2016-07-05 10:00:56 | [diff] [blame] | 167 | RTC_CHECK_NE(first_sequence, it->first); |
sprang | 233bd87 | 2015-09-08 20:25:16 | [diff] [blame] | 168 | |
| 169 | // Could not add timestamp, feedback packet might be full. Return and |
| 170 | // try again with a fresh packet. |
sprang | 233bd87 | 2015-09-08 20:25:16 | [diff] [blame] | 171 | break; |
| 172 | } |
Erik Språng | 956ed71 | 2016-07-05 10:00:56 | [diff] [blame] | 173 | |
sprang | 233bd87 | 2015-09-08 20:25:16 | [diff] [blame] | 174 | // 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ång | 956ed71 | 2016-07-05 10:00:56 | [diff] [blame] | 177 | window_start_seq_ = it->first + 1; |
sprang | 233bd87 | 2015-09-08 20:25:16 | [diff] [blame] | 178 | } |
sprang | 233bd87 | 2015-09-08 20:25:16 | [diff] [blame] | 179 | |
| 180 | return true; |
| 181 | } |
| 182 | |
| 183 | } // namespace webrtc |