|  | /* | 
|  | *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved. | 
|  | * | 
|  | *  Use of this source code is governed by a BSD-style license | 
|  | *  that can be found in the LICENSE file in the root of the source | 
|  | *  tree. An additional intellectual property rights grant can be found | 
|  | *  in the file PATENTS.  All contributing project authors may | 
|  | *  be found in the AUTHORS file in the root of the source tree. | 
|  | */ | 
|  | #ifndef MODULES_REMOTE_BITRATE_ESTIMATOR_PACKET_ARRIVAL_MAP_H_ | 
|  | #define MODULES_REMOTE_BITRATE_ESTIMATOR_PACKET_ARRIVAL_MAP_H_ | 
|  |  | 
|  | #include <algorithm> | 
|  | #include <cstddef> | 
|  | #include <cstdint> | 
|  | #include <memory> | 
|  |  | 
|  | #include "api/units/timestamp.h" | 
|  | #include "rtc_base/checks.h" | 
|  |  | 
|  | namespace webrtc { | 
|  |  | 
|  | // PacketArrivalTimeMap is an optimized map of packet sequence number to arrival | 
|  | // time, limited in size to never exceed `kMaxNumberOfPackets`. It will grow as | 
|  | // needed, and remove old packets, and will expand to allow earlier packets to | 
|  | // be added (out-of-order). | 
|  | // | 
|  | // Not yet received packets have the arrival time zero. The queue will not span | 
|  | // larger than necessary and the last packet should always be received. The | 
|  | // first packet in the queue doesn't have to be received in case of receiving | 
|  | // packets out-of-order. | 
|  | class PacketArrivalTimeMap { | 
|  | public: | 
|  | struct PacketArrivalTime { | 
|  | Timestamp arrival_time; | 
|  | int64_t sequence_number; | 
|  | }; | 
|  | // Impossible to request feedback older than what can be represented by 15 | 
|  | // bits. | 
|  | static constexpr int kMaxNumberOfPackets = (1 << 15); | 
|  |  | 
|  | PacketArrivalTimeMap() = default; | 
|  | PacketArrivalTimeMap(const PacketArrivalTimeMap&) = delete; | 
|  | PacketArrivalTimeMap& operator=(const PacketArrivalTimeMap&) = delete; | 
|  | ~PacketArrivalTimeMap() = default; | 
|  |  | 
|  | // Indicates if the packet with `sequence_number` has already been received. | 
|  | bool has_received(int64_t sequence_number) const { | 
|  | return sequence_number >= begin_sequence_number() && | 
|  | sequence_number < end_sequence_number() && | 
|  | arrival_times_[Index(sequence_number)] >= Timestamp::Zero(); | 
|  | } | 
|  |  | 
|  | // Returns the sequence number of the first entry in the map, i.e. the | 
|  | // sequence number that a `begin()` iterator would represent. | 
|  | int64_t begin_sequence_number() const { return begin_sequence_number_; } | 
|  |  | 
|  | // Returns the sequence number of the element just after the map, i.e. the | 
|  | // sequence number that an `end()` iterator would represent. | 
|  | int64_t end_sequence_number() const { return end_sequence_number_; } | 
|  |  | 
|  | // Returns an element by `sequence_number`, which must be valid, i.e. | 
|  | // between [begin_sequence_number, end_sequence_number). | 
|  | Timestamp get(int64_t sequence_number) { | 
|  | RTC_DCHECK_GE(sequence_number, begin_sequence_number()); | 
|  | RTC_DCHECK_LT(sequence_number, end_sequence_number()); | 
|  | return arrival_times_[Index(sequence_number)]; | 
|  | } | 
|  |  | 
|  | // Returns timestamp and sequence number of the received packet with sequence | 
|  | // number equal or larger than `sequence_number`. `sequence_number` must be in | 
|  | // range [begin_sequence_number, end_sequence_number). | 
|  | PacketArrivalTime FindNextAtOrAfter(int64_t sequence_number) const { | 
|  | RTC_DCHECK_GE(sequence_number, begin_sequence_number()); | 
|  | RTC_DCHECK_LT(sequence_number, end_sequence_number()); | 
|  | while (true) { | 
|  | Timestamp t = arrival_times_[Index(sequence_number)]; | 
|  | if (t >= Timestamp::Zero()) { | 
|  | return {.arrival_time = t, .sequence_number = sequence_number}; | 
|  | } | 
|  | ++sequence_number; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Clamps `sequence_number` between [begin_sequence_number, | 
|  | // end_sequence_number]. | 
|  | int64_t clamp(int64_t sequence_number) const { | 
|  | return std::clamp(sequence_number, begin_sequence_number(), | 
|  | end_sequence_number()); | 
|  | } | 
|  |  | 
|  | // Erases all elements from the beginning of the map until `sequence_number`. | 
|  | void EraseTo(int64_t sequence_number); | 
|  |  | 
|  | // Records the fact that a packet with `sequence_number` arrived at | 
|  | // `arrival_time_ms`. | 
|  | void AddPacket(int64_t sequence_number, Timestamp arrival_time); | 
|  |  | 
|  | // Removes packets from the beginning of the map as long as they are received | 
|  | // before `sequence_number` and with an age older than `arrival_time_limit` | 
|  | void RemoveOldPackets(int64_t sequence_number, Timestamp arrival_time_limit); | 
|  |  | 
|  | private: | 
|  | static constexpr int kMinCapacity = 128; | 
|  |  | 
|  | // Returns index in the `arrival_times_` for value for `sequence_number`. | 
|  | int Index(int64_t sequence_number) const { | 
|  | // Note that sequence_number might be negative, thus taking '%' requires | 
|  | // extra handling and can be slow. Because capacity is a power of two, it | 
|  | // is much faster to use '&' operator. | 
|  | return sequence_number & capacity_minus_1_; | 
|  | } | 
|  |  | 
|  | void SetNotReceived(int64_t begin_sequence_number_inclusive, | 
|  | int64_t end_sequence_number_exclusive); | 
|  |  | 
|  | // Adjust capacity to match new_size, may reduce capacity. | 
|  | // On return guarantees capacity >= new_size. | 
|  | void AdjustToSize(int new_size); | 
|  | void Reallocate(int new_capacity); | 
|  |  | 
|  | int capacity() const { return capacity_minus_1_ + 1; } | 
|  | bool has_seen_packet() const { return arrival_times_ != nullptr; } | 
|  |  | 
|  | // Circular buffer. Packet with sequence number `sequence_number` | 
|  | // is stored in the slot `sequence_number % capacity_` | 
|  | std::unique_ptr<Timestamp[]> arrival_times_ = nullptr; | 
|  |  | 
|  | // Allocated size of the `arrival_times_` | 
|  | // capacity_ is a power of 2 in range [kMinCapacity, kMaxNumberOfPackets] | 
|  | // `capacity - 1` is used much more often than `capacity`, thus that value is | 
|  | // stored. | 
|  | int capacity_minus_1_ = -1; | 
|  |  | 
|  | // The unwrapped sequence number for valid range of sequence numbers. | 
|  | // arrival_times_ entries only valid for sequence numbers in range | 
|  | // `begin_sequence_number_ <= sequence_number < end_sequence_number_` | 
|  | int64_t begin_sequence_number_ = 0; | 
|  | int64_t end_sequence_number_ = 0; | 
|  | }; | 
|  |  | 
|  | }  // namespace webrtc | 
|  |  | 
|  | #endif  // MODULES_REMOTE_BITRATE_ESTIMATOR_PACKET_ARRIVAL_MAP_H_ |